Version 1.2.0-dev.3.0
svn merge -r 32187:32420 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@32426 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/client/tools/buildbot_annotated_steps.py b/client/tools/buildbot_annotated_steps.py
index a6f1c1f..130d1e5 100755
--- a/client/tools/buildbot_annotated_steps.py
+++ b/client/tools/buildbot_annotated_steps.py
@@ -204,6 +204,8 @@
elif name.startswith('cross') or name.startswith('target'):
status = ProcessBot(name, 'cross-vm',
custom_env=EnvironmentWithoutBotoConfig())
+ elif name.startswith('src-tarball'):
+ status = ProcessBot(name, 'src-tarball')
else:
status = ProcessBot(name, 'compiler')
diff --git a/dart.gyp b/dart.gyp
index 914b088..0ed89c0 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -120,9 +120,6 @@
'target_name': 'api_docs',
'type': 'none',
'dependencies': [
- # TODO(alanknight) : Once we're fully switched over to the new
- # viewer remove the old api_docs gyp file.
- 'utils/apidoc/apidoc.gyp:api_docs',
'utils/apidoc/docgen.gyp:docgen',
],
},
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index 08d89ec..5827d47 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -55,7 +55,7 @@
* Return a request parsed from the given [data], or `null` if the [data] is
* not a valid json representation of a request. The [data] is expected to
* have the following format:
- *
+ *
* {
* 'id': String,
* 'method': methodName,
@@ -63,7 +63,7 @@
* paramter_name: value
* }
* }
- *
+ *
* where the parameters are optional and can contain any number of name/value
* pairs.
*/
@@ -115,7 +115,7 @@
/**
* Convert the given [value] to a boolean, or throw a [RequestFailure]
* exception if the [value] could not be converted.
- *
+ *
* The value is typically the result of invoking either [getParameter] or
* [getRequiredParameter].
*/
@@ -131,7 +131,7 @@
/**
* Convert the given [value] to an integer, or throw a [RequestFailure]
* exception if the [value] could not be converted.
- *
+ *
* The value is typically the result of invoking either [getParameter] or
* [getRequiredParameter].
*/
@@ -177,7 +177,7 @@
* The error that was caused by attempting to handle the request, or `null` if
* there was no error.
*/
- final Object error;
+ final RequestError error;
/**
* A table mapping the names of result fields to their values. The table
@@ -197,7 +197,7 @@
* by a [request] referencing a context that does not exist.
*/
Response.contextDoesNotExist(Request request)
- : this(request.id, 'Context does not exist');
+ : this(request.id, new RequestError(-1, 'Context does not exist'));
/**
* Initialize a newly created instance to represent an error condition caused
@@ -205,7 +205,7 @@
* passed a non-boolean value.
*/
Response.expectedBoolean(Request request, String value)
- : this(request.id, 'Expected a boolean value, but found "$value"');
+ : this(request.id, new RequestError(-2, 'Expected a boolean value, but found "$value"'));
/**
* Initialize a newly created instance to represent an error condition caused
@@ -213,21 +213,21 @@
* passed a non-integer value.
*/
Response.expectedInteger(Request request, String value)
- : this(request.id, 'Expected an integer value, but found "$value"');
+ : this(request.id, new RequestError(-3, 'Expected an integer value, but found "$value"'));
/**
* Initialize a newly created instance to represent an error condition caused
* by a malformed request.
*/
Response.invalidRequestFormat()
- : this('', 'Invalid request');
+ : this('', new RequestError(-4, 'Invalid request'));
/**
* Initialize a newly created instance to represent an error condition caused
* by a [request] that does not have a required parameter.
*/
Response.missingRequiredParameter(Request request, String parameterName)
- : this(request.id, 'Missing required parameter: $parameterName');
+ : this(request.id, new RequestError(-5, 'Missing required parameter: $parameterName'));
/**
* Initialize a newly created instance to represent an error condition caused
@@ -235,14 +235,14 @@
* unknown analysis option was provided.
*/
Response.unknownAnalysisOption(Request request, String optionName)
- : this(request.id, 'Unknown analysis option: "$optionName"');
+ : this(request.id, new RequestError(-6, 'Unknown analysis option: "$optionName"'));
/**
* Initialize a newly created instance to represent an error condition caused
* by a [request] that cannot be handled by any known handlers.
*/
Response.unknownRequest(Request request)
- : this(request.id, 'Unknown request');
+ : this(request.id, new RequestError(-7, 'Unknown request'));
/**
* Return the value of the result field with the given [name].
@@ -265,7 +265,11 @@
Map<String, Object> toJson() {
Map jsonObject = new Map();
jsonObject[ID] = id;
- jsonObject[ERROR] = error;
+ if (error == null) {
+ jsonObject[ERROR] = null;
+ } else {
+ jsonObject[ERROR] = error.toJson();
+ }
if (!result.isEmpty) {
jsonObject[RESULT] = result;
}
@@ -274,6 +278,139 @@
}
/**
+ * Instances of the class [RequestError] represent information about an error that
+ * occurred while attempting to respond to a [Request].
+ */
+class RequestError {
+ /**
+ * The name of the JSON attribute containing the code that uniquely identifies
+ * the error that occurred.
+ */
+ static const String CODE = 'code';
+
+ /**
+ * The name of the JSON attribute containing an object with additional data
+ * related to the error.
+ */
+ static const String DATA = 'data';
+
+ /**
+ * The name of the JSON attribute containing a short description of the error.
+ */
+ static const String MESSAGE = 'message';
+
+ /**
+ * An error code indicating a parse error. Invalid JSON was received by the
+ * server. An error occurred on the server while parsing the JSON text.
+ */
+ static const int CODE_PARSE_ERROR = -32700;
+
+ /**
+ * An error code indicating an invalid request. The JSON sent is not a valid
+ * [Request] object.
+ */
+ static const int CODE_INVALID_REQUEST = -32600;
+
+ /**
+ * An error code indicating a method not found. The method does not exist or
+ * is not currently available.
+ */
+ static const int CODE_METHOD_NOT_FOUND = -32601;
+
+ /**
+ * An error code indicating one or more invalid parameters.
+ */
+ static const int CODE_INVALID_PARAMS = -32602;
+
+ /**
+ * An error code indicating an internal error.
+ */
+ static const int CODE_INTERNAL_ERROR = -32603;
+
+ /*
+ * In addition, codes -32000 to -32099 indicate a server error. They are
+ * reserved for implementation-defined server-errors.
+ */
+
+ /**
+ * The code that uniquely identifies the error that occurred.
+ */
+ final int code;
+
+ /**
+ * A short description of the error.
+ */
+ final String message;
+
+ /**
+ * A table mapping the names of notification parameters to their values.
+ */
+ final Map<String, Object> data = new Map<String, Object>();
+
+ /**
+ * Initialize a newly created [Error] to have the given [code] and [message].
+ */
+ RequestError(this.code, this.message);
+
+ /**
+ * Initialize a newly created [Error] to indicate a parse error. Invalid JSON
+ * was received by the server. An error occurred on the server while parsing
+ * the JSON text.
+ */
+ RequestError.parseError() : this(CODE_PARSE_ERROR, "Parse error");
+
+ /**
+ * Initialize a newly created [Error] to indicate an invalid request. The
+ * JSON sent is not a valid [Request] object.
+ */
+ RequestError.invalidRequest() : this(CODE_INVALID_REQUEST, "Invalid request");
+
+ /**
+ * Initialize a newly created [Error] to indicate that a method was not found.
+ * Either the method does not exist or is not currently available.
+ */
+ RequestError.methodNotFound() : this(CODE_METHOD_NOT_FOUND, "Method not found");
+
+ /**
+ * Initialize a newly created [Error] to indicate one or more invalid
+ * parameters.
+ */
+ RequestError.invalidParameters() : this(CODE_INVALID_PARAMS, "Invalid parameters");
+
+ /**
+ * Initialize a newly created [Error] to indicate an internal error.
+ */
+ RequestError.internalError() : this(CODE_INTERNAL_ERROR, "Internal error");
+
+ /**
+ * Return the value of the data with the given [name], or `null` if there is
+ * no such data associated with this error.
+ */
+ Object getData(String name) => data[name];
+
+ /**
+ * Set the value of the data with the given [name] to the given [value].
+ */
+ void setData(String name, Object value) {
+ data[name] = value;
+ }
+
+ /**
+ * Return a table representing the structure of the Json object that will be
+ * sent to the client to represent this response.
+ */
+ Map<String, Object> toJson() {
+ Map jsonObject = new Map();
+ jsonObject[CODE] = code;
+ jsonObject[MESSAGE] = message;
+ if (!data.isEmpty) {
+ jsonObject[DATA] = data;
+ }
+ return jsonObject;
+ }
+}
+
+/**
* Instances of the class [Notification] represent a notification from the
* server about an event that occurred.
*/
diff --git a/pkg/analysis_server/test/protocol_test.dart b/pkg/analysis_server/test/protocol_test.dart
index 9909031..2bb24fd 100644
--- a/pkg/analysis_server/test/protocol_test.dart
+++ b/pkg/analysis_server/test/protocol_test.dart
@@ -61,7 +61,7 @@
expect(response.error, isNotNull);
expect(response.toJson(), equals({
Response.ID: '0',
- Response.ERROR: 'Context does not exist'
+ Response.ERROR: {'code': -1, 'message': 'Context does not exist'}
}));
}
@@ -71,7 +71,7 @@
expect(response.error, isNotNull);
expect(response.toJson(), equals({
Response.ID: '',
- Response.ERROR: 'Invalid request'
+ Response.ERROR: {'code': -4, 'message': 'Invalid request'}
}));
}
@@ -81,7 +81,7 @@
expect(response.error, isNotNull);
expect(response.toJson(), equals({
Response.ID: '0',
- Response.ERROR: 'Missing required parameter: x'
+ Response.ERROR: {'code': -5, 'message': 'Missing required parameter: x'}
}));
}
@@ -91,7 +91,7 @@
expect(response.error, isNotNull);
expect(response.toJson(), equals({
Response.ID: '0',
- Response.ERROR: 'Unknown request'
+ Response.ERROR: {'code': -7, 'message': 'Unknown request'}
}));
}
diff --git a/pkg/analyzer/bin/analyzer.dart b/pkg/analyzer/bin/analyzer.dart
index 2ce52a5..76510c0 100644
--- a/pkg/analyzer/bin/analyzer.dart
+++ b/pkg/analyzer/bin/analyzer.dart
@@ -47,13 +47,12 @@
print("angular:$angularTime");
print("other:${totalTime
- (scanTime + parseTime + resolveTime + errorsTime + hintsTime
- + angularTime)}}");
+ + angularTime)}");
print("total:$totalTime");
print("");
print("Time spent in instanceof = ${instanceOfTimer.elapsedMilliseconds}");
}
-
- exit(result.ordinal);
+ exitCode = result.ordinal;
}
}
diff --git a/pkg/analyzer/example/parser_driver.dart b/pkg/analyzer/example/parser_driver.dart
index e69197b..4c93836 100644
--- a/pkg/analyzer/example/parser_driver.dart
+++ b/pkg/analyzer/example/parser_driver.dart
@@ -6,7 +6,6 @@
import 'dart:io';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart';
@@ -31,7 +30,7 @@
_parse(File file) {
var src = file.readAsStringSync();
var errorListener = new _ErrorCollector();
- var reader = new CharSequenceReader(new CharSequence(src));
+ var reader = new CharSequenceReader(src);
var scanner = new Scanner(null, reader, errorListener);
var token = scanner.tokenize();
var parser = new Parser(null, errorListener);
diff --git a/pkg/analyzer/example/scanner_driver.dart b/pkg/analyzer/example/scanner_driver.dart
index a19c6eb..8eccee9 100644
--- a/pkg/analyzer/example/scanner_driver.dart
+++ b/pkg/analyzer/example/scanner_driver.dart
@@ -7,7 +7,6 @@
import 'dart:io';
import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
main(List<String> args) {
@@ -26,7 +25,7 @@
_scan(File file) {
var src = file.readAsStringSync();
- var reader = new CharSequenceReader(new CharSequence(src));
+ var reader = new CharSequenceReader(src);
var scanner = new Scanner(null, reader, null);
var token = scanner.tokenize();
while (token.type != TokenType.EOF) {
diff --git a/pkg/analyzer/lib/analyzer.dart b/pkg/analyzer/lib/analyzer.dart
index be32717..5572950 100644
--- a/pkg/analyzer/lib/analyzer.dart
+++ b/pkg/analyzer/lib/analyzer.dart
@@ -8,7 +8,6 @@
import 'package:path/path.dart' as pathos;
-import 'src/generated/java_core.dart' show CharSequence;
import 'src/error.dart';
import 'src/generated/ast.dart';
import 'src/generated/error.dart';
@@ -37,7 +36,7 @@
throw new ArgumentError("Source $source doesn't exist");
}
- var reader = new CharSequenceReader(new CharSequence(contents));
+ var reader = new CharSequenceReader(contents);
var scanner = new Scanner(source, reader, errorCollector);
var token = scanner.tokenize();
var parser = new Parser(source, errorCollector);
@@ -57,7 +56,7 @@
if (name == null) name = '<unknown source>';
var source = new StringSource(contents, name);
var errorCollector = new _ErrorCollector();
- var reader = new CharSequenceReader(new CharSequence(contents));
+ var reader = new CharSequenceReader(contents);
var scanner = new Scanner(source, reader, errorCollector);
var token = scanner.tokenize();
var parser = new Parser(source, errorCollector);
diff --git a/pkg/analyzer/lib/src/analyzer_impl.dart b/pkg/analyzer/lib/src/analyzer_impl.dart
index 7f79c5d..1c63f03 100644
--- a/pkg/analyzer/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer/lib/src/analyzer_impl.dart
@@ -6,6 +6,8 @@
import 'dart:io';
+import 'package:path/path.dart' as pathos;
+
import 'generated/java_io.dart';
import 'generated/engine.dart';
import 'generated/error.dart';
@@ -128,10 +130,9 @@
void addLibrarySources(LibraryElement library, Set<LibraryElement> libraries,
Set<CompilationUnitElement> units) {
- if (library == null || libraries.contains(library)) {
+ if (library == null || !libraries.add(library) ) {
return;
}
- libraries.add(library);
// may be skip library
{
UriKind uriKind = library.source.uriKind;
@@ -192,9 +193,14 @@
// may be file in SDK
if (sdk is DirectoryBasedDartSdk) {
DirectoryBasedDartSdk directoryBasedSdk = sdk;
- String sdkLibPath = directoryBasedSdk.libraryDirectory.getPath() + JavaFile.separator;
- if (file.getPath().startsWith(sdkLibPath)) {
- return UriKind.DART_URI;
+ var libraryDirectory = directoryBasedSdk.libraryDirectory.getAbsolutePath();
+ var sdkLibPath = libraryDirectory + pathos.separator;
+ var filePath = file.getPath();
+ if (filePath.startsWith(sdkLibPath)) {
+ var internalPath = pathos.join(libraryDirectory, '_internal') + pathos.separator;
+ if (!filePath.startsWith(internalPath)) {
+ return UriKind.DART_URI;
+ }
}
}
// some generic file
diff --git a/pkg/analyzer/lib/src/error.dart b/pkg/analyzer/lib/src/error.dart
index 5deee45..4c9b7af 100644
--- a/pkg/analyzer/lib/src/error.dart
+++ b/pkg/analyzer/lib/src/error.dart
@@ -7,7 +7,6 @@
import 'dart:math' as math;
import 'generated/error.dart';
-import 'generated/java_core.dart';
import 'generated/source.dart';
/// The maximum line length when printing extracted source code when converting
@@ -97,8 +96,6 @@
String get result => _buffer.toString();
- void accept(CharBuffer contents, _) =>
- _buffer.write(contents.subSequence(0, contents.length()));
-
- void accept2(String contents, _) => _buffer.write(contents);
+ void accept(String contents, _) =>
+ _buffer.write(contents.substring(0, contents.length));
}
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index b4c10ce..c7f631c 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -4281,6 +4281,11 @@
*/
abstract class Expression extends ASTNode {
/**
+ * An empty array of expressions.
+ */
+ static List<Expression> EMPTY_ARRAY = new List<Expression>(0);
+
+ /**
* The static type of this expression, or `null` if the AST structure has not been resolved.
*/
Type2 staticType;
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 4ecc945..597ceeb 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -1154,6 +1154,12 @@
*/
abstract class HtmlElement implements Element {
/**
+ * Return the [CompilationUnitElement] associated with this Angular HTML file, maybe
+ * `null` if not an Angular file.
+ */
+ CompilationUnitElement get angularCompilationUnit;
+
+ /**
* Return an array containing all of the script elements contained in the HTML file. This includes
* scripts with libraries that are defined by the content of a script tag as well as libraries
* that are referenced in the {@core source} attribute of a script tag.
@@ -1342,6 +1348,13 @@
bool hasExtUri();
/**
+ * Return `true` if this library is created for Angular analysis.
+ *
+ * @return `true` if this library is created for Angular analysis
+ */
+ bool get isAngularHtml;
+
+ /**
* Answer `true` if this library is an application that can be run in the browser.
*
* @return `true` if this library is an application that can be run in the browser
@@ -4177,37 +4190,39 @@
}
void appendTo(JavaStringBuilder builder) {
- builder.append("(");
- String closing = null;
- ParameterKind kind = ParameterKind.REQUIRED;
- int parameterCount = _parameters.length;
- for (int i = 0; i < parameterCount; i++) {
- if (i > 0) {
- builder.append(", ");
- }
- ParameterElementImpl parameter = _parameters[i] as ParameterElementImpl;
- ParameterKind parameterKind = parameter.parameterKind;
- if (parameterKind != kind) {
- if (closing != null) {
- builder.append(closing);
+ if (this.kind != ElementKind.GETTER) {
+ builder.append("(");
+ String closing = null;
+ ParameterKind kind = ParameterKind.REQUIRED;
+ int parameterCount = _parameters.length;
+ for (int i = 0; i < parameterCount; i++) {
+ if (i > 0) {
+ builder.append(", ");
}
- if (identical(parameterKind, ParameterKind.POSITIONAL)) {
- builder.append("[");
- closing = "]";
- } else if (identical(parameterKind, ParameterKind.NAMED)) {
- builder.append("{");
- closing = "}";
- } else {
- closing = null;
+ ParameterElementImpl parameter = _parameters[i] as ParameterElementImpl;
+ ParameterKind parameterKind = parameter.parameterKind;
+ if (parameterKind != kind) {
+ if (closing != null) {
+ builder.append(closing);
+ }
+ if (identical(parameterKind, ParameterKind.POSITIONAL)) {
+ builder.append("[");
+ closing = "]";
+ } else if (identical(parameterKind, ParameterKind.NAMED)) {
+ builder.append("{");
+ closing = "}";
+ } else {
+ closing = null;
+ }
}
+ kind = parameterKind;
+ parameter.appendToWithoutDelimiters(builder);
}
- kind = parameterKind;
- parameter.appendToWithoutDelimiters(builder);
+ if (closing != null) {
+ builder.append(closing);
+ }
+ builder.append(")");
}
- if (closing != null) {
- builder.append(closing);
- }
- builder.append(")");
if (type != null) {
builder.append(Element.RIGHT_ARROW);
builder.append(type.returnType);
@@ -4626,6 +4641,12 @@
Source source;
/**
+ * The element associated with Dart pieces in this HTML unit or `null` if the receiver is
+ * not resolved.
+ */
+ CompilationUnitElement angularCompilationUnit;
+
+ /**
* Initialize a newly created HTML element to have the given name.
*
* @param context the analysis context in which the HTML file is defined
@@ -4899,6 +4920,11 @@
List<CompilationUnitElement> _parts = CompilationUnitElementImpl.EMPTY_ARRAY;
/**
+ * Is `true` if this library is created for Angular analysis.
+ */
+ bool _isAngularHtml2 = false;
+
+ /**
* Initialize a newly created library element to have the given name.
*
* @param context the analysis context in which the library is defined
@@ -5015,6 +5041,8 @@
int get hashCode => _definingCompilationUnit.hashCode;
+ bool get isAngularHtml => _isAngularHtml2;
+
bool get isBrowserApplication => entryPoint != null && isOrImportsBrowserLibrary;
bool get isDartCore => name == "dart.core";
@@ -5027,6 +5055,13 @@
}
/**
+ * Specifies if this library is created for Angular analysis.
+ */
+ void set angularHtml(bool isAngularHtml) {
+ this._isAngularHtml2 = isAngularHtml;
+ }
+
+ /**
* Set the compilation unit that defines this library to the given compilation unit.
*
* @param definingCompilationUnit the compilation unit that defines this library
@@ -6244,6 +6279,11 @@
*/
class AngularComponentElementImpl extends AngularHasSelectorElementImpl implements AngularComponentElement {
/**
+ * The offset of the defining <code>NgComponent</code> annotation.
+ */
+ int _annotationOffset = 0;
+
+ /**
* The array containing all of the properties declared by this component.
*/
List<AngularPropertyElement> _properties = AngularPropertyElement.EMPTY_ARRAY;
@@ -6280,7 +6320,9 @@
* @param nameOffset the offset of the name of this element in the file that contains the
* declaration of this element
*/
- AngularComponentElementImpl(String name, int nameOffset) : super(name, nameOffset);
+ AngularComponentElementImpl(String name, int nameOffset, int annotationOffset) : super(name, nameOffset) {
+ this._annotationOffset = annotationOffset;
+ }
accept(ElementVisitor visitor) => visitor.visitAngularComponentElement(this);
@@ -6304,6 +6346,8 @@
safelyVisitChildren(_properties, visitor);
super.visitChildren(visitor);
}
+
+ String get identifier => "AngularComponent@${_annotationOffset}";
}
/**
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 1b226dc..a2cc12b 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -408,16 +408,6 @@
List<Source> getLibrariesDependingOn(Source librarySource);
/**
- * Return the [AngularElement]s accessible in the library defined by the given source, or an
- * empty array if given source is not a library, not resolved or cannot be analyzed for some
- * reason.
- *
- * @param source the source defining the library whose [AngularElement]s is to be returned
- * @return the [AngularElement]s accessible in the library defined by the given source
- */
- List<AngularElement> getLibraryAngularElements(Source source);
-
- /**
* Return the element model corresponding to the library defined by the given source, or
* `null` if the element model does not currently exist or if the library cannot be analyzed
* for some reason.
@@ -1015,11 +1005,11 @@
}
/**
- * Record that the given source was just accessed.
+ * Record that the AST associated with the given source was just read from the cache.
*
- * @param source the source that was accessed
+ * @param source the source whose AST was accessed
*/
- void accessed(Source source) {
+ void accessedAst(Source source) {
if (_recentlyUsed.remove(source)) {
_recentlyUsed.add(source);
return;
@@ -1065,10 +1055,20 @@
* @param source the source to be removed
*/
void remove(Source source) {
+ _recentlyUsed.remove(source);
_sourceMap.remove(source);
}
/**
+ * Record that the AST associated with the given source was just removed from the cache.
+ *
+ * @param source the source whose AST was removed
+ */
+ void removedAst(Source source) {
+ _recentlyUsed.remove(source);
+ }
+
+ /**
* Set the maximum size of the cache to the given size.
*
* @param size the maximum number of sources for which AST structures should be kept in the cache
@@ -1090,6 +1090,23 @@
int size() => _sourceMap.length;
/**
+ * Record that the AST associated with the given source was just stored to the cache.
+ *
+ * @param source the source whose AST was stored
+ */
+ void storedAst(Source source) {
+ if (_recentlyUsed.contains(source)) {
+ return;
+ }
+ while (_recentlyUsed.length >= _maxCacheSize) {
+ if (!flushAstFromCache()) {
+ break;
+ }
+ }
+ _recentlyUsed.add(source);
+ }
+
+ /**
* Attempt to flush one AST structure from the cache.
*
* @return `true` if a structure was flushed
@@ -1102,7 +1119,7 @@
SourceEntry sourceEntry = _sourceMap[removedSource];
if (sourceEntry is HtmlEntry) {
HtmlEntryImpl htmlCopy = sourceEntry.writableCopy;
- htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.FLUSHED);
+ htmlCopy.flushAstStructures();
_sourceMap[removedSource] = htmlCopy;
} else if (sourceEntry is DartEntry) {
DartEntryImpl dartCopy = sourceEntry.writableCopy;
@@ -1139,6 +1156,17 @@
}
/**
+ * Information about Angular application.
+ */
+class AngularApplicationInfo {
+ final Source entryPoint;
+
+ final List<AngularElement> elements;
+
+ AngularApplicationInfo(this.entryPoint, this.elements);
+}
+
+/**
* Instances of the class `CacheRetentionPolicy` define the behavior of objects that determine
* how important it is for data to be retained in the analysis cache.
*/
@@ -1225,10 +1253,9 @@
*/
abstract class DartEntry implements SourceEntry {
/**
- * The data descriptor representing the Angular elements accessible in the library. This data is
- * only available for Dart files that are the defining compilation unit of a library.
+ * The data descriptor representing the list of libraries that contain this compilation unit.
*/
- static final DataDescriptor<List<AngularElement>> ANGULAR_ELEMENTS = new DataDescriptor<List<AngularElement>>("DartEntry.ANGULAR_ELEMENTS");
+ static final DataDescriptor<List<Source>> CONTAINING_LIBRARIES = new DataDescriptor<List<Source>>("DartEntry.CONTAINING_LIBRARIES");
/**
* The data descriptor representing the library element for the library. This data is only
@@ -1449,6 +1476,12 @@
List<Source> _includedParts = Source.EMPTY_ARRAY;
/**
+ * The list of libraries that contain this compilation unit. The list will be empty if there are
+ * no known libraries that contain this compilation unit.
+ */
+ List<Source> _containingLibraries = new List<Source>();
+
+ /**
* The information known as a result of resolving this compilation unit as part of the library
* that contains this unit. This field will never be `null`.
*/
@@ -1465,17 +1498,6 @@
LibraryElement _element;
/**
- * The state of the cached [angularElements].
- */
- CacheState _angularElementsState = CacheState.INVALID;
-
- /**
- * The array of Angular elements accessible in the library, or an empty array if the elements are
- * not currently cached.
- */
- List<AngularElement> _angularElements = AngularElement.EMPTY_ARRAY;
-
- /**
* The state of the cached public namespace.
*/
CacheState _publicNamespaceState = CacheState.INVALID;
@@ -1514,6 +1536,16 @@
static int _CLIENT_CODE_INDEX = 2;
/**
+ * Add the given library to the list of libraries that contain this part. This method should only
+ * be invoked on entries that represent a part.
+ *
+ * @param librarySource the source of the library to be added
+ */
+ void addContainingLibrary(Source librarySource) {
+ _containingLibraries.add(librarySource);
+ }
+
+ /**
* Flush any AST structures being maintained by this entry.
*/
void flushAstStructures() {
@@ -1616,9 +1648,7 @@
}
CacheState getState(DataDescriptor descriptor) {
- if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
- return _angularElementsState;
- } else if (identical(descriptor, DartEntry.ELEMENT)) {
+ if (identical(descriptor, DartEntry.ELEMENT)) {
return _elementState;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
return _exportedLibrariesState;
@@ -1670,8 +1700,8 @@
}
Object getValue(DataDescriptor descriptor) {
- if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
- return _angularElements;
+ if (identical(descriptor, DartEntry.CONTAINING_LIBRARIES)) {
+ return new List.from(_containingLibraries);
} else if (identical(descriptor, DartEntry.ELEMENT)) {
return _element;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
@@ -1921,8 +1951,6 @@
* not change the state of any parse results.
*/
void recordResolutionError() {
- _angularElements = AngularElement.EMPTY_ARRAY;
- _angularElementsState = CacheState.ERROR;
_element = null;
_elementState = CacheState.ERROR;
_bitmask = 0;
@@ -1938,9 +1966,6 @@
* invalidated before they could be recorded.
*/
void recordResolutionNotInProcess() {
- if (identical(_angularElementsState, CacheState.IN_PROCESS)) {
- _angularElementsState = CacheState.INVALID;
- }
if (identical(_elementState, CacheState.IN_PROCESS)) {
_elementState = CacheState.INVALID;
}
@@ -1957,6 +1982,16 @@
}
/**
+ * Remove the given library from the list of libraries that contain this part. This method should
+ * only be invoked on entries that represent a part.
+ *
+ * @param librarySource the source of the library to be removed
+ */
+ void removeContainingLibrary(Source librarySource) {
+ _containingLibraries.remove(librarySource);
+ }
+
+ /**
* Remove any resolution information associated with this compilation unit being part of the given
* library, presumably because it is no longer part of the library.
*
@@ -1987,6 +2022,17 @@
}
/**
+ * Set the list of libraries that contain this compilation unit to contain only the given source.
+ * This method should only be invoked on entries that represent a library.
+ *
+ * @param librarySource the source of the single library that the list should contain
+ */
+ void set containingLibrary(Source librarySource) {
+ _containingLibraries.clear();
+ _containingLibraries.add(librarySource);
+ }
+
+ /**
* Set the results of parsing the compilation unit at the given time to the given values.
*
* @param modificationStamp the earliest time at which the source was last modified before the
@@ -2011,10 +2057,7 @@
}
void setState(DataDescriptor descriptor, CacheState state) {
- if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
- _angularElements = updatedValue(state, _angularElements, AngularElement.EMPTY_ARRAY);
- _angularElementsState = state;
- } else if (identical(descriptor, DartEntry.ELEMENT)) {
+ if (identical(descriptor, DartEntry.ELEMENT)) {
_element = updatedValue(state, _element, null);
_elementState = state;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
@@ -2082,10 +2125,7 @@
}
void setValue(DataDescriptor descriptor, Object value) {
- if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
- _angularElements = value as List<AngularElement>;
- _angularElementsState = CacheState.VALID;
- } else if (identical(descriptor, DartEntry.ELEMENT)) {
+ if (identical(descriptor, DartEntry.ELEMENT)) {
_element = value as LibraryElement;
_elementState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
@@ -2163,6 +2203,7 @@
_exportedLibraries = other._exportedLibraries;
_importedLibrariesState = other._importedLibrariesState;
_importedLibraries = other._importedLibraries;
+ _containingLibraries = new List<Source>.from(other._containingLibraries);
_resolutionState.copyFrom(other._resolutionState);
_elementState = other._elementState;
_element = other._element;
@@ -2170,12 +2211,10 @@
_publicNamespace = other._publicNamespace;
_clientServerState = other._clientServerState;
_launchableState = other._launchableState;
- _angularElementsState = other._angularElementsState;
- _angularElements = other._angularElements;
_bitmask = other._bitmask;
}
- bool hasErrorState() => super.hasErrorState() || identical(_sourceKindState, CacheState.ERROR) || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_importedLibrariesState, CacheState.ERROR) || identical(_exportedLibrariesState, CacheState.ERROR) || identical(_includedPartsState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularElementsState, CacheState.ERROR) || identical(_publicNamespaceState, CacheState.ERROR) || identical(_clientServerState, CacheState.ERROR) || identical(_launchableState, CacheState.ERROR) || _resolutionState.hasErrorState();
+ bool hasErrorState() => super.hasErrorState() || identical(_sourceKindState, CacheState.ERROR) || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_importedLibrariesState, CacheState.ERROR) || identical(_exportedLibrariesState, CacheState.ERROR) || identical(_includedPartsState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_publicNamespaceState, CacheState.ERROR) || identical(_clientServerState, CacheState.ERROR) || identical(_launchableState, CacheState.ERROR) || _resolutionState.hasErrorState();
void writeOn(JavaStringBuilder builder) {
builder.append("Dart: ");
@@ -2203,7 +2242,6 @@
builder.append("; launchable = ");
builder.append(_launchableState);
builder.append("; angularElements = ");
- builder.append(_angularElementsState);
_resolutionState.writeOn(builder);
}
@@ -2211,8 +2249,6 @@
* Invalidate all of the resolution information associated with the compilation unit.
*/
void discardCachedResolutionInformation() {
- _angularElements = AngularElement.EMPTY_ARRAY;
- _angularElementsState = CacheState.INVALID;
_element = null;
_elementState = CacheState.INVALID;
_includedParts = Source.EMPTY_ARRAY;
@@ -2483,6 +2519,24 @@
*/
abstract class HtmlEntry implements SourceEntry {
/**
+ * The data descriptor representing the information about an Angular application this source is
+ * used in.
+ */
+ static final DataDescriptor<AngularApplicationInfo> ANGULAR_APPLICATION = new DataDescriptor<AngularApplicationInfo>("HtmlEntry.ANGULAR_APPLICATION");
+
+ /**
+ * The data descriptor representing the information about an Angular component this source is used
+ * as template for.
+ */
+ static final DataDescriptor<AngularComponentElement> ANGULAR_COMPONENT = new DataDescriptor<AngularComponentElement>("HtmlEntry.ANGULAR_COMPONENT");
+
+ /**
+ * The data descriptor representing the information about an Angular application this source is
+ * entry point for.
+ */
+ static final DataDescriptor<AngularApplicationInfo> ANGULAR_ENTRY = new DataDescriptor<AngularApplicationInfo>("HtmlEntry.ANGULAR_ENTRY");
+
+ /**
* The data descriptor representing the errors reported during Angular resolution.
*/
static final DataDescriptor<List<AnalysisError>> ANGULAR_ERRORS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.ANGULAR_ERRORS");
@@ -2508,6 +2562,11 @@
static final DataDescriptor<ht.HtmlUnit> PARSED_UNIT = new DataDescriptor<ht.HtmlUnit>("HtmlEntry.PARSED_UNIT");
/**
+ * The data descriptor representing the resolved AST structure.
+ */
+ static final DataDescriptor<ht.HtmlUnit> RESOLVED_UNIT = new DataDescriptor<ht.HtmlUnit>("HtmlEntry.RESOLVED_UNIT");
+
+ /**
* The data descriptor representing the list of referenced libraries.
*/
static final DataDescriptor<List<Source>> REFERENCED_LIBRARIES = new DataDescriptor<List<Source>>("HtmlEntry.REFERENCED_LIBRARIES");
@@ -2524,6 +2583,14 @@
*/
List<AnalysisError> get allErrors;
+ /**
+ * Return a valid parsed unit, either an unresolved AST structure or the result of resolving the
+ * AST structure, or `null` if there is no parsed unit available.
+ *
+ * @return a valid parsed unit
+ */
+ ht.HtmlUnit get anyParsedUnit;
+
HtmlEntryImpl get writableCopy;
}
@@ -2544,6 +2611,16 @@
ht.HtmlUnit _parsedUnit;
/**
+ * The state of the cached resolved HTML unit.
+ */
+ CacheState _resolvedUnitState = CacheState.INVALID;
+
+ /**
+ * The resolved HTML unit, or `null` if the resolved HTML unit is not currently cached.
+ */
+ ht.HtmlUnit _resolvedUnit;
+
+ /**
* The state of the cached parse errors.
*/
CacheState _parseErrorsState = CacheState.INVALID;
@@ -2587,6 +2664,36 @@
HtmlElement _element;
/**
+ * The state of the [angularApplication].
+ */
+ CacheState _angularApplicationState = CacheState.VALID;
+
+ /**
+ * Information about the Angular Application this unit is used in.
+ */
+ AngularApplicationInfo _angularApplication;
+
+ /**
+ * The state of the [angularEntry].
+ */
+ CacheState _angularEntryState = CacheState.VALID;
+
+ /**
+ * Information about the Angular Application this unit is entry point for.
+ */
+ AngularApplicationInfo _angularEntry = null;
+
+ /**
+ * The state of the [angularComponent].
+ */
+ CacheState _angularComponentState = CacheState.VALID;
+
+ /**
+ * Information about the [AngularComponentElement] this unit is used as template for.
+ */
+ AngularComponentElement _angularComponent = null;
+
+ /**
* The state of the Angular resolution errors.
*/
CacheState _angularErrorsState = CacheState.INVALID;
@@ -2608,6 +2715,20 @@
*/
List<AnalysisError> _hints = AnalysisError.NO_ERRORS;
+ /**
+ * Flush any AST structures being maintained by this entry.
+ */
+ void flushAstStructures() {
+ if (identical(_parsedUnitState, CacheState.VALID)) {
+ _parsedUnitState = CacheState.FLUSHED;
+ _parsedUnit = null;
+ }
+ if (identical(_resolvedUnitState, CacheState.VALID)) {
+ _resolvedUnitState = CacheState.FLUSHED;
+ _resolvedUnit = null;
+ }
+ }
+
List<AnalysisError> get allErrors {
List<AnalysisError> errors = new List<AnalysisError>();
if (_parseErrors != null) {
@@ -2636,10 +2757,28 @@
return new List.from(errors);
}
+ ht.HtmlUnit get anyParsedUnit {
+ if (identical(_parsedUnitState, CacheState.VALID)) {
+ // parsedUnitAccessed = true;
+ return _parsedUnit;
+ }
+ if (identical(_resolvedUnitState, CacheState.VALID)) {
+ // resovledUnitAccessed = true;
+ return _resolvedUnit;
+ }
+ return null;
+ }
+
SourceKind get kind => SourceKind.HTML;
CacheState getState(DataDescriptor descriptor) {
- if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+ if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+ return _angularApplicationState;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+ return _angularComponentState;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+ return _angularEntryState;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
return _angularErrorsState;
} else if (identical(descriptor, HtmlEntry.ELEMENT)) {
return _elementState;
@@ -2647,6 +2786,8 @@
return _parseErrorsState;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
return _parsedUnitState;
+ } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+ return _resolvedUnitState;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
return _referencedLibrariesState;
} else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
@@ -2658,7 +2799,13 @@
}
Object getValue(DataDescriptor descriptor) {
- if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+ if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+ return _angularApplication;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+ return _angularComponent;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+ return _angularEntry;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
return _angularErrors;
} else if (identical(descriptor, HtmlEntry.ELEMENT)) {
return _element;
@@ -2666,6 +2813,8 @@
return _parseErrors;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
return _parsedUnit;
+ } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+ return _resolvedUnit;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
return _referencedLibraries;
} else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
@@ -2688,6 +2837,8 @@
_parseErrorsState = CacheState.INVALID;
_parsedUnit = null;
_parsedUnitState = CacheState.INVALID;
+ _resolvedUnit = null;
+ _resolvedUnitState = CacheState.INVALID;
_referencedLibraries = Source.EMPTY_ARRAY;
_referencedLibrariesState = CacheState.INVALID;
invalidateAllResolutionInformation();
@@ -2725,13 +2876,23 @@
*/
void recordResolutionError() {
setState(HtmlEntry.ANGULAR_ERRORS, CacheState.ERROR);
+ setState(HtmlEntry.RESOLVED_UNIT, CacheState.ERROR);
setState(HtmlEntry.ELEMENT, CacheState.ERROR);
setState(HtmlEntry.RESOLUTION_ERRORS, CacheState.ERROR);
setState(HtmlEntry.HINTS, CacheState.ERROR);
}
void setState(DataDescriptor descriptor, CacheState state) {
- if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+ if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+ _angularApplication = updatedValue(state, _angularApplication, null);
+ _angularApplicationState = state;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+ _angularComponent = updatedValue(state, _angularComponent, null);
+ _angularComponentState = state;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+ _angularEntry = updatedValue(state, _angularEntry, null);
+ _angularEntryState = state;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
_angularErrors = updatedValue(state, _angularErrors, null);
_angularErrorsState = state;
} else if (identical(descriptor, HtmlEntry.ELEMENT)) {
@@ -2743,6 +2904,9 @@
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
_parsedUnit = updatedValue(state, _parsedUnit, null);
_parsedUnitState = state;
+ } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+ _resolvedUnit = updatedValue(state, _resolvedUnit, null);
+ _resolvedUnitState = state;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
_referencedLibraries = updatedValue(state, _referencedLibraries, Source.EMPTY_ARRAY);
_referencedLibrariesState = state;
@@ -2758,7 +2922,16 @@
}
void setValue(DataDescriptor descriptor, Object value) {
- if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+ if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+ _angularApplication = value as AngularApplicationInfo;
+ _angularApplicationState = CacheState.VALID;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+ _angularComponent = value as AngularComponentElement;
+ _angularComponentState = CacheState.VALID;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+ _angularEntry = value as AngularApplicationInfo;
+ _angularEntryState = CacheState.VALID;
+ } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
_angularErrors = value as List<AnalysisError>;
_angularErrorsState = CacheState.VALID;
} else if (identical(descriptor, HtmlEntry.ELEMENT)) {
@@ -2770,6 +2943,9 @@
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
_parsedUnit = value as ht.HtmlUnit;
_parsedUnitState = CacheState.VALID;
+ } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+ _resolvedUnit = value as ht.HtmlUnit;
+ _resolvedUnitState = CacheState.VALID;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
_referencedLibraries = value == null ? Source.EMPTY_ARRAY : (value as List<Source>);
_referencedLibrariesState = CacheState.VALID;
@@ -2787,12 +2963,20 @@
void copyFrom(SourceEntryImpl entry) {
super.copyFrom(entry);
HtmlEntryImpl other = entry as HtmlEntryImpl;
+ _angularApplicationState = other._angularApplicationState;
+ _angularApplication = other._angularApplication;
+ _angularComponentState = other._angularComponentState;
+ _angularComponent = other._angularComponent;
+ _angularEntryState = other._angularEntryState;
+ _angularEntry = other._angularEntry;
_angularErrorsState = other._angularErrorsState;
_angularErrors = other._angularErrors;
_parseErrorsState = other._parseErrorsState;
_parseErrors = other._parseErrors;
_parsedUnitState = other._parsedUnitState;
_parsedUnit = other._parsedUnit;
+ _resolvedUnitState = other._resolvedUnitState;
+ _resolvedUnit = other._resolvedUnit;
_referencedLibrariesState = other._referencedLibrariesState;
_referencedLibraries = other._referencedLibraries;
_resolutionErrors = other._resolutionErrors;
@@ -2803,7 +2987,7 @@
_hintsState = other._hintsState;
}
- bool hasErrorState() => super.hasErrorState() || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_resolutionErrorsState, CacheState.ERROR) || identical(_referencedLibrariesState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularErrorsState, CacheState.ERROR) || identical(_hintsState, CacheState.ERROR);
+ bool hasErrorState() => super.hasErrorState() || identical(_parsedUnitState, CacheState.ERROR) || identical(_resolvedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_resolutionErrorsState, CacheState.ERROR) || identical(_referencedLibrariesState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularErrorsState, CacheState.ERROR) || identical(_hintsState, CacheState.ERROR);
void writeOn(JavaStringBuilder builder) {
builder.append("Html: ");
@@ -2812,12 +2996,20 @@
builder.append(_parseErrorsState);
builder.append("; parsedUnit = ");
builder.append(_parsedUnitState);
+ builder.append("; resolvedUnit = ");
+ builder.append(_resolvedUnitState);
builder.append("; resolutionErrors = ");
builder.append(_resolutionErrorsState);
builder.append("; referencedLibraries = ");
builder.append(_referencedLibrariesState);
builder.append("; element = ");
builder.append(_elementState);
+ builder.append("; angularApplication = ");
+ builder.append(_angularApplicationState);
+ builder.append("; angularComponent = ");
+ builder.append(_angularComponentState);
+ builder.append("; angularEntry = ");
+ builder.append(_angularEntryState);
builder.append("; angularErrors = ");
builder.append(_angularErrorsState);
}
@@ -3246,6 +3438,11 @@
IncrementalAnalysisCache _incrementalAnalysisCache;
/**
+ * The object used to manage the list of sources that need to be analyzed.
+ */
+ WorkManager _workManager = new WorkManager();
+
+ /**
* Initialize a newly created analysis context.
*/
AnalysisContextImpl() : super() {
@@ -3294,11 +3491,22 @@
// only re-analyze those libraries.
logInformation("Added Dart sources, invalidating all resolution information");
for (MapEntry<Source, SourceEntry> mapEntry in _cache.entrySet()) {
+ Source source = mapEntry.getKey();
SourceEntry sourceEntry = mapEntry.getValue();
- if (!mapEntry.getKey().isInSystemLibrary && sourceEntry is DartEntry) {
- DartEntryImpl dartCopy = sourceEntry.writableCopy;
+ if (!source.isInSystemLibrary && sourceEntry is DartEntry) {
+ DartEntry dartEntry = sourceEntry;
+ DartEntryImpl dartCopy = dartEntry.writableCopy;
+ removeFromParts(source, dartEntry);
dartCopy.invalidateAllResolutionInformation();
mapEntry.setValue(dartCopy);
+ SourcePriority priority = SourcePriority.UNKNOWN;
+ SourceKind kind = dartCopy.kind;
+ if (identical(kind, SourceKind.LIBRARY)) {
+ priority = SourcePriority.LIBRARY;
+ } else if (identical(kind, SourceKind.PART)) {
+ priority = SourcePriority.NORMAL_PART;
+ }
+ _workManager.add(source, priority);
}
}
}
@@ -3407,29 +3615,35 @@
return null;
}
+ ResolvableHtmlUnit computeResolvableAngularComponentHtmlUnit(Source source) {
+ HtmlEntry htmlEntry = getReadableHtmlEntry(source);
+ if (htmlEntry == null) {
+ throw new AnalysisException.con1("computeResolvableAngularComponentHtmlUnit invoked for non-HTML file: ${source.fullName}");
+ }
+ htmlEntry = cacheHtmlResolutionData(source, htmlEntry, HtmlEntry.RESOLVED_UNIT);
+ ht.HtmlUnit unit = htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT);
+ if (unit == null) {
+ AnalysisException cause = htmlEntry.exception;
+ throw new AnalysisException.con2("Internal error: computeResolvableAngularComponentHtmlUnit could not resolve ${source.fullName}", cause);
+ }
+ // If the unit is ever modified by resolution then we will need to create a copy of it.
+ return new ResolvableHtmlUnit(htmlEntry.modificationTime, unit);
+ }
+
ResolvableCompilationUnit computeResolvableCompilationUnit(Source source) {
- while (true) {
- {
- DartEntry dartEntry = getReadableDartEntry(source);
- if (dartEntry == null) {
- throw new AnalysisException.con1("computeResolvableCompilationUnit for non-Dart: ${source.fullName}");
- }
- if (identical(dartEntry.getState(DartEntry.PARSED_UNIT), CacheState.ERROR)) {
- AnalysisException cause = dartEntry.exception;
- if (cause == null) {
- throw new AnalysisException.con1("Internal error: computeResolvableCompilationUnit could not parse ${source.fullName}");
- } else {
- throw new AnalysisException.con2("Internal error: computeResolvableCompilationUnit could not parse ${source.fullName}", cause);
- }
- }
- DartEntryImpl dartCopy = dartEntry.writableCopy;
- CompilationUnit unit = dartCopy.resolvableCompilationUnit;
- if (unit != null) {
- _cache.put(source, dartCopy);
- return new ResolvableCompilationUnit(dartCopy.modificationTime, unit);
- }
+ {
+ DartEntry dartEntry = getReadableDartEntry(source);
+ if (dartEntry == null) {
+ throw new AnalysisException.con1("computeResolvableCompilationUnit for non-Dart: ${source.fullName}");
}
- cacheDartParseData(source, getReadableDartEntry(source), DartEntry.PARSED_UNIT);
+ dartEntry = cacheDartParseData(source, dartEntry, DartEntry.PARSED_UNIT);
+ DartEntryImpl dartCopy = dartEntry.writableCopy;
+ CompilationUnit unit = dartCopy.resolvableCompilationUnit;
+ if (unit == null) {
+ throw new AnalysisException.con2("Internal error: computeResolvableCompilationUnit could not parse ${source.fullName}", dartEntry.exception);
+ }
+ _cache.put(source, dartCopy);
+ return new ResolvableCompilationUnit(dartCopy.modificationTime, unit);
}
}
@@ -3581,25 +3795,11 @@
}
List<Source> getLibrariesContaining(Source source) {
- {
- SourceEntry sourceEntry = _cache.get(source);
- if (sourceEntry == null || sourceEntry.kind != SourceKind.PART) {
- return <Source> [source];
- }
- List<Source> librarySources = new List<Source>();
- for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
- sourceEntry = entry.getValue();
- if (identical(sourceEntry.kind, SourceKind.LIBRARY)) {
- if (contains((sourceEntry as DartEntry).getValue(DartEntry.INCLUDED_PARTS), source)) {
- librarySources.add(entry.getKey());
- }
- }
- }
- if (librarySources.isEmpty) {
- return Source.EMPTY_ARRAY;
- }
- return new List.from(librarySources);
+ DartEntry dartEntry = getReadableDartEntry(source);
+ if (dartEntry == null) {
+ return Source.EMPTY_ARRAY;
}
+ return dartEntry.getValue(DartEntry.CONTAINING_LIBRARIES);
}
List<Source> getLibrariesDependingOn(Source librarySource) {
@@ -3623,14 +3823,6 @@
}
}
- List<AngularElement> getLibraryAngularElements(Source source) {
- SourceEntry sourceEntry = getReadableSourceEntry(source);
- if (sourceEntry is DartEntry) {
- return sourceEntry.getValue(DartEntry.ANGULAR_ELEMENTS);
- }
- return AngularElement.EMPTY_ARRAY;
- }
-
LibraryElement getLibraryElement(Source source) {
SourceEntry sourceEntry = getReadableSourceEntry(source);
if (sourceEntry is DartEntry) {
@@ -3667,7 +3859,7 @@
{
dartEntry = getReadableDartEntry(source);
if (dartEntry == null) {
- AnalysisEngine.instance.logger.logError3(new AnalysisException.con1("A Dart file became a non-Dart file: ${source.fullName}"));
+ AnalysisEngine.instance.logger.logError2("Could not compute the public namespace for ${library.source.fullName}", new AnalysisException.con1("A Dart file became a non-Dart file: ${source.fullName}"));
return null;
}
if (identical(dartEntry.getValue(DartEntry.ELEMENT), library)) {
@@ -3744,9 +3936,7 @@
SourceEntry sourceEntry = getReadableSourceEntry(htmlSource);
if (sourceEntry is HtmlEntry) {
HtmlEntry htmlEntry = sourceEntry;
- if (htmlEntry.getValue(HtmlEntry.ELEMENT) != null) {
- return htmlEntry.getValue(HtmlEntry.PARSED_UNIT);
- }
+ return htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT);
}
return null;
}
@@ -3755,7 +3945,7 @@
/**
* Return a list of the sources that would be processed by [performAnalysisTask]. This
- * method duplicates, and must therefore be kept in sync with, [getNextTaskAnalysisTask].
+ * method duplicates, and must therefore be kept in sync with, [getNextAnalysisTask].
* This method is intended to be used for testing purposes only.
*
* @return a list of the sources that would be processed by [performAnalysisTask]
@@ -3876,10 +4066,10 @@
AnalysisResult performAnalysisTask() {
int getStart = JavaSystem.currentTimeMillis();
- AnalysisTask task = nextTaskAnalysisTask;
+ AnalysisTask task = nextAnalysisTask;
int getEnd = JavaSystem.currentTimeMillis();
if (task == null && validateCacheConsistency()) {
- task = nextTaskAnalysisTask;
+ task = nextAnalysisTask;
}
if (task == null) {
return new AnalysisResult(getChangeNotices(true), getEnd - getStart, null, -1);
@@ -3914,7 +4104,7 @@
DartEntry dartEntry = getReadableDartEntry(librarySource);
if (dartEntry != null) {
DartEntryImpl dartCopy = dartEntry.writableCopy;
- recordElementData(dartCopy, library, htmlSource);
+ recordElementData(dartEntry, dartCopy, library, library.source, htmlSource);
_cache.put(librarySource, dartCopy);
}
}
@@ -4080,6 +4270,7 @@
dartCopy.recordResolutionError();
dartCopy.exception = thrownException;
_cache.put(unitSource, dartCopy);
+ _cache.remove(unitSource);
if (thrownException != null) {
throw thrownException;
}
@@ -4111,15 +4302,19 @@
dartCopy.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED);
dartCopy.setValue2(DartEntry.RESOLVED_UNIT, librarySource, unit);
dartCopy.setValue2(DartEntry.RESOLUTION_ERRORS, librarySource, errors);
- if (identical(source, librarySource)) {
- recordElementData(dartCopy, library.libraryElement, htmlSource);
- recordAngularComponents(library, dartCopy);
+ if (source == librarySource) {
+ recordElementData(dartEntry, dartCopy, library.libraryElement, librarySource, htmlSource);
}
+ _cache.storedAst(source);
} else {
dartCopy.recordResolutionError();
+ _cache.remove(source);
}
dartCopy.exception = thrownException;
_cache.put(source, dartCopy);
+ if (source != librarySource) {
+ _workManager.add(source, SourcePriority.PRIORITY_PART);
+ }
if (source == unitSource) {
unitEntry = dartCopy;
}
@@ -4151,6 +4346,7 @@
// good chance that we'll be able to do so without error.
//
dartCopy.recordResolutionError();
+ _cache.remove(source);
}
dartCopy.exception = thrownException;
_cache.put(source, dartCopy);
@@ -4179,6 +4375,18 @@
}
/**
+ * Record that we have accessed the AST structure associated with the given source. At the moment,
+ * there is no differentiation between the parsed and resolved forms of the AST.
+ *
+ * @param source the source whose AST structure was accessed
+ */
+ void accessedAst(Source source) {
+ {
+ _cache.accessedAst(source);
+ }
+ }
+
+ /**
* Add all of the sources contained in the given source container to the given list of sources.
*
* Note: This method must only be invoked while we are synchronized on [cacheLock].
@@ -4227,9 +4435,10 @@
}
/**
- * Given a source for a Dart file, return a cache entry in which the data represented by the given
- * descriptor is available. This method assumes that the data can be produced by resolving the
- * directives in the source if they are not already cached.
+ * Given a source for a Dart file, return a cache entry in which the state of the data represented
+ * by the given descriptor is either [CacheState#VALID] or [CacheState#ERROR]. This
+ * method assumes that the data can be produced by resolving the directives in the source if they
+ * are not already cached.
*
* @param source the source representing the Dart file
* @param dartEntry the cache entry associated with the Dart file
@@ -4256,8 +4465,9 @@
/**
* Given a source for a Dart file and the library that contains it, return a cache entry in which
- * the data represented by the given descriptor is available. This method assumes that the data
- * can be produced by generating hints for the library if the data is not already cached.
+ * the state of the data represented by the given descriptor is either [CacheState#VALID] or
+ * [CacheState#ERROR]. This method assumes that the data can be produced by generating hints
+ * for the library if the data is not already cached.
*
* @param unitSource the source representing the Dart file
* @param librarySource the source representing the library containing the Dart file
@@ -4283,9 +4493,9 @@
}
/**
- * Given a source for a Dart file, return a cache entry in which the data represented by the given
- * descriptor is available. This method assumes that the data can be produced by parsing the
- * source if it is not already cached.
+ * Given a source for a Dart file, return a cache entry in which the state of the data represented
+ * by the given descriptor is either [CacheState#VALID] or [CacheState#ERROR]. This
+ * method assumes that the data can be produced by parsing the source if it is not already cached.
*
* @param source the source representing the Dart file
* @param dartEntry the cache entry associated with the Dart file
@@ -4318,9 +4528,9 @@
/**
* Given a source for a Dart file and the library that contains it, return a cache entry in which
- * the data represented by the given descriptor is available. This method assumes that the data
- * can be produced by resolving the source in the context of the library if it is not already
- * cached.
+ * the state of the data represented by the given descriptor is either [CacheState#VALID] or
+ * [CacheState#ERROR]. This method assumes that the data can be produced by resolving the
+ * source in the context of the library if it is not already cached.
*
* @param unitSource the source representing the Dart file
* @param librarySource the source representing the library containing the Dart file
@@ -4349,8 +4559,9 @@
/**
* Given a source for a Dart file and the library that contains it, return a cache entry in which
- * the data represented by the given descriptor is available. This method assumes that the data
- * can be produced by verifying the source in the given library if the data is not already cached.
+ * the state of the data represented by the given descriptor is either [CacheState#VALID] or
+ * [CacheState#ERROR]. This method assumes that the data can be produced by verifying the
+ * source in the given library if the data is not already cached.
*
* @param unitSource the source representing the Dart file
* @param librarySource the source representing the library containing the Dart file
@@ -4377,8 +4588,9 @@
/**
* Given a source for an HTML file, return a cache entry in which all of the data represented by
- * the given descriptors is available. This method assumes that the data can be produced by
- * parsing the source if it is not already cached.
+ * the state of the given descriptors is either [CacheState#VALID] or
+ * [CacheState#ERROR]. This method assumes that the data can be produced by parsing the
+ * source if it is not already cached.
*
* @param source the source representing the HTML file
* @param htmlEntry the cache entry associated with the HTML file
@@ -4388,6 +4600,12 @@
* resolved
*/
HtmlEntry cacheHtmlParseData(Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) {
+ if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
+ ht.HtmlUnit unit = htmlEntry.anyParsedUnit;
+ if (unit != null) {
+ return htmlEntry;
+ }
+ }
//
// Check to see whether we already have the information being requested.
//
@@ -4404,9 +4622,10 @@
}
/**
- * Given a source for an HTML file, return a cache entry in which the the data represented by the
- * given descriptor is available. This method assumes that the data can be produced by resolving
- * the source if it is not already cached.
+ * Given a source for an HTML file, return a cache entry in which the state of the data
+ * represented by the given descriptor is either [CacheState#VALID] or
+ * [CacheState#ERROR]. This method assumes that the data can be produced by resolving the
+ * source if it is not already cached.
*
* @param source the source representing the HTML file
* @param dartEntry the cache entry associated with the HTML file
@@ -4599,6 +4818,7 @@
Object getDartParseData(Source source, DartEntry dartEntry, DataDescriptor descriptor) {
dartEntry = cacheDartParseData(source, dartEntry, descriptor);
if (identical(descriptor, DartEntry.PARSED_UNIT)) {
+ accessedAst(source);
return dartEntry.anyParsedCompilationUnit;
}
return dartEntry.getValue(descriptor);
@@ -4640,6 +4860,8 @@
dartEntry = cacheDartResolutionData(unitSource, librarySource, dartEntry, descriptor);
if (identical(descriptor, DartEntry.ELEMENT)) {
return dartEntry.getValue(descriptor);
+ } else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
+ accessedAst(unitSource);
}
return dartEntry.getValue2(descriptor, librarySource);
}
@@ -4701,6 +4923,10 @@
return defaultValue;
}
htmlEntry = cacheHtmlParseData(source, htmlEntry, descriptor);
+ if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
+ accessedAst(source);
+ return htmlEntry.anyParsedUnit;
+ }
return htmlEntry.getValue(descriptor);
}
@@ -4739,6 +4965,9 @@
*/
Object getHtmlResolutionData2(Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) {
htmlEntry = cacheHtmlResolutionData(source, htmlEntry, descriptor);
+ if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+ accessedAst(source);
+ }
return htmlEntry.getValue(descriptor);
}
@@ -4748,7 +4977,7 @@
*
* @return the next task that needs to be performed
*/
- AnalysisTask get nextTaskAnalysisTask {
+ AnalysisTask get nextAnalysisTask {
{
bool hintsEnabled = _options.hint;
//
@@ -4763,7 +4992,7 @@
// Look for a priority source that needs to be analyzed.
//
for (Source source in _priorityOrder) {
- AnalysisTask task = getNextTaskAnalysisTask2(source, _cache.get(source), true, hintsEnabled);
+ AnalysisTask task = getNextAnalysisTask2(source, _cache.get(source), true, hintsEnabled);
if (task != null) {
return task;
}
@@ -4771,49 +5000,26 @@
//
// Look for a non-priority source that needs to be analyzed.
//
- for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
- AnalysisTask task = getNextTaskAnalysisTask2(entry.getKey(), entry.getValue(), false, hintsEnabled);
+ Source source = _workManager.nextSource;
+ while (source != null) {
+ AnalysisTask task = getNextAnalysisTask2(source, _cache.get(source), false, hintsEnabled);
if (task != null) {
return task;
}
+ _workManager.remove(source);
+ source = _workManager.nextSource;
}
- //
- // Look for HTML sources that should be resolved as Angular templates.
- //
- for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
- SourceEntry sourceEntry = entry.getValue();
- if (sourceEntry is DartEntry) {
- DartEntry dartEntry = sourceEntry;
- List<AngularElement> angularElements = dartEntry.getValue(DartEntry.ANGULAR_ELEMENTS);
- for (AngularElement angularElement in angularElements) {
- // prepare Angular component
- if (angularElement is! AngularComponentElement) {
- continue;
- }
- AngularComponentElement component = angularElement as AngularComponentElement;
- // prepare HTML template
- Source templateSource = component.templateSource;
- if (templateSource == null) {
- continue;
- }
- // prepare HTML template entry
- HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
- if (htmlEntry == null) {
- continue;
- }
- // we need an entry with invalid Angular errors
- CacheState angularErrorsState = htmlEntry.getState(HtmlEntry.ANGULAR_ERRORS);
- if (angularErrorsState != CacheState.INVALID) {
- continue;
- }
- // do Angular component resolution
- HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
- htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.IN_PROCESS);
- _cache.put(templateSource, htmlCopy);
- return new ResolveAngularComponentTemplateTask(this, templateSource, component, angularElements);
- }
- }
- }
+ // //
+ // // Look for a non-priority source that needs to be analyzed and was missed by the loop above.
+ // //
+ // for (Map.Entry<Source, SourceEntry> entry : cache.entrySet()) {
+ // source = entry.getKey();
+ // AnalysisTask task = getNextAnalysisTask(source, entry.getValue(), false, hintsEnabled);
+ // if (task != null) {
+ // System.out.println("Failed to analyze " + source.getFullName());
+ // return task;
+ // }
+ // }
return null;
}
}
@@ -4831,16 +5037,9 @@
* @param hintsEnabled `true` if hints are currently enabled
* @return the next task that needs to be performed for the given source
*/
- AnalysisTask getNextTaskAnalysisTask2(Source source, SourceEntry sourceEntry, bool isPriority, bool hintsEnabled) {
+ AnalysisTask getNextAnalysisTask2(Source source, SourceEntry sourceEntry, bool isPriority, bool hintsEnabled) {
if (sourceEntry is DartEntry) {
DartEntry dartEntry = sourceEntry;
- if (!source.exists()) {
- DartEntryImpl dartCopy = dartEntry.writableCopy;
- dartCopy.recordParseError();
- dartCopy.exception = new AnalysisException.con1("Source does not exist");
- _cache.put(source, dartCopy);
- return null;
- }
CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS);
if (identical(parseErrorsState, CacheState.INVALID) || (isPriority && identical(parseErrorsState, CacheState.FLUSHED))) {
DartEntryImpl dartCopy = dartEntry.writableCopy;
@@ -4864,7 +5063,8 @@
_cache.put(source, dartCopy);
return new ResolveDartDependenciesTask(this, source);
}
- for (Source librarySource in getLibrariesContaining(source)) {
+ List<Source> librariesContaining = dartEntry.getValue(DartEntry.CONTAINING_LIBRARIES);
+ for (Source librarySource in librariesContaining) {
SourceEntry libraryEntry = _cache.get(librarySource);
if (libraryEntry is DartEntry) {
CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT);
@@ -4915,27 +5115,52 @@
}
} else if (sourceEntry is HtmlEntry) {
HtmlEntry htmlEntry = sourceEntry;
- if (!source.exists()) {
- HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
- htmlCopy.recordParseError();
- htmlCopy.exception = new AnalysisException.con1("Source does not exist");
- _cache.put(source, htmlCopy);
- return null;
- }
- CacheState parsedUnitState = htmlEntry.getState(HtmlEntry.PARSED_UNIT);
- if (identical(parsedUnitState, CacheState.INVALID) || (isPriority && identical(parsedUnitState, CacheState.FLUSHED))) {
- HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
- htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.IN_PROCESS);
- _cache.put(source, htmlCopy);
+ CacheState parseErrorsState = htmlEntry.getState(HtmlEntry.PARSE_ERRORS);
+ if (identical(parseErrorsState, CacheState.INVALID) || (isPriority && identical(parseErrorsState, CacheState.FLUSHED))) {
+ HtmlEntryImpl dartCopy = htmlEntry.writableCopy;
+ dartCopy.setState(HtmlEntry.PARSE_ERRORS, CacheState.IN_PROCESS);
+ _cache.put(source, dartCopy);
return new ParseHtmlTask(this, source);
}
- CacheState elementState = htmlEntry.getState(HtmlEntry.ELEMENT);
- if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
+ if (isPriority && parseErrorsState != CacheState.ERROR) {
+ ht.HtmlUnit parsedUnit = htmlEntry.anyParsedUnit;
+ if (parsedUnit == null) {
+ HtmlEntryImpl dartCopy = htmlEntry.writableCopy;
+ dartCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.IN_PROCESS);
+ _cache.put(source, dartCopy);
+ return new ParseHtmlTask(this, source);
+ }
+ }
+ CacheState resolvedUnitState = htmlEntry.getState(HtmlEntry.RESOLVED_UNIT);
+ if (identical(resolvedUnitState, CacheState.INVALID) || (isPriority && identical(resolvedUnitState, CacheState.FLUSHED))) {
HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
- htmlCopy.setState(HtmlEntry.ELEMENT, CacheState.IN_PROCESS);
+ htmlCopy.setState(HtmlEntry.RESOLVED_UNIT, CacheState.IN_PROCESS);
_cache.put(source, htmlCopy);
return new ResolveHtmlTask(this, source);
}
+ CacheState angularErrorsState = htmlEntry.getState(HtmlEntry.ANGULAR_ERRORS);
+ if (identical(angularErrorsState, CacheState.INVALID)) {
+ AngularApplicationInfo entryInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_ENTRY);
+ if (entryInfo != null) {
+ HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+ htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.IN_PROCESS);
+ _cache.put(source, htmlCopy);
+ return new ResolveAngularEntryHtmlTask(this, source, entryInfo);
+ }
+ AngularApplicationInfo applicationInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_APPLICATION);
+ if (applicationInfo != null) {
+ AngularComponentElement component = htmlEntry.getValue(HtmlEntry.ANGULAR_COMPONENT);
+ if (component != null) {
+ HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+ htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.IN_PROCESS);
+ _cache.put(source, htmlCopy);
+ return new ResolveAngularComponentTemplateTask(this, source, component, applicationInfo);
+ }
+ }
+ HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+ htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, AnalysisError.NO_ERRORS);
+ _cache.put(source, htmlCopy);
+ }
}
return null;
}
@@ -4969,7 +5194,6 @@
sourceEntry = createSourceEntry(source);
}
if (sourceEntry is DartEntry) {
- _cache.accessed(source);
return sourceEntry as DartEntry;
}
return null;
@@ -4990,7 +5214,6 @@
sourceEntry = createSourceEntry(source);
}
if (sourceEntry is HtmlEntry) {
- _cache.accessed(source);
return sourceEntry as HtmlEntry;
}
return null;
@@ -5010,9 +5233,6 @@
if (sourceEntry == null) {
sourceEntry = createSourceEntry(source);
}
- if (sourceEntry != null) {
- _cache.accessed(source);
- }
return sourceEntry;
}
}
@@ -5039,8 +5259,8 @@
* Look at the given source to see whether a task needs to be performed related to it. If so, add
* the source to the set of sources that need to be processed. This method duplicates, and must
* therefore be kept in sync with,
- * [getNextTaskAnalysisTask]. This method is
- * intended to be used for testing purposes only.
+ * [getNextAnalysisTask]. This method is intended to
+ * be used for testing purposes only.
*
* <b>Note:</b> This method must only be invoked while we are synchronized on [cacheLock].
*
@@ -5108,11 +5328,27 @@
sources.add(source);
return;
}
- CacheState elementState = htmlEntry.getState(HtmlEntry.ELEMENT);
- if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
+ CacheState resolvedUnitState = htmlEntry.getState(HtmlEntry.RESOLVED_UNIT);
+ if (identical(resolvedUnitState, CacheState.INVALID) || (isPriority && identical(resolvedUnitState, CacheState.FLUSHED))) {
sources.add(source);
return;
}
+ CacheState angularErrorsState = htmlEntry.getState(HtmlEntry.ANGULAR_ERRORS);
+ if (identical(angularErrorsState, CacheState.INVALID)) {
+ AngularApplicationInfo entryInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_ENTRY);
+ if (entryInfo != null) {
+ sources.add(source);
+ return;
+ }
+ AngularApplicationInfo applicationInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_APPLICATION);
+ if (applicationInfo != null) {
+ AngularComponentElement component = htmlEntry.getValue(HtmlEntry.ANGULAR_COMPONENT);
+ if (component != null) {
+ sources.add(source);
+ return;
+ }
+ }
+ }
}
}
@@ -5123,15 +5359,19 @@
*/
void invalidateAllResolutionInformation() {
for (MapEntry<Source, SourceEntry> mapEntry in _cache.entrySet()) {
+ Source source = mapEntry.getKey();
SourceEntry sourceEntry = mapEntry.getValue();
if (sourceEntry is HtmlEntry) {
HtmlEntryImpl htmlCopy = sourceEntry.writableCopy;
htmlCopy.invalidateAllResolutionInformation();
mapEntry.setValue(htmlCopy);
} else if (sourceEntry is DartEntry) {
- DartEntryImpl dartCopy = sourceEntry.writableCopy;
+ DartEntry dartEntry = sourceEntry;
+ removeFromParts(source, dartEntry);
+ DartEntryImpl dartCopy = dartEntry.writableCopy;
dartCopy.invalidateAllResolutionInformation();
mapEntry.setValue(dartCopy);
+ _workManager.add(source, SourcePriority.UNKNOWN);
}
}
}
@@ -5142,6 +5382,9 @@
*
* <b>Note:</b> This method must only be invoked while we are synchronized on [cacheLock].
*
+ * <b>Note:</b> Any cache entries that were accessed before this method was invoked must be
+ * re-accessed after this method returns.
+ *
* @param librarySource the source of the library being invalidated
* @param writer the writer to which debugging information should be written
*/
@@ -5155,8 +5398,8 @@
DartEntryImpl libraryCopy = libraryEntry.writableCopy;
int oldTime = libraryCopy.modificationTime;
libraryCopy.invalidateAllResolutionInformation();
- libraryCopy.setState(DartEntry.INCLUDED_PARTS, CacheState.INVALID);
_cache.put(librarySource, libraryCopy);
+ _workManager.add(librarySource, SourcePriority.LIBRARY);
if (writer != null) {
writer.println(" Invalidated library source: ${debuggingString(librarySource)} (previously modified at ${oldTime})");
}
@@ -5165,6 +5408,10 @@
if (partEntry is DartEntry) {
DartEntryImpl partCopy = partEntry.writableCopy;
oldTime = partCopy.modificationTime;
+ if (partEntry != libraryCopy) {
+ partCopy.removeContainingLibrary(librarySource);
+ _workManager.add(librarySource, SourcePriority.NORMAL_PART);
+ }
partCopy.invalidateAllResolutionInformation();
_cache.put(partSource, partCopy);
if (writer != null) {
@@ -5233,10 +5480,11 @@
* @param library the [Library] that was resolved
* @param dartCopy the [DartEntryImpl] to record new Angular components
*/
- void recordAngularComponents(Library library, DartEntryImpl dartCopy) {
+ void recordAngularComponents(HtmlEntryImpl entry, AngularApplicationInfo app) {
// reset old Angular errors
- List<AngularElement> oldAngularElements = dartCopy.getValue(DartEntry.ANGULAR_ELEMENTS);
- if (oldAngularElements != null) {
+ AngularApplicationInfo oldApp = entry.getValue(HtmlEntry.ANGULAR_ENTRY);
+ if (oldApp != null) {
+ List<AngularElement> oldAngularElements = oldApp.elements;
for (AngularElement angularElement in oldAngularElements) {
if (angularElement is AngularComponentElement) {
AngularComponentElement component = angularElement;
@@ -5244,6 +5492,8 @@
if (templateSource != null) {
HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+ htmlCopy.setValue(HtmlEntry.ANGULAR_APPLICATION, null);
+ htmlCopy.setValue(HtmlEntry.ANGULAR_COMPONENT, null);
htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, AnalysisError.NO_ERRORS);
_cache.put(templateSource, htmlCopy);
// notify about (disappeared) HTML errors
@@ -5253,46 +5503,63 @@
}
}
}
- // invalidate new Angular errors
- List<AngularElement> newAngularElements = library.angularElements;
- for (AngularElement angularElement in newAngularElements) {
- if (angularElement is AngularComponentElement) {
- AngularComponentElement component = angularElement;
- Source templateSource = component.templateSource;
- if (templateSource != null) {
- HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
- HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
- htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
- _cache.put(templateSource, htmlCopy);
+ // prepare for new Angular analysis
+ if (app != null) {
+ List<AngularElement> newAngularElements = app.elements;
+ for (AngularElement angularElement in newAngularElements) {
+ if (angularElement is AngularComponentElement) {
+ AngularComponentElement component = angularElement;
+ Source templateSource = component.templateSource;
+ if (templateSource != null) {
+ HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
+ HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+ htmlCopy.setValue(HtmlEntry.ANGULAR_APPLICATION, app);
+ htmlCopy.setValue(HtmlEntry.ANGULAR_COMPONENT, component);
+ htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
+ _cache.put(templateSource, htmlCopy);
+ _workManager.add(templateSource, SourcePriority.HTML);
+ }
}
}
}
- // remember Angular elements to resolve HTML templates later
- dartCopy.setValue(DartEntry.ANGULAR_ELEMENTS, newAngularElements);
+ // remember Angular application
+ entry.setValue(HtmlEntry.ANGULAR_ENTRY, app);
+ entry.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
}
/**
* Given a cache entry and a library element, record the library element and other information
* gleaned from the element in the cache entry.
*
+ * @param dartEntry the original cache entry from which the copy was made
* @param dartCopy the cache entry in which data is to be recorded
* @param library the library element used to record information
+ * @param librarySource the source for the library used to record information
* @param htmlSource the source for the HTML library
*/
- void recordElementData(DartEntryImpl dartCopy, LibraryElement library, Source htmlSource) {
+ void recordElementData(DartEntry dartEntry, DartEntryImpl dartCopy, LibraryElement library, Source librarySource, Source htmlSource) {
dartCopy.setValue(DartEntry.ELEMENT, library);
dartCopy.setValue(DartEntry.IS_LAUNCHABLE, library.entryPoint != null);
dartCopy.setValue(DartEntry.IS_CLIENT, isClient(library, htmlSource, new Set<LibraryElement>()));
- List<Source> unitSources = new List<Source>();
- unitSources.add(library.definingCompilationUnit.source);
// TODO(brianwilkerson) Understand why we're doing this both here and in
// ResolveDartDependenciesTask and whether we should also be capturing the imported and exported
// sources here.
- for (CompilationUnitElement part in library.parts) {
- Source partSource = part.source;
- unitSources.add(partSource);
+ removeFromParts(librarySource, dartEntry);
+ List<CompilationUnitElement> parts = library.parts;
+ int count = parts.length;
+ List<Source> unitSources = new List<Source>(count + 1);
+ unitSources[0] = library.definingCompilationUnit.source;
+ for (int i = 0; i < count; i++) {
+ Source unitSource = parts[i].source;
+ unitSources[i + 1] = unitSource;
+ DartEntry unitEntry = getReadableDartEntry(unitSource);
+ if (unitSource != null) {
+ DartEntryImpl unitCopy = unitEntry.writableCopy;
+ unitCopy.addContainingLibrary(librarySource);
+ _cache.put(unitSource, unitCopy);
+ }
}
- dartCopy.setValue(DartEntry.INCLUDED_PARTS, new List.from(unitSources));
+ dartCopy.setValue(DartEntry.INCLUDED_PARTS, unitSources);
}
/**
@@ -5316,7 +5583,6 @@
throw new AnalysisException.con1("Internal error: attempting to verify non-Dart file as a Dart file: ${source.fullName}");
}
dartEntry = sourceEntry as DartEntry;
- _cache.accessed(source);
int sourceTime = source.modificationStamp;
int resultTime = task.modificationTime;
if (sourceTime == resultTime) {
@@ -5348,8 +5614,11 @@
// will be re-verified using the up-to-date sources.
//
// dartCopy.setState(DartEntry.VERIFICATION_ERRORS, librarySource, CacheState.INVALID);
+ removeFromParts(source, dartEntry);
dartCopy.invalidateAllInformation();
dartCopy.modificationTime = sourceTime;
+ _cache.removedAst(source);
+ _workManager.add(source, SourcePriority.UNKNOWN);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5416,7 +5685,6 @@
if (unitSource == librarySource) {
libraryEntry = dartEntry;
}
- _cache.accessed(unitSource);
int sourceTime = unitSource.modificationStamp;
int resultTime = results.modificationTime;
if (sourceTime == resultTime) {
@@ -5449,8 +5717,11 @@
// will be re-analyzed using the up-to-date sources.
//
// dartCopy.setState(DartEntry.HINTS, librarySource, CacheState.INVALID);
+ removeFromParts(unitSource, dartEntry);
dartCopy.invalidateAllInformation();
dartCopy.modificationTime = sourceTime;
+ _cache.removedAst(unitSource);
+ _workManager.add(unitSource, SourcePriority.UNKNOWN);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5511,7 +5782,6 @@
throw new AnalysisException.con1("Internal error: attempting to parse non-Dart file as a Dart file: ${source.fullName}");
}
dartEntry = sourceEntry as DartEntry;
- _cache.accessed(source);
int sourceTime = source.modificationStamp;
int resultTime = task.modificationTime;
if (sourceTime == resultTime) {
@@ -5529,18 +5799,24 @@
dartCopy.setValue(SourceEntry.LINE_INFO, lineInfo);
if (task.hasPartOfDirective() && !task.hasLibraryDirective()) {
dartCopy.setValue(DartEntry.SOURCE_KIND, SourceKind.PART);
+ _workManager.add(source, SourcePriority.NORMAL_PART);
} else {
dartCopy.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY);
+ dartCopy.containingLibrary = source;
+ _workManager.add(source, SourcePriority.LIBRARY);
}
dartCopy.setValue(DartEntry.PARSED_UNIT, task.compilationUnit);
dartCopy.setValue(DartEntry.PARSE_ERRORS, task.errors);
+ _cache.storedAst(source);
ChangeNoticeImpl notice = getNotice(source);
notice.setErrors(dartEntry.allErrors, lineInfo);
// Verify that the incrementally parsed and resolved unit in the incremental cache
// is structurally equivalent to the fully parsed unit
_incrementalAnalysisCache = IncrementalAnalysisCache.verifyStructure(_incrementalAnalysisCache, source, task.compilationUnit);
} else {
+ removeFromParts(source, dartEntry);
dartCopy.recordParseError();
+ _cache.removedAst(source);
}
dartCopy.exception = thrownException;
_cache.put(source, dartCopy);
@@ -5554,8 +5830,11 @@
// will be re-analyzed using the up-to-date sources.
//
// dartCopy.recordParseNotInProcess();
+ removeFromParts(source, dartEntry);
dartCopy.invalidateAllInformation();
dartCopy.modificationTime = sourceTime;
+ _cache.removedAst(source);
+ _workManager.add(source, SourcePriority.UNKNOWN);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5595,7 +5874,6 @@
throw new AnalysisException.con1("Internal error: attempting to parse non-HTML file as a HTML file: ${source.fullName}");
}
htmlEntry = sourceEntry as HtmlEntry;
- _cache.accessed(source);
int sourceTime = source.modificationStamp;
int resultTime = task.modificationTime;
if (sourceTime == resultTime) {
@@ -5615,10 +5893,12 @@
htmlCopy.setValue(HtmlEntry.PARSED_UNIT, unit);
htmlCopy.setValue(HtmlEntry.PARSE_ERRORS, task.errors);
htmlCopy.setValue(HtmlEntry.REFERENCED_LIBRARIES, task.referencedLibraries);
+ _cache.storedAst(source);
ChangeNoticeImpl notice = getNotice(source);
notice.setErrors(htmlEntry.allErrors, lineInfo);
} else {
htmlCopy.recordParseError();
+ _cache.removedAst(source);
}
htmlCopy.exception = thrownException;
_cache.put(source, htmlCopy);
@@ -5642,6 +5922,7 @@
// }
htmlCopy.invalidateAllInformation();
htmlCopy.modificationTime = sourceTime;
+ _cache.removedAst(source);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5650,6 +5931,7 @@
//
htmlCopy.setState(SourceEntry.LINE_INFO, CacheState.ERROR);
htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.ERROR);
+ htmlCopy.setState(HtmlEntry.RESOLVED_UNIT, CacheState.ERROR);
htmlCopy.setState(HtmlEntry.REFERENCED_LIBRARIES, CacheState.ERROR);
}
htmlCopy.exception = thrownException;
@@ -5682,7 +5964,6 @@
throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
}
htmlEntry = sourceEntry as HtmlEntry;
- _cache.accessed(source);
int sourceTime = source.modificationStamp;
int resultTime = task.modificationTime;
if (sourceTime == resultTime) {
@@ -5724,6 +6005,87 @@
// }
htmlCopy.invalidateAllInformation();
htmlCopy.modificationTime = sourceTime;
+ _cache.removedAst(source);
+ } else {
+ //
+ // We could not determine whether the sources were up-to-date or out-of-date. Mark the
+ // cache so that we won't attempt to re-analyze the sources until there's a good chance
+ // that we'll be able to do so without error.
+ //
+ htmlCopy.recordResolutionError();
+ }
+ htmlCopy.exception = thrownException;
+ _cache.put(source, htmlCopy);
+ htmlEntry = htmlCopy;
+ }
+ }
+ if (thrownException != null) {
+ throw thrownException;
+ }
+ return htmlEntry;
+ }
+
+ /**
+ * Record the results produced by performing a [ResolveAngularEntryHtmlTask]. If the results
+ * were computed from data that is now out-of-date, then the results will not be recorded.
+ *
+ * @param task the task that was performed
+ * @throws AnalysisException if the results could not be recorded
+ */
+ HtmlEntry recordResolveAngularEntryHtmlTaskResults(ResolveAngularEntryHtmlTask task) {
+ Source source = task.source;
+ AnalysisException thrownException = task.exception;
+ HtmlEntry htmlEntry = null;
+ {
+ SourceEntry sourceEntry = _cache.get(source);
+ if (sourceEntry is! HtmlEntry) {
+ // This shouldn't be possible because we should never have performed the task if the source
+ // didn't represent an HTML file, but check to be safe.
+ throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
+ }
+ htmlEntry = sourceEntry as HtmlEntry;
+ int sourceTime = source.modificationStamp;
+ int resultTime = task.modificationTime;
+ if (sourceTime == resultTime) {
+ if (htmlEntry.modificationTime != sourceTime) {
+ // The source has changed without the context being notified. Simulate notification.
+ sourceChanged(source);
+ htmlEntry = getReadableHtmlEntry(source);
+ if (htmlEntry == null) {
+ throw new AnalysisException.con1("An HTML file became a non-HTML file: ${source.fullName}");
+ }
+ }
+ HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+ if (thrownException == null) {
+ htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, task.resolutionErrors);
+ ChangeNoticeImpl notice = getNotice(source);
+ notice.htmlUnit = task.resolvedUnit;
+ notice.setErrors(htmlCopy.allErrors, htmlCopy.getValue(SourceEntry.LINE_INFO));
+ } else {
+ htmlCopy.recordResolutionError();
+ }
+ htmlCopy.exception = thrownException;
+ _cache.put(source, htmlCopy);
+ htmlEntry = htmlCopy;
+ } else {
+ HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+ if (thrownException == null || resultTime >= 0) {
+ //
+ // The analysis was performed on out-of-date sources. Mark the cache so that the sources
+ // will be re-analyzed using the up-to-date sources.
+ //
+ // if (htmlCopy.getState(HtmlEntry.ANGULAR_ERRORS) == CacheState.IN_PROCESS) {
+ // htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
+ // }
+ // if (htmlCopy.getState(HtmlEntry.ELEMENT) == CacheState.IN_PROCESS) {
+ // htmlCopy.setState(HtmlEntry.ELEMENT, CacheState.INVALID);
+ // }
+ // if (htmlCopy.getState(HtmlEntry.RESOLUTION_ERRORS) == CacheState.IN_PROCESS) {
+ // htmlCopy.setState(HtmlEntry.RESOLUTION_ERRORS, CacheState.INVALID);
+ // }
+ htmlCopy.invalidateAllInformation();
+ htmlCopy.modificationTime = sourceTime;
+ _cache.removedAst(source);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5763,7 +6125,6 @@
throw new AnalysisException.con1("Internal error: attempting to resolve Dart dependencies in a non-Dart file: ${source.fullName}");
}
dartEntry = sourceEntry as DartEntry;
- _cache.accessed(source);
int sourceTime = source.modificationStamp;
int resultTime = task.modificationTime;
if (sourceTime == resultTime) {
@@ -5775,11 +6136,22 @@
throw new AnalysisException.con1("A Dart file became a non-Dart file: ${source.fullName}");
}
}
+ removeFromParts(source, dartEntry);
DartEntryImpl dartCopy = dartEntry.writableCopy;
if (thrownException == null) {
+ List<Source> newParts = task.includedSources;
+ for (int i = 0; i < newParts.length; i++) {
+ Source partSource = newParts[i];
+ DartEntry partEntry = getReadableDartEntry(partSource);
+ if (partEntry != null && partEntry != dartEntry) {
+ DartEntryImpl partCopy = partEntry.writableCopy;
+ partCopy.addContainingLibrary(source);
+ _cache.put(partSource, partCopy);
+ }
+ }
dartCopy.setValue(DartEntry.EXPORTED_LIBRARIES, task.exportedSources);
dartCopy.setValue(DartEntry.IMPORTED_LIBRARIES, task.importedSources);
- dartCopy.setValue(DartEntry.INCLUDED_PARTS, task.includedSources);
+ dartCopy.setValue(DartEntry.INCLUDED_PARTS, newParts);
} else {
dartCopy.recordDependencyError();
}
@@ -5795,8 +6167,11 @@
// will be re-analyzed using the up-to-date sources.
//
// dartCopy.recordDependencyNotInProcess();
+ removeFromParts(source, dartEntry);
dartCopy.invalidateAllInformation();
dartCopy.modificationTime = sourceTime;
+ _cache.removedAst(source);
+ _workManager.add(source, SourcePriority.UNKNOWN);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5839,7 +6214,6 @@
throw new AnalysisException.con1("Internal error: attempting to resolve non-Dart file as a Dart file: ${unitSource.fullName}");
}
dartEntry = sourceEntry as DartEntry;
- _cache.accessed(unitSource);
int sourceTime = unitSource.modificationStamp;
int resultTime = task.modificationTime;
if (sourceTime == resultTime) {
@@ -5854,8 +6228,10 @@
DartEntryImpl dartCopy = dartEntry.writableCopy;
if (thrownException == null) {
dartCopy.setValue2(DartEntry.RESOLVED_UNIT, librarySource, task.resolvedUnit);
+ _cache.storedAst(unitSource);
} else {
dartCopy.setState2(DartEntry.RESOLVED_UNIT, librarySource, CacheState.ERROR);
+ _cache.removedAst(unitSource);
}
dartCopy.exception = thrownException;
_cache.put(unitSource, dartCopy);
@@ -5871,8 +6247,11 @@
// if (dartCopy.getState(DartEntry.RESOLVED_UNIT) == CacheState.IN_PROCESS) {
// dartCopy.setState(DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID);
// }
+ removeFromParts(unitSource, dartEntry);
dartCopy.invalidateAllInformation();
dartCopy.modificationTime = sourceTime;
+ _cache.removedAst(unitSource);
+ _workManager.add(unitSource, SourcePriority.UNKNOWN);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5912,7 +6291,6 @@
throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
}
htmlEntry = sourceEntry as HtmlEntry;
- _cache.accessed(source);
int sourceTime = source.modificationStamp;
int resultTime = task.modificationTime;
if (sourceTime == resultTime) {
@@ -5926,15 +6304,20 @@
}
HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
if (thrownException == null) {
+ htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.FLUSHED);
+ htmlCopy.setValue(HtmlEntry.RESOLVED_UNIT, task.resolvedUnit);
htmlCopy.setValue(HtmlEntry.ELEMENT, task.element);
htmlCopy.setValue(HtmlEntry.RESOLUTION_ERRORS, task.resolutionErrors);
+ _cache.storedAst(source);
ChangeNoticeImpl notice = getNotice(source);
notice.htmlUnit = task.resolvedUnit;
notice.setErrors(htmlCopy.allErrors, htmlCopy.getValue(SourceEntry.LINE_INFO));
} else {
htmlCopy.recordResolutionError();
+ _cache.removedAst(source);
}
htmlCopy.exception = thrownException;
+ recordAngularComponents(htmlCopy, task.angularApplication);
_cache.put(source, htmlCopy);
htmlEntry = htmlCopy;
} else {
@@ -5953,6 +6336,7 @@
// }
htmlCopy.invalidateAllInformation();
htmlCopy.modificationTime = sourceTime;
+ _cache.removedAst(source);
} else {
//
// We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5973,6 +6357,46 @@
}
/**
+ * Remove the given library from the list of containing libraries for all of the parts referenced
+ * by the given entry.
+ *
+ * <b>Note:</b> This method must only be invoked while we are synchronized on [cacheLock].
+ *
+ * @param librarySource the library to be removed
+ * @param dartEntry the entry containing the list of included parts
+ */
+ void removeFromParts(Source librarySource, DartEntry dartEntry) {
+ List<Source> oldParts = dartEntry.getValue(DartEntry.INCLUDED_PARTS);
+ for (int i = 0; i < oldParts.length; i++) {
+ Source partSource = oldParts[i];
+ DartEntry partEntry = getReadableDartEntry(partSource);
+ if (partEntry != null && partEntry != dartEntry) {
+ DartEntryImpl partCopy = partEntry.writableCopy;
+ partCopy.removeContainingLibrary(librarySource);
+ _cache.put(partSource, partCopy);
+ }
+ }
+ }
+
+ /**
+ * Remove the given source from the priority order if it is in the list.
+ *
+ * @param source the source to be removed
+ */
+ void removeFromPriorityOrder(Source source) {
+ int count = _priorityOrder.length;
+ List<Source> newOrder = new List<Source>();
+ for (int i = 0; i < count; i++) {
+ if (_priorityOrder[i] != source) {
+ newOrder.add(_priorityOrder[i]);
+ }
+ }
+ if (newOrder.length < count) {
+ analysisPriorityOrder = newOrder;
+ }
+ }
+
+ /**
* Create an entry for the newly added source. Return `true` if the new source is a Dart
* file.
*
@@ -5994,6 +6418,11 @@
_cache.put(source, sourceCopy);
logInformation("Added new source: ${debuggingString(source)} (previously modified at ${oldTime})");
}
+ if (sourceEntry is HtmlEntry) {
+ _workManager.add(source, SourcePriority.HTML);
+ } else {
+ _workManager.add(source, SourcePriority.UNKNOWN);
+ }
return sourceEntry is DartEntry;
}
@@ -6020,6 +6449,8 @@
htmlCopy.modificationTime = source.modificationStamp;
htmlCopy.invalidateAllInformation();
_cache.put(source, htmlCopy);
+ _cache.removedAst(source);
+ _workManager.add(source, SourcePriority.HTML);
logInformation("Modified HTML source: ${debuggingString(source)} (previously modified at ${oldTime})");
} else if (sourceEntry is DartEntry) {
List<Source> containingLibraries = getLibrariesContaining(source);
@@ -6037,10 +6468,13 @@
// for (Source library : containingLibraries) {
invalidateLibraryResolution(library, writer);
}
+ removeFromParts(source, sourceEntry);
DartEntryImpl dartCopy = sourceEntry.writableCopy;
dartCopy.modificationTime = source.modificationStamp;
dartCopy.invalidateAllInformation();
_cache.put(source, dartCopy);
+ _cache.removedAst(source);
+ _workManager.add(source, SourcePriority.UNKNOWN);
logInformation(writer.toString());
}
}
@@ -6067,6 +6501,8 @@
}
}
_cache.remove(source);
+ _workManager.remove(source);
+ removeFromPriorityOrder(source);
logInformation(writer.toString());
}
@@ -6081,6 +6517,7 @@
*/
bool validateCacheConsistency() {
int consistencyCheckStart = JavaSystem.nanoTime();
+ List<Source> missingSources = new List<Source>();
int inconsistentCount = 0;
{
for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
@@ -6091,10 +6528,29 @@
sourceChanged(source);
inconsistentCount++;
}
+ if (sourceEntry.exception != null) {
+ if (!source.exists()) {
+ missingSources.add(source);
+ }
+ }
}
}
int consistencyCheckEnd = JavaSystem.nanoTime();
- logInformation("Consistency check found ${inconsistentCount} inconsistent entries in ${((consistencyCheckEnd - consistencyCheckStart) / 1000000.0)} ms");
+ PrintStringWriter writer = new PrintStringWriter();
+ writer.print("Consistency check took ");
+ writer.print((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
+ writer.println(" ms and found");
+ writer.print(" ");
+ writer.print(inconsistentCount);
+ writer.println(" inconsistent entries");
+ writer.print(" ");
+ writer.print(missingSources.length);
+ writer.println(" missing sources");
+ for (Source source in missingSources) {
+ writer.print(" ");
+ writer.println(source.fullName);
+ }
+ logInformation(writer.toString());
return inconsistentCount > 0;
}
}
@@ -6120,6 +6576,8 @@
HtmlEntry visitResolveAngularComponentTemplateTask(ResolveAngularComponentTemplateTask task) => AnalysisContextImpl_this.recordResolveAngularComponentTemplateTaskResults(task);
+ SourceEntry visitResolveAngularEntryHtmlTask(ResolveAngularEntryHtmlTask task) => AnalysisContextImpl_this.recordResolveAngularEntryHtmlTaskResults(task);
+
DartEntry visitResolveDartDependenciesTask(ResolveDartDependenciesTask task) => AnalysisContextImpl_this.recordResolveDartDependenciesTaskResults(task);
DartEntry visitResolveDartLibraryTask(ResolveDartLibraryTask task) => AnalysisContextImpl_this.recordResolveDartLibraryTaskResults(task);
@@ -6917,6 +7375,8 @@
}
}
+ ResolvableHtmlUnit computeResolvableAngularComponentHtmlUnit(Source source) => _basis.computeResolvableAngularComponentHtmlUnit(source);
+
ResolvableCompilationUnit computeResolvableCompilationUnit(Source source) => _basis.computeResolvableCompilationUnit(source);
ResolvableHtmlUnit computeResolvableHtmlUnit(Source source) => _basis.computeResolvableHtmlUnit(source);
@@ -7078,16 +7538,6 @@
}
}
- List<AngularElement> getLibraryAngularElements(Source source) {
- InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-getLibraryAngularElements");
- try {
- instrumentation.metric3("contextId", _contextId);
- return _basis.getLibraryAngularElements(source);
- } finally {
- instrumentation.log();
- }
- }
-
LibraryElement getLibraryElement(Source source) {
InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-getLibraryElement");
try {
@@ -7388,6 +7838,16 @@
/**
* Return an AST structure corresponding to the given source, but ensure that the structure has
+ * not already been resolved and will not be resolved by any other threads.
+ *
+ * @param source the compilation unit for which an AST structure should be returned
+ * @return the AST structure representing the content of the source
+ * @throws AnalysisException if the analysis could not be performed
+ */
+ ResolvableHtmlUnit computeResolvableAngularComponentHtmlUnit(Source source);
+
+ /**
+ * Return an AST structure corresponding to the given source, but ensure that the structure has
* not already been resolved and will not be resolved by any other threads or in any other
* library.
*
@@ -7717,6 +8177,44 @@
}
/**
+ * The enumerated type `Priority` defines the priority levels used to return sources in an
+ * optimal order.
+ */
+class SourcePriority extends Enum<SourcePriority> {
+ /**
+ * Used for a Dart source that is known to be a part contained in a library that was recently
+ * resolved. These parts are given a higher priority because there is a high probability that
+ * their AST structure is still in the cache and therefore would not need to be re-created.
+ */
+ static final SourcePriority PRIORITY_PART = new SourcePriority('PRIORITY_PART', 0);
+
+ /**
+ * Used for a Dart source that is known to be a library.
+ */
+ static final SourcePriority LIBRARY = new SourcePriority('LIBRARY', 1);
+
+ /**
+ * Used for a Dart source that is known to be a part but whose library has not yet been
+ * resolved.
+ */
+ static final SourcePriority NORMAL_PART = new SourcePriority('NORMAL_PART', 2);
+
+ /**
+ * Used for a Dart source whose kind is unknown.
+ */
+ static final SourcePriority UNKNOWN = new SourcePriority('UNKNOWN', 3);
+
+ /**
+ * Used for an HTML source.
+ */
+ static final SourcePriority HTML = new SourcePriority('HTML', 4);
+
+ static final List<SourcePriority> values = [PRIORITY_PART, LIBRARY, NORMAL_PART, UNKNOWN, HTML];
+
+ SourcePriority(String name, int ordinal) : super(name, ordinal);
+}
+
+/**
* Instances of the class `TimestampedData` represent analysis data for which we have a
* modification time.
*/
@@ -7741,21 +8239,194 @@
}
/**
+ * Instances of the class `WorkManager` manage a list of sources that need to have analysis
+ * work performed on them.
+ */
+class WorkManager {
+ /**
+ * An array containing the various queues is priority order.
+ */
+ List<List<Source>> _workQueues;
+
+ /**
+ * Initialize a newly created manager to have no work queued up.
+ */
+ WorkManager() {
+ int queueCount = SourcePriority.values.length;
+ _workQueues = new List<List>(queueCount);
+ for (int i = 0; i < queueCount; i++) {
+ _workQueues[i] = new List<Source>();
+ }
+ }
+
+ /**
+ * Record that the given source needs to be analyzed. The priority level is used to control when
+ * the source will be analyzed with respect to other sources.
+ *
+ * @param source the source that needs to be analyzed
+ * @param priority the priority level of the source
+ */
+ void add(Source source, SourcePriority priority) {
+ // TODO(brianwilkerson) Optimize the order of the libraries so that libraries that depend on
+ // other libraries get analyzed after the other libraries.
+ int queueCount = _workQueues.length;
+ int ordinal = priority.ordinal;
+ for (int i = 0; i < queueCount; i++) {
+ List<Source> queue = _workQueues[i];
+ if (i == ordinal) {
+ if (!queue.contains(source)) {
+ queue.add(source);
+ }
+ } else {
+ queue.remove(source);
+ }
+ }
+ }
+
+ /**
+ * Return the next source for which some analysis work needs to be done.
+ *
+ * @return the next source for which some analysis work needs to be done
+ */
+ Source get nextSource {
+ int queueCount = _workQueues.length;
+ for (int i = 0; i < queueCount; i++) {
+ List<Source> queue = _workQueues[i];
+ if (!queue.isEmpty) {
+ return queue[0];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Record that the given source is fully analyzed.
+ *
+ * @param source the source that is fully analyzed
+ */
+ void remove(Source source) {
+ int queueCount = _workQueues.length;
+ for (int i = 0; i < queueCount; i++) {
+ _workQueues[i].remove(source);
+ }
+ }
+}
+
+/**
+ * An [Expression] with optional [AngularFilterNode]s.
+ *
+ * @coverage dart.engine.ast
+ */
+class AngularExpression {
+ /**
+ * The [Expression] to apply filters to.
+ */
+ final Expression expression;
+
+ /**
+ * The filters to apply.
+ */
+ final List<AngularFilterNode> filters;
+
+ AngularExpression(this.expression, this.filters);
+
+ /**
+ * Return the offset of the character immediately following the last character of this node's
+ * source range. This is equivalent to `node.getOffset() + node.getLength()`.
+ *
+ * @return the offset of the character just past the node's source range
+ */
+ int get end {
+ if (filters.isEmpty) {
+ return expression.end;
+ }
+ AngularFilterNode lastFilter = filters[filters.length - 1];
+ List<AngularFilterArgument> filterArguments = lastFilter.arguments;
+ if (filterArguments.isEmpty) {
+ return lastFilter.name.end;
+ }
+ return filterArguments[filterArguments.length - 1].expression.end;
+ }
+
+ /**
+ * Return Dart [Expression]s this Angular expression consists of.
+ */
+ List<Expression> get expressions {
+ List<Expression> expressions = [];
+ expressions.add(expression);
+ for (AngularFilterNode filter in filters) {
+ expressions.add(filter.name);
+ for (AngularFilterArgument filterArgument in filter.arguments) {
+ expressions.addAll(filterArgument.subExpressions);
+ expressions.add(filterArgument.expression);
+ }
+ }
+ return expressions;
+ }
+
+ /**
+ * Return the number of characters in the expression's source range.
+ */
+ int get length => end - offset;
+
+ /**
+ * Return the offset of the first character in the expression's source range.
+ */
+ int get offset => expression.offset;
+}
+
+/**
+ * Angular filter argument.
+ *
+ * @coverage dart.engine.ast
+ */
+class AngularFilterArgument {
+ /**
+ * The [TokenType#COLON] token.
+ */
+ final Token token;
+
+ /**
+ * The argument expression.
+ */
+ final Expression expression;
+
+ /**
+ * The optional sub-[Expression]s.
+ */
+ List<Expression> subExpressions = Expression.EMPTY_ARRAY;
+
+ AngularFilterArgument(this.token, this.expression);
+}
+
+/**
+ * Angular filter node.
+ *
+ * @coverage dart.engine.ast
+ */
+class AngularFilterNode {
+ /**
+ * The [TokenType#BAR] token.
+ */
+ final Token token;
+
+ /**
+ * The name of the filter.
+ */
+ final SimpleIdentifier name;
+
+ /**
+ * The arguments for this filter.
+ */
+ final List<AngularFilterArgument> arguments;
+
+ AngularFilterNode(this.token, this.name, this.arguments);
+}
+
+/**
* Instances of the class [AngularHtmlUnitResolver] resolve Angular specific expressions.
*/
class AngularHtmlUnitResolver extends ht.RecursiveXmlVisitor<Object> {
- static int _OPENING_DELIMITER_CHAR = 0x7B;
-
- static int _CLOSING_DELIMITER_CHAR = 0x7D;
-
- static String _OPENING_DELIMITER = "{{";
-
- static String _CLOSING_DELIMITER = "}}";
-
- static int _OPENING_DELIMITER_LENGTH = _OPENING_DELIMITER.length;
-
- static int _CLOSING_DELIMITER_LENGTH = _CLOSING_DELIMITER.length;
-
static String _NG_APP = "ng-app";
/**
@@ -7776,6 +8447,21 @@
}
/**
+ * Returns the array of all top-level Angular elements that could be used in the application with
+ * this entry point. Maybe `null` of not an Angular entry point.
+ */
+ static List<AngularElement> getAngularElements(AnalysisContext context, ht.HtmlUnit unit) {
+ if (hasAngularAnnotation(unit)) {
+ CompilationUnit dartUnit = getDartUnit(context, unit);
+ if (dartUnit != null) {
+ LibraryElement libraryElement = dartUnit.element.library;
+ return getAngularElements2(libraryElement);
+ }
+ }
+ return null;
+ }
+
+ /**
* @return `true` if the given [HtmlUnit] has <code>ng-app</code> annotation.
*/
static bool hasAngularAnnotation(ht.HtmlUnit htmlUnit) {
@@ -7792,8 +8478,72 @@
return new SimpleIdentifier(token);
}
+ /**
+ * Adds [AngularElement] declared by the given top-level [Element].
+ *
+ * @param angularElements the list to fill with top-level [AngularElement]s
+ * @param classElement the [ClassElement] to get [AngularElement]s from
+ */
+ static void addAngularElements(Set<AngularElement> angularElements, ClassElement classElement) {
+ for (ToolkitObjectElement toolkitObject in classElement.toolkitObjects) {
+ if (toolkitObject is AngularElement) {
+ angularElements.add(toolkitObject);
+ }
+ }
+ }
+
+ /**
+ * Returns the array of all top-level Angular elements that could be used in this library.
+ *
+ * @param libraryElement the [LibraryElement] to analyze
+ * @return the array of all top-level Angular elements that could be used in this library
+ */
+ static void addAngularElements2(Set<AngularElement> angularElements, LibraryElement library, Set<LibraryElement> visited) {
+ if (!visited.add(library)) {
+ return;
+ }
+ // add Angular elements from current library
+ for (CompilationUnitElement unit in library.units) {
+ for (ClassElement type in unit.types) {
+ addAngularElements(angularElements, type);
+ }
+ }
+ // handle imports
+ for (ImportElement importElement in library.imports) {
+ LibraryElement importedLibrary = importElement.importedLibrary;
+ addAngularElements2(angularElements, importedLibrary, visited);
+ }
+ }
+
static StringToken createStringToken(String name, int offset) => new StringToken(TokenType.IDENTIFIER, name, offset);
+ /**
+ * Returns the array of all top-level Angular elements that could be used in this library.
+ *
+ * @param libraryElement the [LibraryElement] to analyze
+ * @return the array of all top-level Angular elements that could be used in this library
+ */
+ static List<AngularElement> getAngularElements2(LibraryElement libraryElement) {
+ Set<AngularElement> angularElements = new Set();
+ addAngularElements2(angularElements, libraryElement, new Set());
+ return new List.from(angularElements);
+ }
+
+ /**
+ * Returns the external Dart [CompilationUnit] referenced by the given [HtmlUnit].
+ */
+ static CompilationUnit getDartUnit(AnalysisContext context, ht.HtmlUnit unit) {
+ for (HtmlScriptElement script in unit.element.scripts) {
+ if (script is ExternalHtmlScriptElement) {
+ Source scriptSource = script.scriptSource;
+ if (scriptSource != null) {
+ return context.resolveCompilationUnit2(scriptSource, scriptSource);
+ }
+ }
+ }
+ return null;
+ }
+
InternalAnalysisContext _context;
TypeProvider _typeProvider;
@@ -7838,40 +8588,69 @@
}
/**
- * Resolves [source] as an [AngularComponentElement] template file.
- *
- * @param angularElements the [AngularElement]s accessible in the component's library, not
- * `null`
- * @param component the [AngularComponentElement] to resolve template for, not `null`
+ * The [AngularApplicationInfo] for the Web application with this entry point, may be
+ * `null` if not an entry point.
*/
- void resolveComponentTemplate(List<AngularElement> angularElements, AngularComponentElement component) {
- _isAngular = true;
- resolveInternal(angularElements, component);
+ AngularApplicationInfo calculateAngularApplication() {
+ // check if Angular at all
+ if (!hasAngularAnnotation(_unit)) {
+ return null;
+ }
+ // prepare resolved Dart unit
+ CompilationUnit dartUnit = getDartUnit(_context, _unit);
+ if (dartUnit == null) {
+ return null;
+ }
+ // prepare accessible Angular elements
+ LibraryElement libraryElement = dartUnit.element.library;
+ List<AngularElement> angularElements = getAngularElements2(libraryElement);
+ // resolve template URIs
+ // TODO(scheglov) resolve to HtmlElement to allow F3 ?
+ for (AngularElement angularElement in angularElements) {
+ if (angularElement is AngularComponentElement) {
+ AngularComponentElement component = angularElement;
+ String templateUri = component.templateUri;
+ if (templateUri == null) {
+ continue;
+ }
+ try {
+ Source templateSource = _source.resolveRelative(parseUriWithException(templateUri));
+ if (templateSource == null || !templateSource.exists()) {
+ templateSource = _context.sourceFactory.resolveUri(_source, "package:${templateUri}");
+ if (templateSource == null || !templateSource.exists()) {
+ reportError7(component.templateUriOffset, templateUri.length, AngularCode.URI_DOES_NOT_EXIST, [templateUri]);
+ continue;
+ }
+ }
+ if (!AnalysisEngine.isHtmlFileName(templateUri)) {
+ continue;
+ }
+ (component as AngularComponentElementImpl).templateSource = templateSource;
+ } on URISyntaxException catch (exception) {
+ reportError7(component.templateUriOffset, templateUri.length, AngularCode.INVALID_URI, [templateUri]);
+ }
+ }
+ }
+ // done
+ return new AngularApplicationInfo(_source, angularElements);
}
/**
- * Resolves [source] as an entry-point HTML file, that references an external Dart script.
+ * Resolves [source] as an [AngularComponentElement] template file.
+ *
+ * @param application the Angular application we are resolving for
+ * @param component the [AngularComponentElement] to resolve template for, not `null`
*/
- void resolveEntryPoint() {
- // check if Angular at all
- if (!hasAngularAnnotation(_unit)) {
- return;
- }
- // prepare accessible Angular elements
- List<AngularElement> angularElements;
- {
- // prepare external Dart script source
- Source dartSource = getDartSource(_unit);
- if (dartSource == null) {
- return;
- }
- // ensure resolved
- _context.resolveCompilationUnit2(dartSource, dartSource);
- // get cached Angular elements
- angularElements = _context.getLibraryAngularElements(dartSource);
- }
- // perform resolution
- resolveInternal(angularElements, null);
+ void resolveComponentTemplate(AngularApplicationInfo application, AngularComponentElement component) {
+ _isAngular = true;
+ resolveInternal(application.elements, component);
+ }
+
+ /**
+ * Resolves [source] as an Angular application entry point.
+ */
+ void resolveEntryPoint(AngularApplicationInfo application) {
+ resolveInternal(application.elements, null);
}
Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
@@ -7976,16 +8755,63 @@
TypeProvider get typeProvider => _typeProvider;
/**
- * Parses given [String] as an [Expression] at the given offset.
+ * Parses given [String] as an [AngularExpression] at the given offset.
*/
- Expression parseExpression(String contents, int offset) => parseExpression2(contents, 0, contents.length, offset);
+ AngularExpression parseAngularExpression(String contents, int offset) => parseAngularExpression2(contents, 0, contents.length, offset);
- Expression parseExpression2(String contents, int startIndex, int endIndex, int offset) {
+ AngularExpression parseAngularExpression2(String contents, int startIndex, int endIndex, int offset) {
Token token = scanDart(contents, startIndex, endIndex, offset);
- return parseExpression3(token);
+ return parseAngularExpression3(token);
}
- Expression parseExpression3(Token token) => ht.HtmlParser.parseEmbeddedExpression(_source, token, _errorListener);
+ AngularExpression parseAngularExpression3(Token token) {
+ List<Token> tokens = splitAtBar(token);
+ Expression mainExpression = parseDartExpression3(tokens[0]);
+ // parse filters
+ List<AngularFilterNode> filters = [];
+ for (int i = 1; i < tokens.length; i++) {
+ Token filterToken = tokens[i];
+ Token barToken = filterToken;
+ filterToken = filterToken.next;
+ // TODO(scheglov) report missing identifier
+ SimpleIdentifier name = parseDartExpression3(filterToken) as SimpleIdentifier;
+ filterToken = name.endToken.next;
+ // parse arguments
+ List<AngularFilterArgument> arguments = [];
+ while (filterToken.type != TokenType.EOF) {
+ // skip ":"
+ Token colonToken = filterToken;
+ if (identical(colonToken.type, TokenType.COLON)) {
+ filterToken = filterToken.next;
+ } else {
+ reportError8(colonToken, AngularCode.MISSING_FILTER_COLON, []);
+ }
+ // parse argument
+ Expression argument = parseDartExpression3(filterToken);
+ arguments.add(new AngularFilterArgument(colonToken, argument));
+ // next token
+ filterToken = argument.endToken.next;
+ }
+ filters.add(new AngularFilterNode(barToken, name, arguments));
+ }
+ // done
+ return new AngularExpression(mainExpression, filters);
+ }
+
+ /**
+ * Parses given [String] as an [Expression] at the given offset.
+ */
+ Expression parseDartExpression(String contents, int offset) => parseDartExpression2(contents, 0, contents.length, offset);
+
+ Expression parseDartExpression2(String contents, int startIndex, int endIndex, int offset) {
+ Token token = scanDart(contents, startIndex, endIndex, offset);
+ return parseDartExpression3(token);
+ }
+
+ Expression parseDartExpression3(Token token) {
+ Parser parser = new Parser(_source, _errorListener);
+ return parser.parseExpression(token);
+ }
void popNameScope() {
_nameScope = _resolver.popNameScope();
@@ -8010,6 +8836,20 @@
}
/**
+ * Reports given [ErrorCode] at the given [Token].
+ */
+ void reportError8(Token token, ErrorCode errorCode, List<Object> arguments) {
+ reportError7(token.offset, token.length, errorCode, arguments);
+ }
+
+ void resolveExpression(AngularExpression angularExpression) {
+ List<Expression> dartExpressions = angularExpression.expressions;
+ for (Expression dartExpression in dartExpressions) {
+ resolveNode(dartExpression);
+ }
+ }
+
+ /**
* Resolves given [ASTNode] using [resolver].
*/
void resolveNode(ASTNode node) {
@@ -8030,6 +8870,8 @@
// create LibraryElementImpl
_libraryElement = new LibraryElementImpl(_context, null);
_libraryElement.definingCompilationUnit = _unitElement;
+ _libraryElement.angularHtml = true;
+ _injectedLibraries.add(_libraryElement);
// create FunctionElementImpl
_functionElement = new FunctionElementImpl.con2(0);
_unitElement.functions = <FunctionElement> [_functionElement];
@@ -8073,18 +8915,14 @@
}
/**
- * Returns the external Dart script [Source] referenced by the given [HtmlUnit].
+ * Defines variable for the given [AngularElement].
*/
- Source getDartSource(ht.HtmlUnit unit) {
- for (HtmlScriptElement script in unit.element.scripts) {
- if (script is ExternalHtmlScriptElement) {
- Source scriptSource = script.scriptSource;
- if (scriptSource != null) {
- return scriptSource;
- }
- }
- }
- return null;
+ void defineTopElementVariable(AngularElement element) {
+ ClassElement classElement = element.enclosingElement as ClassElement;
+ InterfaceType type = classElement.type;
+ LocalVariableElementImpl variable = createLocalVariable2(type, element.name);
+ defineTopVariable(variable);
+ variable.toolkitObjects = <AngularElement> [element];
}
/**
@@ -8094,28 +8932,28 @@
* @param expressions the list to which embedded expressions are to be added
* @param token the token whose value is to be parsed
*/
- void parseEmbeddedExpressions(List<ht.EmbeddedExpression> expressions, ht.Token token) {
+ void parseEmbeddedExpressions(List<AngularMoustacheXmlExpression> expressions, ht.Token token) {
// prepare Token information
String lexeme = token.lexeme;
int offset = token.offset;
// find expressions between {{ and }}
- int startIndex = StringUtilities.indexOf2(lexeme, 0, _OPENING_DELIMITER_CHAR, _OPENING_DELIMITER_CHAR);
+ int startIndex = StringUtilities.indexOf2(lexeme, 0, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR);
while (startIndex >= 0) {
- int endIndex = StringUtilities.indexOf2(lexeme, startIndex + _OPENING_DELIMITER_LENGTH, _CLOSING_DELIMITER_CHAR, _CLOSING_DELIMITER_CHAR);
+ int endIndex = StringUtilities.indexOf2(lexeme, startIndex + AngularMoustacheXmlExpression.OPENING_DELIMITER_LENGTH, AngularMoustacheXmlExpression.CLOSING_DELIMITER_CHAR, AngularMoustacheXmlExpression.CLOSING_DELIMITER_CHAR);
if (endIndex < 0) {
// TODO(brianwilkerson) Should we report this error or will it be reported by something else?
return;
- } else if (startIndex + _OPENING_DELIMITER_LENGTH < endIndex) {
- startIndex += _OPENING_DELIMITER_LENGTH;
- Expression expression = parseExpression2(lexeme, startIndex, endIndex, offset);
- expressions.add(new ht.EmbeddedExpression(startIndex, expression, endIndex));
+ } else if (startIndex + AngularMoustacheXmlExpression.OPENING_DELIMITER_LENGTH < endIndex) {
+ startIndex += AngularMoustacheXmlExpression.OPENING_DELIMITER_LENGTH;
+ AngularExpression expression = parseAngularExpression2(lexeme, startIndex, endIndex, offset);
+ expressions.add(new AngularMoustacheXmlExpression(startIndex, endIndex, expression));
}
- startIndex = StringUtilities.indexOf2(lexeme, endIndex + _CLOSING_DELIMITER_LENGTH, _OPENING_DELIMITER_CHAR, _OPENING_DELIMITER_CHAR);
+ startIndex = StringUtilities.indexOf2(lexeme, endIndex + AngularMoustacheXmlExpression.CLOSING_DELIMITER_LENGTH, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR);
}
}
void parseEmbeddedExpressions2(ht.XmlAttributeNode node) {
- List<ht.EmbeddedExpression> expressions = new List<ht.EmbeddedExpression>();
+ List<AngularMoustacheXmlExpression> expressions = [];
parseEmbeddedExpressions(expressions, node.valueToken);
if (!expressions.isEmpty) {
node.expressions = new List.from(expressions);
@@ -8123,7 +8961,7 @@
}
void parseEmbeddedExpressions3(ht.XmlTagNode node) {
- List<ht.EmbeddedExpression> expressions = new List<ht.EmbeddedExpression>();
+ List<AngularMoustacheXmlExpression> expressions = [];
ht.Token token = node.attributeEnd;
ht.Token endToken = node.endToken;
bool inChild = false;
@@ -8159,10 +8997,17 @@
_injectedLibraries.add(typeLibrary);
}
- void resolveExpressions(List<ht.EmbeddedExpression> expressions) {
- for (ht.EmbeddedExpression embeddedExpression in expressions) {
- Expression expression = embeddedExpression.expression;
- resolveNode(expression);
+ void resolveExpression2(AngularXmlExpression angularXmlExpression) {
+ AngularExpression angularExpression = angularXmlExpression.expression;
+ resolveExpression(angularExpression);
+ }
+
+ void resolveExpressions(List<ht.XmlExpression> expressions) {
+ for (ht.XmlExpression xmlExpression in expressions) {
+ if (xmlExpression is AngularXmlExpression) {
+ AngularXmlExpression angularXmlExpression = xmlExpression;
+ resolveExpression2(angularXmlExpression);
+ }
}
}
@@ -8179,6 +9024,10 @@
// add built-in processors
_processors.add(NgModelProcessor.INSTANCE);
// _processors.add(NgRepeatProcessor.INSTANCE);
+ // add element's libraries
+ for (AngularElement angularElement in angularElements) {
+ _injectedLibraries.add(angularElement.library);
+ }
// add accessible processors
for (AngularElement angularElement in angularElements) {
NgProcessor processor = createProcessor(angularElement);
@@ -8188,17 +9037,18 @@
}
// prepare Dart library
createLibraryElement();
- _unit.compilationUnitElement = _libraryElement.definingCompilationUnit;
+ (_unit.element as HtmlElementImpl).angularCompilationUnit = _unitElement;
// prepare Dart resolver
createResolver();
- // may be resolving component template
- LocalVariableElementImpl componentVariable = null;
+ // maybe resolving component template
if (component != null) {
- ClassElement componentClassElement = component.enclosingElement as ClassElement;
- InterfaceType componentType = componentClassElement.type;
- componentVariable = createLocalVariable2(componentType, component.name);
- defineTopVariable(componentVariable);
- componentVariable.toolkitObjects = <AngularElement> [component];
+ defineTopElementVariable(component);
+ }
+ // define filters
+ for (AngularElement angularElement in angularElements) {
+ if (angularElement is AngularFilterElement) {
+ defineTopElementVariable(angularElement);
+ }
}
// run this HTML visitor
_unit.accept(this);
@@ -8218,6 +9068,20 @@
}
}
+ List<Token> splitAtBar(Token token) {
+ List<Token> tokens = [];
+ tokens.add(token);
+ while (token.type != TokenType.EOF) {
+ if (identical(token.type, TokenType.BAR)) {
+ tokens.add(token);
+ Token eofToken = new Token(TokenType.EOF, 0);
+ token.previous.setNext(eofToken);
+ }
+ token = token.next;
+ }
+ return tokens;
+ }
+
/**
* The "ng-model" directive is special, it contributes to the top-level name scope. These models
* can be used before actual "ng-model" attribute in HTML. So, we need to define them once we
@@ -8255,6 +9119,108 @@
}
/**
+ * Implementation of [AngularXmlExpression] for an [AngularExpression] enclosed between
+ * <code>{{</code> and <code>}}</code>.
+ */
+class AngularMoustacheXmlExpression extends AngularXmlExpression {
+ static int OPENING_DELIMITER_CHAR = 0x7B;
+
+ static int CLOSING_DELIMITER_CHAR = 0x7D;
+
+ static String OPENING_DELIMITER = "{{";
+
+ static String CLOSING_DELIMITER = "}}";
+
+ static int OPENING_DELIMITER_LENGTH = OPENING_DELIMITER.length;
+
+ static int CLOSING_DELIMITER_LENGTH = CLOSING_DELIMITER.length;
+
+ /**
+ * The offset of the first character of the opening delimiter.
+ */
+ int _openingOffset = 0;
+
+ /**
+ * The offset of the first character of the closing delimiter.
+ */
+ int _closingOffset = 0;
+
+ AngularMoustacheXmlExpression(int openingOffset, int closingOffset, AngularExpression expression) : super(expression) {
+ this._openingOffset = openingOffset;
+ this._closingOffset = closingOffset;
+ }
+
+ int get end => _closingOffset + CLOSING_DELIMITER_LENGTH;
+
+ int get length => _closingOffset + CLOSING_DELIMITER_LENGTH - _openingOffset;
+
+ int get offset => _openingOffset;
+}
+
+/**
+ * Implementation of [AngularXmlExpression] for an [AngularExpression] embedded without
+ * any wrapping characters.
+ */
+class AngularRawXmlExpression extends AngularXmlExpression {
+ AngularRawXmlExpression(AngularExpression expression) : super(expression);
+
+ int get end => expression.end;
+
+ int get length => expression.length;
+
+ int get offset => expression.offset;
+}
+
+/**
+ * Abstract Angular specific [XmlExpression].
+ */
+abstract class AngularXmlExpression extends ht.XmlExpression {
+ /**
+ * The expression that is enclosed between the delimiters.
+ */
+ final AngularExpression expression;
+
+ AngularXmlExpression(this.expression);
+
+ ht.XmlExpression_Reference getReference(int offset) {
+ // main expression
+ ht.XmlExpression_Reference reference = getReference2(expression.expression, offset);
+ if (reference != null) {
+ return reference;
+ }
+ // filters
+ for (AngularFilterNode filter in expression.filters) {
+ // filter name
+ reference = getReference2(filter.name, offset);
+ if (reference != null) {
+ return reference;
+ }
+ // filter arguments
+ for (AngularFilterArgument filterArgument in filter.arguments) {
+ reference = getReference2(filterArgument.expression, offset);
+ if (reference != null) {
+ return reference;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * If the given [ASTNode] has an [Element] at the given offset, then returns
+ * [Reference] with this [Element].
+ */
+ ht.XmlExpression_Reference getReference2(ASTNode root, int offset) {
+ ASTNode node = new NodeLocator.con1(offset).searchWithin(root);
+ if (node != null) {
+ Element element = ElementLocator.locate(node);
+ return new ht.XmlExpression_Reference(element, node.offset, node.length);
+ }
+ return null;
+ }
+}
+
+/**
* Recursively visits [HtmlUnit] and every embedded [Expression].
*/
abstract class ExpressionVisitor extends ht.RecursiveXmlVisitor<Object> {
@@ -8276,12 +9242,21 @@
}
/**
- * Visits [Expression]s of the given [EmbeddedExpression]s.
+ * Visits [Expression]s of the given [XmlExpression]s.
*/
- void visitExpressions(List<ht.EmbeddedExpression> expressions) {
- for (ht.EmbeddedExpression embeddedExpression in expressions) {
- Expression expression = embeddedExpression.expression;
- visitExpression(expression);
+ void visitExpressions(List<ht.XmlExpression> expressions) {
+ for (ht.XmlExpression xmlExpression in expressions) {
+ if (xmlExpression is AngularXmlExpression) {
+ AngularXmlExpression angularXmlExpression = xmlExpression;
+ List<Expression> dartExpressions = angularXmlExpression.expression.expressions;
+ for (Expression dartExpression in dartExpressions) {
+ visitExpression(dartExpression);
+ }
+ }
+ if (xmlExpression is ht.RawXmlExpression) {
+ ht.RawXmlExpression rawXmlExpression = xmlExpression;
+ visitExpression(rawXmlExpression.expression);
+ }
}
}
}
@@ -8306,8 +9281,8 @@
attribute.element = property;
// resolve if binding
if (property.propertyKind != AngularPropertyKind.ATTR) {
- Expression expression = parseExpression(resolver, attribute);
- resolver.resolveNode(expression);
+ AngularExpression expression = parseAngularExpression(resolver, attribute);
+ resolver.resolveExpression(expression);
setExpression(attribute, expression);
}
}
@@ -8368,8 +9343,8 @@
resolver.pushNameScope();
try {
onNgEventDirective(resolver);
- Expression expression = parseExpression(resolver, attribute);
- resolver.resolveNode(expression);
+ AngularExpression expression = parseAngularExpression(resolver, attribute);
+ resolver.resolveExpression(expression);
setExpression(attribute, expression);
} finally {
resolver.popNameScope();
@@ -8396,31 +9371,46 @@
* [NgDirectiveProcessor] describes any <code>NgDirective</code> annotation instance.
*/
abstract class NgDirectiveProcessor extends NgProcessor {
- static ht.EmbeddedExpression newEmbeddedExpression(Expression e) => new ht.EmbeddedExpression(e.offset, e, e.end);
+ static AngularRawXmlExpression newAngularRawXmlExpression(AngularExpression e) => new AngularRawXmlExpression(e);
- Expression parseExpression(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
- int offset = attribute.valueToken.offset + 1;
- String value = attribute.text;
- Token token = resolver.scanDart(value, 0, value.length, offset);
- return resolver.parseExpression3(token);
+ static ht.RawXmlExpression newRawXmlExpression(Expression e) => new ht.RawXmlExpression(e);
+
+ AngularExpression parseAngularExpression(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
+ Token token = scanAttribute(resolver, attribute);
+ return resolver.parseAngularExpression3(token);
+ }
+
+ Expression parseDartExpression(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
+ Token token = scanAttribute(resolver, attribute);
+ return resolver.parseDartExpression3(token);
+ }
+
+ /**
+ * Sets single [AngularExpression] for [XmlAttributeNode].
+ */
+ void setExpression(ht.XmlAttributeNode attribute, AngularExpression expression) {
+ setExpression3(attribute, newAngularRawXmlExpression(expression));
}
/**
* Sets single [Expression] for [XmlAttributeNode].
*/
- void setExpression(ht.XmlAttributeNode attribute, Expression expression) {
- attribute.expressions = <ht.EmbeddedExpression> [newEmbeddedExpression(expression)];
+ void setExpression2(ht.XmlAttributeNode attribute, Expression expression) {
+ setExpression3(attribute, newRawXmlExpression(expression));
}
- /**
- * Sets [Expression]s for [XmlAttributeNode].
- */
- void setExpressions(ht.XmlAttributeNode attribute, List<Expression> expressions) {
- List<ht.EmbeddedExpression> embExpressions = [];
- for (Expression expression in expressions) {
- embExpressions.add(newEmbeddedExpression(expression));
- }
- attribute.expressions = new List.from(embExpressions);
+ void setExpressions(ht.XmlAttributeNode attribute, List<ht.XmlExpression> xmlExpressions) {
+ attribute.expressions = new List.from(xmlExpressions);
+ }
+
+ Token scanAttribute(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
+ int offset = attribute.valueToken.offset + 1;
+ String value = attribute.text;
+ return resolver.scanDart(value, 0, value.length, offset);
+ }
+
+ void setExpression3(ht.XmlAttributeNode attribute, ht.XmlExpression xmlExpression) {
+ attribute.expressions = <ht.XmlExpression> [xmlExpression];
}
}
@@ -8434,7 +9424,7 @@
void apply(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
ht.XmlAttributeNode attribute = node.getAttribute(_NG_MODEL);
- Expression expression = parseExpression(resolver, attribute);
+ Expression expression = parseDartExpression(resolver, attribute);
// identifiers have been already handled by "apply top"
if (expression is SimpleIdentifier) {
return;
@@ -8442,7 +9432,7 @@
// resolve
resolver.resolveNode(expression);
// remember expression
- setExpression(attribute, expression);
+ setExpression2(attribute, expression);
}
bool canApply(ht.XmlTagNode node) => node.getAttribute(_NG_MODEL) != null;
@@ -8453,7 +9443,7 @@
*/
void applyTopDeclarations(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
ht.XmlAttributeNode attribute = node.getAttribute(_NG_MODEL);
- Expression expression = parseExpression(resolver, attribute);
+ Expression expression = parseDartExpression(resolver, attribute);
// if not identifier, then not a top-level model, delay until "apply"
if (expression is! SimpleIdentifier) {
return;
@@ -8466,7 +9456,7 @@
// remember expression
identifier.staticElement = element;
identifier.staticType = type;
- setExpression(attribute, identifier);
+ setExpression2(attribute, identifier);
}
}
@@ -8642,6 +9632,15 @@
E visitResolveAngularComponentTemplateTask(ResolveAngularComponentTemplateTask task);
/**
+ * Visit a [ResolveAngularEntryHtmlTask].
+ *
+ * @param task the task to be visited
+ * @return the result of visiting the task
+ * @throws AnalysisException if the visitor throws an exception for some reason
+ */
+ E visitResolveAngularEntryHtmlTask(ResolveAngularEntryHtmlTask task);
+
+ /**
* Visit a [ResolveDartDependenciesTask].
*
* @param task the task to be visited
@@ -8907,7 +9906,7 @@
return;
}
// Produce an updated token stream
- CharacterReader reader = new CharSequenceReader(new CharSequence(cache.newContents));
+ CharacterReader reader = new CharSequenceReader(cache.newContents);
BooleanErrorListener errorListener = new BooleanErrorListener();
IncrementalScanner scanner = new IncrementalScanner(cache.source, reader, errorListener);
scanner.rescan(cache.resolvedUnit.beginToken, cache.offset, cache.oldLength, cache.newLength);
@@ -9097,15 +10096,7 @@
Source_ContentReceiver_ParseDartTask_internalPerform(this.ParseDartTask_this, this.errorListener, this.token);
- void accept(CharBuffer contents, int modificationTime) {
- doScan(contents, modificationTime);
- }
-
- void accept2(String contents, int modificationTime) {
- doScan(new CharSequence(contents), modificationTime);
- }
-
- void doScan(CharSequence contents, int modificationTime) {
+ void accept(String contents, int modificationTime) {
ParseDartTask_this._modificationTime = modificationTime;
TimeCounter_TimeCounterHandle timeCounterScan = PerformanceStatistics.scan.start();
try {
@@ -9301,9 +10292,9 @@
AngularComponentElement _component;
/**
- * All Angular elements accessible in the component library.
+ * The Angular application to resolve in context of.
*/
- List<AngularElement> _angularElements;
+ AngularApplicationInfo _application;
/**
* The source to be resolved.
@@ -9331,11 +10322,11 @@
* @param context the context in which the task is to be performed
* @param source the source to be resolved
* @param component the component that uses this HTML template, not `null`
- * @param angularElements all Angular elements accessible in the component library
+ * @param application the Angular application to resolve in context of
*/
- ResolveAngularComponentTemplateTask(InternalAnalysisContext context, this.source, AngularComponentElement component, List<AngularElement> angularElements) : super(context) {
+ ResolveAngularComponentTemplateTask(InternalAnalysisContext context, this.source, AngularComponentElement component, AngularApplicationInfo application) : super(context) {
this._component = component;
- this._angularElements = angularElements;
+ this._application = application;
}
accept(AnalysisTaskVisitor visitor) => visitor.visitResolveAngularComponentTemplateTask(this);
@@ -9360,7 +10351,7 @@
String get taskDescription => "resolving Angular template ${source}";
void internalPerform() {
- ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableHtmlUnit(source);
+ ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableAngularComponentHtmlUnit(source);
ht.HtmlUnit unit = resolvableHtmlUnit.compilationUnit;
if (unit == null) {
throw new AnalysisException.con1("Internal error: computeResolvableHtmlUnit returned a value without a parsed HTML unit");
@@ -9371,7 +10362,100 @@
LineInfo lineInfo = context.getLineInfo(source);
// do resolve
AngularHtmlUnitResolver resolver = new AngularHtmlUnitResolver(context, errorListener, source, lineInfo, unit);
- resolver.resolveComponentTemplate(_angularElements, _component);
+ resolver.resolveComponentTemplate(_application, _component);
+ // remember errors
+ _resolutionErrors = errorListener.getErrors2(source);
+ // remember resolved unit
+ _resolvedUnit = unit;
+ }
+}
+
+/**
+ * Instances of the class `ResolveAngularEntryHtmlTask` resolve a specific HTML file as an
+ * Angular entry point.
+ */
+class ResolveAngularEntryHtmlTask extends AnalysisTask {
+ /**
+ * The source to be resolved.
+ */
+ final Source source;
+
+ /**
+ * The Angular application to resolve in context of.
+ */
+ AngularApplicationInfo _application;
+
+ /**
+ * The time at which the contents of the source were last modified.
+ */
+ int _modificationTime = -1;
+
+ /**
+ * The [HtmlUnit] that was resolved by this task.
+ */
+ ht.HtmlUnit _resolvedUnit;
+
+ /**
+ * The element produced by resolving the source.
+ */
+ HtmlElement _element = null;
+
+ /**
+ * The resolution errors that were discovered while resolving the source.
+ */
+ List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
+
+ /**
+ * Initialize a newly created task to perform analysis within the given context.
+ *
+ * @param context the context in which the task is to be performed
+ * @param source the source to be resolved
+ * @param application the Angular application to resolve in context of
+ */
+ ResolveAngularEntryHtmlTask(InternalAnalysisContext context, this.source, AngularApplicationInfo application) : super(context) {
+ this._application = application;
+ }
+
+ accept(AnalysisTaskVisitor visitor) => visitor.visitResolveAngularEntryHtmlTask(this);
+
+ HtmlElement get element => _element;
+
+ /**
+ * Return the time at which the contents of the source that was parsed were last modified, or a
+ * negative value if the task has not yet been performed or if an exception occurred.
+ *
+ * @return the time at which the contents of the source that was parsed were last modified
+ */
+ int get modificationTime => _modificationTime;
+
+ List<AnalysisError> get resolutionErrors => _resolutionErrors;
+
+ /**
+ * Return the [HtmlUnit] that was resolved by this task.
+ *
+ * @return the [HtmlUnit] that was resolved by this task
+ */
+ ht.HtmlUnit get resolvedUnit => _resolvedUnit;
+
+ String get taskDescription {
+ if (source == null) {
+ return "resolve as Angular entry point null source";
+ }
+ return "resolve as Angular entry point ${source.fullName}";
+ }
+
+ void internalPerform() {
+ ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableAngularComponentHtmlUnit(source);
+ ht.HtmlUnit unit = resolvableHtmlUnit.compilationUnit;
+ if (unit == null) {
+ throw new AnalysisException.con1("Internal error: computeResolvableHtmlUnit returned a value without a parsed HTML unit");
+ }
+ _modificationTime = resolvableHtmlUnit.modificationTime;
+ // prepare for resolution
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ LineInfo lineInfo = context.getLineInfo(source);
+ // do resolve
+ new AngularHtmlUnitResolver(context, errorListener, source, lineInfo, unit).resolveEntryPoint(_application);
// remember errors
_resolutionErrors = errorListener.getErrors2(source);
// remember resolved unit
@@ -9750,6 +10834,16 @@
List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
/**
+ * The flag that says is this unit is an Angular application.
+ */
+ bool _isAngularApplication2 = false;
+
+ /**
+ * The Angular application information, maybe `null`
+ */
+ AngularApplicationInfo _angularApplication;
+
+ /**
* Initialize a newly created task to perform analysis within the given context.
*
* @param context the context in which the task is to be performed
@@ -9759,6 +10853,12 @@
accept(AnalysisTaskVisitor visitor) => visitor.visitResolveHtmlTask(this);
+ /**
+ * Returns the [AngularApplicationInfo] for the Web application with this Angular entry
+ * point, maybe `null` if not an Angular entry point.
+ */
+ AngularApplicationInfo get angularApplication => _angularApplication;
+
HtmlElement get element => _element;
/**
@@ -9778,6 +10878,11 @@
*/
ht.HtmlUnit get resolvedUnit => _resolvedUnit;
+ /**
+ * Returns `true` if analyzed unit is an Angular application.
+ */
+ bool get isAngularApplication => _isAngularApplication2;
+
String get taskDescription {
if (source == null) {
return "resolve as html null source";
@@ -9795,11 +10900,13 @@
// build standard HTML element
HtmlUnitBuilder builder = new HtmlUnitBuilder(context);
_element = builder.buildHtmlElement2(source, _modificationTime, unit);
- // resolve toolkit-specific features
+ RecordingErrorListener errorListener = builder.errorListener;
LineInfo lineInfo = context.getLineInfo(source);
- new AngularHtmlUnitResolver(context, builder.errorListener, source, lineInfo, unit).resolveEntryPoint();
+ // try to resolve as an Angular entry point
+ _isAngularApplication2 = AngularHtmlUnitResolver.hasAngularAnnotation(unit);
+ _angularApplication = new AngularHtmlUnitResolver(context, errorListener, source, lineInfo, unit).calculateAngularApplication();
// record all resolution errors
- _resolutionErrors = builder.errorListener.getErrors2(source);
+ _resolutionErrors = errorListener.getErrors2(source);
// remember resolved unit
_resolvedUnit = unit;
}
@@ -9832,13 +10939,6 @@
void logError2(String message, Exception exception);
/**
- * Log the given exception as one representing an error.
- *
- * @param exception the exception being logged
- */
- void logError3(Exception exception);
-
- /**
* Log the given informational message.
*
* @param message an explanation of why the error occurred or what it means
@@ -9865,9 +10965,6 @@
void logError2(String message, Exception exception) {
}
- void logError3(Exception exception) {
- }
-
void logInformation(String message) {
}
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 31618d8..70408c6 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -143,7 +143,7 @@
class AngularCode extends Enum<AngularCode> implements ErrorCode {
static final AngularCode CANNOT_PARSE_SELECTOR = new AngularCode.con1('CANNOT_PARSE_SELECTOR', 0, "The selector '%s' cannot be parsed");
- static final AngularCode INVALID_PROPERTY_KIND = new AngularCode.con1('INVALID_PROPERTY_KIND', 1, "Unknown property binding kind '%s', use one of the '@', '=>', '=>!' or '<=>'");
+ static final AngularCode INVALID_PROPERTY_KIND = new AngularCode.con2('INVALID_PROPERTY_KIND', 1, "Unknown property binding kind '%s', use one of the '@', '=>', '=>!' or '<=>'", ErrorSeverity.ERROR);
static final AngularCode INVALID_PROPERTY_FIELD = new AngularCode.con1('INVALID_PROPERTY_FIELD', 2, "Unknown property field '%s'");
@@ -157,21 +157,17 @@
static final AngularCode INVALID_REPEAT_ITEM_SYNTAX = new AngularCode.con1('INVALID_REPEAT_ITEM_SYNTAX', 7, "Item must by identifier or in '(_key_, _value_)' pair.");
- static final AngularCode INVALID_URI = new AngularCode.con1('INVALID_URI', 8, "Invalid URI syntax: '%s'");
+ static final AngularCode INVALID_URI = new AngularCode.con2('INVALID_URI', 8, "Invalid URI syntax: '%s'", ErrorSeverity.ERROR);
- static final AngularCode MISSING_CSS_URL = new AngularCode.con1('MISSING_CSS_URL', 9, "Argument 'cssUrl' must be provided");
+ static final AngularCode MISSING_FILTER_COLON = new AngularCode.con1('MISSING_FILTER_COLON', 9, "Missing ':' before filter argument");
- static final AngularCode MISSING_FILTER_COLON = new AngularCode.con1('MISSING_FILTER_COLON', 10, "Missing ':' before filter argument");
+ static final AngularCode MISSING_NAME = new AngularCode.con1('MISSING_NAME', 10, "Argument 'name' must be provided");
- static final AngularCode MISSING_NAME = new AngularCode.con1('MISSING_NAME', 11, "Argument 'name' must be provided");
+ static final AngularCode MISSING_PUBLISH_AS = new AngularCode.con1('MISSING_PUBLISH_AS', 11, "Argument 'publishAs' must be provided");
- static final AngularCode MISSING_PUBLISH_AS = new AngularCode.con1('MISSING_PUBLISH_AS', 12, "Argument 'publishAs' must be provided");
+ static final AngularCode MISSING_SELECTOR = new AngularCode.con1('MISSING_SELECTOR', 12, "Argument 'selector' must be provided");
- static final AngularCode MISSING_TEMPLATE_URL = new AngularCode.con1('MISSING_TEMPLATE_URL', 13, "Argument 'templateUrl' must be provided");
-
- static final AngularCode MISSING_SELECTOR = new AngularCode.con1('MISSING_SELECTOR', 14, "Argument 'selector' must be provided");
-
- static final AngularCode URI_DOES_NOT_EXIST = new AngularCode.con1('URI_DOES_NOT_EXIST', 15, "Target of URI does not exist: '%s'");
+ static final AngularCode URI_DOES_NOT_EXIST = new AngularCode.con1('URI_DOES_NOT_EXIST', 13, "Target of URI does not exist: '%s'");
static final List<AngularCode> values = [
CANNOT_PARSE_SELECTOR,
@@ -183,11 +179,9 @@
INVALID_REPEAT_SYNTAX,
INVALID_REPEAT_ITEM_SYNTAX,
INVALID_URI,
- MISSING_CSS_URL,
MISSING_FILTER_COLON,
MISSING_NAME,
MISSING_PUBLISH_AS,
- MISSING_TEMPLATE_URL,
MISSING_SELECTOR,
URI_DOES_NOT_EXIST];
@@ -221,11 +215,11 @@
String get correction => null;
- ErrorSeverity get errorSeverity => _severity;
+ ErrorSeverity get errorSeverity => ErrorSeverity.INFO;
String get message => _message;
- ErrorType get type => ErrorType.TOOLKIT;
+ ErrorType get type => ErrorType.ANGULAR;
}
/**
@@ -756,6 +750,14 @@
*/
static final HintCode UNUSED_IMPORT = new HintCode.con1('UNUSED_IMPORT', 22, "Unused import");
+ /**
+ * Hint for cases where the source expects a method or function to return a non-void result, but
+ * the method or function signature returns void.
+ *
+ * @param name the name of the method or function that returns void
+ */
+ static final HintCode USE_OF_VOID_RESULT = new HintCode.con1('USE_OF_VOID_RESULT', 23, "The result of '%s' is being used, even though it is declared to be 'void'");
+
static final List<HintCode> values = [
DEAD_CODE,
DEAD_CODE_CATCH_FOLLOWING_CATCH,
@@ -779,7 +781,8 @@
UNNECESSARY_CAST,
UNNECESSARY_TYPE_CHECK_FALSE,
UNNECESSARY_TYPE_CHECK_TRUE,
- UNUSED_IMPORT];
+ UNUSED_IMPORT,
+ USE_OF_VOID_RESULT];
/**
* The template used to create the message to be displayed for this error.
@@ -906,9 +909,9 @@
static final ErrorType SYNTACTIC_ERROR = new ErrorType('SYNTACTIC_ERROR', 6, ErrorSeverity.ERROR);
/**
- * Toolkit specific semantic problems.
+ * Angular specific semantic problems.
*/
- static final ErrorType TOOLKIT = new ErrorType('TOOLKIT', 7, ErrorSeverity.INFO);
+ static final ErrorType ANGULAR = new ErrorType('ANGULAR', 7, ErrorSeverity.INFO);
static final List<ErrorType> values = [
TODO,
@@ -918,7 +921,7 @@
STATIC_WARNING,
STATIC_TYPE_WARNING,
SYNTACTIC_ERROR,
- TOOLKIT];
+ ANGULAR];
/**
* The severity of this type of error.
diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
index 9a24e05..2d511c1 100644
--- a/pkg/analyzer/lib/src/generated/html.dart
+++ b/pkg/analyzer/lib/src/generated/html.dart
@@ -16,7 +16,7 @@
import 'parser.dart' show Parser;
import 'ast.dart';
import 'element.dart';
-import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver;
+import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver, ExpressionVisitor;
/**
* Instances of the class `Token` represent a token that was scanned from the input. Each
@@ -141,38 +141,28 @@
}
/**
- * Instances of the class `EmbeddedExpression` represent an expression enclosed between
- * <code>{{</code> and <code>}}</code> delimiters.
+ * Implementation of [XmlExpression] for an [Expression] embedded without any wrapping
+ * characters.
*/
-class EmbeddedExpression {
- /**
- * The offset of the first character of the opening delimiter.
- */
- final int openingOffset;
-
- /**
- * The expression that is enclosed between the delimiters.
- */
+class RawXmlExpression extends XmlExpression {
final Expression expression;
- /**
- * The offset of the first character of the closing delimiter.
- */
- final int closingOffset;
+ RawXmlExpression(this.expression);
- /**
- * An empty array of embedded expressions.
- */
- static List<EmbeddedExpression> EMPTY_ARRAY = new List<EmbeddedExpression>(0);
+ int get end => expression.end;
- /**
- * Initialize a newly created embedded expression to represent the given expression.
- *
- * @param openingOffset the offset of the first character of the opening delimiter
- * @param expression the expression that is enclosed between the delimiters
- * @param closingOffset the offset of the first character of the closing delimiter
- */
- EmbeddedExpression(this.openingOffset, this.expression, this.closingOffset);
+ int get length => expression.length;
+
+ int get offset => expression.offset;
+
+ XmlExpression_Reference getReference(int offset) {
+ ASTNode node = new NodeLocator.con1(offset).searchWithin(expression);
+ if (node != null) {
+ Element element = ElementLocator.locate(node);
+ return new XmlExpression_Reference(element, node.offset, node.length);
+ }
+ return null;
+ }
}
/**
@@ -296,7 +286,8 @@
}
List<Expression> result = [null];
try {
- htmlUnit.accept(new RecursiveXmlVisitor_HtmlUnitUtils_getExpression(offset, result));
+ // TODO(scheglov) this code is very Angular specific
+ htmlUnit.accept(new ExpressionVisitor_HtmlUnitUtils_getExpression(offset, result));
} on HtmlUnitUtils_FoundExpressionError catch (e) {
return result[0];
}
@@ -361,31 +352,18 @@
}
}
-class RecursiveXmlVisitor_HtmlUnitUtils_getExpression extends RecursiveXmlVisitor<Object> {
+class ExpressionVisitor_HtmlUnitUtils_getExpression extends ExpressionVisitor {
int offset = 0;
List<Expression> result;
- RecursiveXmlVisitor_HtmlUnitUtils_getExpression(this.offset, this.result) : super();
+ ExpressionVisitor_HtmlUnitUtils_getExpression(this.offset, this.result) : super();
- Object visitXmlAttributeNode(XmlAttributeNode node) {
- findExpression(offset, result, node.expressions);
- return super.visitXmlAttributeNode(node);
- }
-
- Object visitXmlTagNode(XmlTagNode node) {
- findExpression(offset, result, node.expressions);
- return super.visitXmlTagNode(node);
- }
-
- void findExpression(int offset, List<Expression> result, List<EmbeddedExpression> expressions) {
- for (EmbeddedExpression embeddedExpression in expressions) {
- Expression expression = embeddedExpression.expression;
- Expression at = HtmlUnitUtils.getExpressionAt(expression, offset);
- if (at != null) {
- result[0] = at;
- throw new HtmlUnitUtils_FoundExpressionError();
- }
+ void visitExpression(Expression expression) {
+ Expression at = HtmlUnitUtils.getExpressionAt(expression, offset);
+ if (at != null) {
+ result[0] = at;
+ throw new HtmlUnitUtils_FoundExpressionError();
}
}
}
@@ -651,7 +629,7 @@
XmlNode current = newParent;
while (current != null) {
if (identical(current, this)) {
- AnalysisEngine.instance.logger.logError3(new IllegalArgumentException(buildRecursiveStructureMessage(newParent)));
+ AnalysisEngine.instance.logger.logError2("Circular structure while setting an XML node's parent", new IllegalArgumentException(buildRecursiveStructureMessage(newParent)));
return;
}
current = current.parent;
@@ -1069,7 +1047,7 @@
return -1;
}
- String getString(int start, int endDelta) => _string.substring(start, _charOffset + 1 + endDelta);
+ String getString(int start, int endDelta) => _string.substring(start, _charOffset + 1 + endDelta).toString();
int peek() {
if (_charOffset + 1 < _stringLength) {
@@ -1080,60 +1058,6 @@
}
/**
- * Instances of the class `CharBufferScanner` implement a scanner that reads from a character
- * buffer. The scanning logic is in the superclass.
- *
- * @coverage dart.engine.html
- */
-class CharBufferScanner extends AbstractScanner {
- /**
- * The buffer from which characters will be read.
- */
- CharSequence _buffer;
-
- /**
- * The number of characters in the buffer.
- */
- int _bufferLength = 0;
-
- /**
- * The index of the last character that was read.
- */
- int _charOffset = 0;
-
- /**
- * Initialize a newly created scanner to scan the characters in the given character buffer.
- *
- * @param source the source being scanned
- * @param buffer the buffer from which characters will be read
- */
- CharBufferScanner(Source source, CharSequence buffer) : super(source) {
- this._buffer = buffer;
- this._bufferLength = buffer.length();
- this._charOffset = -1;
- }
-
- int get offset => _charOffset;
-
- int advance() {
- if (++_charOffset < _bufferLength) {
- return _buffer.charAt(_charOffset);
- }
- _charOffset = _bufferLength;
- return -1;
- }
-
- String getString(int start, int endDelta) => _buffer.subSequence(start, _charOffset + 1 + endDelta).toString();
-
- int peek() {
- if (_charOffset + 1 < _bufferLength) {
- return _buffer.charAt(_charOffset + 1);
- }
- return -1;
- }
-}
-
-/**
* Instances of the class `ToSourceVisitor` write a source representation of a visited XML
* node (and all of it's children) to a writer.
*
@@ -1288,7 +1212,7 @@
Token _value;
- List<EmbeddedExpression> expressions = EmbeddedExpression.EMPTY_ARRAY;
+ List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
/**
* Construct a new instance representing an XML attribute.
@@ -1367,57 +1291,6 @@
}
/**
- * Instances of the class `EmbeddedDartVisitor` implement a recursive visitor for HTML files
- * that will invoke another visitor on all embedded dart scripts and expressions.
- */
-class EmbeddedDartVisitor<R> implements XmlVisitor<R> {
- /**
- * The visitor used to visit embedded Dart code.
- */
- ASTVisitor<R> _dartVisitor;
-
- /**
- * Initialize a newly created visitor to visit all of the nodes in an HTML structure and to use
- * the given visitor to visit all of the nodes representing any embedded scripts or expressions.
- *
- * @param dartVisitor the visitor used to visit embedded Dart code
- */
- EmbeddedDartVisitor(ASTVisitor<R> dartVisitor) {
- this._dartVisitor = dartVisitor;
- }
-
- R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
- node.visitChildren(this);
- CompilationUnit script = node.script;
- if (script != null) {
- script.accept(_dartVisitor);
- }
- return null;
- }
-
- R visitHtmlUnit(HtmlUnit node) {
- node.visitChildren(this);
- return null;
- }
-
- R visitXmlAttributeNode(XmlAttributeNode node) {
- node.visitChildren(this);
- for (EmbeddedExpression expression in node.expressions) {
- expression.expression.accept(_dartVisitor);
- }
- return null;
- }
-
- R visitXmlTagNode(XmlTagNode node) {
- node.visitChildren(this);
- for (EmbeddedExpression expression in node.expressions) {
- expression.expression.accept(_dartVisitor);
- }
- return null;
- }
-}
-
-/**
* The interface `XmlVisitor` defines the behavior of objects that can be used to visit an
* [XmlNode] structure.
*
@@ -1434,6 +1307,65 @@
}
/**
+ * Instances of the class `XmlExpression` represent an abstract expression embedded into
+ * [XmlNode].
+ */
+abstract class XmlExpression {
+ /**
+ * An empty array of expressions.
+ */
+ static List<XmlExpression> EMPTY_ARRAY = new List<XmlExpression>(0);
+
+ /**
+ * Check if the given offset belongs to the expression's source range.
+ */
+ bool contains(int offset) => this.offset <= offset && offset < end;
+
+ /**
+ * Return the offset of the character immediately following the last character of this
+ * expression's source range. This is equivalent to `getOffset() + getLength()`.
+ *
+ * @return the offset of the character just past the expression's source range
+ */
+ int get end;
+
+ /**
+ * Return the number of characters in the expression's source range.
+ */
+ int get length;
+
+ /**
+ * Return the offset of the first character in the expression's source range.
+ */
+ int get offset;
+
+ /**
+ * Return the [Reference] at the given offset.
+ *
+ * @param offset the offset from the beginning of the file
+ * @return the [Reference] at the given offset, maybe `null`
+ */
+ XmlExpression_Reference getReference(int offset);
+}
+
+/**
+ * The reference to the [Element].
+ */
+class XmlExpression_Reference {
+ Element element;
+
+ int offset = 0;
+
+ int length = 0;
+
+ XmlExpression_Reference(Element element, int offset, int length) {
+ this.element = element;
+ this.offset = offset;
+ this.length = length;
+ }
+}
+
+/**
* Instances of `HtmlScanner` receive and scan HTML content from a [Source].<br/>
* For example, the following code scans HTML source and returns the result:
*
@@ -1477,14 +1409,7 @@
this._source = source;
}
- void accept(CharBuffer contents, int modificationTime) {
- this._modificationTime = modificationTime;
- _scanner = new CharBufferScanner(_source, contents);
- _scanner.passThroughElements = _SCRIPT_TAG;
- _token = _scanner.tokenize();
- }
-
- void accept2(String contents, int modificationTime) {
+ void accept(String contents, int modificationTime) {
this._modificationTime = modificationTime;
_scanner = new StringScanner(_source, contents);
_scanner.passThroughElements = _SCRIPT_TAG;
@@ -1838,7 +1763,7 @@
/**
* The expressions that are embedded in the tag's content.
*/
- List<EmbeddedExpression> expressions = EmbeddedExpression.EMPTY_ARRAY;
+ List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
/**
* Construct a new instance representing an XML or HTML element
@@ -2056,7 +1981,7 @@
*/
static sc.Token scanDartSource(Source source, LineInfo lineInfo, String contents, int contentOffset, AnalysisErrorListener errorListener) {
LineInfo_Location location = lineInfo.getLocation(contentOffset);
- sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), errorListener);
+ sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(contents, contentOffset), errorListener);
scanner.setSourceStart(location.lineNumber, location.columnNumber);
return scanner.tokenize();
}
@@ -2106,7 +2031,7 @@
String contents = tagNode.content;
int contentOffset = attributeEnd.end;
LineInfo_Location location = _lineInfo.getLocation(contentOffset);
- sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), _errorListener);
+ sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(contents, contentOffset), _errorListener);
scanner.setSourceStart(location.lineNumber, location.columnNumber);
sc.Token firstToken = scanner.tokenize();
Parser parser = new Parser(source, _errorListener);
@@ -2168,12 +2093,6 @@
List<XmlTagNode> _tagNodes;
/**
- * The element associated with Dart pieces in this HTML unit or `null` if the receiver is
- * not resolved.
- */
- CompilationUnitElement compilationUnitElement;
-
- /**
* Construct a new instance representing the content of an HTML file.
*
* @param beginToken the first token in the file (not `null`)
diff --git a/pkg/analyzer/lib/src/generated/index.dart b/pkg/analyzer/lib/src/generated/index.dart
index be2d4f8..12d012ac 100644
--- a/pkg/analyzer/lib/src/generated/index.dart
+++ b/pkg/analyzer/lib/src/generated/index.dart
@@ -15,7 +15,7 @@
import 'ast.dart';
import 'element.dart';
import 'resolver.dart' show Namespace, NamespaceBuilder;
-import 'engine.dart' show AnalysisEngine, AnalysisContext, InstrumentedAnalysisContextImpl, AngularHtmlUnitResolver;
+import 'engine.dart';
import 'html.dart' as ht;
/**
@@ -121,7 +121,13 @@
*/
static Source getLibrarySourceOrNull(Element element) {
LibraryElement library = element.library;
- return library != null ? library.source : null;
+ if (library == null) {
+ return null;
+ }
+ if (library.isAngularHtml) {
+ return null;
+ }
+ return library.source;
}
/**
@@ -216,17 +222,7 @@
libraryToUnits[library] = newParts;
}
// remember libraries in which unit is used
- Map<Source, Set<Source>> unitToLibraries = _contextToUnitToLibraries[context];
- if (unitToLibraries == null) {
- unitToLibraries = {};
- _contextToUnitToLibraries[context] = unitToLibraries;
- }
- Set<Source> libraries = unitToLibraries[unit];
- if (libraries == null) {
- libraries = new Set();
- unitToLibraries[unit] = libraries;
- }
- libraries.add(library);
+ recordUnitInLibrary(context, library, unit);
// remove locations
removeLocations(context, library, unit);
// remove keys
@@ -234,29 +230,38 @@
Map<MemoryIndexStoreImpl_Source2, Set<MemoryIndexStoreImpl_ElementRelationKey>> sourceToKeys = _contextToSourceToKeys[context];
if (sourceToKeys != null) {
MemoryIndexStoreImpl_Source2 source2 = new MemoryIndexStoreImpl_Source2(library, unit);
- sourceToKeys.remove(source2);
+ bool hadSource = sourceToKeys.remove(source2) != null;
+ if (hadSource) {
+ _sourceCount--;
+ }
}
}
// OK, we can index
return true;
}
- bool aboutToIndex2(AnalysisContext context, Source source) {
+ bool aboutToIndex2(AnalysisContext context, HtmlElement htmlElement) {
context = unwrapContext(context);
// may be already removed in other thread
if (isRemovedContext(context)) {
return false;
}
// remove locations
- removeLocations(context, source, source);
+ Source source = htmlElement.source;
+ removeLocations(context, null, source);
// remove keys
{
Map<MemoryIndexStoreImpl_Source2, Set<MemoryIndexStoreImpl_ElementRelationKey>> sourceToKeys = _contextToSourceToKeys[context];
if (sourceToKeys != null) {
- MemoryIndexStoreImpl_Source2 source2 = new MemoryIndexStoreImpl_Source2(source, source);
- sourceToKeys.remove(source2);
+ MemoryIndexStoreImpl_Source2 source2 = new MemoryIndexStoreImpl_Source2(null, source);
+ bool hadSource = sourceToKeys.remove(source2) != null;
+ if (hadSource) {
+ _sourceCount--;
+ }
}
}
+ // remember libraries in which unit is used
+ recordUnitInLibrary(context, null, source);
// OK, we can index
return true;
}
@@ -315,6 +320,7 @@
if (element is Member) {
element = (element as Member).baseElement;
}
+ // System.out.println(element + " " + relationship + " " + location);
// prepare information
AnalysisContext elementContext = element.context;
AnalysisContext locationContext = location.element.context;
@@ -503,6 +509,20 @@
_removedContexts[context] = true;
}
+ void recordUnitInLibrary(AnalysisContext context, Source library, Source unit) {
+ Map<Source, Set<Source>> unitToLibraries = _contextToUnitToLibraries[context];
+ if (unitToLibraries == null) {
+ unitToLibraries = {};
+ _contextToUnitToLibraries[context] = unitToLibraries;
+ }
+ Set<Source> libraries = unitToLibraries[unit];
+ if (libraries == null) {
+ libraries = new Set();
+ unitToLibraries[unit] = libraries;
+ }
+ libraries.add(library);
+ }
+
/**
* Removes locations recorded in the given library/unit pair.
*/
@@ -678,12 +698,21 @@
}
/**
- * Visits [Expression]s of the given [EmbeddedExpression]s.
+ * Visits [Expression]s of the given [XmlExpression]s.
*/
- void visitExpressions(List<ht.EmbeddedExpression> expressions) {
- for (ht.EmbeddedExpression embeddedExpression in expressions) {
- Expression expression = embeddedExpression.expression;
- visitExpression(expression);
+ void visitExpressions(List<ht.XmlExpression> expressions) {
+ for (ht.XmlExpression xmlExpression in expressions) {
+ if (xmlExpression is AngularXmlExpression) {
+ AngularXmlExpression angularXmlExpression = xmlExpression;
+ List<Expression> dartExpressions = angularXmlExpression.expression.expressions;
+ for (Expression dartExpression in dartExpressions) {
+ visitExpression(dartExpression);
+ }
+ }
+ if (xmlExpression is ht.RawXmlExpression) {
+ ht.RawXmlExpression rawXmlExpression = xmlExpression;
+ visitExpression(rawXmlExpression.expression);
+ }
}
}
}
@@ -777,7 +806,7 @@
if (unit.element == null) {
return;
}
- if (unit.compilationUnitElement == null) {
+ if (unit.element.angularCompilationUnit == null) {
return;
}
_queue.enqueue(new IndexHtmlUnitOperation(_store, context, unit));
@@ -1229,7 +1258,7 @@
Object visitHtmlUnit(ht.HtmlUnit node) {
_htmlUnitElement = node.element;
- CompilationUnitElement dartUnitElement = node.compilationUnitElement;
+ CompilationUnitElement dartUnitElement = _htmlUnitElement.angularCompilationUnit;
_indexContributor.enterScope(dartUnitElement);
return super.visitHtmlUnit(node);
}
@@ -1392,18 +1421,14 @@
bool aboutToIndex(AnalysisContext context, CompilationUnitElement unitElement);
/**
- * Notifies the index store that we are going to index the given [Source].
- *
- * This method should be used only for a [Source] that cannot be a part of multiple
- * libraries. Otherwise [aboutToIndex] should be
- * used.
+ * Notifies the index store that we are going to index the given [HtmlElement].
*
* @param the [AnalysisContext] in which unit being indexed
- * @param source the [Source] being indexed
+ * @param htmlElement the [HtmlElement] being indexed
* @return `true` the given [AnalysisContext] is active, or `false` if it was
* removed before, so no any unit may be indexed with it
*/
- bool aboutToIndex2(AnalysisContext context, Source source);
+ bool aboutToIndex2(AnalysisContext context, HtmlElement htmlElement);
/**
* Return the locations of the elements that have the given relationship with the given element.
@@ -2656,7 +2681,7 @@
void performOperation() {
{
try {
- bool mayIndex = _indexStore.aboutToIndex2(_context, _source);
+ bool mayIndex = _indexStore.aboutToIndex2(_context, _htmlElement);
if (!mayIndex) {
return;
}
diff --git a/pkg/analyzer/lib/src/generated/java_io.dart b/pkg/analyzer/lib/src/generated/java_io.dart
index bdd7fd8..0957f27 100644
--- a/pkg/analyzer/lib/src/generated/java_io.dart
+++ b/pkg/analyzer/lib/src/generated/java_io.dart
@@ -1,7 +1,7 @@
library java.io;
import "dart:io";
-import 'java_core.dart' show JavaIOException;
+import 'java_core.dart' show JavaIOException, CharSequence;
import 'package:path/path.dart' as pathos;
class JavaSystemIO {
@@ -56,7 +56,7 @@
static final int separatorChar = Platform.pathSeparator.codeUnitAt(0);
String _path;
JavaFile(String path) {
- _path = pathos.normalize(path);
+ _path = pathos.absolute(path);
}
JavaFile.relative(JavaFile base, String child) {
if (child.isEmpty) {
@@ -103,6 +103,9 @@
}
return false;
}
+ bool isFile() {
+ return _newFile().existsSync();
+ }
bool isDirectory() {
return _newDirectory().existsSync();
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 9647bf9..4c93ace 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -7,7 +7,6 @@
library engine.parser;
-import 'dart:collection';
import 'java_core.dart';
import 'java_engine.dart';
import 'instrumentation.dart';
@@ -218,7 +217,7 @@
ASTNode visitAssertStatement(AssertStatement node) {
if (identical(_oldNode, node.condition)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -232,7 +231,7 @@
throw new InsufficientContextException();
} else if (identical(_oldNode, node.rightHandSide)) {
if (isCascadeAllowed(node)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return _parser.parseExpressionWithoutCascade();
}
@@ -422,7 +421,7 @@
if (identical(_oldNode, node.parameter)) {
return _parser.parseNormalFormalParameter();
} else if (identical(_oldNode, node.defaultValue)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -431,7 +430,7 @@
if (identical(_oldNode, node.body)) {
return _parser.parseStatement2();
} else if (identical(_oldNode, node.condition)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -457,14 +456,14 @@
ASTNode visitExpressionFunctionBody(ExpressionFunctionBody node) {
if (identical(_oldNode, node.expression)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
ASTNode visitExpressionStatement(ExpressionStatement node) {
if (identical(_oldNode, node.expression)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -524,9 +523,9 @@
} else if (identical(_oldNode, node.initialization)) {
throw new InsufficientContextException();
} else if (identical(_oldNode, node.condition)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
} else if (node.updaters.contains(_oldNode)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
} else if (identical(_oldNode, node.body)) {
return _parser.parseStatement2();
}
@@ -614,7 +613,7 @@
ASTNode visitIfStatement(IfStatement node) {
if (identical(_oldNode, node.condition)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
} else if (identical(_oldNode, node.thenStatement)) {
return _parser.parseStatement2();
} else if (identical(_oldNode, node.elseStatement)) {
@@ -649,7 +648,7 @@
if (identical(_oldNode, node.target)) {
throw new InsufficientContextException();
} else if (identical(_oldNode, node.index)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -670,7 +669,7 @@
if (node.leftBracket == null) {
throw new InsufficientContextException();
}
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -726,7 +725,7 @@
if (identical(_oldNode, node.typeArguments)) {
return _parser.parseTypeArgumentList();
} else if (node.elements.contains(_oldNode)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -742,9 +741,9 @@
ASTNode visitMapLiteralEntry(MapLiteralEntry node) {
if (identical(_oldNode, node.key)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
} else if (identical(_oldNode, node.value)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -783,7 +782,7 @@
if (identical(_oldNode, node.name)) {
return _parser.parseLabel();
} else if (identical(_oldNode, node.expression)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -806,7 +805,7 @@
ASTNode visitParenthesizedExpression(ParenthesizedExpression node) {
if (identical(_oldNode, node.expression)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -878,7 +877,7 @@
ASTNode visitReturnStatement(ReturnStatement node) {
if (identical(_oldNode, node.expression)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return notAChild(node);
}
@@ -931,7 +930,7 @@
if (node.labels.contains(_oldNode)) {
return _parser.parseLabel();
} else if (identical(_oldNode, node.expression)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
} else if (node.statements.contains(_oldNode)) {
return _parser.parseStatement2();
}
@@ -949,7 +948,7 @@
ASTNode visitSwitchStatement(SwitchStatement node) {
if (identical(_oldNode, node.expression)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
} else if (node.members.contains(_oldNode)) {
throw new InsufficientContextException();
}
@@ -963,7 +962,7 @@
ASTNode visitThrowExpression(ThrowExpression node) {
if (identical(_oldNode, node.expression)) {
if (isCascadeAllowed2(node)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
}
return _parser.parseExpressionWithoutCascade();
}
@@ -1061,7 +1060,7 @@
ASTNode visitWhileStatement(WhileStatement node) {
if (identical(_oldNode, node.condition)) {
- return _parser.parseExpression4();
+ return _parser.parseExpression2();
} else if (identical(_oldNode, node.body)) {
return _parser.parseStatement2();
}
@@ -1415,7 +1414,7 @@
InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseExpression");
try {
_currentToken = token;
- return parseExpression4();
+ return parseExpression2();
} finally {
instrumentation.log();
}
@@ -1510,9 +1509,9 @@
// have an identifier followed by a colon.
//
if (matchesIdentifier() && matches4(peek(), TokenType.COLON)) {
- return new NamedExpression(parseLabel(), parseExpression4());
+ return new NamedExpression(parseLabel(), parseExpression2());
} else {
- return parseExpression4();
+ return parseExpression2();
}
}
@@ -1550,7 +1549,7 @@
if (foundNamedArgument) {
if (!generatedError && argument is! NamedExpression) {
// Report the error, once, but allow the arguments to be in any order in the AST.
- reportError12(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, []);
+ reportError13(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, []);
generatedError = true;
}
} else if (argument is NamedExpression) {
@@ -1610,7 +1609,7 @@
}
if (identical(_currentToken, statementStart)) {
// Ensure that we are making progress and report an error if we're not.
- reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+ reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
advance();
}
statementStart = _currentToken;
@@ -1661,7 +1660,7 @@
//
// We appear to have a variable declaration with a type of "void".
//
- reportError11(ParserErrorCode.VOID_VARIABLE, returnType, []);
+ reportError12(ParserErrorCode.VOID_VARIABLE, returnType, []);
return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, validateModifiersForField(modifiers), returnType);
}
}
@@ -1672,7 +1671,7 @@
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType);
}
- reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+ reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
return null;
}
} else if (matches(Keyword.GET) && matchesIdentifier2(peek())) {
@@ -1692,7 +1691,7 @@
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.externalKeyword, null);
}
- reportError13(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
+ reportError14(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
return null;
} else if (matches4(peek(), TokenType.PERIOD) && matchesIdentifier2(peek2(2)) && matches4(peek2(3), TokenType.OPEN_PAREN)) {
return parseConstructor(commentAndMetadata, modifiers.externalKeyword, validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, parseSimpleIdentifier(), andAdvance, parseSimpleIdentifier(), parseFormalParameterList());
@@ -1707,7 +1706,7 @@
return parseMethodDeclaration2(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, null, methodName, parameters);
} else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
if (modifiers.constKeyword == null && modifiers.finalKeyword == null && modifiers.varKeyword == null) {
- reportError12(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
+ reportError13(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
}
return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, validateModifiersForField(modifiers), null);
}
@@ -1742,7 +1741,7 @@
// At this point it consists of a type name, so we'll treat it as a field declaration
// with a missing field name and semicolon.
//
- reportError13(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
+ reportError14(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
try {
lockErrorListener();
return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, validateModifiersForField(modifiers), type);
@@ -1753,7 +1752,7 @@
SimpleIdentifier methodName = parseSimpleIdentifier();
FormalParameterList parameters = parseFormalParameterList();
if (methodName.name == className) {
- reportError11(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type, []);
+ reportError12(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type, []);
return parseConstructor(commentAndMetadata, modifiers.externalKeyword, validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, methodName, null, null, parameters);
}
validateModifiersForGetterOrSetterOrMethod(modifiers);
@@ -1807,15 +1806,15 @@
if ((matches(Keyword.IMPORT) || matches(Keyword.EXPORT) || matches(Keyword.LIBRARY) || matches(Keyword.PART)) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT) && !matches4(peek(), TokenType.OPEN_PAREN)) {
Directive directive = parseDirective(commentAndMetadata);
if (declarations.length > 0 && !directiveFoundAfterDeclaration) {
- reportError12(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, []);
+ reportError13(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, []);
directiveFoundAfterDeclaration = true;
}
if (directive is LibraryDirective) {
if (libraryDirectiveFound) {
- reportError12(ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES, []);
+ reportError13(ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES, []);
} else {
if (directives.length > 0) {
- reportError13(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, directive.libraryToken, []);
+ reportError14(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, directive.libraryToken, []);
}
libraryDirectiveFound = true;
}
@@ -1823,29 +1822,29 @@
partDirectiveFound = true;
} else if (partDirectiveFound) {
if (directive is ExportDirective) {
- reportError13(ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
+ reportError14(ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
} else if (directive is ImportDirective) {
- reportError13(ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
+ reportError14(ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
}
}
if (directive is PartOfDirective) {
if (partOfDirectiveFound) {
- reportError12(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []);
+ reportError13(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []);
} else {
int directiveCount = directives.length;
for (int i = 0; i < directiveCount; i++) {
- reportError13(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directives[i].keyword, []);
+ reportError14(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directives[i].keyword, []);
}
partOfDirectiveFound = true;
}
} else {
if (partOfDirectiveFound) {
- reportError13(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directive.keyword, []);
+ reportError14(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directive.keyword, []);
}
}
directives.add(directive);
} else if (matches5(TokenType.SEMICOLON)) {
- reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+ reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
advance();
} else {
CompilationUnitMember member = parseCompilationUnitMember(commentAndMetadata);
@@ -1854,7 +1853,7 @@
}
}
if (identical(_currentToken, memberStart)) {
- reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+ reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
advance();
while (!matches5(TokenType.EOF) && !couldBeStartOfCompilationUnitMember()) {
advance();
@@ -1920,7 +1919,7 @@
*
* @return the expression that was parsed
*/
- Expression parseExpression4() {
+ Expression parseExpression2() {
if (matches(Keyword.THROW)) {
return parseThrowExpression();
} else if (matches(Keyword.RETHROW)) {
@@ -1946,7 +1945,7 @@
} else if (tokenType.isAssignmentOperator) {
Token operator = andAdvance;
ensureAssignable(expression);
- return new AssignmentExpression(expression, operator, parseExpression4());
+ return new AssignmentExpression(expression, operator, parseExpression2());
}
return expression;
}
@@ -2056,9 +2055,9 @@
} else if (!optional(TokenType.COMMA)) {
// TODO(brianwilkerson) The token is wrong, we need to recover from this case.
if (getEndToken(leftParenthesis) != null) {
- reportError12(ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
+ reportError13(ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
} else {
- reportError13(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, _currentToken.previous, []);
+ reportError14(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, _currentToken.previous, []);
break;
}
}
@@ -2069,11 +2068,11 @@
if (matches5(TokenType.OPEN_SQUARE_BRACKET)) {
wasOptionalParameter = true;
if (leftSquareBracket != null && !reportedMuliplePositionalGroups) {
- reportError12(ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, []);
+ reportError13(ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, []);
reportedMuliplePositionalGroups = true;
}
if (leftCurlyBracket != null && !reportedMixedGroups) {
- reportError12(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
+ reportError13(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
reportedMixedGroups = true;
}
leftSquareBracket = andAdvance;
@@ -2082,11 +2081,11 @@
} else if (matches5(TokenType.OPEN_CURLY_BRACKET)) {
wasOptionalParameter = true;
if (leftCurlyBracket != null && !reportedMulipleNamedGroups) {
- reportError12(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, []);
+ reportError13(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, []);
reportedMulipleNamedGroups = true;
}
if (leftSquareBracket != null && !reportedMixedGroups) {
- reportError12(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
+ reportError13(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
reportedMixedGroups = true;
}
leftCurlyBracket = andAdvance;
@@ -2100,7 +2099,7 @@
parameters.add(parameter);
currentParameters.add(parameter);
if (identical(kind, ParameterKind.REQUIRED) && wasOptionalParameter) {
- reportError11(ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter, []);
+ reportError12(ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter, []);
}
//
// Handle the end of parameter groups.
@@ -2111,11 +2110,11 @@
currentParameters = normalParameters;
if (leftSquareBracket == null) {
if (leftCurlyBracket != null) {
- reportError12(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
+ reportError13(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
rightCurlyBracket = rightSquareBracket;
rightSquareBracket = null;
} else {
- reportError12(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["["]);
+ reportError13(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["["]);
}
}
kind = ParameterKind.REQUIRED;
@@ -2124,11 +2123,11 @@
currentParameters = normalParameters;
if (leftCurlyBracket == null) {
if (leftSquareBracket != null) {
- reportError12(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
+ reportError13(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
rightSquareBracket = rightCurlyBracket;
rightCurlyBracket = null;
} else {
- reportError12(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["{"]);
+ reportError13(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["{"]);
}
}
kind = ParameterKind.REQUIRED;
@@ -2139,10 +2138,10 @@
// Check that the groups were closed correctly.
//
if (leftSquareBracket != null && rightSquareBracket == null) {
- reportError12(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
+ reportError13(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
}
if (leftCurlyBracket != null && rightCurlyBracket == null) {
- reportError12(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
+ reportError13(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
}
//
// Build the parameter list.
@@ -2259,9 +2258,9 @@
* @return the map literal entry that was parsed
*/
MapLiteralEntry parseMapLiteralEntry() {
- Expression key = parseExpression4();
+ Expression key = parseExpression2();
Token separator = expect2(TokenType.COLON);
- Expression value = parseExpression4();
+ Expression value = parseExpression2();
return new MapLiteralEntry(key, separator, value);
}
@@ -2301,7 +2300,7 @@
FormalParameterList parameters = parseFormalParameterList();
if (thisKeyword == null) {
if (holder.keyword != null) {
- reportError13(ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword, []);
+ reportError14(ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword, []);
}
return new FunctionTypedFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.type, identifier, parameters);
} else {
@@ -2311,9 +2310,9 @@
TypeName type = holder.type;
if (type != null) {
if (matches3(type.name.beginToken, Keyword.VOID)) {
- reportError13(ParserErrorCode.VOID_PARAMETER, type.name.beginToken, []);
+ reportError14(ParserErrorCode.VOID_PARAMETER, type.name.beginToken, []);
} else if (holder.keyword != null && matches3(holder.keyword, Keyword.VAR)) {
- reportError13(ParserErrorCode.VAR_AND_TYPE, holder.keyword, []);
+ reportError14(ParserErrorCode.VAR_AND_TYPE, holder.keyword, []);
}
}
if (thisKeyword != null) {
@@ -2375,7 +2374,7 @@
if (matchesIdentifier()) {
return new SimpleIdentifier(andAdvance);
}
- reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+ reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
return createSyntheticIdentifier();
}
@@ -2423,7 +2422,7 @@
}
}
if (strings.length < 1) {
- reportError12(ParserErrorCode.EXPECTED_STRING_LITERAL, []);
+ reportError13(ParserErrorCode.EXPECTED_STRING_LITERAL, []);
return createSyntheticStringLiteral();
} else if (strings.length == 1) {
return strings[0];
@@ -2469,13 +2468,13 @@
TypeName parseTypeName() {
Identifier typeName;
if (matches(Keyword.VAR)) {
- reportError12(ParserErrorCode.VAR_AS_TYPE_NAME, []);
+ reportError13(ParserErrorCode.VAR_AS_TYPE_NAME, []);
typeName = new SimpleIdentifier(andAdvance);
} else if (matchesIdentifier()) {
typeName = parsePrefixedIdentifier();
} else {
typeName = createSyntheticIdentifier();
- reportError12(ParserErrorCode.EXPECTED_TYPE_NAME, []);
+ reportError13(ParserErrorCode.EXPECTED_TYPE_NAME, []);
}
TypeArgumentList typeArguments = null;
if (matches5(TokenType.LT)) {
@@ -2570,7 +2569,7 @@
*/
void appendScalarValue(JavaStringBuilder builder, String escapeSequence, int scalarValue, int startIndex, int endIndex) {
if (scalarValue < 0 || scalarValue > Character.MAX_CODE_POINT || (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) {
- reportError12(ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
+ reportError13(ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
return;
}
if (scalarValue < Character.MAX_VALUE) {
@@ -2730,7 +2729,7 @@
*/
void ensureAssignable(Expression expression) {
if (expression != null && !expression.isAssignable) {
- reportError12(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, []);
+ reportError13(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, []);
}
}
@@ -2747,7 +2746,7 @@
}
// Remove uses of this method in favor of matches?
// Pass in the error code to use to report the error?
- reportError12(ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
+ reportError13(ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
return _currentToken;
}
@@ -2765,9 +2764,9 @@
// Remove uses of this method in favor of matches?
// Pass in the error code to use to report the error?
if (identical(type, TokenType.SEMICOLON)) {
- reportError13(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [type.lexeme]);
+ reportError14(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [type.lexeme]);
} else {
- reportError12(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
+ reportError13(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
}
return _currentToken;
}
@@ -3308,7 +3307,7 @@
ArgumentDefinitionTest parseArgumentDefinitionTest() {
Token question = expect2(TokenType.QUESTION);
SimpleIdentifier identifier = parseSimpleIdentifier();
- reportError13(ParserErrorCode.DEPRECATED_ARGUMENT_DEFINITION_TEST, question, []);
+ reportError14(ParserErrorCode.DEPRECATED_ARGUMENT_DEFINITION_TEST, question, []);
return new ArgumentDefinitionTest(question, identifier);
}
@@ -3325,15 +3324,15 @@
AssertStatement parseAssertStatement() {
Token keyword = expect(Keyword.ASSERT);
Token leftParen = expect2(TokenType.OPEN_PAREN);
- Expression expression = parseExpression4();
+ Expression expression = parseExpression2();
if (expression is AssignmentExpression) {
- reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression, []);
+ reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression, []);
} else if (expression is CascadeExpression) {
- reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression, []);
+ reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression, []);
} else if (expression is ThrowExpression) {
- reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression, []);
+ reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression, []);
} else if (expression is RethrowExpression) {
- reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression, []);
+ reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression, []);
}
Token rightParen = expect2(TokenType.CLOSE_PAREN);
Token semicolon = expect2(TokenType.SEMICOLON);
@@ -3412,7 +3411,7 @@
Expression parseAssignableSelector(Expression prefix, bool optional) {
if (matches5(TokenType.OPEN_SQUARE_BRACKET)) {
Token leftBracket = andAdvance;
- Expression index = parseExpression4();
+ Expression index = parseExpression2();
Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET);
return new IndexExpression.forTarget(prefix, leftBracket, index, rightBracket);
} else if (matches5(TokenType.PERIOD)) {
@@ -3421,7 +3420,7 @@
} else {
if (!optional) {
// Report the missing selector.
- reportError12(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
+ reportError13(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
}
return prefix;
}
@@ -3494,7 +3493,7 @@
label = parseSimpleIdentifier();
}
if (!_inLoop && !_inSwitch && label == null) {
- reportError13(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword, []);
+ reportError14(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword, []);
}
Token semicolon = expect2(TokenType.SEMICOLON);
return new BreakStatement(breakKeyword, label, semicolon);
@@ -3525,12 +3524,12 @@
functionName = parseSimpleIdentifier();
} else if (identical(_currentToken.type, TokenType.OPEN_SQUARE_BRACKET)) {
Token leftBracket = andAdvance;
- Expression index = parseExpression4();
+ Expression index = parseExpression2();
Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET);
expression = new IndexExpression.forCascade(period, leftBracket, index, rightBracket);
period = null;
} else {
- reportError13(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, [_currentToken.lexeme]);
+ reportError14(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, [_currentToken.lexeme]);
functionName = createSyntheticIdentifier();
}
if (identical(_currentToken.type, TokenType.OPEN_PAREN)) {
@@ -3621,29 +3620,29 @@
if (extendsClause == null) {
extendsClause = parseExtendsClause();
if (withClause != null) {
- reportError13(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword, []);
+ reportError14(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword, []);
} else if (implementsClause != null) {
- reportError13(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, implementsClause.keyword, []);
+ reportError14(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, implementsClause.keyword, []);
}
} else {
- reportError13(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.keyword, []);
+ reportError14(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.keyword, []);
parseExtendsClause();
}
} else if (matches(Keyword.WITH)) {
if (withClause == null) {
withClause = parseWithClause();
if (implementsClause != null) {
- reportError13(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, implementsClause.keyword, []);
+ reportError14(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, implementsClause.keyword, []);
}
} else {
- reportError13(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword, []);
+ reportError14(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword, []);
parseWithClause();
}
} else if (matches(Keyword.IMPLEMENTS)) {
if (implementsClause == null) {
implementsClause = parseImplementsClause();
} else {
- reportError13(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, implementsClause.keyword, []);
+ reportError14(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, implementsClause.keyword, []);
parseImplementsClause();
}
} else {
@@ -3651,7 +3650,7 @@
}
}
if (withClause != null && extendsClause == null) {
- reportError13(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword, []);
+ reportError14(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword, []);
}
//
// Look for and skip over the extra-lingual 'native' specification.
@@ -3673,7 +3672,7 @@
} else {
leftBracket = createSyntheticToken2(TokenType.OPEN_CURLY_BRACKET);
rightBracket = createSyntheticToken2(TokenType.CLOSE_CURLY_BRACKET);
- reportError12(ParserErrorCode.MISSING_CLASS_BODY, []);
+ reportError13(ParserErrorCode.MISSING_CLASS_BODY, []);
}
ClassDeclaration classDeclaration = new ClassDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, abstractKeyword, keyword, name, typeParameters, extendsClause, withClause, implementsClause, leftBracket, members, rightBracket);
classDeclaration.nativeClause = nativeClause;
@@ -3698,7 +3697,7 @@
Token memberStart = _currentToken;
while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET) && (closingBracket != null || (!matches(Keyword.CLASS) && !matches(Keyword.TYPEDEF)))) {
if (matches5(TokenType.SEMICOLON)) {
- reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+ reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
advance();
} else {
ClassMember member = parseClassMember(className);
@@ -3707,7 +3706,7 @@
}
}
if (identical(_currentToken, memberStart)) {
- reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+ reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
advance();
}
memberStart = _currentToken;
@@ -3755,12 +3754,12 @@
semicolon = andAdvance;
} else {
if (matches5(TokenType.OPEN_CURLY_BRACKET)) {
- reportError12(ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
+ reportError13(ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
Token leftBracket = andAdvance;
parseClassMembers(className.name, getEndToken(leftBracket));
expect2(TokenType.CLOSE_CURLY_BRACKET);
} else {
- reportError13(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
+ reportError14(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
}
semicolon = createSyntheticToken2(TokenType.SEMICOLON);
}
@@ -3838,7 +3837,7 @@
}
try {
BooleanErrorListener listener = new BooleanErrorListener();
- Scanner scanner = new Scanner(null, new SubSequenceReader(new CharSequence(referenceSource), sourceOffset), listener);
+ Scanner scanner = new Scanner(null, new SubSequenceReader(referenceSource, sourceOffset), listener);
scanner.setSourceStart(1, 1);
Token firstToken = scanner.tokenize();
if (listener.errorReported) {
@@ -3959,7 +3958,7 @@
validateModifiersForTopLevelFunction(modifiers);
return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
} else if (matches(Keyword.OPERATOR) && isOperator(peek())) {
- reportError13(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
+ reportError14(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType));
} else if (matchesIdentifier() && matchesAny(peek(), [
TokenType.OPEN_PAREN,
@@ -3976,28 +3975,28 @@
//
// We appear to have a variable declaration with a type of "void".
//
- reportError11(ParserErrorCode.VOID_VARIABLE, returnType, []);
+ reportError12(ParserErrorCode.VOID_VARIABLE, returnType, []);
return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiersForTopLevelVariable(modifiers), null), expect2(TokenType.SEMICOLON));
}
}
- reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+ reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
return null;
}
} else if ((matches(Keyword.GET) || matches(Keyword.SET)) && matchesIdentifier2(peek())) {
validateModifiersForTopLevelFunction(modifiers);
return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, null);
} else if (matches(Keyword.OPERATOR) && isOperator(peek())) {
- reportError13(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
+ reportError14(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modifiers.externalKeyword, null));
} else if (!matchesIdentifier()) {
- reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+ reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
return null;
} else if (matches4(peek(), TokenType.OPEN_PAREN)) {
validateModifiersForTopLevelFunction(modifiers);
return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, null);
} else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
if (modifiers.constKeyword == null && modifiers.finalKeyword == null && modifiers.varKeyword == null) {
- reportError12(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
+ reportError13(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
}
return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiersForTopLevelVariable(modifiers), null), expect2(TokenType.SEMICOLON));
}
@@ -4006,13 +4005,13 @@
validateModifiersForTopLevelFunction(modifiers);
return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
} else if (matches(Keyword.OPERATOR) && isOperator(peek())) {
- reportError13(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
+ reportError14(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType));
} else if (matches5(TokenType.AT)) {
return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiersForTopLevelVariable(modifiers), returnType), expect2(TokenType.SEMICOLON));
} else if (!matchesIdentifier()) {
// TODO(brianwilkerson) Generalize this error. We could also be parsing a top-level variable at this point.
- reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+ reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
Token semicolon;
if (matches5(TokenType.SEMICOLON)) {
semicolon = andAdvance;
@@ -4089,21 +4088,21 @@
redirectedConstructor = parseConstructorName();
body = new EmptyFunctionBody(expect2(TokenType.SEMICOLON));
if (factoryKeyword == null) {
- reportError11(ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, redirectedConstructor, []);
+ reportError12(ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, redirectedConstructor, []);
}
} else {
body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
if (constKeyword != null && factoryKeyword != null && externalKeyword == null) {
- reportError13(ParserErrorCode.CONST_FACTORY, factoryKeyword, []);
+ reportError14(ParserErrorCode.CONST_FACTORY, factoryKeyword, []);
} else if (body is EmptyFunctionBody) {
if (factoryKeyword != null && externalKeyword == null) {
- reportError13(ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword, []);
+ reportError14(ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword, []);
}
} else {
if (constKeyword != null) {
- reportError11(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body, []);
+ reportError12(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body, []);
} else if (!bodyAllowed) {
- reportError11(ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body, []);
+ reportError12(ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body, []);
}
}
}
@@ -4158,14 +4157,14 @@
Statement parseContinueStatement() {
Token continueKeyword = expect(Keyword.CONTINUE);
if (!_inLoop && !_inSwitch) {
- reportError13(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword, []);
+ reportError14(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword, []);
}
SimpleIdentifier label = null;
if (matchesIdentifier()) {
label = parseSimpleIdentifier();
}
if (_inSwitch && !_inLoop && label == null) {
- reportError13(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword, []);
+ reportError14(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword, []);
}
Token semicolon = expect2(TokenType.SEMICOLON);
return new ContinueStatement(continueKeyword, label, semicolon);
@@ -4257,7 +4256,7 @@
Statement body = parseStatement2();
Token whileKeyword = expect(Keyword.WHILE);
Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
- Expression condition = parseExpression4();
+ Expression condition = parseExpression2();
Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
Token semicolon = expect2(TokenType.SEMICOLON);
return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, condition, rightParenthesis, semicolon);
@@ -4300,7 +4299,7 @@
while (_currentToken.type.isEqualityOperator) {
Token operator = andAdvance;
if (leftEqualityExpression) {
- reportError11(ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression, []);
+ reportError12(ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression, []);
}
expression = new BinaryExpression(expression, operator, parseRelationalExpression());
leftEqualityExpression = true;
@@ -4339,9 +4338,9 @@
*/
List<Expression> parseExpressionList() {
List<Expression> expressions = new List<Expression>();
- expressions.add(parseExpression4());
+ expressions.add(parseExpression2());
while (optional(TokenType.COMMA)) {
- expressions.add(parseExpression4());
+ expressions.add(parseExpression2());
}
return expressions;
}
@@ -4374,7 +4373,7 @@
if (isTypedIdentifier(_currentToken)) {
type = parseReturnType();
} else if (!optional) {
- reportError12(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
+ reportError13(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
}
}
return new FinalConstVarOrType(keyword, type);
@@ -4400,20 +4399,20 @@
NormalFormalParameter parameter = parseNormalFormalParameter();
if (matches5(TokenType.EQ)) {
Token seperator = andAdvance;
- Expression defaultValue = parseExpression4();
+ Expression defaultValue = parseExpression2();
if (identical(kind, ParameterKind.NAMED)) {
- reportError13(ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator, []);
+ reportError14(ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator, []);
} else if (identical(kind, ParameterKind.REQUIRED)) {
- reportError11(ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter, []);
+ reportError12(ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter, []);
}
return new DefaultFormalParameter(parameter, kind, seperator, defaultValue);
} else if (matches5(TokenType.COLON)) {
Token seperator = andAdvance;
- Expression defaultValue = parseExpression4();
+ Expression defaultValue = parseExpression2();
if (identical(kind, ParameterKind.POSITIONAL)) {
- reportError13(ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, seperator, []);
+ reportError14(ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, seperator, []);
} else if (identical(kind, ParameterKind.REQUIRED)) {
- reportError11(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter, []);
+ reportError12(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter, []);
}
return new DefaultFormalParameter(parameter, kind, seperator, defaultValue);
} else if (kind != ParameterKind.REQUIRED) {
@@ -4459,22 +4458,22 @@
} else if (isInitializedVariableDeclaration()) {
variableList = parseVariableDeclarationList(commentAndMetadata);
} else {
- initialization = parseExpression4();
+ initialization = parseExpression2();
}
if (matches(Keyword.IN)) {
DeclaredIdentifier loopVariable = null;
SimpleIdentifier identifier = null;
if (variableList == null) {
// We found: <expression> 'in'
- reportError12(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, []);
+ reportError13(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, []);
} else {
NodeList<VariableDeclaration> variables = variableList.variables;
if (variables.length > 1) {
- reportError12(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, [variables.length.toString()]);
+ reportError13(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, [variables.length.toString()]);
}
VariableDeclaration variable = variables[0];
if (variable.initializer != null) {
- reportError12(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, []);
+ reportError13(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, []);
}
Token keyword = variableList.keyword;
TypeName type = variableList.type;
@@ -4487,7 +4486,7 @@
}
}
Token inKeyword = expect(Keyword.IN);
- Expression iterator = parseExpression4();
+ Expression iterator = parseExpression2();
Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
Statement body = parseStatement2();
if (loopVariable == null) {
@@ -4499,7 +4498,7 @@
Token leftSeparator = expect2(TokenType.SEMICOLON);
Expression condition = null;
if (!matches5(TokenType.SEMICOLON)) {
- condition = parseExpression4();
+ condition = parseExpression2();
}
Token rightSeparator = expect2(TokenType.SEMICOLON);
List<Expression> updaters = null;
@@ -4541,12 +4540,12 @@
try {
if (matches5(TokenType.SEMICOLON)) {
if (!mayBeEmpty) {
- reportError12(emptyErrorCode, []);
+ reportError13(emptyErrorCode, []);
}
return new EmptyFunctionBody(andAdvance);
} else if (matches5(TokenType.FUNCTION)) {
Token functionDefinition = andAdvance;
- Expression expression = parseExpression4();
+ Expression expression = parseExpression2();
Token semicolon = null;
if (!inExpression) {
semicolon = expect2(TokenType.SEMICOLON);
@@ -4570,7 +4569,7 @@
return new NativeFunctionBody(nativeToken, stringLiteral, expect2(TokenType.SEMICOLON));
} else {
// Invalid function body
- reportError12(emptyErrorCode, []);
+ reportError13(emptyErrorCode, []);
return new EmptyFunctionBody(createSyntheticToken2(TokenType.SEMICOLON));
}
} finally {
@@ -4611,10 +4610,10 @@
parameters = parseFormalParameterList();
validateFormalParameterList(parameters);
} else {
- reportError12(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, []);
+ reportError13(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, []);
}
} else if (matches5(TokenType.OPEN_PAREN)) {
- reportError12(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
+ reportError13(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
parseFormalParameterList();
}
FunctionBody body;
@@ -4665,9 +4664,9 @@
Token propertyKeyword = declaration.propertyKeyword;
if (propertyKeyword != null) {
if (identical((propertyKeyword as KeywordToken).keyword, Keyword.GET)) {
- reportError13(ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword, []);
+ reportError14(ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword, []);
} else {
- reportError13(ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword, []);
+ reportError14(ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword, []);
}
}
return new FunctionDeclarationStatement(declaration);
@@ -4699,12 +4698,12 @@
typeParameters = parseTypeParameterList();
}
if (matches5(TokenType.SEMICOLON) || matches5(TokenType.EOF)) {
- reportError12(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
+ reportError13(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
FormalParameterList parameters = new FormalParameterList(createSyntheticToken2(TokenType.OPEN_PAREN), null, null, null, createSyntheticToken2(TokenType.CLOSE_PAREN));
Token semicolon = expect2(TokenType.SEMICOLON);
return new FunctionTypeAlias(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, returnType, name, typeParameters, parameters, semicolon);
} else if (!matches5(TokenType.OPEN_PAREN)) {
- reportError12(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
+ reportError13(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
// TODO(brianwilkerson) Recover from this error. At the very least we should skip to the start
// of the next valid compilation unit member, allowing for the possibility of finding the
// typedef parameters before that point.
@@ -4739,13 +4738,13 @@
Token propertyKeyword = expect(Keyword.GET);
SimpleIdentifier name = parseSimpleIdentifier();
if (matches5(TokenType.OPEN_PAREN) && matches4(peek(), TokenType.CLOSE_PAREN)) {
- reportError12(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
+ reportError13(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
advance();
advance();
}
FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, false);
if (externalKeyword != null && body is! EmptyFunctionBody) {
- reportError12(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY, []);
+ reportError13(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY, []);
}
return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null, name, null, body);
}
@@ -4783,7 +4782,7 @@
Statement parseIfStatement() {
Token ifKeyword = expect(Keyword.IF);
Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
- Expression condition = parseExpression4();
+ Expression condition = parseExpression2();
Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
Statement thenStatement = parseStatement2();
Token elseKeyword = null;
@@ -4903,9 +4902,9 @@
// TODO(brianwilkerson) Recovery: This should be extended to handle arbitrary tokens until we
// can find a token that can start a compilation unit member.
StringLiteral string = parseStringLiteral();
- reportError11(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string, []);
+ reportError12(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string, []);
} else {
- reportError13(missingNameError, missingNameToken, []);
+ reportError14(missingNameError, missingNameToken, []);
}
List<SimpleIdentifier> components = new List<SimpleIdentifier>();
components.add(createSyntheticIdentifier());
@@ -4944,12 +4943,12 @@
return new ListLiteral(modifier, typeArguments, leftBracket, null, andAdvance);
}
List<Expression> elements = new List<Expression>();
- elements.add(parseExpression4());
+ elements.add(parseExpression2());
while (optional(TokenType.COMMA)) {
if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) {
return new ListLiteral(modifier, typeArguments, leftBracket, elements, andAdvance);
}
- elements.add(parseExpression4());
+ elements.add(parseExpression2());
}
Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET);
return new ListLiteral(modifier, typeArguments, leftBracket, elements, rightBracket);
@@ -4978,7 +4977,7 @@
} else if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.INDEX)) {
return parseListLiteral(modifier, typeArguments);
}
- reportError12(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL, []);
+ reportError13(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL, []);
return new ListLiteral(modifier, typeArguments, createSyntheticToken2(TokenType.OPEN_SQUARE_BRACKET), null, createSyntheticToken2(TokenType.CLOSE_SQUARE_BRACKET));
}
@@ -5077,11 +5076,11 @@
FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.MISSING_FUNCTION_BODY, false);
if (externalKeyword != null) {
if (body is! EmptyFunctionBody) {
- reportError11(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body, []);
+ reportError12(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body, []);
}
} else if (staticKeyword != null) {
if (body is EmptyFunctionBody) {
- reportError11(ParserErrorCode.ABSTRACT_STATIC_METHOD, body, []);
+ reportError12(ParserErrorCode.ABSTRACT_STATIC_METHOD, body, []);
}
}
return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, null, null, name, parameters, body);
@@ -5109,49 +5108,49 @@
}
if (matches(Keyword.ABSTRACT)) {
if (modifiers.abstractKeyword != null) {
- reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
advance();
} else {
modifiers.abstractKeyword = andAdvance;
}
} else if (matches(Keyword.CONST)) {
if (modifiers.constKeyword != null) {
- reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
advance();
} else {
modifiers.constKeyword = andAdvance;
}
} else if (matches(Keyword.EXTERNAL) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT)) {
if (modifiers.externalKeyword != null) {
- reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
advance();
} else {
modifiers.externalKeyword = andAdvance;
}
} else if (matches(Keyword.FACTORY) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT)) {
if (modifiers.factoryKeyword != null) {
- reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
advance();
} else {
modifiers.factoryKeyword = andAdvance;
}
} else if (matches(Keyword.FINAL)) {
if (modifiers.finalKeyword != null) {
- reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
advance();
} else {
modifiers.finalKeyword = andAdvance;
}
} else if (matches(Keyword.STATIC) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT)) {
if (modifiers.staticKeyword != null) {
- reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
advance();
} else {
modifiers.staticKeyword = andAdvance;
}
} else if (matches(Keyword.VAR)) {
if (modifiers.varKeyword != null) {
- reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
advance();
} else {
modifiers.varKeyword = andAdvance;
@@ -5246,7 +5245,7 @@
if (matches4(peek(), TokenType.STRING)) {
Token afterString = skipStringLiteral(_currentToken.next);
if (afterString != null && identical(afterString.type, TokenType.COLON)) {
- return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+ return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
}
}
return parseBlock();
@@ -5295,7 +5294,7 @@
//
// We appear to have a variable declaration with a type of "void".
//
- reportError11(ParserErrorCode.VOID_VARIABLE, returnType, []);
+ reportError12(ParserErrorCode.VOID_VARIABLE, returnType, []);
return parseVariableDeclarationStatement(commentAndMetadata);
}
} else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) {
@@ -5305,7 +5304,7 @@
//
return parseVariableDeclarationStatement2(commentAndMetadata, null, returnType);
}
- reportError12(ParserErrorCode.MISSING_STATEMENT, []);
+ reportError13(ParserErrorCode.MISSING_STATEMENT, []);
// TODO(brianwilkerson) Recover from this error.
return new EmptyStatement(createSyntheticToken2(TokenType.SEMICOLON));
}
@@ -5315,23 +5314,23 @@
TokenType.OPEN_CURLY_BRACKET,
TokenType.OPEN_SQUARE_BRACKET,
TokenType.INDEX])) {
- return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+ return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
} else if (matches4(peek(), TokenType.IDENTIFIER)) {
Token afterType = skipTypeName(peek());
if (afterType != null) {
if (matches4(afterType, TokenType.OPEN_PAREN) || (matches4(afterType, TokenType.PERIOD) && matches4(afterType.next, TokenType.IDENTIFIER) && matches4(afterType.next.next, TokenType.OPEN_PAREN))) {
- return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+ return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
}
}
}
return parseVariableDeclarationStatement(commentAndMetadata);
} else if (identical(keyword, Keyword.NEW) || identical(keyword, Keyword.TRUE) || identical(keyword, Keyword.FALSE) || identical(keyword, Keyword.NULL) || identical(keyword, Keyword.SUPER) || identical(keyword, Keyword.THIS)) {
- return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+ return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
} else {
//
// We have found an error of some kind. Try to recover.
//
- reportError12(ParserErrorCode.MISSING_STATEMENT, []);
+ reportError13(ParserErrorCode.MISSING_STATEMENT, []);
return new EmptyStatement(createSyntheticToken2(TokenType.SEMICOLON));
}
} else if (matches5(TokenType.SEMICOLON)) {
@@ -5341,10 +5340,10 @@
} else if (isFunctionDeclaration()) {
return parseFunctionDeclarationStatement();
} else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) {
- reportError12(ParserErrorCode.MISSING_STATEMENT, []);
+ reportError13(ParserErrorCode.MISSING_STATEMENT, []);
return new EmptyStatement(createSyntheticToken2(TokenType.SEMICOLON));
} else {
- return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+ return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
}
}
@@ -5371,17 +5370,17 @@
if (matches(Keyword.OPERATOR)) {
operatorKeyword = andAdvance;
} else {
- reportError13(ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken, []);
+ reportError14(ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken, []);
operatorKeyword = createSyntheticToken(Keyword.OPERATOR);
}
if (!_currentToken.isUserDefinableOperator) {
- reportError12(ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
}
SimpleIdentifier name = new SimpleIdentifier(andAdvance);
if (matches5(TokenType.EQ)) {
Token previous = _currentToken.previous;
if ((matches4(previous, TokenType.EQ_EQ) || matches4(previous, TokenType.BANG_EQ)) && _currentToken.offset == previous.offset + 2) {
- reportError12(ParserErrorCode.INVALID_OPERATOR, ["${previous.lexeme}${_currentToken.lexeme}"]);
+ reportError13(ParserErrorCode.INVALID_OPERATOR, ["${previous.lexeme}${_currentToken.lexeme}"]);
advance();
}
}
@@ -5389,7 +5388,7 @@
validateFormalParameterList(parameters);
FunctionBody body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
if (externalKeyword != null && body is! EmptyFunctionBody) {
- reportError12(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY, []);
+ reportError13(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY, []);
}
return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, null, returnType, null, operatorKeyword, name, parameters, body);
}
@@ -5474,7 +5473,7 @@
return operand;
}
if (operand is Literal || operand is FunctionExpressionInvocation) {
- reportError12(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
+ reportError13(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
}
Token operator = andAdvance;
return new PostfixExpression(operand, operator);
@@ -5569,7 +5568,7 @@
return parseFunctionExpression();
}
Token leftParenthesis = andAdvance;
- Expression expression = parseExpression4();
+ Expression expression = parseExpression2();
Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
return new ParenthesizedExpression(leftParenthesis, expression, rightParenthesis);
} else if (matches5(TokenType.LT)) {
@@ -5581,13 +5580,13 @@
// Recover from having a return type of "void" where a return type is not expected.
//
// TODO(brianwilkerson) Improve this error message.
- reportError12(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
+ reportError13(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
advance();
return parsePrimaryExpression();
} else if (matches5(TokenType.HASH)) {
return parseSymbolLiteral();
} else {
- reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+ reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
return createSyntheticIdentifier();
}
}
@@ -5677,7 +5676,7 @@
if (matches5(TokenType.SEMICOLON)) {
return new ReturnStatement(returnKeyword, null, andAdvance);
}
- Expression expression = parseExpression4();
+ Expression expression = parseExpression2();
Token semicolon = expect2(TokenType.SEMICOLON);
return new ReturnStatement(returnKeyword, expression, semicolon);
}
@@ -5708,7 +5707,7 @@
validateFormalParameterList(parameters);
FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, false);
if (externalKeyword != null && body is! EmptyFunctionBody) {
- reportError12(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY, []);
+ reportError13(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY, []);
}
return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null, name, parameters, body);
}
@@ -5754,7 +5753,7 @@
while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET) && !isSwitchMember()) {
statements.add(parseStatement2());
if (identical(_currentToken, statementStart)) {
- reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+ reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
advance();
}
statementStart = _currentToken;
@@ -5774,7 +5773,7 @@
while (hasMore) {
if (matches5(TokenType.STRING_INTERPOLATION_EXPRESSION)) {
Token openToken = andAdvance;
- Expression expression = parseExpression4();
+ Expression expression = parseExpression2();
Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET);
elements.add(new InterpolationExpression(openToken, expression, rightBracket));
} else {
@@ -5841,7 +5840,7 @@
Set<String> definedLabels = new Set<String>();
Token keyword = expect(Keyword.SWITCH);
Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
- Expression expression = parseExpression4();
+ Expression expression = parseExpression2();
Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET);
Token defaultKeyword = null;
@@ -5852,7 +5851,7 @@
SimpleIdentifier identifier = parseSimpleIdentifier();
String label = identifier.token.lexeme;
if (definedLabels.contains(label)) {
- reportError13(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, identifier.token, [label]);
+ reportError14(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, identifier.token, [label]);
} else {
definedLabels.add(label);
}
@@ -5861,15 +5860,15 @@
}
if (matches(Keyword.CASE)) {
Token caseKeyword = andAdvance;
- Expression caseExpression = parseExpression4();
+ Expression caseExpression = parseExpression2();
Token colon = expect2(TokenType.COLON);
members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, parseStatements2()));
if (defaultKeyword != null) {
- reportError13(ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, caseKeyword, []);
+ reportError14(ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, caseKeyword, []);
}
} else if (matches(Keyword.DEFAULT)) {
if (defaultKeyword != null) {
- reportError13(ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, peek(), []);
+ reportError14(ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, peek(), []);
}
defaultKeyword = andAdvance;
Token colon = expect2(TokenType.COLON);
@@ -5877,7 +5876,7 @@
} else {
// We need to advance, otherwise we could end up in an infinite loop, but this could be a
// lot smarter about recovering from the error.
- reportError12(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, []);
+ reportError13(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, []);
while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET) && !matches(Keyword.CASE) && !matches(Keyword.DEFAULT)) {
advance();
}
@@ -5910,7 +5909,7 @@
if (matchesIdentifier()) {
components.add(andAdvance);
} else {
- reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+ reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
components.add(createSyntheticToken2(TokenType.IDENTIFIER));
break;
}
@@ -5918,7 +5917,7 @@
} else if (_currentToken.isOperator) {
components.add(andAdvance);
} else {
- reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+ reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
components.add(createSyntheticToken2(TokenType.IDENTIFIER));
}
return new SymbolLiteral(poundSign, new List.from(components));
@@ -5937,10 +5936,10 @@
Expression parseThrowExpression() {
Token keyword = expect(Keyword.THROW);
if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) {
- reportError13(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
+ reportError14(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
return new ThrowExpression(keyword, createSyntheticIdentifier());
}
- Expression expression = parseExpression4();
+ Expression expression = parseExpression2();
return new ThrowExpression(keyword, expression);
}
@@ -5957,7 +5956,7 @@
Expression parseThrowExpressionWithoutCascade() {
Token keyword = expect(Keyword.THROW);
if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) {
- reportError13(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
+ reportError14(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
return new ThrowExpression(keyword, createSyntheticIdentifier());
}
Expression expression = parseExpressionWithoutCascade();
@@ -6021,7 +6020,7 @@
finallyClause = parseBlock();
} else {
if (catchClauses.isEmpty) {
- reportError12(ParserErrorCode.MISSING_CATCH_OR_FINALLY, []);
+ reportError13(ParserErrorCode.MISSING_CATCH_OR_FINALLY, []);
}
}
return new TryStatement(tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
@@ -6062,12 +6061,12 @@
next = skipTypeParameterList(next);
if (next != null && matches4(next, TokenType.EQ)) {
TypeAlias typeAlias = parseClassTypeAlias(commentAndMetadata, null, keyword);
- reportError13(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
+ reportError14(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
return typeAlias;
}
} else if (matches4(next, TokenType.EQ)) {
TypeAlias typeAlias = parseClassTypeAlias(commentAndMetadata, null, keyword);
- reportError13(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
+ reportError14(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
return typeAlias;
}
}
@@ -6124,13 +6123,13 @@
return new PrefixExpression(firstOperator, new PrefixExpression(secondOperator, new SuperExpression(andAdvance)));
} else {
// Invalid operator before 'super'
- reportError12(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
+ reportError13(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
return new PrefixExpression(operator, new SuperExpression(andAdvance));
}
}
return new PrefixExpression(operator, parseAssignableExpression(false));
} else if (matches5(TokenType.PLUS)) {
- reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+ reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
return createSyntheticIdentifier();
}
return parsePostfixExpression();
@@ -6153,7 +6152,7 @@
Expression initializer = null;
if (matches5(TokenType.EQ)) {
equals = andAdvance;
- initializer = parseExpression4();
+ initializer = parseExpression2();
}
return new VariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, name, equals, initializer);
}
@@ -6191,7 +6190,7 @@
*/
VariableDeclarationList parseVariableDeclarationList2(CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
if (type != null && keyword != null && matches3(keyword, Keyword.VAR)) {
- reportError13(ParserErrorCode.VAR_AND_TYPE, keyword, []);
+ reportError14(ParserErrorCode.VAR_AND_TYPE, keyword, []);
}
List<VariableDeclaration> variables = new List<VariableDeclaration>();
variables.add(parseVariableDeclaration());
@@ -6264,7 +6263,7 @@
try {
Token keyword = expect(Keyword.WHILE);
Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
- Expression condition = parseExpression4();
+ Expression condition = parseExpression2();
Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
Statement body = parseStatement2();
return new WhileStatement(keyword, leftParenthesis, condition, rightParenthesis, body);
@@ -6315,7 +6314,7 @@
* @param node the node specifying the location of the error
* @param arguments the arguments to the error, used to compose the error message
*/
- void reportError11(ParserErrorCode errorCode, ASTNode node, List<Object> arguments) {
+ void reportError12(ParserErrorCode errorCode, ASTNode node, List<Object> arguments) {
reportError(new AnalysisError.con2(_source, node.offset, node.length, errorCode, arguments));
}
@@ -6325,8 +6324,8 @@
* @param errorCode the error code of the error to be reported
* @param arguments the arguments to the error, used to compose the error message
*/
- void reportError12(ParserErrorCode errorCode, List<Object> arguments) {
- reportError13(errorCode, _currentToken, arguments);
+ void reportError13(ParserErrorCode errorCode, List<Object> arguments) {
+ reportError14(errorCode, _currentToken, arguments);
}
/**
@@ -6336,7 +6335,7 @@
* @param token the token specifying the location of the error
* @param arguments the arguments to the error, used to compose the error message
*/
- void reportError13(ParserErrorCode errorCode, Token token, List<Object> arguments) {
+ void reportError14(ParserErrorCode errorCode, Token token, List<Object> arguments) {
reportError(new AnalysisError.con2(_source, token.offset, token.length, errorCode, arguments));
}
@@ -6817,14 +6816,14 @@
} else if (currentChar == 0x78) {
if (currentIndex + 2 >= length) {
// Illegal escape sequence: not enough hex digits
- reportError12(ParserErrorCode.INVALID_HEX_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_HEX_ESCAPE, []);
return length;
}
int firstDigit = lexeme.codeUnitAt(currentIndex + 1);
int secondDigit = lexeme.codeUnitAt(currentIndex + 2);
if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit)) {
// Illegal escape sequence: invalid hex digit
- reportError12(ParserErrorCode.INVALID_HEX_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_HEX_ESCAPE, []);
} else {
builder.appendChar(((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16)));
}
@@ -6833,7 +6832,7 @@
currentIndex++;
if (currentIndex >= length) {
// Illegal escape sequence: not enough hex digits
- reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
return length;
}
currentChar = lexeme.codeUnitAt(currentIndex);
@@ -6841,7 +6840,7 @@
currentIndex++;
if (currentIndex >= length) {
// Illegal escape sequence: incomplete escape
- reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
return length;
}
currentChar = lexeme.codeUnitAt(currentIndex);
@@ -6850,7 +6849,7 @@
while (currentChar != 0x7D) {
if (!isHexDigit(currentChar)) {
// Illegal escape sequence: invalid hex digit
- reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
currentIndex++;
while (currentIndex < length && lexeme.codeUnitAt(currentIndex) != 0x7D) {
currentIndex++;
@@ -6862,21 +6861,21 @@
currentIndex++;
if (currentIndex >= length) {
// Illegal escape sequence: incomplete escape
- reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
return length;
}
currentChar = lexeme.codeUnitAt(currentIndex);
}
if (digitCount < 1 || digitCount > 6) {
// Illegal escape sequence: not enough or too many hex digits
- reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
}
appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), value, index, currentIndex);
return currentIndex + 1;
} else {
if (currentIndex + 3 >= length) {
// Illegal escape sequence: not enough hex digits
- reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
return length;
}
int firstDigit = currentChar;
@@ -6885,7 +6884,7 @@
int fourthDigit = lexeme.codeUnitAt(currentIndex + 3);
if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit) || !isHexDigit(thirdDigit) || !isHexDigit(fourthDigit)) {
// Illegal escape sequence: invalid hex digits
- reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+ reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
} else {
appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), (((((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16)) << 4) + Character.digit(thirdDigit, 16)) << 4) + Character.digit(fourthDigit, 16), index, currentIndex + 3);
}
@@ -6916,7 +6915,7 @@
void validateFormalParameterList(FormalParameterList parameterList) {
for (FormalParameter parameter in parameterList.parameters) {
if (parameter is FieldFormalParameter) {
- reportError11(ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, parameter.identifier, []);
+ reportError12(ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, parameter.identifier, []);
}
}
}
@@ -6930,16 +6929,16 @@
Token validateModifiersForClass(Modifiers modifiers) {
validateModifiersForTopLevelDeclaration(modifiers);
if (modifiers.constKeyword != null) {
- reportError13(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
+ reportError14(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
}
if (modifiers.externalKeyword != null) {
- reportError13(ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword, []);
+ reportError14(ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword, []);
}
if (modifiers.finalKeyword != null) {
- reportError13(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
+ reportError14(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
}
if (modifiers.varKeyword != null) {
- reportError13(ParserErrorCode.VAR_CLASS, modifiers.varKeyword, []);
+ reportError14(ParserErrorCode.VAR_CLASS, modifiers.varKeyword, []);
}
return modifiers.abstractKeyword;
}
@@ -6953,25 +6952,25 @@
*/
Token validateModifiersForConstructor(Modifiers modifiers) {
if (modifiers.abstractKeyword != null) {
- reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+ reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
}
if (modifiers.finalKeyword != null) {
- reportError13(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []);
+ reportError14(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []);
}
if (modifiers.staticKeyword != null) {
- reportError13(ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword, []);
+ reportError14(ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword, []);
}
if (modifiers.varKeyword != null) {
- reportError13(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKeyword, []);
+ reportError14(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKeyword, []);
}
Token externalKeyword = modifiers.externalKeyword;
Token constKeyword = modifiers.constKeyword;
Token factoryKeyword = modifiers.factoryKeyword;
if (externalKeyword != null && constKeyword != null && constKeyword.offset < externalKeyword.offset) {
- reportError13(ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword, []);
+ reportError14(ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword, []);
}
if (externalKeyword != null && factoryKeyword != null && factoryKeyword.offset < externalKeyword.offset) {
- reportError13(ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword, []);
+ reportError14(ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword, []);
}
return constKeyword;
}
@@ -6985,13 +6984,13 @@
*/
Token validateModifiersForField(Modifiers modifiers) {
if (modifiers.abstractKeyword != null) {
- reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+ reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
}
if (modifiers.externalKeyword != null) {
- reportError13(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
+ reportError14(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
}
if (modifiers.factoryKeyword != null) {
- reportError13(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
+ reportError14(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
}
Token staticKeyword = modifiers.staticKeyword;
Token constKeyword = modifiers.constKeyword;
@@ -6999,23 +6998,23 @@
Token varKeyword = modifiers.varKeyword;
if (constKeyword != null) {
if (finalKeyword != null) {
- reportError13(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
+ reportError14(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
}
if (varKeyword != null) {
- reportError13(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
+ reportError14(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
}
if (staticKeyword != null && constKeyword.offset < staticKeyword.offset) {
- reportError13(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword, []);
+ reportError14(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword, []);
}
} else if (finalKeyword != null) {
if (varKeyword != null) {
- reportError13(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
+ reportError14(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
}
if (staticKeyword != null && finalKeyword.offset < staticKeyword.offset) {
- reportError13(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword, []);
+ reportError14(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword, []);
}
} else if (varKeyword != null && staticKeyword != null && varKeyword.offset < staticKeyword.offset) {
- reportError13(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword, []);
+ reportError14(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword, []);
}
return lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
}
@@ -7027,7 +7026,7 @@
*/
void validateModifiersForFunctionDeclarationStatement(Modifiers modifiers) {
if (modifiers.abstractKeyword != null || modifiers.constKeyword != null || modifiers.externalKeyword != null || modifiers.factoryKeyword != null || modifiers.finalKeyword != null || modifiers.staticKeyword != null || modifiers.varKeyword != null) {
- reportError12(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, []);
+ reportError13(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, []);
}
}
@@ -7038,24 +7037,24 @@
*/
void validateModifiersForGetterOrSetterOrMethod(Modifiers modifiers) {
if (modifiers.abstractKeyword != null) {
- reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+ reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
}
if (modifiers.constKeyword != null) {
- reportError13(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
+ reportError14(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
}
if (modifiers.factoryKeyword != null) {
- reportError13(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
+ reportError14(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
}
if (modifiers.finalKeyword != null) {
- reportError13(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
+ reportError14(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
}
if (modifiers.varKeyword != null) {
- reportError13(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
+ reportError14(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
}
Token externalKeyword = modifiers.externalKeyword;
Token staticKeyword = modifiers.staticKeyword;
if (externalKeyword != null && staticKeyword != null && staticKeyword.offset < externalKeyword.offset) {
- reportError13(ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword, []);
+ reportError14(ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword, []);
}
}
@@ -7066,22 +7065,22 @@
*/
void validateModifiersForOperator(Modifiers modifiers) {
if (modifiers.abstractKeyword != null) {
- reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+ reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
}
if (modifiers.constKeyword != null) {
- reportError13(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
+ reportError14(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
}
if (modifiers.factoryKeyword != null) {
- reportError13(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
+ reportError14(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
}
if (modifiers.finalKeyword != null) {
- reportError13(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
+ reportError14(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
}
if (modifiers.staticKeyword != null) {
- reportError13(ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword, []);
+ reportError14(ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword, []);
}
if (modifiers.varKeyword != null) {
- reportError13(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
+ reportError14(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
}
}
@@ -7092,10 +7091,10 @@
*/
void validateModifiersForTopLevelDeclaration(Modifiers modifiers) {
if (modifiers.factoryKeyword != null) {
- reportError13(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, modifiers.factoryKeyword, []);
+ reportError14(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, modifiers.factoryKeyword, []);
}
if (modifiers.staticKeyword != null) {
- reportError13(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, modifiers.staticKeyword, []);
+ reportError14(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, modifiers.staticKeyword, []);
}
}
@@ -7107,16 +7106,16 @@
void validateModifiersForTopLevelFunction(Modifiers modifiers) {
validateModifiersForTopLevelDeclaration(modifiers);
if (modifiers.abstractKeyword != null) {
- reportError12(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, []);
+ reportError13(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, []);
}
if (modifiers.constKeyword != null) {
- reportError13(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
+ reportError14(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
}
if (modifiers.finalKeyword != null) {
- reportError13(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
+ reportError14(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
}
if (modifiers.varKeyword != null) {
- reportError13(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
+ reportError14(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
}
}
@@ -7130,24 +7129,24 @@
Token validateModifiersForTopLevelVariable(Modifiers modifiers) {
validateModifiersForTopLevelDeclaration(modifiers);
if (modifiers.abstractKeyword != null) {
- reportError12(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, []);
+ reportError13(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, []);
}
if (modifiers.externalKeyword != null) {
- reportError13(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
+ reportError14(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
}
Token constKeyword = modifiers.constKeyword;
Token finalKeyword = modifiers.finalKeyword;
Token varKeyword = modifiers.varKeyword;
if (constKeyword != null) {
if (finalKeyword != null) {
- reportError13(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
+ reportError14(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
}
if (varKeyword != null) {
- reportError13(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
+ reportError14(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
}
} else if (finalKeyword != null) {
if (varKeyword != null) {
- reportError13(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
+ reportError14(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
}
}
return lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
@@ -7162,19 +7161,19 @@
void validateModifiersForTypedef(Modifiers modifiers) {
validateModifiersForTopLevelDeclaration(modifiers);
if (modifiers.abstractKeyword != null) {
- reportError13(ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword, []);
+ reportError14(ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword, []);
}
if (modifiers.constKeyword != null) {
- reportError13(ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword, []);
+ reportError14(ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword, []);
}
if (modifiers.externalKeyword != null) {
- reportError13(ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword, []);
+ reportError14(ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword, []);
}
if (modifiers.finalKeyword != null) {
- reportError13(ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword, []);
+ reportError14(ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword, []);
}
if (modifiers.varKeyword != null) {
- reportError13(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword, []);
+ reportError14(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword, []);
}
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1c9e0cf..3e6f1aa 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -59,31 +59,6 @@
static String _NG_TWO_WAY = "NgTwoWay";
- /**
- * Returns the array of all top-level Angular elements that could be used in this library.
- *
- * @param libraryElement the [LibraryElement] to analyze
- * @return the array of all top-level Angular elements that could be used in this library
- */
- static List<AngularElement> getAngularElements(LibraryElement libraryElement) {
- List<AngularElement> angularElements = [];
- // add Angular elements from current library
- for (CompilationUnitElement unit in libraryElement.units) {
- for (ClassElement type in unit.types) {
- addAngularElements(angularElements, type);
- }
- }
- // handle imports
- for (ImportElement importElement in libraryElement.imports) {
- Namespace namespace = new NamespaceBuilder().createImportNamespace(importElement);
- for (Element importedElement in namespace.definedNames.values) {
- addAngularElements(angularElements, importedElement);
- }
- }
- // done
- return new List.from(angularElements);
- }
-
static Element getElement(ASTNode node, int offset) {
// maybe node is not SimpleStringLiteral
if (node is! SimpleStringLiteral) {
@@ -178,24 +153,6 @@
}
/**
- * Adds [AngularElement] declared by the given top-level [Element].
- *
- * @param angularElements the list to fill with top-level [AngularElement]s
- * @param unitMember the top-level member of unit, such as [ClassElement], to get
- * [AngularElement]s from
- */
- static void addAngularElements(List<AngularElement> angularElements, Element unitMember) {
- if (unitMember is ClassElement) {
- ClassElement type = unitMember;
- for (ToolkitObjectElement toolkitObject in type.toolkitObjects) {
- if (toolkitObject is AngularElement) {
- angularElements.add(toolkitObject);
- }
- }
- }
- }
-
- /**
* Returns the [FieldElement] of the first field in the given [FieldDeclaration].
*/
static FieldElement getOnlyFieldElement(FieldDeclaration fieldDeclaration) {
@@ -248,11 +205,6 @@
}
/**
- * The [AnalysisContext] that performs analysis.
- */
- AnalysisContext _context;
-
- /**
* The listener to which errors will be reported.
*/
AnalysisErrorListener _errorListener;
@@ -288,8 +240,7 @@
* @param errorListener the listener to which errors will be reported.
* @param source the source containing the unit that will be analyzed
*/
- AngularCompilationUnitBuilder(AnalysisContext context, AnalysisErrorListener errorListener, Source source) {
- this._context = context;
+ AngularCompilationUnitBuilder(AnalysisErrorListener errorListener, Source source) {
this._errorListener = errorListener;
this._source = source;
}
@@ -446,33 +397,10 @@
}
// create
if (isValid) {
- AngularComponentElementImpl element = new AngularComponentElementImpl(name, nameOffset);
+ AngularComponentElementImpl element = new AngularComponentElementImpl(name, nameOffset, _annotation.offset);
element.selector = selector;
element.templateUri = templateUri;
element.templateUriOffset = templateUriOffset;
- // resolve template URI
- // TODO(scheglov) resolve to HtmlElement to allow F3 ?
- if (templateUri != null) {
- try {
- parseUriWithException(templateUri);
- // TODO(scheglov) think if there is better solution
- if (templateUri.startsWith("packages/")) {
- templateUri = "package:${templateUri.substring("packages/".length)}";
- }
- Source templateSource = _context.sourceFactory.resolveUri(_source, templateUri);
- if (templateSource == null || !templateSource.exists()) {
- templateSource = _context.sourceFactory.resolveUri(_source, "package:${templateUri}");
- }
- if (templateSource == null || !templateSource.exists()) {
- reportErrorForArgument(_TEMPLATE_URL, AngularCode.URI_DOES_NOT_EXIST, [templateUri]);
- }
- if (AnalysisEngine.isHtmlFileName(templateUri)) {
- element.templateSource = templateSource;
- }
- } on URISyntaxException catch (exception) {
- reportErrorForArgument(_TEMPLATE_URL, AngularCode.INVALID_URI, [templateUri]);
- }
- }
element.styleUri = styleUri;
element.styleUriOffset = styleUriOffset;
element.properties = parseNgComponentProperties(true);
@@ -1891,12 +1819,6 @@
int _modificationStamp = 0;
/**
- * The line information associated with the source for which an element is being built, or
- * `null` if we are not building an element.
- */
- LineInfo _lineInfo;
-
- /**
* The HTML element being built.
*/
HtmlElementImpl _htmlElement;
@@ -1946,7 +1868,6 @@
*/
HtmlElementImpl buildHtmlElement2(Source source, int modificationStamp, ht.HtmlUnit unit) {
this._modificationStamp = modificationStamp;
- _lineInfo = _context.computeLineInfo(source);
HtmlElementImpl result = new HtmlElementImpl(_context, source.shortName);
result.source = source;
_htmlElement = result;
@@ -1989,7 +1910,7 @@
_errorListener.addAll(resolver.errorListener);
} on AnalysisException catch (exception) {
//TODO (danrubel): Handle or forward the exception
- AnalysisEngine.instance.logger.logError3(exception);
+ AnalysisEngine.instance.logger.logError2("Could not resolve script tag", exception);
}
node.scriptElement = script;
_scripts.add(script);
@@ -2032,12 +1953,7 @@
return null;
}
- Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
- for (ht.EmbeddedExpression expression in node.expressions) {
- resolveExpression(expression.expression);
- }
- return null;
- }
+ Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
Object visitXmlTagNode(ht.XmlTagNode node) {
if (_parentNodes.contains(node)) {
@@ -2045,9 +1961,6 @@
}
_parentNodes.add(node);
try {
- for (ht.EmbeddedExpression expression in node.expressions) {
- resolveExpression(expression.expression);
- }
node.visitChildren(this);
} finally {
_parentNodes.remove(node);
@@ -2125,9 +2038,6 @@
int length = attribute.valueToken.length - 2;
reportError(errorCode, offset, length, arguments);
}
-
- void resolveExpression(Expression expression) {
- }
}
/**
@@ -2196,6 +2106,8 @@
sc.TokenType operatorType = node.operator.type;
if (operatorType != sc.TokenType.EQ) {
checkForDeprecatedMemberUse(node.bestElement, node);
+ } else {
+ checkForUseOfVoidResult(node.rightHandSide);
}
return super.visitAssignmentExpression(node);
}
@@ -2280,6 +2192,11 @@
return super.visitSuperConstructorInvocation(node);
}
+ Object visitVariableDeclaration(VariableDeclaration node) {
+ checkForUseOfVoidResult(node.initializer);
+ return super.visitVariableDeclaration(node);
+ }
+
/**
* Check for the passed is expression for the unnecessary type check hint codes as well as null
* checks expressed using an is expression.
@@ -2435,7 +2352,28 @@
* @return `true` if and only if a hint code is generated on the passed node
* @see HintCode#MISSING_RETURN
*/
- bool checkForMissingReturn(TypeName returnType, FunctionBody body) => false;
+ bool checkForMissingReturn(TypeName returnType, FunctionBody body) {
+ // Check that the method or function has a return type, and a function body
+ if (returnType == null || body == null) {
+ return false;
+ }
+ // Check that the body is a BlockFunctionBody
+ if (body is! BlockFunctionBody) {
+ return false;
+ }
+ // Check that the type is resolvable, and is not "void"
+ Type2 returnTypeType = returnType.type;
+ if (returnTypeType == null || returnTypeType.isVoid) {
+ return false;
+ }
+ // Check the block for a return statement, if not, create the hint
+ BlockFunctionBody blockFunctionBody = body as BlockFunctionBody;
+ if (!blockFunctionBody.accept(new ExitDetector())) {
+ _errorReporter.reportError3(HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
+ return true;
+ }
+ return false;
+ }
/**
* Check for the passed class declaration for the
@@ -2550,6 +2488,30 @@
}
return false;
}
+
+ /**
+ * Check for situations where the result of a method or function is used, when it returns 'void'.
+ *
+ * TODO(jwren) Many other situations of use could be covered. We currently cover the cases var x =
+ * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m(), f(m()), return
+ * m().
+ *
+ * @param node expression on the RHS of some assignment
+ * @return `true` if and only if a hint code is generated on the passed node
+ * @see HintCode#USE_OF_VOID_RESULT
+ */
+ bool checkForUseOfVoidResult(Expression expression) {
+ if (expression == null || expression is! MethodInvocation) {
+ return false;
+ }
+ MethodInvocation methodInvocation = expression as MethodInvocation;
+ if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) {
+ SimpleIdentifier methodName = methodInvocation.methodName;
+ _errorReporter.reportError3(HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
+ return true;
+ }
+ return false;
+ }
}
/**
@@ -3019,11 +2981,20 @@
Expression conditionExpression = node.condition;
Statement thenStatement = node.thenStatement;
Statement elseStatement = node.elseStatement;
- // TODO(jwren) Do we want to take constant expressions into account, evaluate if(false) {}
- // differently than if(<condition>), when <condition> evaluates to a constant false value?
if (conditionExpression.accept(this)) {
return true;
}
+ // TODO(jwren) Do we want to take all constant expressions into account?
+ if (conditionExpression is BooleanLiteral) {
+ BooleanLiteral booleanLiteral = conditionExpression;
+ if (booleanLiteral.value) {
+ // if(true) ...
+ return thenStatement.accept(this);
+ } else if (elseStatement != null) {
+ // if (false) ...
+ return elseStatement.accept(this);
+ }
+ }
if (thenStatement == null || elseStatement == null) {
return false;
}
@@ -3031,7 +3002,7 @@
}
bool visitIndexExpression(IndexExpression node) {
- Expression target = node.target;
+ Expression target = node.realTarget;
if (target != null && target.accept(this)) {
return true;
}
@@ -3052,7 +3023,7 @@
bool visitLiteral(Literal node) => false;
bool visitMethodInvocation(MethodInvocation node) {
- Expression target = node.target;
+ Expression target = node.realTarget;
if (target != null && target.accept(this)) {
return true;
}
@@ -3067,7 +3038,13 @@
bool visitPrefixExpression(PrefixExpression node) => false;
- bool visitPropertyAccess(PropertyAccess node) => node.target.accept(this);
+ bool visitPropertyAccess(PropertyAccess node) {
+ Expression target = node.realTarget;
+ if (target != null && target.accept(this)) {
+ return true;
+ }
+ return false;
+ }
bool visitRethrowExpression(RethrowExpression node) => true;
@@ -3081,12 +3058,21 @@
bool visitSwitchStatement(SwitchStatement node) {
bool hasDefault = false;
- for (SwitchMember member in node.members) {
- if (!member.accept(this)) {
- return false;
- }
- if (member is SwitchDefault) {
+ NodeList<SwitchMember> memberList = node.members;
+ List<SwitchMember> members = new List.from(memberList);
+ for (int i = 0; i < members.length; i++) {
+ SwitchMember switchMember = members[i];
+ if (switchMember is SwitchDefault) {
hasDefault = true;
+ // If this is the last member and there are no statements, return false
+ if (switchMember.statements.isEmpty && i + 1 == members.length) {
+ return false;
+ }
+ }
+ // For switch members with no statements, don't visit the children, otherwise, return false if
+ // no return is found in the children statements
+ if (!switchMember.statements.isEmpty && !switchMember.accept(this)) {
+ return false;
}
}
return hasDefault;
@@ -3435,6 +3421,9 @@
}
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
+ if (_unusedImports.isEmpty) {
+ return null;
+ }
// If the prefixed identifier references some A.B, where A is a library prefix, then we can
// lookup the associated ImportDirective in prefixElementMap and remove it from the
// unusedImports list.
@@ -3448,7 +3437,12 @@
return visitIdentifier(element, prefixIdentifier.name);
}
- Object visitSimpleIdentifier(SimpleIdentifier node) => visitIdentifier(node.staticElement, node.name);
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ if (_unusedImports.isEmpty) {
+ return null;
+ }
+ return visitIdentifier(node.staticElement, node.name);
+ }
void set inDefiningCompilationUnit(bool inDefiningCompilationUnit) {
this._inDefiningCompilationUnit = inDefiningCompilationUnit;
@@ -3519,6 +3513,11 @@
} else if (element is PrefixElement) {
_unusedImports.remove(_prefixElementMap[element]);
return null;
+ } else if (element.enclosingElement is! CompilationUnitElement) {
+ // Identifiers that aren't a prefix element and whose enclosing element isn't a
+ // CompilationUnit are ignored- this covers the case the identifier is a relative-reference,
+ // a reference to an identifier not imported by this library.
+ return null;
}
LibraryElement containingLibrary = element.library;
if (containingLibrary == null) {
@@ -5174,7 +5173,7 @@
SimpleIdentifier labelNode = node.label;
LabelElementImpl labelElement = lookupLabel(node, labelNode);
if (labelElement != null && labelElement.isOnSwitchMember) {
- _resolver.reportError8(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labelNode, []);
+ _resolver.reportError9(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labelNode, []);
}
return null;
}
@@ -5300,9 +5299,9 @@
FieldElement fieldElement = enclosingClass.getField(fieldName.name);
fieldName.staticElement = fieldElement;
if (fieldElement == null || fieldElement.isSynthetic) {
- _resolver.reportError8(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ _resolver.reportError9(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
} else if (fieldElement.isStatic) {
- _resolver.reportError8(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName]);
+ _resolver.reportError9(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName]);
}
return null;
}
@@ -5340,7 +5339,7 @@
SimpleIdentifier labelNode = node.label;
LabelElementImpl labelElement = lookupLabel(node, labelNode);
if (labelElement != null && labelElement.isOnSwitchStatement) {
- _resolver.reportError8(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode, []);
+ _resolver.reportError9(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode, []);
}
return null;
}
@@ -5368,7 +5367,7 @@
if (classElement != null) {
FieldElement fieldElement = classElement.getField(fieldName);
if (fieldElement == null || fieldElement.isSynthetic) {
- _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
} else {
ParameterElement parameterElement = node.element;
if (parameterElement is FieldFormalParameterElementImpl) {
@@ -5376,17 +5375,17 @@
Type2 declaredType = fieldFormal.type;
Type2 fieldType = fieldElement.type;
if (fieldElement.isSynthetic) {
- _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
} else if (fieldElement.isStatic) {
- _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
+ _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
} else if (declaredType != null && fieldType != null && !declaredType.isAssignableTo(fieldType)) {
- _resolver.reportError8(StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]);
+ _resolver.reportError9(StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]);
}
} else {
if (fieldElement.isSynthetic) {
- _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
} else if (fieldElement.isStatic) {
- _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
+ _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
}
}
}
@@ -5612,9 +5611,9 @@
return null;
}
if (identical(errorCode, StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION)) {
- _resolver.reportError8(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName, [methodName.name]);
+ _resolver.reportError9(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName, [methodName.name]);
} else if (identical(errorCode, CompileTimeErrorCode.UNDEFINED_FUNCTION)) {
- _resolver.reportError8(CompileTimeErrorCode.UNDEFINED_FUNCTION, methodName, [methodName.name]);
+ _resolver.reportError9(CompileTimeErrorCode.UNDEFINED_FUNCTION, methodName, [methodName.name]);
} else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
String targetTypeName;
if (target == null) {
@@ -5650,7 +5649,7 @@
// The error code will never be generated via type propagation
Type2 targetType = getStaticType(target);
String targetTypeName = targetType == null ? null : targetType.name;
- _resolver.reportError8(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, methodName, [methodName.name, targetTypeName]);
+ _resolver.reportError9(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, methodName, [methodName.name, targetTypeName]);
}
return null;
}
@@ -5708,13 +5707,13 @@
}
if (element == null) {
if (identifier.inSetterContext()) {
- _resolver.reportError8(StaticWarningCode.UNDEFINED_SETTER, identifier, [identifier.name, prefixElement.name]);
+ _resolver.reportError9(StaticWarningCode.UNDEFINED_SETTER, identifier, [identifier.name, prefixElement.name]);
} else if (node.parent is Annotation) {
Annotation annotation = node.parent as Annotation;
- _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
return null;
} else {
- _resolver.reportError8(StaticWarningCode.UNDEFINED_GETTER, identifier, [identifier.name, prefixElement.name]);
+ _resolver.reportError9(StaticWarningCode.UNDEFINED_GETTER, identifier, [identifier.name, prefixElement.name]);
}
return null;
}
@@ -5856,17 +5855,17 @@
Element element = resolveSimpleIdentifier(node);
ClassElement enclosingClass = _resolver.enclosingClass;
if (isFactoryConstructorReturnType(node) && element != enclosingClass) {
- _resolver.reportError8(CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node, []);
} else if (isConstructorReturnType(node) && element != enclosingClass) {
- _resolver.reportError8(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
element = null;
} else if (element == null || (element is PrefixElement && !isValidAsPrefix(node))) {
// TODO(brianwilkerson) Recover from this error.
if (isConstructorReturnType(node)) {
- _resolver.reportError8(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
} else if (node.parent is Annotation) {
Annotation annotation = node.parent as Annotation;
- _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
} else {
_resolver.reportErrorProxyConditionalAnalysisError(_resolver.enclosingClass, StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
}
@@ -5903,14 +5902,14 @@
ConstructorElement element = superType.lookUpConstructor(superName, _definingLibrary);
if (element == null) {
if (name != null) {
- _resolver.reportError8(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [superType.displayName, name]);
+ _resolver.reportError9(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [superType.displayName, name]);
} else {
- _resolver.reportError8(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, node, [superType.displayName]);
+ _resolver.reportError9(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, node, [superType.displayName]);
}
return null;
} else {
if (element.isFactory) {
- _resolver.reportError8(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]);
+ _resolver.reportError9(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]);
}
}
if (name != null) {
@@ -5927,7 +5926,7 @@
Object visitSuperExpression(SuperExpression node) {
if (!isSuperInValidContext(node)) {
- _resolver.reportError8(CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node, []);
+ _resolver.reportError9(CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node, []);
}
return super.visitSuperExpression(node);
}
@@ -6483,11 +6482,11 @@
}
} else {
if (labelScope == null) {
- _resolver.reportError8(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
+ _resolver.reportError9(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
} else {
labelElement = labelScope.lookup(labelNode) as LabelElementImpl;
if (labelElement == null) {
- _resolver.reportError8(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
+ _resolver.reportError9(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
} else {
labelNode.staticElement = labelElement;
}
@@ -6496,7 +6495,7 @@
if (labelElement != null) {
ExecutableElement labelContainer = labelElement.getAncestor(ExecutableElement);
if (labelContainer != _resolver.enclosingFunction) {
- _resolver.reportError8(CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE, labelNode, [labelNode.name]);
+ _resolver.reportError9(CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE, labelNode, [labelNode.name]);
labelElement = null;
}
}
@@ -6821,7 +6820,7 @@
}
// we need constructor
if (constructor == null) {
- _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
return;
}
// record element
@@ -6833,13 +6832,13 @@
void resolveAnnotationElementGetter(Annotation annotation, PropertyAccessorElement accessorElement) {
// accessor should be synthetic
if (!accessorElement.isSynthetic) {
- _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
return;
}
// variable should be constant
VariableElement variableElement = accessorElement.variable;
if (!variableElement.isConst) {
- _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+ _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
}
// OK
return;
@@ -6906,13 +6905,13 @@
ParameterElement element = namedParameters[name];
if (element == null) {
ErrorCode errorCode = (reportError ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER : StaticWarningCode.UNDEFINED_NAMED_PARAMETER) as ErrorCode;
- _resolver.reportError8(errorCode, nameNode, [name]);
+ _resolver.reportError9(errorCode, nameNode, [name]);
} else {
resolvedParameters[i] = element;
nameNode.staticElement = element;
}
if (!usedNames.add(name)) {
- _resolver.reportError8(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
+ _resolver.reportError9(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
}
} else {
positionalArgumentCount++;
@@ -6923,10 +6922,10 @@
}
if (positionalArgumentCount < requiredParameters.length) {
ErrorCode errorCode = (reportError ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS) as ErrorCode;
- _resolver.reportError8(errorCode, argumentList, [requiredParameters.length, positionalArgumentCount]);
+ _resolver.reportError9(errorCode, argumentList, [requiredParameters.length, positionalArgumentCount]);
} else if (positionalArgumentCount > unnamedParameterCount) {
ErrorCode errorCode = (reportError ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) as ErrorCode;
- _resolver.reportError8(errorCode, argumentList, [unnamedParameterCount, positionalArgumentCount]);
+ _resolver.reportError9(errorCode, argumentList, [unnamedParameterCount, positionalArgumentCount]);
}
return resolvedParameters;
}
@@ -7123,6 +7122,17 @@
}
}
if (shouldReportMissingMember_static || shouldReportMissingMember_propagated) {
+ if (staticType.isVoid) {
+ if (propertyName.inSetterContext()) {
+ ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_SETTER : HintCode.UNDEFINED_SETTER) as ErrorCode;
+ _resolver.reportError9(errorCode, propertyName, [propertyName.name, staticType.displayName]);
+ } else if (propertyName.inGetterContext()) {
+ ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_GETTER : HintCode.UNDEFINED_GETTER) as ErrorCode;
+ _resolver.reportError9(errorCode, propertyName, [propertyName.name, staticType.displayName]);
+ } else {
+ _resolver.reportError9(StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName, [propertyName.name]);
+ }
+ }
Element staticOrPropagatedEnclosingElt = shouldReportMissingMember_static ? staticType.element : propagatedType.element;
if (staticOrPropagatedEnclosingElt != null) {
bool isStaticProperty = isStatic(staticOrPropagatedEnclosingElt);
@@ -8098,11 +8108,6 @@
LibraryScope _libraryScope;
/**
- * An array of all top-level Angular elements that could be used in this library.
- */
- List<AngularElement> angularElements;
-
- /**
* An empty array that can be used to initialize lists of libraries.
*/
static List<Library> _EMPTY_ARRAY = new List<Library>(0);
@@ -9242,11 +9247,8 @@
try {
for (Source source in library.compilationUnitSources) {
CompilationUnit ast = library.getAST(source);
- new AngularCompilationUnitBuilder(analysisContext, _errorListener, source).build(ast);
+ new AngularCompilationUnitBuilder(_errorListener, source).build(ast);
}
- // remember accessible Angular elements
- LibraryElementImpl libraryElement = library.libraryElement;
- library.angularElements = AngularCompilationUnitBuilder.getAngularElements(libraryElement);
} finally {
timeCounter.stop();
}
@@ -11157,7 +11159,7 @@
* @param node the node specifying the location of the error
* @param arguments the arguments to the error, used to compose the error message
*/
- void reportError8(ErrorCode errorCode, ASTNode node, List<Object> arguments) {
+ void reportError9(ErrorCode errorCode, ASTNode node, List<Object> arguments) {
_errorListener.onError(new AnalysisError.con2(source, node.offset, node.length, errorCode, arguments));
}
@@ -11169,7 +11171,7 @@
* @param length the length of the location of the error
* @param arguments the arguments to the error, used to compose the error message
*/
- void reportError9(ErrorCode errorCode, int offset, int length, List<Object> arguments) {
+ void reportError10(ErrorCode errorCode, int offset, int length, List<Object> arguments) {
_errorListener.onError(new AnalysisError.con2(source, offset, length, errorCode, arguments));
}
@@ -11180,7 +11182,7 @@
* @param token the token specifying the location of the error
* @param arguments the arguments to the error, used to compose the error message
*/
- void reportError10(ErrorCode errorCode, sc.Token token, List<Object> arguments) {
+ void reportError11(ErrorCode errorCode, sc.Token token, List<Object> arguments) {
_errorListener.onError(new AnalysisError.con2(source, token.offset, token.length, errorCode, arguments));
}
@@ -12322,20 +12324,28 @@
*/
Object visitPropertyAccess(PropertyAccess node) {
SimpleIdentifier propertyName = node.propertyName;
- Element element = propertyName.staticElement;
+ Element staticElement = propertyName.staticElement;
Type2 staticType = _dynamicType;
- if (element is MethodElement) {
- staticType = element.type;
- } else if (element is PropertyAccessorElement) {
- staticType = getType(element, node.target != null ? getStaticType(node.target) : null);
+ if (staticElement is MethodElement) {
+ staticType = staticElement.type;
+ } else if (staticElement is PropertyAccessorElement) {
+ Expression realTarget = node.realTarget;
+ staticType = getType(staticElement, realTarget != null ? getStaticType(realTarget) : null);
} else {
}
recordStaticType(propertyName, staticType);
recordStaticType(node, staticType);
- // TODO(brianwilkerson) I think we want to repeat the logic above using the propagated element
- // to get another candidate for the propagated type.
- Type2 propagatedType = _overrideManager.getType(element);
+ Element propagatedElement = propertyName.propagatedElement;
+ Type2 propagatedType = _overrideManager.getType(propagatedElement);
+ if (propagatedElement is MethodElement) {
+ propagatedType = propagatedElement.type;
+ } else if (propagatedElement is PropertyAccessorElement) {
+ Expression realTarget = node.realTarget;
+ propagatedType = getType(propagatedElement, realTarget != null ? realTarget.bestType : null);
+ } else {
+ }
if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType2(propertyName, propagatedType);
recordPropagatedType2(node, propagatedType);
}
return null;
@@ -14056,10 +14066,10 @@
if (parent.parent is InstanceCreationExpression && (parent.parent as InstanceCreationExpression).isConst) {
// If, if this is a const expression, then generate a
// CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
- reportError8(CompileTimeErrorCode.CONST_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
+ reportError9(CompileTimeErrorCode.CONST_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
} else {
// Else, if this expression is a new expression, report a NEW_WITH_NON_TYPE warning.
- reportError8(StaticWarningCode.NEW_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
+ reportError9(StaticWarningCode.NEW_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
}
setElement(prefix, element);
return null;
@@ -14085,14 +14095,14 @@
InstanceCreationExpression creation = node.parent.parent as InstanceCreationExpression;
if (creation.isConst) {
if (element == null) {
- reportError8(CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
+ reportError9(CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
} else {
- reportError8(CompileTimeErrorCode.CONST_WITH_NON_TYPE, typeNameSimple, [typeName]);
+ reportError9(CompileTimeErrorCode.CONST_WITH_NON_TYPE, typeNameSimple, [typeName]);
}
elementValid = false;
} else {
if (element != null) {
- reportError8(StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
+ reportError9(StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
elementValid = false;
}
}
@@ -14105,22 +14115,22 @@
SimpleIdentifier typeNameSimple = getTypeSimpleIdentifier(typeName);
RedirectingConstructorKind redirectingConstructorKind;
if (isBuiltInIdentifier(node) && isTypeAnnotation(node)) {
- reportError8(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, typeName, [typeName.name]);
+ reportError9(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, typeName, [typeName.name]);
} else if (typeNameSimple.name == "boolean") {
- reportError8(StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
+ reportError9(StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
} else if (isTypeNameInCatchClause(node)) {
- reportError8(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
} else if (isTypeNameInAsExpression(node)) {
- reportError8(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
} else if (isTypeNameInIsExpression(node)) {
- reportError8(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
} else if ((redirectingConstructorKind = getRedirectingConstructorKind(node)) != null) {
ErrorCode errorCode = (identical(redirectingConstructorKind, RedirectingConstructorKind.CONST) ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS : StaticWarningCode.REDIRECT_TO_NON_CLASS) as ErrorCode;
- reportError8(errorCode, typeName, [typeName.name]);
+ reportError9(errorCode, typeName, [typeName.name]);
} else if (isTypeNameInTypeArgumentList(node)) {
- reportError8(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
+ reportError9(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
} else {
- reportError8(StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
}
elementValid = false;
}
@@ -14156,16 +14166,16 @@
// The name does not represent a type.
RedirectingConstructorKind redirectingConstructorKind;
if (isTypeNameInCatchClause(node)) {
- reportError8(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
} else if (isTypeNameInAsExpression(node)) {
- reportError8(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
} else if (isTypeNameInIsExpression(node)) {
- reportError8(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
} else if ((redirectingConstructorKind = getRedirectingConstructorKind(node)) != null) {
ErrorCode errorCode = (identical(redirectingConstructorKind, RedirectingConstructorKind.CONST) ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS : StaticWarningCode.REDIRECT_TO_NON_CLASS) as ErrorCode;
- reportError8(errorCode, typeName, [typeName.name]);
+ reportError9(errorCode, typeName, [typeName.name]);
} else if (isTypeNameInTypeArgumentList(node)) {
- reportError8(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
+ reportError9(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
} else {
ASTNode parent = typeName.parent;
while (parent is TypeName) {
@@ -14173,7 +14183,7 @@
}
if (parent is ExtendsClause || parent is ImplementsClause || parent is WithClause || parent is ClassTypeAlias) {
} else {
- reportError8(StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
+ reportError9(StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
}
}
setElement(typeName, this._dynamicType.element);
@@ -14195,7 +14205,7 @@
}
}
if (argumentCount != parameterCount) {
- reportError8(getInvalidTypeParametersErrorCode(node), node, [typeName.name, parameterCount, argumentCount]);
+ reportError9(getInvalidTypeParametersErrorCode(node), node, [typeName.name, parameterCount, argumentCount]);
}
argumentCount = typeArguments.length;
if (argumentCount < parameterCount) {
@@ -14593,7 +14603,7 @@
Element element2 = identifier2.staticElement;
if (element != null && element == element2) {
detectedRepeatOnIndex[j] = true;
- reportError8(CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
+ reportError9(CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
}
}
}
@@ -14618,9 +14628,9 @@
// If the type is not an InterfaceType, then visitTypeName() sets the type to be a DynamicTypeImpl
Identifier name = typeName.name;
if (name.name == sc.Keyword.DYNAMIC.syntax) {
- reportError8(dynamicTypeError, name, [name.name]);
+ reportError9(dynamicTypeError, name, [name.name]);
} else {
- reportError8(nonTypeError, name, [name.name]);
+ reportError9(nonTypeError, name, [name.name]);
}
return null;
}
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index cc29c4b..bb33c66 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -217,7 +217,7 @@
* @param offsetDelta the offset from the beginning of the file to the beginning of the source
* being scanned
*/
- SubSequenceReader(CharSequence sequence, int offsetDelta) : super(sequence) {
+ SubSequenceReader(String sequence, int offsetDelta) : super(sequence) {
this._offsetDelta = offsetDelta;
}
@@ -493,7 +493,7 @@
/**
* The sequence from which characters will be read.
*/
- CharSequence _sequence;
+ String _sequence;
/**
* The number of characters in the string.
@@ -510,9 +510,9 @@
*
* @param sequence the sequence from which characters will be read
*/
- CharSequenceReader(CharSequence sequence) {
+ CharSequenceReader(String sequence) {
this._sequence = sequence;
- this._stringLength = sequence.length();
+ this._stringLength = sequence.length;
this._charOffset = -1;
}
@@ -520,18 +520,18 @@
if (_charOffset + 1 >= _stringLength) {
return -1;
}
- return _sequence.charAt(++_charOffset);
+ return _sequence.codeUnitAt(++_charOffset);
}
int get offset => _charOffset;
- String getString(int start, int endDelta) => _sequence.subSequence(start, _charOffset + 1 + endDelta).toString();
+ String getString(int start, int endDelta) => _sequence.substring(start, _charOffset + 1 + endDelta).toString();
int peek() {
- if (_charOffset + 1 >= _sequence.length()) {
+ if (_charOffset + 1 >= _sequence.length) {
return -1;
}
- return _sequence.charAt(_charOffset + 1);
+ return _sequence.codeUnitAt(_charOffset + 1);
}
void set offset(int offset) {
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index c083950..896a15d 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -384,12 +384,12 @@
* Read all of the configuration files to initialize the library maps.
*/
void initializeLibraryMap() {
+ JavaFile librariesFile = new JavaFile.relative(new JavaFile.relative(libraryDirectory, _INTERNAL_DIR), _LIBRARIES_FILE);
try {
- JavaFile librariesFile = new JavaFile.relative(new JavaFile.relative(libraryDirectory, _INTERNAL_DIR), _LIBRARIES_FILE);
String contents = librariesFile.readAsStringSync();
_libraryMap = new SdkLibrariesReader().readFrom(librariesFile, contents);
} on JavaException catch (exception) {
- AnalysisEngine.instance.logger.logError3(exception);
+ AnalysisEngine.instance.logger.logError2("Could not initialize the library map from ${librariesFile.getAbsolutePath()}", exception);
_libraryMap = new LibraryMap();
}
}
@@ -448,7 +448,7 @@
*/
LibraryMap readFrom2(Source source, String libraryFileContents) {
BooleanErrorListener errorListener = new BooleanErrorListener();
- Scanner scanner = new Scanner(source, new CharSequenceReader(new CharSequence(libraryFileContents)), errorListener);
+ Scanner scanner = new Scanner(source, new CharSequenceReader(libraryFileContents), errorListener);
Parser parser = new Parser(source, errorListener);
CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
SdkLibrariesReader_LibraryBuilder libraryBuilder = new SdkLibrariesReader_LibraryBuilder();
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index fc9d672..af3110c 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -455,20 +455,12 @@
*/
abstract class Source_ContentReceiver {
/**
- * Accept the contents of a source represented as a character buffer.
+ * Accept the contents of a source.
*
* @param contents the contents of the source
* @param modificationTime the time at which the contents were last set
*/
- void accept(CharBuffer contents, int modificationTime);
-
- /**
- * Accept the contents of a source represented as a string.
- *
- * @param contents the contents of the source
- * @param modificationTime the time at which the contents were last set
- */
- void accept2(String contents, int modificationTime);
+ void accept(String contents, int modificationTime);
}
/**
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 0068239..ed1ae3b 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -108,7 +108,7 @@
bool operator ==(Object object) => object != null && this.runtimeType == object.runtimeType && _file == (object as FileBasedSource)._file;
- bool exists() => _contentCache.getContents(this) != null || (_file.exists() && !_file.isDirectory());
+ bool exists() => _contentCache.getContents(this) != null || _file.isFile();
void getContents(Source_ContentReceiver receiver) {
//
@@ -116,7 +116,7 @@
//
String contents = _contentCache.getContents(this);
if (contents != null) {
- receiver.accept2(contents, _contentCache.getModificationStamp(this));
+ receiver.accept(contents, _contentCache.getModificationStamp(this));
return;
}
//
@@ -179,7 +179,7 @@
void getContentsFromFile(Source_ContentReceiver receiver) {
{
}
- receiver.accept2(file.readAsStringSync(), file.lastModified());
+ receiver.accept(file.readAsStringSync(), file.lastModified());
}
/**
diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
index 1693dd6..0edd439 100644
--- a/pkg/analyzer/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
@@ -7,7 +7,6 @@
import 'dart:math';
import 'package:analyzer/analyzer.dart';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -171,7 +170,7 @@
}
Token tokenize(String source) {
- var reader = new CharSequenceReader(new CharSequence(source));
+ var reader = new CharSequenceReader(source);
var scanner = new Scanner(null, reader, this);
var token = scanner.tokenize();
lineInfo = new LineInfo(scanner.lineStarts);
@@ -363,6 +362,9 @@
/// addded to the indent level).
bool allowLineLeadingSpaces;
+ /// A flag to specify whether zero-length spaces should be emmitted.
+ bool emitEmptySpaces = false;
+
/// Used for matching EOL comments
final twoSlashes = new RegExp(r'//[^/]');
@@ -412,7 +414,9 @@
visitArgumentList(ArgumentList node) {
token(node.leftParenthesis);
+ breakableNonSpace();
visitCommaSeparatedNodes(node.arguments);
+ breakableNonSpace();
token(node.rightParenthesis);
}
@@ -453,10 +457,13 @@
visitBlock(Block node) {
token(node.leftBracket);
indent();
- visitNodes(node.statements, precededBy: newlines, separatedBy: newlines);
- unindent();
- newlines();
- token(node.rightBracket);
+ if (!node.statements.isEmpty) {
+ visitNodes(node.statements, precededBy: newlines, separatedBy: newlines);
+ newlines();
+ } else {
+ preserveLeadingNewlines();
+ }
+ token(node.rightBracket, precededBy: unindent);
}
visitBlockFunctionBody(BlockFunctionBody node) {
@@ -524,10 +531,13 @@
});
token(node.leftBracket);
indent();
- visitNodes(node.members, precededBy: newlines, separatedBy: newlines);
- unindent();
- newlines();
- token(node.rightBracket);
+ if (!node.members.isEmpty) {
+ visitNodes(node.members, precededBy: newlines, separatedBy: newlines);
+ newlines();
+ } else {
+ preserveLeadingNewlines();
+ }
+ token(node.rightBracket, precededBy: unindent);
}
visitClassTypeAlias(ClassTypeAlias node) {
@@ -622,7 +632,11 @@
}
visitConstructorInitializers(ConstructorDeclaration node) {
- newlines();
+ if (node.initializers.length > 1) {
+ newlines();
+ } else {
+ preserveLeadingNewlines();
+ }
indent(2);
token(node.separator /* : */);
space();
@@ -932,7 +946,7 @@
visitInstanceCreationExpression(InstanceCreationExpression node) {
token(node.keyword);
- space();
+ nonBreakingSpace();
visit(node.constructorName);
visit(node.argumentList);
}
@@ -994,8 +1008,7 @@
indent();
visitCommaSeparatedNodes(node.elements /*, followedBy: breakableSpace*/);
optionalTrailingComma(node.rightBracket);
- unindent();
- token(node.rightBracket);
+ token(node.rightBracket, precededBy: unindent);
}
visitMapLiteral(MapLiteral node) {
@@ -1218,8 +1231,8 @@
indent();
newlines();
visitNodes(node.members, separatedBy: newlines, followedBy: newlines);
- unindent();
- token(node.rightBracket);
+ token(node.rightBracket, precededBy: unindent);
+
}
visitSymbolLiteral(SymbolLiteral node) {
@@ -1442,8 +1455,8 @@
preserveNewlines = true;
}
- token(Token token, {precededBy(), followedBy(),
- printToken(tok), int minNewlines: 0}) {
+ token(Token token, {precededBy(), followedBy(), printToken(tok),
+ int minNewlines: 0}) {
if (token != null) {
if (needsNewline) {
minNewlines = max(1, minNewlines);
@@ -1469,12 +1482,13 @@
}
emitSpaces() {
- if (leadingSpaces > 0) {
+ if (leadingSpaces > 0 || emitEmptySpaces) {
if (allowLineLeadingSpaces || !writer.currentLine.isWhitespace()) {
writer.spaces(leadingSpaces, breakWeight: currentBreakWeight);
}
leadingSpaces = 0;
allowLineLeadingSpaces = false;
+ emitEmptySpaces = false;
currentBreakWeight = DEFAULT_SPACE_WEIGHT;
}
}
@@ -1493,6 +1507,12 @@
}
}
+ /// Emit a breakable 'non' (zero-length) space
+ breakableNonSpace() {
+ space(n: 0);
+ emitEmptySpaces = true;
+ }
+
/// Emit a non-breakable space.
nonBreakingSpace() {
space(breakWeight: UNBREAKABLE_SPACE_WEIGHT);
@@ -1512,7 +1532,7 @@
append(String string) {
if (string != null && !string.isEmpty) {
emitSpaces();
- writer.print(string);
+ writer.write(string);
}
}
@@ -1538,8 +1558,7 @@
newlines();
visit(statement);
newlines();
- unindent();
- token(CLOSE_CURLY);
+ token(CLOSE_CURLY, precededBy: unindent);
} else {
visit(statement);
}
@@ -1566,6 +1585,7 @@
lines = max(min, countNewlinesBetween(previousToken, currentToken));
preserveNewlines = false;
}
+
emitNewlines(lines);
previousToken =
diff --git a/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart b/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart
index 8e2fb90..bc1568a 100644
--- a/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart
+++ b/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart
@@ -11,7 +11,6 @@
import 'package:path/path.dart' as pathos;
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
import 'package:analyzer/src/generated/scanner.dart' show CharSequenceReader, Scanner;
import 'package:analyzer/src/generated/parser.dart' show Parser;
import 'package:analyzer/src/generated/ast.dart';
@@ -246,7 +245,7 @@
var source = null;
var errorListener = new RecordingErrorListener();
var parser = new Parser(source, errorListener);
- var reader = new CharSequenceReader(new CharSequence(code));
+ var reader = new CharSequenceReader(code);
var scanner = new Scanner(null, reader, errorListener);
var token = scanner.tokenize();
return parser.parseCompilationUnit(token);
diff --git a/pkg/analyzer/lib/src/services/writer.dart b/pkg/analyzer/lib/src/services/writer.dart
index 78b837d..08cde1f 100644
--- a/pkg/analyzer/lib/src/services/writer.dart
+++ b/pkg/analyzer/lib/src/services/writer.dart
@@ -8,16 +8,16 @@
class Line {
- final tokens = <LineToken>[];
+ final List<LineToken> tokens = <LineToken>[];
final bool useTabs;
final int spacesPerIndent;
- final int indent;
+ final int indentLevel;
final LinePrinter printer;
- Line({this.indent: 0, this.useTabs: false, this.spacesPerIndent: 2,
+ Line({this.indentLevel: 0, this.useTabs: false, this.spacesPerIndent: 2,
this.printer: const SimpleLinePrinter()}) {
- if (indent > 0) {
- _indent(indent);
+ if (indentLevel > 0) {
+ indent(indentLevel);
}
}
@@ -26,19 +26,20 @@
}
void addSpaces(int n, {breakWeight: DEFAULT_SPACE_WEIGHT}) {
- if (n > 0) {
- tokens.add(new SpaceToken(n, breakWeight: breakWeight));
- }
+ tokens.add(new SpaceToken(n, breakWeight: breakWeight));
}
void addToken(LineToken token) {
tokens.add(token);
}
+ bool isEmpty() => tokens.isEmpty;
+
bool isWhitespace() => tokens.every((tok) => tok is SpaceToken);
- void _indent(int n) {
- tokens.add(useTabs ? new TabToken(n) : new SpaceToken(n * spacesPerIndent));
+ void indent(int n) {
+ tokens.insert(0,
+ useTabs ? new TabToken(n) : new SpaceToken(n * spacesPerIndent));
}
String toString() => printer.printLine(this);
@@ -79,7 +80,7 @@
var chunks = breakLine(line);
for (var i = 0; i < chunks.length; ++i) {
if (i > 0) {
- buf.write(indent(chunks[i], line.indent));
+ buf.write(indent(chunks[i], line.indentLevel));
} else {
buf.write(chunks[i]);
}
@@ -309,7 +310,7 @@
} else {
linePrinter = new SimpleLinePrinter();
}
- currentLine = new Line(indent: indentCount, printer: linePrinter);
+ currentLine = newLine();
}
LineToken get lastToken => _lastToken;
@@ -321,6 +322,10 @@
void indent() {
++indentCount;
+ // Rather than fiddle with deletions/insertions just start fresh
+ if (currentLine.isWhitespace()) {
+ currentLine = newLine();
+ }
}
void newline() {
@@ -329,7 +334,7 @@
}
_addToken(new NewlineToken(this.lineSeparator));
buffer.write(currentLine.toString());
- currentLine = new Line(indent: indentCount, printer: linePrinter);
+ currentLine = newLine();
}
void newlines(int num) {
@@ -338,12 +343,12 @@
}
}
- void print(x) {
+ void write(x) {
_addToken(new LineToken(x));
}
- void println(String s) {
- print(s);
+ void writeln(String s) {
+ write(s);
newline();
}
@@ -357,8 +362,14 @@
void unindent() {
--indentCount;
+ // Rather than fiddle with deletions/insertions just start fresh
+ if (currentLine.isWhitespace()) {
+ currentLine = newLine();
+ }
}
+ Line newLine() => new Line(indentLevel: indentCount, printer: linePrinter);
+
String toString() {
var source = new StringBuffer(buffer.toString());
if (!currentLine.isWhitespace()) {
diff --git a/pkg/analyzer/lib/src/string_source.dart b/pkg/analyzer/lib/src/string_source.dart
index ab21809..7123bb4 100644
--- a/pkg/analyzer/lib/src/string_source.dart
+++ b/pkg/analyzer/lib/src/string_source.dart
@@ -26,7 +26,7 @@
bool exists() => true;
void getContents(Source_ContentReceiver receiver) =>
- receiver.accept2(_contents, modificationStamp);
+ receiver.accept(_contents, modificationStamp);
String get encoding => throw new UnsupportedError("StringSource doesn't support "
"encoding.");
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index d0f4cb2..fb76d5a 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.11.10
+version: 0.12.0
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 122c5a7..68e4cba 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4494,7 +4494,7 @@
//
// Scan the source.
//
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
Token tokenStream = scanner.tokenize();
//
// Parse the source.
@@ -4544,7 +4544,7 @@
//
// Scan the source.
//
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
Token tokenStream = scanner.tokenize();
//
// Parse the source.
@@ -7403,7 +7403,7 @@
*/
static CompilationUnit parseCompilationUnit(String source, List<ErrorCode> errorCodes) {
GatheringErrorListener listener = new GatheringErrorListener();
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
listener.setLineInfo(new TestSource(), scanner.lineStarts);
Token token = scanner.tokenize();
Parser parser = new Parser(null, listener);
@@ -7424,7 +7424,7 @@
*/
static Expression parseExpression(String source, List<ErrorCode> errorCodes) {
GatheringErrorListener listener = new GatheringErrorListener();
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
listener.setLineInfo(new TestSource(), scanner.lineStarts);
Token token = scanner.tokenize();
Parser parser = new Parser(null, listener);
@@ -7445,7 +7445,7 @@
*/
static Statement parseStatement(String source, List<ErrorCode> errorCodes) {
GatheringErrorListener listener = new GatheringErrorListener();
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
listener.setLineInfo(new TestSource(), scanner.lineStarts);
Token token = scanner.tokenize();
Parser parser = new Parser(null, listener);
@@ -7468,7 +7468,7 @@
*/
static List<Statement> parseStatements(String source, int expectedCount, List<ErrorCode> errorCodes) {
GatheringErrorListener listener = new GatheringErrorListener();
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
listener.setLineInfo(new TestSource(), scanner.lineStarts);
Token token = scanner.tokenize();
Parser parser = new Parser(null, listener);
@@ -7498,7 +7498,7 @@
//
// Scan the source.
//
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
Token tokenStream = scanner.tokenize();
listener.setLineInfo(new TestSource(), scanner.lineStarts);
//
@@ -9431,7 +9431,7 @@
// Parse the original contents.
//
GatheringErrorListener originalListener = new GatheringErrorListener();
- Scanner originalScanner = new Scanner(source, new CharSequenceReader(new CharSequence(originalContents)), originalListener);
+ Scanner originalScanner = new Scanner(source, new CharSequenceReader(originalContents), originalListener);
Token originalTokens = originalScanner.tokenize();
JUnitTestCase.assertNotNull(originalTokens);
Parser originalParser = new Parser(source, originalListener);
@@ -9441,7 +9441,7 @@
// Parse the modified contents.
//
GatheringErrorListener modifiedListener = new GatheringErrorListener();
- Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), modifiedListener);
+ Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(modifiedContents), modifiedListener);
Token modifiedTokens = modifiedScanner.tokenize();
JUnitTestCase.assertNotNull(modifiedTokens);
Parser modifiedParser = new Parser(source, modifiedListener);
@@ -9451,7 +9451,7 @@
// Incrementally parse the modified contents.
//
GatheringErrorListener incrementalListener = new GatheringErrorListener();
- IncrementalScanner incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), incrementalListener);
+ IncrementalScanner incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(modifiedContents), incrementalListener);
Token incrementalTokens = incrementalScanner.rescan(originalTokens, replaceStart, removed.length, added.length);
JUnitTestCase.assertNotNull(incrementalTokens);
IncrementalParser incrementalParser = new IncrementalParser(source, incrementalScanner.tokenMap, incrementalListener);
@@ -11645,7 +11645,7 @@
'parseCompilationUnit_0': new MethodTrampoline(0, (Parser target) => target.parseCompilationUnit2()),
'parseConditionalExpression_0': new MethodTrampoline(0, (Parser target) => target.parseConditionalExpression()),
'parseConstructorName_0': new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
- 'parseExpression_0': new MethodTrampoline(0, (Parser target) => target.parseExpression4()),
+ 'parseExpression_0': new MethodTrampoline(0, (Parser target) => target.parseExpression2()),
'parseExpressionWithoutCascade_0': new MethodTrampoline(0, (Parser target) => target.parseExpressionWithoutCascade()),
'parseExtendsClause_0': new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()),
'parseFormalParameterList_0': new MethodTrampoline(0, (Parser target) => target.parseFormalParameterList()),
@@ -11782,8 +11782,8 @@
'peek_0': new MethodTrampoline(0, (Parser target) => target.peek()),
'peek_1': new MethodTrampoline(1, (Parser target, arg0) => target.peek2(arg0)),
'reportError_1': new MethodTrampoline(1, (Parser target, arg0) => target.reportError(arg0)),
- 'reportError_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target.reportError11(arg0, arg1, arg2)),
- 'reportError_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.reportError12(arg0, arg1)),
+ 'reportError_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target.reportError12(arg0, arg1, arg2)),
+ 'reportError_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.reportError13(arg0, arg1)),
'skipBlock_0': new MethodTrampoline(0, (Parser target) => target.skipBlock()),
'skipFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFinalConstVarOrType(arg0)),
'skipFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFormalParameterList(arg0)),
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 065a1ac..878187a 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -6798,6 +6798,16 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
}
+ void test_undefinedGetter_void() {
+ Source source = addSource(EngineTestCase.createSource([
+ "class T {",
+ " void m() {}",
+ "}",
+ "f(T e) { return e.m().f; }"]));
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
+ }
+
void test_undefinedMethod() {
Source source = addSource(EngineTestCase.createSource(["class A {", " void m() {", " n();", " }", "}"]));
resolve(source);
@@ -6894,6 +6904,16 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
}
+ void test_undefinedSetter_void() {
+ Source source = addSource(EngineTestCase.createSource([
+ "class T {",
+ " void m() {}",
+ "}",
+ "f(T e) { e.m().f = 0; }"]));
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
+ }
+
void test_undefinedSuperMethod() {
Source source = addSource(EngineTestCase.createSource([
"class A {}",
@@ -7317,6 +7337,10 @@
final __test = new StaticTypeWarningCodeTest();
runJUnitTest(__test, __test.test_undefinedGetter_static);
});
+ _ut.test('test_undefinedGetter_void', () {
+ final __test = new StaticTypeWarningCodeTest();
+ runJUnitTest(__test, __test.test_undefinedGetter_void);
+ });
_ut.test('test_undefinedMethod', () {
final __test = new StaticTypeWarningCodeTest();
runJUnitTest(__test, __test.test_undefinedMethod);
@@ -7365,6 +7389,10 @@
final __test = new StaticTypeWarningCodeTest();
runJUnitTest(__test, __test.test_undefinedSetter_static);
});
+ _ut.test('test_undefinedSetter_void', () {
+ final __test = new StaticTypeWarningCodeTest();
+ runJUnitTest(__test, __test.test_undefinedSetter_void);
+ });
_ut.test('test_undefinedSuperMethod', () {
final __test = new StaticTypeWarningCodeTest();
runJUnitTest(__test, __test.test_undefinedSuperMethod);
@@ -7416,20 +7444,6 @@
verify([source]);
}
- void fail_missingReturn_function() {
- Source source = addSource(EngineTestCase.createSource(["int f() {}"]));
- resolve(source);
- assertErrors(source, [HintCode.MISSING_RETURN]);
- verify([source]);
- }
-
- void fail_missingReturn_method() {
- Source source = addSource(EngineTestCase.createSource(["class A {", " int m() {}", "}"]));
- resolve(source);
- assertErrors(source, [HintCode.MISSING_RETURN]);
- verify([source]);
- }
-
void fail_overriddingPrivateMember_getter() {
Source source = addSource(EngineTestCase.createSource([
"import 'lib1.dart';",
@@ -7989,6 +8003,20 @@
verify([source]);
}
+ void test_missingReturn_function() {
+ Source source = addSource(EngineTestCase.createSource(["int f() {}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.MISSING_RETURN]);
+ verify([source]);
+ }
+
+ void test_missingReturn_method() {
+ Source source = addSource(EngineTestCase.createSource(["class A {", " int m() {}", "}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.MISSING_RETURN]);
+ verify([source]);
+ }
+
void test_typeCheck_type_is_Null() {
Source source = addSource(EngineTestCase.createSource(["m(i) {", " bool b = i is Null;", "}"]));
resolve(source);
@@ -8235,6 +8263,86 @@
verify([source, source2]);
}
+ void test_useOfVoidResult_assignmentExpression_function() {
+ Source source = addSource(EngineTestCase.createSource([
+ "void f() {}",
+ "class A {",
+ " n() {",
+ " var a;",
+ " a = f();",
+ " }",
+ "}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_assignmentExpression_method() {
+ Source source = addSource(EngineTestCase.createSource([
+ "class A {",
+ " void m() {}",
+ " n() {",
+ " var a;",
+ " a = m();",
+ " }",
+ "}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_inForLoop() {
+ Source source = addSource(EngineTestCase.createSource([
+ "class A {",
+ " void m() {}",
+ " n() {",
+ " for(var a = m();;) {}",
+ " }",
+ "}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_variableDeclaration_function() {
+ Source source = addSource(EngineTestCase.createSource([
+ "void f() {}",
+ "class A {",
+ " n() {",
+ " var a = f();",
+ " }",
+ "}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_variableDeclaration_method() {
+ Source source = addSource(EngineTestCase.createSource([
+ "class A {",
+ " void m() {}",
+ " n() {",
+ " var a = m();",
+ " }",
+ "}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_variableDeclaration_method2() {
+ Source source = addSource(EngineTestCase.createSource([
+ "class A {",
+ " void m() {}",
+ " n() {",
+ " var a = m(), b = m();",
+ " }",
+ "}"]));
+ resolve(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT, HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
static dartSuite() {
_ut.group('HintCodeTest', () {
_ut.test('test_deadCode_deadBlock_conditionalElse', () {
@@ -8425,6 +8533,14 @@
final __test = new HintCodeTest();
runJUnitTest(__test, __test.test_isNotDouble);
});
+ _ut.test('test_missingReturn_function', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_missingReturn_function);
+ });
+ _ut.test('test_missingReturn_method', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_missingReturn_method);
+ });
_ut.test('test_typeCheck_type_is_Null', () {
final __test = new HintCodeTest();
runJUnitTest(__test, __test.test_typeCheck_type_is_Null);
@@ -8529,6 +8645,30 @@
final __test = new HintCodeTest();
runJUnitTest(__test, __test.test_unusedImport_show);
});
+ _ut.test('test_useOfVoidResult_assignmentExpression_function', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_assignmentExpression_function);
+ });
+ _ut.test('test_useOfVoidResult_assignmentExpression_method', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_assignmentExpression_method);
+ });
+ _ut.test('test_useOfVoidResult_inForLoop', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_inForLoop);
+ });
+ _ut.test('test_useOfVoidResult_variableDeclaration_function', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_variableDeclaration_function);
+ });
+ _ut.test('test_useOfVoidResult_variableDeclaration_method', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_variableDeclaration_method);
+ });
+ _ut.test('test_useOfVoidResult_variableDeclaration_method2', () {
+ final __test = new HintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_variableDeclaration_method2);
+ });
});
}
}
@@ -21694,6 +21834,26 @@
verify([source]);
}
+ void test_useOfVoidResult_implicitReturnValue() {
+ Source source = addSource(EngineTestCase.createSource([
+ "f() {}",
+ "class A {",
+ " n() {",
+ " var a = f();",
+ " }",
+ "}"]));
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_nonVoidReturnValue() {
+ Source source = addSource(EngineTestCase.createSource(["int f() => 1;", "g() {", " var a = f();", "}"]));
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
static dartSuite() {
_ut.group('NonHintCodeTest', () {
_ut.test('test_deadCode_deadBlock_conditionalElse_debugConst', () {
@@ -21876,6 +22036,14 @@
final __test = new NonHintCodeTest();
runJUnitTest(__test, __test.test_unusedImport_prefix_topLevelFunction);
});
+ _ut.test('test_useOfVoidResult_implicitReturnValue', () {
+ final __test = new NonHintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_implicitReturnValue);
+ });
+ _ut.test('test_useOfVoidResult_nonVoidReturnValue', () {
+ final __test = new NonHintCodeTest();
+ runJUnitTest(__test, __test.test_useOfVoidResult_nonVoidReturnValue);
+ });
});
}
}
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index 4923566..6413ba9 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -70,18 +70,18 @@
class CharSequenceReaderTest extends JUnitTestCase {
void test_advance() {
- CharSequenceReader reader = new CharSequenceReader(new CharSequence("x"));
+ CharSequenceReader reader = new CharSequenceReader("x");
JUnitTestCase.assertEquals(0x78, reader.advance());
JUnitTestCase.assertEquals(-1, reader.advance());
JUnitTestCase.assertEquals(-1, reader.advance());
}
void test_creation() {
- JUnitTestCase.assertNotNull(new CharSequenceReader(new CharSequence("x")));
+ JUnitTestCase.assertNotNull(new CharSequenceReader("x"));
}
void test_getOffset() {
- CharSequenceReader reader = new CharSequenceReader(new CharSequence("x"));
+ CharSequenceReader reader = new CharSequenceReader("x");
JUnitTestCase.assertEquals(-1, reader.offset);
reader.advance();
JUnitTestCase.assertEquals(0, reader.offset);
@@ -90,14 +90,14 @@
}
void test_getString() {
- CharSequenceReader reader = new CharSequenceReader(new CharSequence("xyzzy"));
+ CharSequenceReader reader = new CharSequenceReader("xyzzy");
reader.offset = 3;
JUnitTestCase.assertEquals("yzz", reader.getString(1, 0));
JUnitTestCase.assertEquals("zzy", reader.getString(2, 1));
}
void test_peek() {
- CharSequenceReader reader = new CharSequenceReader(new CharSequence("xy"));
+ CharSequenceReader reader = new CharSequenceReader("xy");
JUnitTestCase.assertEquals(0x78, reader.peek());
JUnitTestCase.assertEquals(0x78, reader.peek());
reader.advance();
@@ -109,7 +109,7 @@
}
void test_setOffset() {
- CharSequenceReader reader = new CharSequenceReader(new CharSequence("xyz"));
+ CharSequenceReader reader = new CharSequenceReader("xyz");
reader.offset = 2;
JUnitTestCase.assertEquals(2, reader.offset);
}
@@ -375,7 +375,7 @@
}
void test_comment_disabled_multi() {
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence("/* comment */ ")), AnalysisErrorListener.NULL_LISTENER);
+ Scanner scanner = new Scanner(null, new CharSequenceReader("/* comment */ "), AnalysisErrorListener.NULL_LISTENER);
scanner.preserveComments = false;
Token token = scanner.tokenize();
JUnitTestCase.assertNotNull(token);
@@ -838,7 +838,7 @@
void test_setSourceStart() {
int offsetDelta = 42;
GatheringErrorListener listener = new GatheringErrorListener();
- Scanner scanner = new Scanner(null, new SubSequenceReader(new CharSequence("a"), offsetDelta), listener);
+ Scanner scanner = new Scanner(null, new SubSequenceReader("a", offsetDelta), listener);
scanner.setSourceStart(3, 9);
scanner.tokenize();
List<int> lineStarts = scanner.lineStarts;
@@ -1211,7 +1211,7 @@
}
Token scan2(String source, GatheringErrorListener listener) {
- Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+ Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
Token result = scanner.tokenize();
listener.setLineInfo(new TestSource(), scanner.lineStarts);
return result;
@@ -2250,21 +2250,21 @@
// Scan the original contents.
//
GatheringErrorListener originalListener = new GatheringErrorListener();
- Scanner originalScanner = new Scanner(source, new CharSequenceReader(new CharSequence(originalContents)), originalListener);
+ Scanner originalScanner = new Scanner(source, new CharSequenceReader(originalContents), originalListener);
_originalTokens = originalScanner.tokenize();
JUnitTestCase.assertNotNull(_originalTokens);
//
// Scan the modified contents.
//
GatheringErrorListener modifiedListener = new GatheringErrorListener();
- Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), modifiedListener);
+ Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(modifiedContents), modifiedListener);
Token modifiedTokens = modifiedScanner.tokenize();
JUnitTestCase.assertNotNull(modifiedTokens);
//
// Incrementally scan the modified contents.
//
GatheringErrorListener incrementalListener = new GatheringErrorListener();
- _incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), incrementalListener);
+ _incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(modifiedContents), incrementalListener);
_incrementalTokens = _incrementalScanner.rescan(_originalTokens, replaceStart, removed.length, added.length);
//
// Validate that the results of the incremental scan are the same as the full scan of the
diff --git a/pkg/analyzer/test/services/data/cu_tests.data b/pkg/analyzer/test/services/data/cu_tests.data
index 9091620..65b6c42 100644
--- a/pkg/analyzer/test/services/data/cu_tests.data
+++ b/pkg/analyzer/test/services/data/cu_tests.data
@@ -200,4 +200,50 @@
List<double> tangentImpulses = new List<double>(Settings.MAX_MANIFOLD_POINTS);
ContactImpulse();
+}
+>>> Empty class bodies may be on one line (or more)
+class A extends B { }
+<<<
+class A extends B {}
+>>>
+class A extends B {
+
+}
+<<<
+class A extends B {
+
+}
+>>> Single initializers can be on one line
+class Foo extends Bar {
+ final int b;
+ Foo(int a, this.b): super(a);
+}
+<<<
+class Foo extends Bar {
+ final int b;
+ Foo(int a, this.b): super(a);
+}
+>>> (or not)
+class Foo extends Bar {
+ final int b;
+ Foo(int a, this.b)
+ : super(a);
+}
+<<<
+class Foo extends Bar {
+ final int b;
+ Foo(int a, this.b)
+ : super(a);
+}
+>>> Multiple initializers are one per line
+class Foo extends Bar {
+ final int b;
+ Foo(int a, int b) : super(a), this.b = b == null ? 0 : b;
+}
+<<<
+class Foo extends Bar {
+ final int b;
+ Foo(int a, int b)
+ : super(a),
+ this.b = b == null ? 0 : b;
}
\ No newline at end of file
diff --git a/pkg/analyzer/test/services/data/stmt_tests.data b/pkg/analyzer/test/services/data/stmt_tests.data
index 7557479..c50f2aa 100644
--- a/pkg/analyzer/test/services/data/stmt_tests.data
+++ b/pkg/analyzer/test/services/data/stmt_tests.data
@@ -44,7 +44,8 @@
}
<<<<
blah() {
- print('blah blah blah blah blah blah blah blah blah blah blah blah blah blah $foo');
+ print(
+ 'blah blah blah blah blah blah blah blah blah blah blah blah blah blah $foo');
}
>>>
assert(false);
@@ -98,3 +99,37 @@
break;
}
}
+>>> dartbug.com/16383
+main() {
+ //foo
+}
+<<<
+main() {
+ //foo
+}
+>>> dartbug.com/16379
+var x = new XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX();
+<<<
+var x =
+ new XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX();
+>>>
+main() {
+ throw new FormatException("This is a long exception message that puts this over 80 columns.");
+}
+<<<
+main() {
+ throw new FormatException(
+ "This is a long exception message that puts this over 80 columns.");
+}
+>>> Empty method bodies may be on a single line (or more)
+void main() { }
+<<<
+void main() {}
+>>>
+void main() {
+
+}
+<<<
+void main() {
+
+}
diff --git a/pkg/analyzer/test/services/data/style_guide_tests.data b/pkg/analyzer/test/services/data/style_guide_tests.data
index d0b49ef..781516d 100644
--- a/pkg/analyzer/test/services/data/style_guide_tests.data
+++ b/pkg/analyzer/test/services/data/style_guide_tests.data
@@ -164,8 +164,7 @@
}
<<<
getEmptyFn(a) {
- return () {
- };
+ return () {};
}
>>> DO format constructor initialization lists with each field on its own line.
class MyClass {
diff --git a/pkg/analyzer/test/services/formatter_test.dart b/pkg/analyzer/test/services/formatter_test.dart
index 7703a68..f3557d7 100644
--- a/pkg/analyzer/test/services/formatter_test.dart
+++ b/pkg/analyzer/test/services/formatter_test.dart
@@ -7,7 +7,6 @@
import 'package:path/path.dart';
import 'package:unittest/unittest.dart';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/services/formatter_impl.dart';
import 'package:analyzer/src/services/writer.dart';
@@ -189,8 +188,7 @@
expectCUFormatsTo(
'library a; class B { }',
'library a;\n'
- 'class B {\n'
- '}\n'
+ 'class B {}\n'
);
});
@@ -655,20 +653,6 @@
);
});
- test('CU - constructor initializers', () {
- expectCUFormatsTo(
- 'class A {\n'
- ' int _a;\n'
- ' A(a) : _a = a;\n'
- '}\n',
- 'class A {\n'
- ' int _a;\n'
- ' A(a)\n'
- ' : _a = a;\n'
- '}\n'
- );
- });
-
test('CU - constructor auto field inits', () {
expectCUFormatsTo(
'class A {\n'
@@ -953,8 +937,7 @@
'abstract\n'
'class\n'
'A{}',
- 'abstract class A {\n'
- '}\n'
+ 'abstract class A {}\n'
);
});
@@ -1143,18 +1126,18 @@
group('line', () {
test('space', () {
- var line = new Line(indent: 0);
+ var line = new Line(indentLevel: 0);
line.addSpaces(2);
expect(line.toString(), equals(' '));
});
test('initial indent', () {
- var line = new Line(indent: 2);
+ var line = new Line(indentLevel: 2);
expect(line.toString(), equals(' '));
});
test('initial indent (tabbed)', () {
- var line = new Line(indent:1, useTabs: true);
+ var line = new Line(indentLevel:1, useTabs: true);
expect(line.toString(), equals('\t'));
});
@@ -1165,13 +1148,13 @@
});
test('addToken (2)', () {
- var line = new Line(indent: 1);
+ var line = new Line(indentLevel: 1);
line.addToken(new LineToken('foo'));
expect(line.toString(), equals(' foo'));
});
test('isWhitespace', () {
- var line = new Line(indent: 1);
+ var line = new Line(indentLevel: 1);
expect(line.isWhitespace(), isTrue);
});
@@ -1182,15 +1165,15 @@
test('basic print', () {
var writer = new SourceWriter();
- writer.print('foo');
- writer.print(' ');
- writer.print('bar');
+ writer.write('foo');
+ writer.write(' ');
+ writer.write('bar');
expect(writer.toString(), equals('foo bar'));
});
test('newline', () {
var writer = new SourceWriter();
- writer.print('foo');
+ writer.write('foo');
writer.newline();
expect(writer.toString(), equals('foo\n'));
});
@@ -1203,13 +1186,13 @@
test('basic print (with indents)', () {
var writer = new SourceWriter();
- writer.print('foo');
+ writer.write('foo');
writer.indent();
writer.newline();
- writer.print('bar');
+ writer.write('bar');
writer.unindent();
writer.newline();
- writer.print('baz');
+ writer.write('baz');
expect(writer.toString(), equals('foo\n bar\nbaz'));
});
@@ -1400,7 +1383,7 @@
new CodeFormatter(options).format(CodeKind.STATEMENT, src).source;
Token tokenize(String str) {
- var reader = new CharSequenceReader(new CharSequence(str));
+ var reader = new CharSequenceReader(str);
return new Scanner(null, reader, null).tokenize();
}
diff --git a/pkg/analyzer/test/services/test_utils.dart b/pkg/analyzer/test/services/test_utils.dart
index 65960a1..2a95fb3 100644
--- a/pkg/analyzer/test/services/test_utils.dart
+++ b/pkg/analyzer/test/services/test_utils.dart
@@ -6,7 +6,6 @@
import 'package:unittest/unittest.dart';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext, AnalysisContextImpl;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -198,7 +197,7 @@
Statement parseStatement(String source, [List<ErrorCode> expectedErrorCodes]) {
var listener = new _GatheringErrorListener();
- var reader = new CharSequenceReader(new CharSequence(source));
+ var reader = new CharSequenceReader(source);
var scanner = new Scanner(null, reader, listener);
listener.setLineInfo(new _TestSource(), scanner.lineStarts);
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index 3454899..af0b90c 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -117,7 +117,7 @@
/// It loads source assets within [package] using [provider].
AssetCascade(this.graph, this.package) {
_onDirtyPool.add(_onDirtyController.stream);
- _addPhase(new Phase(this, []));
+ _addPhase(new Phase(this, [], package));
// Keep track of logged errors so we can know that the build failed.
onLog.listen((entry) {
@@ -308,4 +308,6 @@
return future.then((_) => _process());
});
}
+
+ String toString() => "cascade for $package";
}
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index a1af547..7ea442a 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -137,6 +137,8 @@
: id = asset.id,
_asset = asset,
_state = AssetState.AVAILABLE;
+
+ String toString() => "$state asset $id";
}
/// The controller for an [AssetNode].
@@ -199,6 +201,8 @@
node._asset = asset;
node._stateChangeController.add(AssetState.AVAILABLE);
}
+
+ String toString() => "controller for $node";
}
// TODO(nweiz): add an error state.
diff --git a/pkg/barback/lib/src/asset_set.dart b/pkg/barback/lib/src/asset_set.dart
index 08c2db9..b17db97 100644
--- a/pkg/barback/lib/src/asset_set.dart
+++ b/pkg/barback/lib/src/asset_set.dart
@@ -68,4 +68,6 @@
void clear() {
_assets.clear();
}
+
+ String toString() => _assets.toString();
}
diff --git a/pkg/barback/lib/src/group_runner.dart b/pkg/barback/lib/src/group_runner.dart
index 4718d18..d276796 100644
--- a/pkg/barback/lib/src/group_runner.dart
+++ b/pkg/barback/lib/src/group_runner.dart
@@ -13,10 +13,16 @@
import 'stream_pool.dart';
import 'transformer_group.dart';
-/// A class that process all of the phases in a single transformer group.
+/// A class that processes all of the phases in a single transformer group.
///
/// A group takes many inputs, processes them, and emits many outputs.
class GroupRunner {
+ /// The group this runner runs.
+ final TransformerGroup _group;
+
+ /// A string describing the location of [this] in the transformer graph.
+ final String _location;
+
/// The phases defined by this group.
final _phases = new List<Phase>();
@@ -46,10 +52,10 @@
/// ensure that it does so.
final _alreadyEmittedOutputs = new Set<AssetNode>();
- GroupRunner(AssetCascade cascade, TransformerGroup group) {
- var lastPhase = new Phase(cascade, group.phases.first);
+ GroupRunner(AssetCascade cascade, this._group, this._location) {
+ var lastPhase = new Phase(cascade, _group.phases.first, _location);
_phases.add(lastPhase);
- for (var phase in group.phases.skip(1)) {
+ for (var phase in _group.phases.skip(1)) {
lastPhase = lastPhase.addPhase(phase);
_phases.add(lastPhase);
}
@@ -91,4 +97,6 @@
return new Future.value(newOutputs);
}
+
+ String toString() => "group in phase $_location for $_group";
}
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index 2136a12..aa570bf 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -36,6 +36,12 @@
/// The cascade that owns this phase.
final AssetCascade cascade;
+ /// A string describing the location of [this] in the transformer graph.
+ final String _location;
+
+ /// The index of [this] in its parent cascade or group.
+ final int _index;
+
/// The transformers that can access [inputs].
///
/// Their outputs will be available to the next phase.
@@ -111,12 +117,15 @@
// TODO(nweiz): Rather than passing the cascade and the phase everywhere,
// create an interface that just exposes [getInput]. Emit errors via
// [AssetNode]s.
- Phase(this.cascade, Iterable transformers)
+ Phase(AssetCascade cascade, Iterable transformers, String location)
+ : this._(cascade, transformers, location, 0);
+
+ Phase._(this.cascade, Iterable transformers, this._location, this._index)
: _transformers = transformers.where((op) => op is Transformer).toSet() {
_onDirtyPool.add(_onDirtyController.stream);
for (var group in transformers.where((op) => op is TransformerGroup)) {
- var runner = new GroupRunner(cascade, group);
+ var runner = new GroupRunner(cascade, group, "$_location.$_index");
_groups[group] = runner;
_onDirtyPool.add(runner.onDirty);
_onLogPool.add(runner.onLog);
@@ -148,7 +157,7 @@
});
_inputOrigins.add(node.origin);
- var input = new PhaseInput(this, node, _transformers);
+ var input = new PhaseInput(this, node, _transformers, "$_location.$_index");
_inputs[node.id] = input;
input.input.whenRemoved(() {
_inputOrigins.remove(node.origin);
@@ -205,7 +214,7 @@
}
for (var added in newGroups.difference(oldGroups)) {
- var runner = new GroupRunner(cascade, added);
+ var runner = new GroupRunner(cascade, added, "$_location.$_index");
_groups[added] = runner;
_onDirtyPool.add(runner.onDirty);
_onLogPool.add(runner.onLog);
@@ -224,7 +233,7 @@
/// This may only be called on a phase with no phase following it.
Phase addPhase(Iterable transformers) {
assert(_next == null);
- _next = new Phase(cascade, transformers);
+ _next = new Phase._(cascade, transformers, _location, _index + 1);
for (var output in _outputs.values.toList()) {
// Remove [output]'s listeners because now they should get the asset from
// [_next], rather than this phase. Any transforms consuming [output] will
@@ -305,11 +314,13 @@
if (_outputs.containsKey(asset.id)) {
_outputs[asset.id].add(asset);
} else {
- _outputs[asset.id] = new PhaseOutput(this, asset);
+ _outputs[asset.id] = new PhaseOutput(this, asset, "$_location.$_index");
_outputs[asset.id].onAsset.listen((output) {
if (_next != null) _next.addInput(output);
}, onDone: () => _outputs.remove(asset.id));
if (_next != null) _next.addInput(_outputs[asset.id].output);
}
}
+
+ String toString() => "phase $_location.$_index";
}
diff --git a/pkg/barback/lib/src/phase_input.dart b/pkg/barback/lib/src/phase_input.dart
index 13bc700..4937467 100644
--- a/pkg/barback/lib/src/phase_input.dart
+++ b/pkg/barback/lib/src/phase_input.dart
@@ -24,6 +24,9 @@
/// The phase for which this is an input.
final Phase _phase;
+ /// A string describing the location of [this] in the transformer graph.
+ final String _location;
+
/// The transformers to (potentially) run against [input].
final Set<Transformer> _transformers;
@@ -84,7 +87,8 @@
Stream<LogEntry> get onLog => _onLogPool.stream;
final _onLogPool = new StreamPool<LogEntry>.broadcast();
- PhaseInput(this._phase, AssetNode input, Iterable<Transformer> transformers)
+ PhaseInput(this._phase, AssetNode input, Iterable<Transformer> transformers,
+ this._location)
: _transformers = transformers.toSet(),
_inputForwarder = new AssetForwarder(input) {
_onDirtyPool.add(_onDirtyController.stream);
@@ -228,7 +232,8 @@
// results.
return transformer.isPrimary(input.asset).then((isPrimary) {
if (!isPrimary) return;
- var transform = new TransformNode(_phase, transformer, input);
+ var transform = new TransformNode(
+ _phase, transformer, input, _location);
_transforms.add(transform);
_onDirtyPool.add(transform.onDirty);
_onLogPool.add(transform.onLog);
@@ -312,4 +317,6 @@
return transform.apply();
})).then((outputs) => unionAll(outputs));
}
+
+ String toString() => "phase input in $_location for $input";
}
diff --git a/pkg/barback/lib/src/phase_output.dart b/pkg/barback/lib/src/phase_output.dart
index 17a613f..50d39c3 100644
--- a/pkg/barback/lib/src/phase_output.dart
+++ b/pkg/barback/lib/src/phase_output.dart
@@ -28,6 +28,9 @@
/// The phase for which this is an output.
final Phase _phase;
+ /// A string describing the location of [this] in the transformer graph.
+ final String _location;
+
/// The asset node for this output.
AssetNode get output => _outputForwarder.node;
AssetForwarder _outputForwarder;
@@ -53,7 +56,7 @@
output.id);
}
- PhaseOutput(this._phase, AssetNode output)
+ PhaseOutput(this._phase, AssetNode output, this._location)
: _outputForwarder = new AssetForwarder(output) {
assert(!output.state.isRemoved);
add(output);
@@ -109,4 +112,6 @@
}
});
}
+
+ String toString() => "phase output in $_location for $output";
}
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
index 76b29bd..8a79b6c 100644
--- a/pkg/barback/lib/src/transform_node.dart
+++ b/pkg/barback/lib/src/transform_node.dart
@@ -33,6 +33,9 @@
/// The node for the primary asset this transform depends on.
final AssetNode primary;
+ /// A string describing the location of [this] in the transformer graph.
+ final String _location;
+
/// The subscription to [primary]'s [AssetNode.onStateChange] stream.
StreamSubscription _primarySubscription;
@@ -64,7 +67,7 @@
Stream<LogEntry> get onLog => _onLogController.stream;
final _onLogController = new StreamController<LogEntry>.broadcast(sync: true);
- TransformNode(this.phase, this.transformer, this.primary) {
+ TransformNode(this.phase, this.transformer, this.primary, this._location) {
_primarySubscription = primary.onStateChange.listen((state) {
if (state.isRemoved) {
remove();
@@ -219,4 +222,7 @@
var entry = new LogEntry(info, asset, level, message, span);
_onLogController.add(entry);
}
+
+ String toString() =>
+ "transform node in $_location for $transformer on $primary";
}
diff --git a/pkg/barback/lib/src/transformer_group.dart b/pkg/barback/lib/src/transformer_group.dart
index 49359c9..58ffd2a 100644
--- a/pkg/barback/lib/src/transformer_group.dart
+++ b/pkg/barback/lib/src/transformer_group.dart
@@ -25,4 +25,6 @@
TransformerGroup(Iterable<Iterable> phases)
: this.phases = phases.map((phase) => phase.toList()).toList();
+
+ String toString() => "group of $phases";
}
diff --git a/pkg/custom_element/REVISION b/pkg/custom_element/REVISION
new file mode 100644
index 0000000..309f953
--- /dev/null
+++ b/pkg/custom_element/REVISION
@@ -0,0 +1,4 @@
+sources are from:
+
+https://github.com/Polymer/MutationObservers/commit/a8aa7f9cc35c3ebef152be42f87ec2677a87f55e
+https://github.com/dart-lang/CustomElements/commit/44178138302584392ab51515e2959d8ab925b155
diff --git a/pkg/custom_element/lib/custom-elements.debug.js b/pkg/custom_element/lib/custom-elements.debug.js
index fe98775..e3c53e0 100644
--- a/pkg/custom_element/lib/custom-elements.debug.js
+++ b/pkg/custom_element/lib/custom-elements.debug.js
@@ -56,6 +56,547 @@
})();
}
+(function(global) {
+
+ var registrationsTable = new WeakMap();
+
+ // We use setImmediate or postMessage for our future callback.
+ var setImmediate = window.msSetImmediate;
+
+ // Use post message to emulate setImmediate.
+ if (!setImmediate) {
+ var setImmediateQueue = [];
+ var sentinel = String(Math.random());
+ window.addEventListener('message', function(e) {
+ if (e.data === sentinel) {
+ var queue = setImmediateQueue;
+ setImmediateQueue = [];
+ queue.forEach(function(func) {
+ func();
+ });
+ }
+ });
+ setImmediate = function(func) {
+ setImmediateQueue.push(func);
+ window.postMessage(sentinel, '*');
+ };
+ }
+
+ // This is used to ensure that we never schedule 2 callas to setImmediate
+ var isScheduled = false;
+
+ // Keep track of observers that needs to be notified next time.
+ var scheduledObservers = [];
+
+ /**
+ * Schedules |dispatchCallback| to be called in the future.
+ * @param {MutationObserver} observer
+ */
+ function scheduleCallback(observer) {
+ scheduledObservers.push(observer);
+ if (!isScheduled) {
+ isScheduled = true;
+ setImmediate(dispatchCallbacks);
+ }
+ }
+
+ function wrapIfNeeded(node) {
+ return window.ShadowDOMPolyfill &&
+ window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
+ node;
+ }
+
+ function dispatchCallbacks() {
+ // http://dom.spec.whatwg.org/#mutation-observers
+
+ isScheduled = false; // Used to allow a new setImmediate call above.
+
+ var observers = scheduledObservers;
+ scheduledObservers = [];
+ // Sort observers based on their creation UID (incremental).
+ observers.sort(function(o1, o2) {
+ return o1.uid_ - o2.uid_;
+ });
+
+ var anyNonEmpty = false;
+ observers.forEach(function(observer) {
+
+ // 2.1, 2.2
+ var queue = observer.takeRecords();
+ // 2.3. Remove all transient registered observers whose observer is mo.
+ removeTransientObserversFor(observer);
+
+ // 2.4
+ if (queue.length) {
+ observer.callback_(queue, observer);
+ anyNonEmpty = true;
+ }
+ });
+
+ // 3.
+ if (anyNonEmpty)
+ dispatchCallbacks();
+ }
+
+ function removeTransientObserversFor(observer) {
+ observer.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ if (!registrations)
+ return;
+ registrations.forEach(function(registration) {
+ if (registration.observer === observer)
+ registration.removeTransientObservers();
+ });
+ });
+ }
+
+ /**
+ * This function is used for the "For each registered observer observer (with
+ * observer's options as options) in target's list of registered observers,
+ * run these substeps:" and the "For each ancestor ancestor of target, and for
+ * each registered observer observer (with options options) in ancestor's list
+ * of registered observers, run these substeps:" part of the algorithms. The
+ * |options.subtree| is checked to ensure that the callback is called
+ * correctly.
+ *
+ * @param {Node} target
+ * @param {function(MutationObserverInit):MutationRecord} callback
+ */
+ function forEachAncestorAndObserverEnqueueRecord(target, callback) {
+ for (var node = target; node; node = node.parentNode) {
+ var registrations = registrationsTable.get(node);
+
+ if (registrations) {
+ for (var j = 0; j < registrations.length; j++) {
+ var registration = registrations[j];
+ var options = registration.options;
+
+ // Only target ignores subtree.
+ if (node !== target && !options.subtree)
+ continue;
+
+ var record = callback(options);
+ if (record)
+ registration.enqueue(record);
+ }
+ }
+ }
+ }
+
+ var uidCounter = 0;
+
+ /**
+ * The class that maps to the DOM MutationObserver interface.
+ * @param {Function} callback.
+ * @constructor
+ */
+ function JsMutationObserver(callback) {
+ this.callback_ = callback;
+ this.nodes_ = [];
+ this.records_ = [];
+ this.uid_ = ++uidCounter;
+ }
+
+ JsMutationObserver.prototype = {
+ observe: function(target, options) {
+ target = wrapIfNeeded(target);
+
+ // 1.1
+ if (!options.childList && !options.attributes && !options.characterData ||
+
+ // 1.2
+ options.attributeOldValue && !options.attributes ||
+
+ // 1.3
+ options.attributeFilter && options.attributeFilter.length &&
+ !options.attributes ||
+
+ // 1.4
+ options.characterDataOldValue && !options.characterData) {
+
+ throw new SyntaxError();
+ }
+
+ var registrations = registrationsTable.get(target);
+ if (!registrations)
+ registrationsTable.set(target, registrations = []);
+
+ // 2
+ // If target's list of registered observers already includes a registered
+ // observer associated with the context object, replace that registered
+ // observer's options with options.
+ var registration;
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i].observer === this) {
+ registration = registrations[i];
+ registration.removeListeners();
+ registration.options = options;
+ break;
+ }
+ }
+
+ // 3.
+ // Otherwise, add a new registered observer to target's list of registered
+ // observers with the context object as the observer and options as the
+ // options, and add target to context object's list of nodes on which it
+ // is registered.
+ if (!registration) {
+ registration = new Registration(this, target, options);
+ registrations.push(registration);
+ this.nodes_.push(target);
+ }
+
+ registration.addListeners();
+ },
+
+ disconnect: function() {
+ this.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ var registration = registrations[i];
+ if (registration.observer === this) {
+ registration.removeListeners();
+ registrations.splice(i, 1);
+ // Each node can only have one registered observer associated with
+ // this observer.
+ break;
+ }
+ }
+ }, this);
+ this.records_ = [];
+ },
+
+ takeRecords: function() {
+ var copyOfRecords = this.records_;
+ this.records_ = [];
+ return copyOfRecords;
+ }
+ };
+
+ /**
+ * @param {string} type
+ * @param {Node} target
+ * @constructor
+ */
+ function MutationRecord(type, target) {
+ this.type = type;
+ this.target = target;
+ this.addedNodes = [];
+ this.removedNodes = [];
+ this.previousSibling = null;
+ this.nextSibling = null;
+ this.attributeName = null;
+ this.attributeNamespace = null;
+ this.oldValue = null;
+ }
+
+ function copyMutationRecord(original) {
+ var record = new MutationRecord(original.type, original.target);
+ record.addedNodes = original.addedNodes.slice();
+ record.removedNodes = original.removedNodes.slice();
+ record.previousSibling = original.previousSibling;
+ record.nextSibling = original.nextSibling;
+ record.attributeName = original.attributeName;
+ record.attributeNamespace = original.attributeNamespace;
+ record.oldValue = original.oldValue;
+ return record;
+ };
+
+ // We keep track of the two (possibly one) records used in a single mutation.
+ var currentRecord, recordWithOldValue;
+
+ /**
+ * Creates a record without |oldValue| and caches it as |currentRecord| for
+ * later use.
+ * @param {string} oldValue
+ * @return {MutationRecord}
+ */
+ function getRecord(type, target) {
+ return currentRecord = new MutationRecord(type, target);
+ }
+
+ /**
+ * Gets or creates a record with |oldValue| based in the |currentRecord|
+ * @param {string} oldValue
+ * @return {MutationRecord}
+ */
+ function getRecordWithOldValue(oldValue) {
+ if (recordWithOldValue)
+ return recordWithOldValue;
+ recordWithOldValue = copyMutationRecord(currentRecord);
+ recordWithOldValue.oldValue = oldValue;
+ return recordWithOldValue;
+ }
+
+ function clearRecords() {
+ currentRecord = recordWithOldValue = undefined;
+ }
+
+ /**
+ * @param {MutationRecord} record
+ * @return {boolean} Whether the record represents a record from the current
+ * mutation event.
+ */
+ function recordRepresentsCurrentMutation(record) {
+ return record === recordWithOldValue || record === currentRecord;
+ }
+
+ /**
+ * Selects which record, if any, to replace the last record in the queue.
+ * This returns |null| if no record should be replaced.
+ *
+ * @param {MutationRecord} lastRecord
+ * @param {MutationRecord} newRecord
+ * @param {MutationRecord}
+ */
+ function selectRecord(lastRecord, newRecord) {
+ if (lastRecord === newRecord)
+ return lastRecord;
+
+ // Check if the the record we are adding represents the same record. If
+ // so, we keep the one with the oldValue in it.
+ if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
+ return recordWithOldValue;
+
+ return null;
+ }
+
+ /**
+ * Class used to represent a registered observer.
+ * @param {MutationObserver} observer
+ * @param {Node} target
+ * @param {MutationObserverInit} options
+ * @constructor
+ */
+ function Registration(observer, target, options) {
+ this.observer = observer;
+ this.target = target;
+ this.options = options;
+ this.transientObservedNodes = [];
+ }
+
+ Registration.prototype = {
+ enqueue: function(record) {
+ var records = this.observer.records_;
+ var length = records.length;
+
+ // There are cases where we replace the last record with the new record.
+ // For example if the record represents the same mutation we need to use
+ // the one with the oldValue. If we get same record (this can happen as we
+ // walk up the tree) we ignore the new record.
+ if (records.length > 0) {
+ var lastRecord = records[length - 1];
+ var recordToReplaceLast = selectRecord(lastRecord, record);
+ if (recordToReplaceLast) {
+ records[length - 1] = recordToReplaceLast;
+ return;
+ }
+ } else {
+ scheduleCallback(this.observer);
+ }
+
+ records[length] = record;
+ },
+
+ addListeners: function() {
+ this.addListeners_(this.target);
+ },
+
+ addListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes)
+ node.addEventListener('DOMAttrModified', this, true);
+
+ if (options.characterData)
+ node.addEventListener('DOMCharacterDataModified', this, true);
+
+ if (options.childList)
+ node.addEventListener('DOMNodeInserted', this, true);
+
+ if (options.childList || options.subtree)
+ node.addEventListener('DOMNodeRemoved', this, true);
+ },
+
+ removeListeners: function() {
+ this.removeListeners_(this.target);
+ },
+
+ removeListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes)
+ node.removeEventListener('DOMAttrModified', this, true);
+
+ if (options.characterData)
+ node.removeEventListener('DOMCharacterDataModified', this, true);
+
+ if (options.childList)
+ node.removeEventListener('DOMNodeInserted', this, true);
+
+ if (options.childList || options.subtree)
+ node.removeEventListener('DOMNodeRemoved', this, true);
+ },
+
+ /**
+ * Adds a transient observer on node. The transient observer gets removed
+ * next time we deliver the change records.
+ * @param {Node} node
+ */
+ addTransientObserver: function(node) {
+ // Don't add transient observers on the target itself. We already have all
+ // the required listeners set up on the target.
+ if (node === this.target)
+ return;
+
+ this.addListeners_(node);
+ this.transientObservedNodes.push(node);
+ var registrations = registrationsTable.get(node);
+ if (!registrations)
+ registrationsTable.set(node, registrations = []);
+
+ // We know that registrations does not contain this because we already
+ // checked if node === this.target.
+ registrations.push(this);
+ },
+
+ removeTransientObservers: function() {
+ var transientObservedNodes = this.transientObservedNodes;
+ this.transientObservedNodes = [];
+
+ transientObservedNodes.forEach(function(node) {
+ // Transient observers are never added to the target.
+ this.removeListeners_(node);
+
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i] === this) {
+ registrations.splice(i, 1);
+ // Each node can only have one registered observer associated with
+ // this observer.
+ break;
+ }
+ }
+ }, this);
+ },
+
+ handleEvent: function(e) {
+ // Stop propagation since we are managing the propagation manually.
+ // This means that other mutation events on the page will not work
+ // correctly but that is by design.
+ e.stopImmediatePropagation();
+
+ switch (e.type) {
+ case 'DOMAttrModified':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
+
+ var name = e.attrName;
+ var namespace = e.relatedNode.namespaceURI;
+ var target = e.target;
+
+ // 1.
+ var record = new getRecord('attributes', target);
+ record.attributeName = name;
+ record.attributeNamespace = namespace;
+
+ // 2.
+ var oldValue =
+ e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 3.1, 4.2
+ if (!options.attributes)
+ return;
+
+ // 3.2, 4.3
+ if (options.attributeFilter && options.attributeFilter.length &&
+ options.attributeFilter.indexOf(name) === -1 &&
+ options.attributeFilter.indexOf(namespace) === -1) {
+ return;
+ }
+ // 3.3, 4.4
+ if (options.attributeOldValue)
+ return getRecordWithOldValue(oldValue);
+
+ // 3.4, 4.5
+ return record;
+ });
+
+ break;
+
+ case 'DOMCharacterDataModified':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
+ var target = e.target;
+
+ // 1.
+ var record = getRecord('characterData', target);
+
+ // 2.
+ var oldValue = e.prevValue;
+
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 3.1, 4.2
+ if (!options.characterData)
+ return;
+
+ // 3.2, 4.3
+ if (options.characterDataOldValue)
+ return getRecordWithOldValue(oldValue);
+
+ // 3.3, 4.4
+ return record;
+ });
+
+ break;
+
+ case 'DOMNodeRemoved':
+ this.addTransientObserver(e.target);
+ // Fall through.
+ case 'DOMNodeInserted':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
+ var target = e.relatedNode;
+ var changedNode = e.target;
+ var addedNodes, removedNodes;
+ if (e.type === 'DOMNodeInserted') {
+ addedNodes = [changedNode];
+ removedNodes = [];
+ } else {
+
+ addedNodes = [];
+ removedNodes = [changedNode];
+ }
+ var previousSibling = changedNode.previousSibling;
+ var nextSibling = changedNode.nextSibling;
+
+ // 1.
+ var record = getRecord('childList', target);
+ record.addedNodes = addedNodes;
+ record.removedNodes = removedNodes;
+ record.previousSibling = previousSibling;
+ record.nextSibling = nextSibling;
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 2.1, 3.2
+ if (!options.childList)
+ return;
+
+ // 2.2, 3.3
+ return record;
+ });
+
+ }
+
+ clearRecords();
+ }
+ };
+
+ global.JsMutationObserver = JsMutationObserver;
+
+ if (!global.MutationObserver)
+ global.MutationObserver = JsMutationObserver;
+
+
+})(this);
+
window.CustomElements = window.CustomElements || {flags:{}};
(function(scope){
@@ -152,11 +693,11 @@
}
-// TODO(sorvell): on platforms without MutationObserver, mutations may not be
+// TODO(sorvell): on platforms without MutationObserver, mutations may not be
// reliable and therefore attached/detached are not reliable.
// To make these callbacks less likely to fail, we defer all inserts and removes
-// to give a chance for elements to be inserted into dom.
-// This ensures attachedCallback fires for elements that are created and
+// to give a chance for elements to be inserted into dom.
+// This ensures attachedCallback fires for elements that are created and
// immediately added to dom.
var hasPolyfillMutations = (!window.MutationObserver ||
(window.MutationObserver === window.JsMutationObserver));
@@ -421,7 +962,7 @@
// TODO(sorvell): See https://github.com/Polymer/polymer/issues/399
// we'll address this by defaulting to CE polyfill in the presence of the SD
// polyfill. This will avoid spamming excess attached/detached callbacks.
-// If there is a compelling need to run CE native with SD polyfill,
+// If there is a compelling need to run CE native with SD polyfill,
// we'll need to fix this issue.
var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill;
@@ -440,6 +981,7 @@
scope.upgradeSubtree = nop;
scope.observeDocument = nop;
scope.upgradeDocument = nop;
+ scope.upgradeDocumentTree = nop;
scope.takeRecords = nop;
} else {
@@ -615,11 +1157,11 @@
implement(element, definition);
// flag as upgraded
element.__upgraded__ = true;
+ // lifecycle management
+ created(element);
// there should never be a shadow root on element at this point
// we require child nodes be upgraded before `created`
scope.upgradeSubtree(element);
- // lifecycle management
- created(element);
// OUTPUT
return element;
}
@@ -633,11 +1175,6 @@
// getPrototypeOf(Element), we cannot do so when
// we use mixin, so we install a magic reference
customMixin(element, definition.prototype, definition.native);
-
- // Dart note: make sure we pick up the right constructor.
- // dart2js depends on this for dart:mirrors caching to work.
- // See tests/html/custom/mirrors_test.dart
- element.constructor = definition.prototype.constructor;
element.__proto__ = definition.prototype;
}
}
@@ -887,7 +1424,7 @@
Platform.endOfMicrotask :
setTimeout;
async(function() {
- // set internal 'ready' flag, now document.registerElement will trigger
+ // set internal 'ready' flag, now document.registerElement will trigger
// synchronous upgrades
CustomElements.ready = true;
// capture blunt profiling data
@@ -924,9 +1461,9 @@
// When loading at other readyStates, wait for the appropriate DOM event to
// bootstrap.
} else {
- var loadEvent = window.HTMLImports && !HTMLImports.ready
- ? 'HTMLImportsLoaded'
- : document.readyState == 'loading' ? 'DOMContentLoaded' : 'load';
+ var loadEvent = window.HTMLImports && !HTMLImports.ready ?
+ 'HTMLImportsLoaded' : document.readyState == 'loading' ?
+ 'DOMContentLoaded' : 'load';
window.addEventListener(loadEvent, bootstrap);
}
diff --git a/pkg/custom_element/lib/custom-elements.min.js b/pkg/custom_element/lib/custom-elements.min.js
index e1e6c59..78b0c76 100644
--- a/pkg/custom_element/lib/custom-elements.min.js
+++ b/pkg/custom_element/lib/custom-elements.min.js
@@ -25,4 +25,4 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"undefined"==typeof WeakMap&&!function(){var a=Object.defineProperty,b=Date.now()%1e9,c=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}(),window.CustomElements=window.CustomElements||{flags:{}},function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.shadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:void c(a,d)}),c(a,d)}function e(a){return h(a)?(i(a),!0):void l(a)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return A.dom&&console.group("upgrade:",b.localName),a.upgrade(b),A.dom&&console.groupEnd(),!0}}function i(a){l(a),r(a)&&d(a,function(a){l(a)})}function j(a){if(E.push(a),!D){D=!0;var b=window.Platform&&window.Platform.endOfMicrotask||setTimeout;b(k)}}function k(){D=!1;for(var a,b=E,c=0,d=b.length;d>c&&(a=b[c]);c++)a();E=[]}function l(a){C?j(function(){m(a)}):m(a)}function m(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("inserted:",a.localName),r(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?A.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.attachedCallback&&(A.dom&&console.log("inserted:",a.localName),a.attachedCallback())),A.dom&&console.groupEnd())}function n(a){o(a),d(a,function(a){o(a)})}function o(a){C?j(function(){p(a)}):p(a)}function p(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("removed:",a.localName),r(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?A.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.detachedCallback&&a.detachedCallback()),A.dom&&console.groupEnd())}function q(a){return window.ShadowDOMPolyfill?ShadowDOMPolyfill.wrapIfNeeded(a):a}function r(a){for(var b=a,c=q(document);b;){if(b==c)return!0;b=b.parentNode||b.host}}function s(a){if(a.shadowRoot&&!a.shadowRoot.__watched){A.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.shadowRoot;b;)t(b),b=b.olderShadowRoot}}function t(a){a.__watched||(w(a),a.__watched=!0)}function u(a){if(A.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(G(a.addedNodes,function(a){a.localName&&g(a)}),G(a.removedNodes,function(a){a.localName&&n(a)}))}),A.dom&&console.groupEnd()}function v(){u(F.takeRecords()),k()}function w(a){F.observe(a,{childList:!0,subtree:!0})}function x(a){w(a)}function y(a){A.dom&&console.group("upgradeDocument: ",a.baseURI.split("/").pop()),g(a),A.dom&&console.groupEnd()}function z(a){a=q(a),y(a);for(var b,c=a.querySelectorAll("link[rel="+B+"]"),d=0,e=c.length;e>d&&(b=c[d]);d++)b.import&&b.import.__parsed&&z(b.import)}var A=window.logFlags||{},B=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",C=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;a.hasPolyfillMutations=C;var D=!1,E=[],F=new MutationObserver(u),G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.IMPORT_LINK_TYPE=B,a.watchShadow=s,a.upgradeDocumentTree=z,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=x,a.upgradeDocument=y,a.takeRecords=v}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.registerElement: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(b)+"'.");if(m(b))throw new Error("DuplicateDefinitionError: a type with name '"+String(b)+"' is already registered");if(!g.prototype)throw new Error("Options missing required prototype property");return g.__name=b.toLowerCase(),g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),n(g.__name,g),g.ctor=o(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,(a.ready||a.performedInitialDocumentUpgrade)&&a.upgradeDocumentTree(document),g.ctor}function c(a){var b=m(a);return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.__name,c&&(a.is=a.__name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(x(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),b.removeAttribute("unresolved"),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.constructor=b.prototype.constructor,a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){if(!a.setAttribute._polyfilled){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a){l.call(this,a,null,c)},a.setAttribute._polyfilled=!0}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments);var e=this.getAttribute(a);this.attributeChangedCallback&&e!==d&&this.attributeChangedCallback(a,d,e)}function m(a){return a?w[a.toLowerCase()]:void 0}function n(a,b){if(w[a])throw new Error("a type with that name is already registered.");w[a]=b}function o(a){return function(){return f(a)}}function p(a,b){var c=m(b||a);if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=p(a);return d.setAttribute("is",b),d}var d=x(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function q(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=w[b||a.localName];if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function r(b){var c=y.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var s=a.flags,t=Boolean(document.registerElement),u=!s.register&&t&&!window.ShadowDOMPolyfill;if(u){var v=function(){};a.registry={},a.upgradeElement=v,a.watchShadow=v,a.upgrade=v,a.upgradeAll=v,a.upgradeSubtree=v,a.observeDocument=v,a.upgradeDocument=v,a.takeRecords=v}else{var w={},x=document.createElement.bind(document),y=Node.prototype.cloneNode;document.registerElement=b,document.createElement=p,Node.prototype.cloneNode=r,a.registry=w,a.upgrade=q}document.register=document.registerElement,a.hasNative=t,a.useNative=u}(window.CustomElements),function(a){function b(a){return"link"===a.localName&&a.getAttribute("rel")===c}var c=a.IMPORT_LINK_TYPE,d={selectors:["link[rel="+c+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(d.selectors);e(b,function(a){d[d.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(a){b(a)&&this.parseImport(a)},parseImport:function(a){a.import&&d.parse(a.import)}},e=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.parser=d,a.IMPORT_LINK_TYPE=c}(window.CustomElements),function(a){function b(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.performedInitialDocumentUpgrade=!0;var a=window.Platform&&Platform.endOfMicrotask?Platform.endOfMicrotask:setTimeout;a(function(){CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState||a.flags.eager)b();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var c=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"loading"==document.readyState?"DOMContentLoaded":"load";window.addEventListener(c,b)}else b()}(window.CustomElements),function(){if(HTMLElement.prototype.createShadowRoot){var a=HTMLElement.prototype.createShadowRoot;HTMLElement.prototype.createShadowRoot=function(){var b=a.call(this);return b.host=this,CustomElements.watchShadow(this),b}}if(window.ShadowDOMPolyfill){var b=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],c={};b.forEach(function(a){c[a]=CustomElements[a]}),b.forEach(function(a){CustomElements[a]=function(b){return c[a](window.ShadowDOMPolyfill.wrapIfNeeded(b))}})}if(window.CustomElements&&!CustomElements.useNative){var d=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=d.call(this,a,b);return CustomElements.upgradeAll(c),c}}}();
\ No newline at end of file
+"undefined"==typeof WeakMap&&!function(){var a=Object.defineProperty,b=Date.now()%1e9,c=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new WeakMap,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g,a.MutationObserver||(a.MutationObserver=g)}(this),window.CustomElements=window.CustomElements||{flags:{}},function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.shadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(l(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return A.dom&&console.group("upgrade:",b.localName),a.upgrade(b),A.dom&&console.groupEnd(),!0}}function i(a){l(a),r(a)&&d(a,function(a){l(a)})}function j(a){if(E.push(a),!D){D=!0;var b=window.Platform&&window.Platform.endOfMicrotask||setTimeout;b(k)}}function k(){D=!1;for(var a,b=E,c=0,d=b.length;d>c&&(a=b[c]);c++)a();E=[]}function l(a){C?j(function(){m(a)}):m(a)}function m(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("inserted:",a.localName),r(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?A.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.attachedCallback&&(A.dom&&console.log("inserted:",a.localName),a.attachedCallback())),A.dom&&console.groupEnd())}function n(a){o(a),d(a,function(a){o(a)})}function o(a){C?j(function(){p(a)}):p(a)}function p(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("removed:",a.localName),r(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?A.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.detachedCallback&&a.detachedCallback()),A.dom&&console.groupEnd())}function q(a){return window.ShadowDOMPolyfill?ShadowDOMPolyfill.wrapIfNeeded(a):a}function r(a){for(var b=a,c=q(document);b;){if(b==c)return!0;b=b.parentNode||b.host}}function s(a){if(a.shadowRoot&&!a.shadowRoot.__watched){A.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.shadowRoot;b;)t(b),b=b.olderShadowRoot}}function t(a){a.__watched||(w(a),a.__watched=!0)}function u(a){if(A.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(G(a.addedNodes,function(a){a.localName&&g(a)}),G(a.removedNodes,function(a){a.localName&&n(a)}))}),A.dom&&console.groupEnd()}function v(){u(F.takeRecords()),k()}function w(a){F.observe(a,{childList:!0,subtree:!0})}function x(a){w(a)}function y(a){A.dom&&console.group("upgradeDocument: ",a.baseURI.split("/").pop()),g(a),A.dom&&console.groupEnd()}function z(a){a=q(a),y(a);for(var b,c=a.querySelectorAll("link[rel="+B+"]"),d=0,e=c.length;e>d&&(b=c[d]);d++)b.import&&b.import.__parsed&&z(b.import)}var A=window.logFlags||{},B=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",C=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;a.hasPolyfillMutations=C;var D=!1,E=[],F=new MutationObserver(u),G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.IMPORT_LINK_TYPE=B,a.watchShadow=s,a.upgradeDocumentTree=z,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=x,a.upgradeDocument=y,a.takeRecords=v}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.registerElement: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(b)+"'.");if(m(b))throw new Error("DuplicateDefinitionError: a type with name '"+String(b)+"' is already registered");if(!g.prototype)throw new Error("Options missing required prototype property");return g.__name=b.toLowerCase(),g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),n(g.__name,g),g.ctor=o(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,(a.ready||a.performedInitialDocumentUpgrade)&&a.upgradeDocumentTree(document),g.ctor}function c(a){var b=m(a);return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.__name,c&&(a.is=a.__name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(x(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),b.removeAttribute("unresolved"),h(b,c),b.__upgraded__=!0,j(b),a.upgradeSubtree(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){if(!a.setAttribute._polyfilled){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a){l.call(this,a,null,c)},a.setAttribute._polyfilled=!0}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments);var e=this.getAttribute(a);this.attributeChangedCallback&&e!==d&&this.attributeChangedCallback(a,d,e)}function m(a){return a?w[a.toLowerCase()]:void 0}function n(a,b){if(w[a])throw new Error("a type with that name is already registered.");w[a]=b}function o(a){return function(){return f(a)}}function p(a,b){var c=m(b||a);if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=p(a);return d.setAttribute("is",b),d}var d=x(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function q(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=w[b||a.localName];if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function r(b){var c=y.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var s=a.flags,t=Boolean(document.registerElement),u=!s.register&&t&&!window.ShadowDOMPolyfill;if(u){var v=function(){};a.registry={},a.upgradeElement=v,a.watchShadow=v,a.upgrade=v,a.upgradeAll=v,a.upgradeSubtree=v,a.observeDocument=v,a.upgradeDocument=v,a.upgradeDocumentTree=v,a.takeRecords=v}else{var w={},x=document.createElement.bind(document),y=Node.prototype.cloneNode;document.registerElement=b,document.createElement=p,Node.prototype.cloneNode=r,a.registry=w,a.upgrade=q}document.register=document.registerElement,a.hasNative=t,a.useNative=u}(window.CustomElements),function(a){function b(a){return"link"===a.localName&&a.getAttribute("rel")===c}var c=a.IMPORT_LINK_TYPE,d={selectors:["link[rel="+c+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(d.selectors);e(b,function(a){d[d.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(a){b(a)&&this.parseImport(a)},parseImport:function(a){a.import&&d.parse(a.import)}},e=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.parser=d,a.IMPORT_LINK_TYPE=c}(window.CustomElements),function(a){function b(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.performedInitialDocumentUpgrade=!0;var a=window.Platform&&Platform.endOfMicrotask?Platform.endOfMicrotask:setTimeout;a(function(){CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState||a.flags.eager)b();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var c=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"loading"==document.readyState?"DOMContentLoaded":"load";window.addEventListener(c,b)}else b()}(window.CustomElements),function(){if(HTMLElement.prototype.createShadowRoot){var a=HTMLElement.prototype.createShadowRoot;HTMLElement.prototype.createShadowRoot=function(){var b=a.call(this);return b.host=this,CustomElements.watchShadow(this),b}}if(window.ShadowDOMPolyfill){var b=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],c={};b.forEach(function(a){c[a]=CustomElements[a]}),b.forEach(function(a){CustomElements[a]=function(b){return c[a](window.ShadowDOMPolyfill.wrapIfNeeded(b))}})}if(window.CustomElements&&!CustomElements.useNative){var d=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=d.call(this,a,b);return CustomElements.upgradeAll(c),c}}}();
\ No newline at end of file
diff --git a/pkg/custom_element/lib/polyfill.dart b/pkg/custom_element/lib/polyfill.dart
index 939fb36..413d7d6 100644
--- a/pkg/custom_element/lib/polyfill.dart
+++ b/pkg/custom_element/lib/polyfill.dart
@@ -54,12 +54,6 @@
*/
Future loadCustomElementPolyfill() {
if (!document.supportsRegister && !js.context.hasProperty('CustomElements')) {
- if (!MutationObserver.supported) {
- var script = new ScriptElement()
- ..src = '/packages/mutation_observer/mutation_observer.js';
- document.head.append(script);
- }
-
var script = new ScriptElement()
..src = '/packages/custom_element/custom-elements.debug.js';
document.head.append(script);
diff --git a/pkg/custom_element/pubspec.yaml b/pkg/custom_element/pubspec.yaml
index 39302d5..95a25ea 100644
--- a/pkg/custom_element/pubspec.yaml
+++ b/pkg/custom_element/pubspec.yaml
@@ -1,14 +1,12 @@
name: custom_element
-version: 0.9.1+2
+version: 0.9.3
author: "Polymer.dart Team <web-ui-dev@dartlang.org>"
homepage: http://www.dartlang.org/
description: >
Custom Elements let authors define their own elements. Authors associate code
with custom tag names, and then use those custom tag names as they would any
standard tag.
-dependencies:
- mutation_observer: ">=0.9.0 <0.10.0"
dev_dependencies:
unittest: ">=0.9.0 <0.10.0"
environment:
- sdk: ">=1.0.0 <2.0.0"
+ sdk: ">=1.2.0-dev.4.0 <2.0.0"
diff --git a/pkg/docgen/bin/docgen.dart b/pkg/docgen/bin/docgen.dart
index 2a116de..f1275c5 100644
--- a/pkg/docgen/bin/docgen.dart
+++ b/pkg/docgen/bin/docgen.dart
@@ -22,7 +22,9 @@
var includeSdk = results['parse-sdk'] || results['include-sdk'];
var scriptDir = path.dirname(Platform.script.toFilePath());
var introduction = includeSdk ? '' : results['introduction'];
- docgen(results.rest.map(path.normalize).toList(),
+ var files = results.rest.map(path.normalize).toList();
+ if (files.isEmpty) _printHelpAndExit();
+ docgen(files,
packageRoot: results['package-root'],
outputToYaml: !results['json'],
includePrivate: results['include-private'],
@@ -32,7 +34,19 @@
introFileName: introduction,
out: results['out'],
excludeLibraries: excludedLibraries,
- includeDependentPackages: results['include-dependent-packages']);
+ includeDependentPackages: results['include-dependent-packages'],
+ serve: results['serve'],
+ noDocs: results['no-docs'],
+ startPage: results['startPage']);
+}
+
+/**
+ * Print help if we are passed the help option or invalid arguments.
+ */
+void _printHelpAndExit() {
+ print(_initArgParser().getUsage());
+ print('Usage: dart docgen.dart [OPTIONS] fooDir/barFile');
+ exit(0);
}
/**
@@ -44,11 +58,7 @@
help: 'Prints help and usage information.',
negatable: false,
callback: (help) {
- if (help) {
- print(parser.getUsage());
- print('Usage: dart docgen.dart [OPTIONS] fooDir/barFile');
- exit(0);
- }
+ if (help) _printHelpAndExit();
});
parser.addFlag('verbose', abbr: 'v',
help: 'Output more logging information.', negatable: false,
@@ -72,6 +82,11 @@
parser.addFlag('append',
help: 'Append to the docs folder, library_list.json and index.txt',
defaultsTo: false, negatable: false);
+ parser.addFlag('serve', help: 'Clone the documentation viewer repo locally '
+ '(if not already present) and start a simple server', defaultsTo: false,
+ negatable: false);
+ parser.addFlag('no-docs', help: 'Do not generate any new documentation',
+ defaultsTo: false, negatable: false);
parser.addOption('introduction',
help: 'Adds the provided markdown text file as the introduction'
' for the generated documentation.', defaultsTo: '');
@@ -87,5 +102,12 @@
'in the directory with its pubspec. Includes documentation for all '
'of its dependent packages.',
defaultsTo: false, negatable: false);
+ parser.addOption('startPage',
+ help: 'By default the viewer will start at the SDK introduction page.'
+ 'To start at some other page, e.g. for a package, provide the name '
+ 'of the package in this argument, e.g. --startPage=intl will make '
+ 'the start page of the viewer be the intl package.',
+ defaultsTo: null);
+
return parser;
}
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index 168b637..bb50090 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -26,9 +26,11 @@
import 'src/io.dart';
import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart'
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart'
+ as dart2js_mirrors;
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart'
as dart2js;
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart'
as dart2js_util;
import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
@@ -96,12 +98,6 @@
[Writing API Documentation](https://code.google.com/p/dart/wiki/WritingApiDocumentation).
""";
-// TODO(efortuna): The use of this field is odd (this is based on how it was
-// originally used. Try to cleanup.
-/// Index of all indexable items. This also ensures that no class is
-/// created more than once.
-Map<String, Indexable> entityMap = new Map<String, Indexable>();
-
/// Docgen constructor initializes the link resolver for markdown parsing.
/// Also initializes the command line arguments.
///
@@ -110,19 +106,38 @@
/// also be documented.
/// If [parseSdk] is `true`, then all Dart SDK libraries will be documented.
/// This option is useful when only the SDK libraries are needed.
+/// If [serve] is `true`, then after generating the documents we fire up a
+/// simple server to view the documentation.
///
/// Returned Future completes with true if document generation is successful.
Future<bool> docgen(List<String> files, {String packageRoot,
bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
bool parseSdk: false, bool append: false, String introFileName: '',
out: _DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries : const [],
- bool includeDependentPackages: false}) {
- return _Generator.generateDocumentation(files, packageRoot: packageRoot,
- outputToYaml: outputToYaml, includePrivate: includePrivate,
- includeSdk: includeSdk, parseSdk: parseSdk, append: append,
- introFileName: introFileName, out: out,
- excludeLibraries: excludeLibraries,
- includeDependentPackages: includeDependentPackages);
+ bool includeDependentPackages: false, bool serve: false,
+ bool noDocs: false, String startPage}) {
+ var result;
+ if (!noDocs) {
+ _Viewer.ensureMovedViewerCode();
+ result = _Generator.generateDocumentation(files, packageRoot: packageRoot,
+ outputToYaml: outputToYaml, includePrivate: includePrivate,
+ includeSdk: includeSdk, parseSdk: parseSdk, append: append,
+ introFileName: introFileName, out: out,
+ excludeLibraries: excludeLibraries,
+ includeDependentPackages: includeDependentPackages,
+ startPage: startPage);
+ _Viewer.addBackViewerCode();
+ if (serve) {
+ result.then((success) {
+ if (success) {
+ _Viewer._cloneAndServe();
+ }
+ });
+ }
+ } else if (serve) {
+ _Viewer._cloneAndServe();
+ }
+ return result;
}
/// Analyzes set of libraries by getting a mirror system and triggers the
@@ -152,15 +167,15 @@
String get docName {
if (mirror == null) return '';
if (mirror is LibraryMirror) {
- return mirror.qualifiedName.replaceAll('.','-');
+ return dart2js_util.qualifiedNameOf(mirror).replaceAll('.','-');
}
var mirrorOwner = mirror.owner;
- if (mirrorOwner == null) return mirror.qualifiedName;
- var simpleName = mirror.simpleName;
+ if (mirrorOwner == null) return dart2js_util.qualifiedNameOf(mirror);
+ var simpleName = dart2js_util.nameOf(mirror);
if (mirror is MethodMirror && (mirror as MethodMirror).isConstructor) {
// We name constructors specially -- repeating the class name and a
// "-" to separate the constructor from its name (if any).
- simpleName = '${mirrorOwner.simpleName}-$simpleName';
+ simpleName = '${dart2js_util.nameOf(mirrorOwner)}-$simpleName';
}
return Indexable.getDocgenObject(mirrorOwner, owner).docName + '.' +
simpleName;
@@ -189,18 +204,19 @@
/// Docgen representation of an item to be documented, that wraps around a
/// dart2js mirror.
abstract class MirrorBased {
+ /// The original dart2js mirror around which this object wraps.
DeclarationMirror get mirror;
/// Returns a list of meta annotations assocated with a mirror.
List<Annotation> _createAnnotations(DeclarationMirror mirror,
Library owningLibrary) {
var annotationMirrors = mirror.metadata.where((e) =>
- e is dart2js.Dart2JsConstructedConstantMirror);
+ e is dart2js_mirrors.Dart2JsConstructedConstantMirror);
var annotations = [];
annotationMirrors.forEach((annotation) {
var docgenAnnotation = new Annotation(annotation, owningLibrary);
if (!_SKIPPED_ANNOTATIONS.contains(
- docgenAnnotation.mirror.qualifiedName)) {
+ dart2js_util.qualifiedNameOf(docgenAnnotation.mirror))) {
annotations.add(docgenAnnotation);
}
});
@@ -208,8 +224,14 @@
}
}
+/// Top level documentation traversal and generation object.
+///
+/// Yes, everything in this class is used statically so this technically doesn't
+/// need to be its own class, but it's grouped together for semantic separation
+/// from the other classes and functionality in this library.
class _Generator {
- static var _outputDirectory;
+ /// The directory where the output docs are generated.
+ static String _outputDirectory;
/// This is set from the command line arguments flag --include-private
static bool _includePrivate = false;
@@ -220,6 +242,7 @@
/// --exclude-lib.
static List<String> _excluded;
+ /// Logger for printing out progress of documentation generation.
static Logger logger = new Logger('Docgen');
/// Docgen constructor initializes the link resolver for markdown parsing.
@@ -237,7 +260,7 @@
bool includeSdk: false, bool parseSdk: false, bool append: false,
String introFileName: '', out: _DEFAULT_OUTPUT_DIRECTORY,
List<String> excludeLibraries : const [],
- bool includeDependentPackages: false}) {
+ bool includeDependentPackages: false, String startPage}) {
_excluded = excludeLibraries;
_includePrivate = includePrivate;
logger.onRecord.listen((record) => print(record.message));
@@ -259,7 +282,7 @@
if (mirrorSystem.libraries.isEmpty) {
throw new StateError('No library mirrors were created.');
}
- Indexable.initializeTopLevelLibraries(mirrorSystem);
+ Indexable._initializeTopLevelLibraries(mirrorSystem);
var availableLibraries = mirrorSystem.libraries.values.where(
(each) => each.uri.scheme == 'file');
@@ -272,10 +295,10 @@
librariesToDocument.addAll(
(includeSdk || parseSdk) ? Indexable._sdkLibraries : []);
librariesToDocument.removeWhere(
- (x) => _excluded.contains(x.simpleName));
+ (x) => _excluded.contains(dart2js_util.nameOf(x)));
_documentLibraries(librariesToDocument, includeSdk: includeSdk,
outputToYaml: outputToYaml, append: append, parseSdk: parseSdk,
- introFileName: introFileName);
+ introFileName: introFileName, startPage: startPage);
return true;
});
}
@@ -305,56 +328,50 @@
mode: append ? FileMode.APPEND : FileMode.WRITE);
}
+ /// Resolve all the links in the introductory comments for a given library or
+ /// package as specified by [filename].
+ static String _readIntroductionFile(String fileName, bool includeSdk) {
+ var linkResolver = (name) => Indexable.globalFixReference(name);
+ var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : '';
+ var introText = defaultText;
+ if (fileName.isNotEmpty) {
+ var introFile = new File(fileName);
+ introText = introFile.existsSync() ? introFile.readAsStringSync() :
+ defaultText;
+ }
+ return markdown.markdownToHtml(introText,
+ linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
+ }
+
/// Creates documentation for filtered libraries.
static void _documentLibraries(List<LibraryMirror> libs,
{bool includeSdk: false, bool outputToYaml: true, bool append: false,
- bool parseSdk: false, String introFileName: ''}) {
+ bool parseSdk: false, String introFileName: '', String startPage}) {
libs.forEach((lib) {
// Files belonging to the SDK have a uri that begins with 'dart:'.
if (includeSdk || !lib.uri.toString().startsWith('dart:')) {
var library = generateLibrary(lib);
- entityMap[library.name] = library;
}
});
- var filteredEntities = entityMap.values.where(_isFullChainVisible);
-
- /*var filteredEntities2 = new Set<MirrorBased>();
- for (Map<String, Set<MirrorBased>> firstLevel in mirrorToDocgen.values) {
- for (Set<MirrorBased> items in firstLevel.values) {
- for (MirrorBased item in items) {
+ var filteredEntities = new Set<Indexable>();
+ for (Map<String, Set<Indexable>> firstLevel in
+ Indexable._mirrorToDocgen.values) {
+ for (Set<Indexable> items in firstLevel.values) {
+ for (Indexable item in items) {
if (_isFullChainVisible(item)) {
- filteredEntities2.add(item);
+ if (item is! Method ||
+ (item is Method && item.methodInheritedFrom == null)) {
+ filteredEntities.add(item);
+ }
}
}
}
- }*/
-
- /*print('THHHHHEEE DIFFERENCE IS');
- var set1 = new Set.from(filteredEntities);
- var set2 = new Set.from(filteredEntities2);
- var aResult = set2.difference(set1);
- for (MirrorBased r in aResult) {
- print(' a result is $r and ${r.docName}');
- }*/
- //print(set1.difference(set2));
+ }
// Outputs a JSON file with all libraries and their preview comments.
// This will help the viewer know what libraries are available to read in.
var libraryMap;
- var linkResolver = (name) => Indexable.globalFixReference(name);
-
- String readIntroductionFile(String fileName, includeSdk) {
- var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : '';
- var introText = defaultText;
- if (fileName.isNotEmpty) {
- var introFile = new File(fileName);
- introText = introFile.existsSync() ? introFile.readAsStringSync() :
- defaultText;
- }
- return markdown.markdownToHtml(introText,
- linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
- }
if (append) {
var docsDir = listDir(_outputDirectory);
@@ -370,16 +387,27 @@
var intro = libraryMap['introduction'];
var spacing = intro.isEmpty ? '' : '<br/><br/>';
libraryMap['introduction'] =
- "$intro$spacing${readIntroductionFile(introFileName, includeSdk)}";
+ "$intro$spacing${_readIntroductionFile(introFileName, includeSdk)}";
outputToYaml = libraryMap['filetype'] == 'yaml';
} else {
libraryMap = {
'libraries' : filteredEntities.where((e) =>
e is Library).map((e) => e.previewMap).toList(),
- 'introduction' : readIntroductionFile(introFileName, includeSdk),
+ 'introduction' : _readIntroductionFile(introFileName, includeSdk),
'filetype' : outputToYaml ? 'yaml' : 'json'
};
}
+ _writeOutputFiles(libraryMap, filteredEntities, outputToYaml, append,
+ startPage);
+ }
+
+ /// Output all of the libraries and classes into json or yaml files for
+ /// consumption by a viewer.
+ static void _writeOutputFiles(libraryMap,
+ Iterable<Indexable> filteredEntities, bool outputToYaml, bool append,
+ String startPage) {
+ if (startPage != null) libraryMap['startPage'] = startPage;
+
_writeToFile(JSON.encode(libraryMap), 'library_list.json');
// Output libraries and classes to file after all information is generated.
@@ -404,6 +432,7 @@
_writeToFile(JSON.encode(index), 'index.json');
}
+ /// Helper method to serialize the given Indexable out to a file.
static void _writeIndexableToFile(Indexable result, bool outputToYaml) {
var outputFile = result.fileName;
var output;
@@ -427,7 +456,8 @@
}
}
-
+ /// Helper accessor to determine the full pathname of the root of the dart
+ /// checkout.
static String get _rootDirectory {
var scriptDir = path.absolute(path.dirname(Platform.script.toFilePath()));
var root = scriptDir;
@@ -472,11 +502,6 @@
static String _obtainPackageRoot(String packageRoot, bool parseSdk,
List<String> files) {
if (packageRoot == null && !parseSdk) {
- // TODO(efortuna): This logic seems not very robust, but it's from the
- // original version of the code, pre-refactor, so I'm leavingt it for now.
- // Revisit to make more robust.
- // TODO(efortuna): See lines 303-311 in
- // https://codereview.chromium.org/116043013/diff/390001/pkg/docgen/lib/docgen.dart
var type = FileSystemEntity.typeSync(files.first);
if (type == FileSystemEntityType.DIRECTORY) {
var files2 = listDir(files.first, recursive: true);
@@ -570,16 +595,14 @@
return sdk;
}
+ /// Return true if this item and all of its owners are all visible.
static bool _isFullChainVisible(Indexable item) {
- // TODO: reconcile with isVisible.
- // TODO: Also should be able to take MirrorBased items in general probably.
- var result = _includePrivate || (!item.isPrivate && (item.owner != null ?
+ return _includePrivate || (!item.isPrivate && (item.owner != null ?
_isFullChainVisible(item.owner) : true));
- return result;
}
/// Currently left public for testing purposes. :-/
- static Library generateLibrary(dart2js.Dart2JsLibraryMirror library) {
+ static Library generateLibrary(dart2js_mirrors.Dart2JsLibraryMirror library) {
var result = new Library(library);
result._findPackage(library);
logger.fine('Generated library for ${result.name}');
@@ -587,6 +610,134 @@
}
}
+/// Convenience methods wrapped up in a class to pull down the docgen viewer for
+/// a viewable website, and start up a server for viewing.
+class _Viewer {
+ static String _dartdocViewerString = path.join(Directory.current.path,
+ 'dartdoc-viewer');
+ static Directory _dartdocViewerDir = new Directory(_dartdocViewerString);
+ static Directory _topLevelTempDir;
+ static bool movedViewerCode = false;
+
+ /// If our dartdoc-viewer code is already checked out, move it to a temporary
+ /// directory outside of the package directory, so we don't try to process it
+ /// for documentation.
+ static void ensureMovedViewerCode() {
+ // TODO(efortuna): This will need to be modified to run on anyone's package
+ // outside of the checkout!
+ if (_dartdocViewerDir.existsSync()) {
+ _topLevelTempDir = new Directory(
+ _Generator._rootDirectory).createTempSync();
+ _dartdocViewerDir.renameSync(_topLevelTempDir.path);
+ }
+ }
+
+ /// Move the dartdoc-viewer code back into place for "webpage deployment."
+ static void addBackViewerCode() {
+ if (movedViewerCode) _dartdocViewerDir.renameSync(_dartdocViewerString);
+ }
+
+ /// Serve up our generated documentation for viewing in a browser.
+ static void _cloneAndServe() {
+ // If the viewer code is already there, then don't clone again.
+ if (_dartdocViewerDir.existsSync()) {
+ _moveDirectoryAndServe();
+ }
+ else {
+ var processResult = Process.runSync('git', ['clone', '-b', 'master',
+ 'git://github.com/dart-lang/dartdoc-viewer.git'],
+ runInShell: true);
+
+ if (processResult.exitCode == 0) {
+ _moveDirectoryAndServe();
+ } else {
+ print('Error cloning git repository:');
+ print('process output: ${processResult.stdout}');
+ print('process stderr: ${processResult.stderr}');
+ }
+ }
+ }
+
+ /// Move the generated json/yaml docs directory to the dartdoc-viewer
+ /// directory, to run as a webpage.
+ static void _moveDirectoryAndServe() {
+ var processResult = Process.runSync('pub', ['update'], runInShell: true,
+ workingDirectory: path.join(_dartdocViewerDir.path, 'client'));
+ print('process output: ${processResult.stdout}');
+ print('process stderr: ${processResult.stderr}');
+
+ var dir = new Directory(_Generator._outputDirectory == null? 'docs' :
+ _Generator._outputDirectory);
+ var webDocsDir = new Directory(path.join(_dartdocViewerDir.path, 'client',
+ 'web', 'docs'));
+ if (dir.existsSync()) {
+ // Move the docs folder to dartdoc-viewer/client/web/docs
+ dir.renameSync(webDocsDir.path);
+ }
+
+ if (webDocsDir.existsSync()) {
+ // Compile the code to JavaScript so we can run on any browser.
+ print('Compile app to JavaScript for viewing.');
+ var processResult = Process.runSync('dart', ['deploy.dart'],
+ workingDirectory : path.join(_dartdocViewerDir.path, 'client'),
+ runInShell: true);
+ print('process output: ${processResult.stdout}');
+ print('process stderr: ${processResult.stderr}');
+ _runServer();
+ }
+ }
+
+ /// A simple HTTP server. Implemented here because this is part of the SDK,
+ /// so it shouldn't have any external dependencies.
+ static void _runServer() {
+ // Launch a server to serve out of the directory dartdoc-viewer/client/web.
+ HttpServer.bind('localhost', 8080).then((HttpServer httpServer) {
+ print('Server launched. Navigate your browser to: '
+ 'http://localhost:${httpServer.port}');
+ httpServer.listen((HttpRequest request) {
+ var response = request.response;
+ var basePath = path.join(_dartdocViewerDir.path, 'client', 'out',
+ 'web');
+ var requestPath = path.join(basePath, request.uri.path.substring(1));
+ bool found = true;
+ var file = new File(requestPath);
+ if (file.existsSync()) {
+ // Set the correct header type.
+ if (requestPath.endsWith('.html')) {
+ response.headers.set('Content-Type', 'text/html');
+ } else if (requestPath.endsWith('.js')) {
+ response.headers.set('Content-Type', 'application/javascript');
+ } else if (requestPath.endsWith('.dart')) {
+ response.headers.set('Content-Type', 'application/dart');
+ } else if (requestPath.endsWith('.css')) {
+ response.headers.set('Content-Type', 'text/css');
+ }
+ } else {
+ if (requestPath == basePath) {
+ response.headers.set('Content-Type', 'text/html');
+ file = new File(path.join(basePath, 'index.html'));
+ } else {
+ print('Path not found: $requestPath');
+ found = false;
+ response.statusCode = HttpStatus.NOT_FOUND;
+ response.close();
+ }
+ }
+
+ if (found) {
+ // Serve up file contents.
+ file.openRead().pipe(response).catchError((e) {
+ print('HttpServer: error while closing the response stream $e');
+ });
+ }
+ },
+ onError: (e) {
+ print('HttpServer: an error occured $e');
+ });
+ });
+ }
+}
+
/// An item that is categorized in our mirrorToDocgen map, as a distinct,
/// searchable element.
///
@@ -631,14 +782,14 @@
Indexable(this.mirror) {
this.isPrivate = _isHidden(mirror);
- var map = _mirrorToDocgen[this.mirror.qualifiedName];
+ var map = _mirrorToDocgen[dart2js_util.qualifiedNameOf(this.mirror)];
if (map == null) map = new Map<String, Set<Indexable>>();
var set = map[owner.docName];
if (set == null) set = new Set<Indexable>();
set.add(this);
map[owner.docName] = set;
- _mirrorToDocgen[this.mirror.qualifiedName] = map;
+ _mirrorToDocgen[dart2js_util.qualifiedNameOf(this.mirror)] = map;
}
/** Walk up the owner chain to find the owning library. */
@@ -647,7 +798,7 @@
return _getOwningLibrary(indexable.owner);
}
- static initializeTopLevelLibraries(MirrorSystem mirrorSystem) {
+ static _initializeTopLevelLibraries(MirrorSystem mirrorSystem) {
_sdkLibraries = mirrorSystem.libraries.values.where(
(each) => each.uri.scheme == 'dart');
_coreLibrary = new Library(_sdkLibraries.singleWhere((lib) =>
@@ -659,8 +810,6 @@
/// have them replaced with hyphens.
String get docName;
- markdown.Node fixReferenceWithScope(String name) => null;
-
/// Converts all [foo] references in comments to <a>libraryName.foo</a>.
markdown.Node fixReference(String name) {
// Attempt the look up the whole name up in the scope.
@@ -676,24 +825,36 @@
String findElementInScope(String name) =>
_findElementInScope(name, packagePrefix);
+ /// For a given name, determine if we need to resolve it as a qualified name
+ /// or a simple name in the source mirors.
static determineLookupFunc(name) => name.contains('.') ?
dart2js_util.lookupQualifiedInScope :
(mirror, name) => mirror.lookupInScope(name);
- // The qualified name (for URL purposes) and the file name are the same,
- // of the form packageName/ClassName or packageName/ClassName.methodName.
- // This defines both the URL and the directory structure.
- String get fileName {
- return packagePrefix + ownerPrefix + name;
- }
+ /// The reference to this element based on where it is printed as a
+ /// documentation file and also the unique URL to refer to this item.
+ ///
+ /// The qualified name (for URL purposes) and the file name are the same,
+ /// of the form packageName/ClassName or packageName/ClassName.methodName.
+ /// This defines both the URL and the directory structure.
+ String get fileName => packagePrefix + ownerPrefix + name;
+ /// The full docName of the owner element, appended with a '.' for this
+ /// object's name to be appended.
String get ownerPrefix => owner.docName != '' ? owner.docName + '.' : '';
+ /// The prefix String to refer to the package that this item is in, for URLs
+ /// and comment resolution.
+ ///
+ /// The prefix can be prepended to a qualified name to get a fully unique
+ /// name among all packages.
String get packagePrefix => '';
- /// Documentation comment with converted markdown.
+ /// Documentation comment with converted markdown and all links resolved.
String _comment;
+ /// Accessor to documentation comment with markdown converted to html and all
+ /// links resolved.
String get comment {
if (_comment != null) return _comment;
@@ -706,30 +867,19 @@
set comment(x) => _comment = x;
- String get name => mirror.simpleName;
+ /// The simple name to refer to this item.
+ String get name => dart2js_util.nameOf(mirror);
+ /// Accessor to the parent item that owns this item.
+ ///
+ /// "Owning" is defined as the object one scope-level above which this item
+ /// is defined. Ex: The owner for a top level class, would be its enclosing
+ /// library. The owner of a local variable in a method would be the enclosing
+ /// method.
Indexable get owner => new DummyMirror(mirror.owner);
/// Generates MDN comments from database.json.
- String _mdnComment() {
- //Check if MDN is loaded.
- if (_mdn == null) {
- // Reading in MDN related json file.
- var root = _Generator._rootDirectory;
- var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
- _mdn = JSON.decode(new File(mdnPath).readAsStringSync());
- }
- // TODO: refactor OOP
- if (this is Library) return '';
- var domAnnotation = this.annotations.firstWhere(
- (e) => e.mirror.qualifiedName == 'metadata.DomName',
- orElse: () => null);
- if (domAnnotation == null) return '';
- var domName = domAnnotation.parameters.single;
- var parts = domName.split('.');
- if (parts.length == 2) return _mdnMemberComment(parts[0], parts[1]);
- if (parts.length == 1) return _mdnTypeComment(parts[0]);
- }
+ String _mdnComment();
/// Generates the MDN Comment for variables and method DOM elements.
String _mdnMemberComment(String type, String member) {
@@ -740,7 +890,7 @@
if (mdnMember == null) return '';
if (mdnMember['help'] == null || mdnMember['help'] == '') return '';
if (mdnMember['url'] == null) return '';
- return _htmlMdn(mdnMember['help'], mdnMember['url']);
+ return _htmlifyMdn(mdnMember['help'], mdnMember['url']);
}
/// Generates the MDN Comment for class DOM elements.
@@ -749,10 +899,11 @@
if (mdnType == null) return '';
if (mdnType['summary'] == null || mdnType['summary'] == "") return '';
if (mdnType['srcUrl'] == null) return '';
- return _htmlMdn(mdnType['summary'], mdnType['srcUrl']);
+ return _htmlifyMdn(mdnType['summary'], mdnType['srcUrl']);
}
- String _htmlMdn(String content, String url) {
+ /// Encloses the given content in an MDN div and the original source link.
+ String _htmlifyMdn(String content, String url) {
return '<div class="mdn">' + content.trim() + '<p class="mdn-note">'
'<a href="' + url.trim() + '">from Mdn</a></p></div>';
}
@@ -770,7 +921,9 @@
return finalMap;
}
- String _getCommentText() {
+ /// Accessor to obtain the raw comment text for a given item, _without_ any
+ /// of the links resolved.
+ String get _commentText {
String commentText;
mirror.metadata.forEach((metadata) {
if (metadata is CommentInstanceMirror) {
@@ -795,10 +948,10 @@
/// links to the subclasses's version of the methods.
String _commentToHtml([Indexable resolvingScope]) {
if (resolvingScope == null) resolvingScope = this;
- var commentText = _getCommentText();
+ var commentText = _commentText;
_unresolvedComment = commentText;
- var linkResolver = (name) => resolvingScope.fixReferenceWithScope(name);
+ var linkResolver = (name) => resolvingScope.fixReference(name);
commentText = commentText == null ? '' :
markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver,
inlineSyntaxes: _MARKDOWN_SYNTAXES);
@@ -809,16 +962,15 @@
/// The optional parameter [containingLibrary] is contains data for variables
/// defined at the top level of a library (potentially for exporting
/// purposes).
- Map<String, Variable> _createVariables(Map<String, VariableMirror> mirrorMap,
+ Map<String, Variable> _createVariables(Iterable<VariableMirror> mirrors,
Indexable owner) {
var data = {};
// TODO(janicejl): When map to map feature is created, replace the below
// with a filter. Issue(#9590).
- mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
+ mirrors.forEach((VariableMirror mirror) {
if (_Generator._includePrivate || !_isHidden(mirror)) {
- var variable = new Variable(mirrorName, mirror, owner);
- entityMap[variable.docName] = variable;
- data[mirrorName] = entityMap[variable.docName];
+ var mirrorName = dart2js_util.nameOf(mirror);
+ data[mirrorName] = new Variable(mirrorName, mirror, owner);
}
});
return data;
@@ -828,14 +980,12 @@
/// The optional parameter [containingLibrary] is contains data for variables
/// defined at the top level of a library (potentially for exporting
/// purposes).
- Map<String, Method> _createMethods(Map<String, MethodMirror> mirrorMap,
+ Map<String, Method> _createMethods(Iterable<MethodMirror> mirrors,
Indexable owner) {
var group = new Map<String, Method>();
- mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
+ mirrors.forEach((MethodMirror mirror) {
if (_Generator._includePrivate || !mirror.isPrivate) {
- var method = new Method(mirror, owner);
- entityMap[method.docName] = method;
- group[mirror.simpleName] = method;
+ group[dart2js_util.nameOf(mirror)] = new Method(mirror, owner);
}
});
return group;
@@ -846,15 +996,16 @@
Indexable owner) {
var data = {};
mirrorList.forEach((ParameterMirror mirror) {
- data[mirror.simpleName] = new Parameter(mirror, _getOwningLibrary(owner));
+ data[dart2js_util.nameOf(mirror)] =
+ new Parameter(mirror, _getOwningLibrary(owner));
});
return data;
}
/// Returns a map of [Generic] objects constructed from the class mirror.
- Map<String, Generic> _createGenerics(ClassMirror mirror) {
+ Map<String, Generic> _createGenerics(TypeMirror mirror) {
return new Map.fromIterable(mirror.typeVariables,
- key: (e) => e.toString(),
+ key: (e) => dart2js_util.nameOf(e),
value: (e) => new Generic(e));
}
@@ -862,8 +1013,7 @@
String toString() => "${super.toString()}(${name.toString()})";
/// Return a map representation of this type.
- Map toMap() {}
-
+ Map toMap();
/// A declaration is private if itself is private, or the owner is private.
// Issue(12202) - A declaration is public even if it's owner is private.
@@ -884,13 +1034,14 @@
///
/// An example that starts with _ is _js_helper.
/// An example that contains ._ is dart._collection.dev
- // This is because LibraryMirror.isPrivate returns `false` all the time.
bool _isLibraryPrivate(LibraryMirror mirror) {
- var sdkLibrary = LIBRARIES[mirror.simpleName];
+ // This method is needed because LibraryMirror.isPrivate returns `false` all
+ // the time.
+ var sdkLibrary = LIBRARIES[dart2js_util.nameOf(mirror)];
if (sdkLibrary != null) {
return !sdkLibrary.documented;
- } else if (mirror.simpleName.startsWith('_') ||
- mirror.simpleName.contains('._')) {
+ } else if (dart2js_util.nameOf(mirror).startsWith('_') ||
+ dart2js_util.nameOf(mirror).contains('._')) {
return true;
}
return false;
@@ -1011,16 +1162,18 @@
return null;
}
- Map expandMethodMap(Map<String, Method> mapToExpand) => {
- 'setters': recurseMap(_filterMap(new Map(), mapToExpand,
+ /// Expand the method map [mapToExpand] into a more detailed map that
+ /// separates out setters, getters, constructors, operators, and methods.
+ Map _expandMethodMap(Map<String, Method> mapToExpand) => {
+ 'setters': recurseMap(_filterMap(mapToExpand,
(key, val) => val.mirror.isSetter)),
- 'getters': recurseMap(_filterMap(new Map(), mapToExpand,
+ 'getters': recurseMap(_filterMap(mapToExpand,
(key, val) => val.mirror.isGetter)),
- 'constructors': recurseMap(_filterMap(new Map(), mapToExpand,
+ 'constructors': recurseMap(_filterMap(mapToExpand,
(key, val) => val.mirror.isConstructor)),
- 'operators': recurseMap(_filterMap(new Map(), mapToExpand,
+ 'operators': recurseMap(_filterMap(mapToExpand,
(key, val) => val.mirror.isOperator)),
- 'methods': recurseMap(_filterMap(new Map(), mapToExpand,
+ 'methods': recurseMap(_filterMap(mapToExpand,
(key, val) => val.mirror.isRegularMethod && !val.mirror.isOperator))
};
@@ -1037,14 +1190,16 @@
return outputMap;
}
- Map _filterMap(exported, map, test) {
+ Map _filterMap(Map map, Function test) {
+ var exported = new Map();
map.forEach((key, value) {
if (test(key, value)) exported[key] = value;
});
return exported;
}
- bool get _isVisible => _Generator._includePrivate || !isPrivate;
+ /// Accessor to determine if this item and all of its owners are visible.
+ bool get _isVisible => _Generator._isFullChainVisible(this);
/// Given a Dart2jsMirror, find the corresponding Docgen [MirrorBased] object.
///
@@ -1056,7 +1211,7 @@
static Indexable getDocgenObject(DeclarationMirror mirror,
[Indexable owner]) {
Map<String, Set<Indexable>> docgenObj =
- _mirrorToDocgen[mirror.qualifiedName];
+ _mirrorToDocgen[dart2js_util.qualifiedNameOf(mirror)];
if (docgenObj == null) {
return new DummyMirror(mirror, owner);
}
@@ -1090,6 +1245,8 @@
return new DummyMirror(mirror, owner);
}
+ /// Returns true if [mirror] is the correct type of mirror that this Docgen
+ /// object wraps. (Workaround for the fact that Types are not first class.)
bool _isValidMirror(DeclarationMirror mirror);
}
@@ -1107,7 +1264,7 @@
Map<String, Class> errors = {};
String packageName = '';
- bool hasBeenCheckedForPackage = false;
+ bool _hasBeenCheckedForPackage = false;
String packageIntro;
/// Returns the [Library] for the given [mirror] if it has already been
@@ -1122,38 +1279,36 @@
Library._(LibraryMirror libraryMirror) : super(libraryMirror) {
var exported = _calcExportedItems(libraryMirror);
- var exportedClasses = exported['classes']..addAll(libraryMirror.classes);
+ var exportedClasses = _addAll(exported['classes'],
+ dart2js_util.typesOf(libraryMirror.declarations));
_findPackage(mirror);
classes = {};
typedefs = {};
errors = {};
- exportedClasses.forEach((String mirrorName, ClassMirror classMirror) {
- if (classMirror.isTypedef) {
+ exportedClasses.forEach((String mirrorName, TypeMirror mirror) {
+ if (mirror is TypedefMirror) {
// This is actually a Dart2jsTypedefMirror, and it does define value,
// but we don't have visibility to that type.
- var mirror = classMirror;
if (_Generator._includePrivate || !mirror.isPrivate) {
- var aTypedef = new Typedef(mirror, this);
- entityMap[Indexable.getDocgenObject(mirror).docName] = aTypedef;
- typedefs[mirror.simpleName] = aTypedef;
+ typedefs[dart2js_util.nameOf(mirror)] = new Typedef(mirror, this);
}
- } else {
- var clazz = new Class(classMirror, this);
+ } else if (mirror is ClassMirror) {
+ var clazz = new Class(mirror, this);
if (clazz.isError()) {
- errors[classMirror.simpleName] = clazz;
- } else if (classMirror.isClass) {
- classes[classMirror.simpleName] = clazz;
+ errors[dart2js_util.nameOf(mirror)] = clazz;
} else {
- throw new ArgumentError(
- '${classMirror.simpleName} - no class type match. ');
+ classes[dart2js_util.nameOf(mirror)] = clazz;
}
+ } else {
+ throw new ArgumentError(
+ '${dart2js_util.nameOf(mirror)} - no class type match. ');
}
});
- this.functions = _createMethods(exported['methods']
- ..addAll(libraryMirror.functions), this);
- this.variables = _createVariables(exported['variables']
- ..addAll(libraryMirror.variables), this);
+ this.functions = _createMethods(_addAll(exported['methods'],
+ dart2js_util.methodsOf(libraryMirror.declarations)).values, this);
+ this.variables = _createVariables(_addAll(exported['variables'],
+ dart2js_util.variablesOf(libraryMirror.declarations)).values, this);
}
/// Look for the specified name starting with the current member, and
@@ -1169,14 +1324,24 @@
return super.findElementInScope(name);
}
+ String _mdnComment() => '';
+
+ /// Helper that maps [mirrors] to their simple name in map.
+ Map _addAll(Map map, Iterable<DeclarationMirror> mirrors) {
+ for (var mirror in mirrors) {
+ map[dart2js_util.nameOf(mirror)] = mirror;
+ }
+ return map;
+ }
+
/// For a library's [mirror], determine the name of the package (if any) we
/// believe it came from (because of its file URI).
///
/// If no package could be determined, we return an empty string.
String _findPackage(LibraryMirror mirror) {
if (mirror == null) return '';
- if (hasBeenCheckedForPackage) return packageName;
- hasBeenCheckedForPackage = true;
+ if (_hasBeenCheckedForPackage) return packageName;
+ _hasBeenCheckedForPackage = true;
if (mirror.uri.scheme != 'file') return '';
// We assume that we are documenting only libraries under package/lib
packageName = _packageName(mirror);
@@ -1221,8 +1386,6 @@
return spec["name"];
}
- markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
String get packagePrefix => packageName == null || packageName.isEmpty ?
'' : '$packageName/';
@@ -1237,7 +1400,9 @@
String get name => docName;
- String get docName => mirror.qualifiedName.replaceAll('.','-');
+ String get docName {
+ return dart2js_util.qualifiedNameOf(mirror).replaceAll('.','-');
+ }
/// For the given library determine what items (if any) are exported.
///
@@ -1245,7 +1410,7 @@
/// values of which point to a map of exported name identifiers with values
/// corresponding to the actual DeclarationMirror.
Map<String, Map<String, DeclarationMirror>> _calcExportedItems(
- LibraryMirror library) {
+ LibrarySourceMirror library) {
var exports = {};
exports['classes'] = {};
exports['methods'] = {};
@@ -1257,9 +1422,12 @@
if (!showExport) {
// Add all items, and then remove the hidden ones.
// Ex: "export foo hide bar"
- exports['classes'].addAll(export.targetLibrary.classes);
- exports['methods'].addAll(export.targetLibrary.functions);
- exports['variables'].addAll(export.targetLibrary.variables);
+ _addAll(exports['classes'],
+ dart2js_util.typesOf(export.targetLibrary.declarations));
+ _addAll(exports['methods'],
+ dart2js_util.methodsOf(export.targetLibrary.declarations));
+ _addAll(exports['variables'],
+ dart2js_util.variablesOf(export.targetLibrary.declarations));
}
for (CombinatorMirror combinator in export.combinators) {
for (String identifier in combinator.identifiers) {
@@ -1270,7 +1438,7 @@
// (such as the polymer package) are curently broken in this
// way, so we just produce a warning.
print('Warning identifier $identifier not found in library '
- '${export.targetLibrary.qualifiedName}');
+ '${dart2js_util.qualifiedNameOf(export.targetLibrary)}');
} else {
var subMap = exports['classes'];
if (declaration is MethodMirror) {
@@ -1302,9 +1470,8 @@
}
/// Checks if the given name is a key for any of the Class Maps.
- bool containsKey(String name) {
- return classes.containsKey(name) || errors.containsKey(name);
- }
+ bool containsKey(String name) =>
+ classes.containsKey(name) || errors.containsKey(name);
/// Generates a map describing the [Library] object.
Map toMap() => {
@@ -1312,7 +1479,7 @@
'qualifiedName': qualifiedName,
'comment': comment,
'variables': recurseMap(variables),
- 'functions': expandMethodMap(functions),
+ 'functions': _expandMethodMap(functions),
'classes': {
'class': classes.values.where((c) => c._isVisible)
.map((e) => e.previewMap).toList(),
@@ -1330,14 +1497,42 @@
}
abstract class OwnedIndexable extends Indexable {
+ /// The object one scope-level above which this item is defined.
+ ///
+ /// Ex: The owner for a top level class, would be its enclosing library.
+ /// The owner of a local variable in a method would be the enclosing method.
Indexable owner;
+ /// List of the meta annotations on this item.
+ List<Annotation> annotations;
+
/// Returns this object's qualified name, but following the conventions
/// we're using in Dartdoc, which is that library names with dots in them
/// have them replaced with hyphens.
- String get docName => owner.docName + '.' + mirror.simpleName;
+ String get docName => owner.docName + '.' + dart2js_util.nameOf(mirror);
OwnedIndexable(DeclarationMirror mirror, this.owner) : super(mirror);
+
+ /// Generates MDN comments from database.json.
+ String _mdnComment() {
+ //Check if MDN is loaded.
+ if (Indexable._mdn == null) {
+ // Reading in MDN related json file.
+ var root = _Generator._rootDirectory;
+ var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
+ Indexable._mdn = JSON.decode(new File(mdnPath).readAsStringSync());
+ }
+ var domAnnotation = this.annotations.firstWhere(
+ (e) => e.mirror.qualifiedName == 'metadata.DomName',
+ orElse: () => null);
+ if (domAnnotation == null) return '';
+ var domName = domAnnotation.parameters.single;
+ var parts = domName.split('.');
+ if (parts.length == 2) return _mdnMemberComment(parts[0], parts[1]);
+ if (parts.length == 1) return _mdnTypeComment(parts[0]);
+ }
+
+ String get packagePrefix => owner.packagePrefix;
}
/// A class containing contents of a Dart class.
@@ -1366,9 +1561,6 @@
Class superclass;
bool isAbstract;
- /// List of the meta annotations on the class.
- List<Annotation> annotations;
-
/// Make sure that we don't check for inherited comments more than once.
bool _commentsEnsured = false;
@@ -1378,7 +1570,6 @@
var clazz = Indexable.getDocgenObject(mirror, owner);
if (clazz is DummyMirror) {
clazz = new Class._(mirror, owner);
- entityMap[clazz.docName] = clazz;
}
return clazz;
}
@@ -1401,7 +1592,7 @@
}
}
- Class._(ClassMirror classMirror, Indexable owner) :
+ Class._(ClassSourceMirror classMirror, Indexable owner) :
super(classMirror, owner) {
inheritedVariables = {};
@@ -1413,27 +1604,25 @@
new Class._possiblyDifferentOwner(classMirror.superclass, owner);
interfaces = superinterfaces.toList();
- variables = _createVariables(classMirror.variables, this);
- methods = _createMethods(classMirror.methods, this);
+ variables = _createVariables(
+ dart2js_util.variablesOf(classMirror.declarations), this);
+ methods = _createMethods(classMirror.declarations.values.where(
+ (mirror) => mirror is MethodMirror), this);
annotations = _createAnnotations(classMirror, _getOwningLibrary(owner));
generics = _createGenerics(classMirror);
isAbstract = classMirror.isAbstract;
inheritedMethods = new Map<String, Method>();
- // Tell all superclasses that you are a subclass, unless you are not
+ // Tell superclass that you are a subclass, unless you are not
// visible or an intermediary mixin class.
- if (!classMirror.isNameSynthetic && _isVisible) {
- parentChain().forEach((parentClass) {
- parentClass.addSubclass(this);
- });
+ if (!classMirror.isNameSynthetic && _isVisible && superclass != null) {
+ superclass.addSubclass(this);
}
if (this.superclass != null) addInherited(superclass);
interfaces.forEach((interface) => addInherited(interface));
}
- String get packagePrefix => owner.packagePrefix;
-
String _lookupInClassAndSuperclasses(String name) {
var lookupFunc = Indexable.determineLookupFunc(name);
var classScope = this;
@@ -1459,17 +1648,8 @@
return result == null ? super.findElementInScope(name) : result;
}
- markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
String get typeName => 'class';
- /// Returns a list of all the parent classes.
- List<Class> parentChain() {
- // TODO(efortuna): Seems like we can get rid of this method.
- var parent = superclass == null ? [] : [superclass];
- return parent;
- }
-
/// Add all inherited variables and methods from the provided superclass.
/// If [_includePrivate] is true, it also adds the variables and methods from
/// the superclass.
@@ -1559,7 +1739,7 @@
/// If a class extends a private superclass, find the closest public
/// superclass of the private superclass.
String validSuperclass() {
- if (superclass == null) return 'dart.core.Object';
+ if (superclass == null) return 'dart-core.Object';
if (superclass._isVisible) return superclass.qualifiedName;
return superclass.validSuperclass();
}
@@ -1577,8 +1757,8 @@
.map((x) => x.qualifiedName).toList(),
'variables': recurseMap(variables),
'inheritedVariables': recurseMap(inheritedVariables),
- 'methods': expandMethodMap(methods),
- 'inheritedMethods': expandMethodMap(inheritedMethods),
+ 'methods': _expandMethodMap(methods),
+ 'inheritedMethods': _expandMethodMap(inheritedMethods),
'annotations': annotations.map((a) => a.toMap()).toList(),
'generics': recurseMap(generics)
};
@@ -1596,9 +1776,6 @@
/// Generic information about the typedef.
Map<String, Generic> generics;
- /// List of the meta annotations on the typedef.
- List<Annotation> annotations;
-
/// Returns the [Library] for the given [mirror] if it has already been
/// created, else creates it.
factory Typedef(TypedefMirror mirror, Library owningLibrary) {
@@ -1611,9 +1788,9 @@
Typedef._(TypedefMirror mirror, Library owningLibrary) :
super(mirror, owningLibrary) {
- returnType = Indexable.getDocgenObject(mirror.value.returnType).docName;
+ returnType = Indexable.getDocgenObject(mirror.referent.returnType).docName;
generics = _createGenerics(mirror);
- parameters = _createParameters(mirror.value.parameters, owningLibrary);
+ parameters = _createParameters(mirror.referent.parameters, owningLibrary);
annotations = _createAnnotations(mirror, owningLibrary);
}
@@ -1627,6 +1804,8 @@
'generics': recurseMap(generics)
};
+ markdown.Node fixReference(String name) => null;
+
String get typeName => 'typedef';
bool _isValidMirror(DeclarationMirror mirror) => mirror is TypedefMirror;
@@ -1641,9 +1820,6 @@
Type type;
String _variableName;
- /// List of the meta annotations on the variable.
- List<Annotation> annotations;
-
factory Variable(String variableName, VariableMirror mirror,
Indexable owner) {
var variable = Indexable.getDocgenObject(mirror);
@@ -1676,8 +1852,6 @@
'annotations': annotations.map((a) => a.toMap()).toList()
};
- String get packagePrefix => owner.packagePrefix;
-
String get typeName => 'property';
get comment {
@@ -1688,8 +1862,6 @@
return super.comment;
}
- markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
String findElementInScope(String name) {
var lookupFunc = Indexable.determineLookupFunc(name);
var result = lookupFunc(mirror, name);
@@ -1726,10 +1898,7 @@
/// Qualified name to state where the comment is inherited from.
String commentInheritedFrom = "";
- /// List of the meta annotations on the method.
- List<Annotation> annotations;
-
- factory Method(MethodMirror mirror, Indexable owner, // Indexable newOwner.
+ factory Method(MethodMirror mirror, Indexable owner,
[Method methodInheritedFrom]) {
var method = Indexable.getDocgenObject(mirror, owner);
if (method is DummyMirror) {
@@ -1748,13 +1917,9 @@
annotations = _createAnnotations(mirror, _getOwningLibrary(owner));
}
- String get packagePrefix => owner.packagePrefix;
-
Method get originallyInheritedFrom => methodInheritedFrom == null ?
this : methodInheritedFrom.originallyInheritedFrom;
- markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
/// Look for the specified name starting with the current member, and
/// progressively working outward to the current library scope.
String findElementInScope(String name) {
@@ -1786,7 +1951,8 @@
if ((mirror as MethodMirror).isConstructor) {
// We name constructors specially -- including the class name again and a
// "-" to separate the constructor from its name (if any).
- return '${owner.docName}.${mirror.owner.simpleName}-${mirror.simpleName}';
+ return '${owner.docName}.${dart2js_util.nameOf(mirror.owner)}-'
+ '${dart2js_util.nameOf(mirror)}';
}
return super.docName;
}
@@ -1838,14 +2004,16 @@
}
var result = super.comment;
if (result == '' && methodInheritedFrom != null) {
- // this should be NOT from the MIRROR, but from the COMMENT
+ // This should be NOT from the MIRROR, but from the COMMENT.
+ methodInheritedFrom.comment; // Ensure comment field has been populated.
_unresolvedComment = methodInheritedFrom._unresolvedComment;
- var linkResolver = (name) => fixReferenceWithScope(name);
+ var linkResolver = (name) => fixReference(name);
comment = _unresolvedComment == null ? '' :
markdown.markdownToHtml(_unresolvedComment.trim(),
linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
- commentInheritedFrom = methodInheritedFrom.commentInheritedFrom;
+ commentInheritedFrom = comment != '' ?
+ methodInheritedFrom.commentInheritedFrom : '';
result = comment;
}
return result;
@@ -1868,11 +2036,11 @@
List<Annotation> annotations;
Parameter(this.mirror, Library owningLibrary) {
- name = mirror.simpleName;
+ name = dart2js_util.nameOf(mirror);
isOptional = mirror.isOptional;
isNamed = mirror.isNamed;
hasDefaultValue = mirror.hasDefaultValue;
- defaultValue = mirror.defaultValue;
+ defaultValue = '${mirror.defaultValue}';
type = new Type(mirror.type, owningLibrary);
annotations = _createAnnotations(mirror, owningLibrary);
}
@@ -1894,8 +2062,8 @@
TypeVariableMirror mirror;
Generic(this.mirror);
Map toMap() => {
- 'name': mirror.toString(),
- 'type': mirror.upperBound.qualifiedName
+ 'name': dart2js_util.nameOf(mirror),
+ 'type': dart2js_util.qualifiedNameOf(mirror.upperBound)
};
}
@@ -1936,7 +2104,7 @@
/// Returns a list of [Type] objects constructed from TypeMirrors.
List<Type> _createTypeGenerics(TypeMirror mirror) {
- if (mirror is ClassMirror && !mirror.isTypedef) {
+ if (mirror is ClassMirror) {
var innerList = [];
mirror.typeArguments.forEach((e) {
innerList.add(new Type(e, owningLibrary));
@@ -1966,7 +2134,7 @@
Annotation(InstanceMirror originalMirror, this.owningLibrary) {
mirror = originalMirror.type;
- parameters = originalMirror.type.variables.values
+ parameters = dart2js_util.variablesOf(originalMirror.type.declarations)
.where((e) => e.isFinal)
.map((e) => originalMirror.getField(e.simpleName).reflectee)
.where((e) => e != null)
@@ -1977,4 +2145,4 @@
'name': Indexable.getDocgenObject(mirror, owningLibrary).docName,
'parameters': parameters
};
-}
\ No newline at end of file
+}
diff --git a/pkg/docgen/test/multi_library_test.dart b/pkg/docgen/test/multi_library_test.dart
index f4d91d9..79a1431 100644
--- a/pkg/docgen/test/multi_library_test.dart
+++ b/pkg/docgen/test/multi_library_test.dart
@@ -6,6 +6,8 @@
import 'package:unittest/unittest.dart';
import '../lib/docgen.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart'
+ as dart2js_util;
const String DART_LIBRARY_1 = '''
library testLib;
@@ -104,8 +106,9 @@
var fileName3 = path.join(TEMP_DIRNAME.path, 'temp3.dart');
file = new File(fileName3);
file.writeAsStringSync(DART_LIBRARY_3);
- return [new Uri.file(fileName), new Uri.file(fileName3),
- new Uri.file(fileName3)];
+ return [new Uri.file(fileName, windows: Platform.isWindows),
+ new Uri.file(fileName2, windows: Platform.isWindows),
+ new Uri.file(fileName3, windows: Platform.isWindows)];
}
main() {
@@ -126,8 +129,10 @@
// Test for linking to parameter [c]
var importedLib = libraryMirror.libraryDependencies.firstWhere(
(dep) => dep.isImport).targetLibrary;
- var aClassMirror = importedLib.classes.values.first;
- expect(aClassMirror.qualifiedName, 'testLib2.foo.B');
+ var aClassMirror =
+ dart2js_util.classesOf(importedLib.declarations).first;
+ expect(dart2js_util.qualifiedNameOf(aClassMirror),
+ 'testLib2.foo.B');
var exportedClass = Indexable.getDocgenObject(aClassMirror, library);
expect(exportedClass is Class, isTrue);
@@ -152,10 +157,12 @@
// Test a third library referencing another exported library in a
// separate file.
importedLib = libraryMirror.libraryDependencies.firstWhere(
- (dep) => dep.isImport && dep.targetLibrary.qualifiedName ==
+ (dep) => dep.isImport &&
+ dart2js_util.qualifiedNameOf(dep.targetLibrary) ==
'testLib.bar').targetLibrary;
- aClassMirror = importedLib.classes.values.first;
- expect(aClassMirror.qualifiedName, 'testLib.bar.C');
+ aClassMirror = dart2js_util.classesOf(importedLib.declarations).first;
+ expect(dart2js_util.qualifiedNameOf(aClassMirror),
+ 'testLib.bar.C');
exportedClass = Indexable.getDocgenObject(aClassMirror, library);
expect(exportedClass is Class, isTrue);
expect(exportedClass.docName, 'testLib.C');
diff --git a/pkg/docgen/test/single_library_test.dart b/pkg/docgen/test/single_library_test.dart
index 3ce19a3..ea5ad6b 100644
--- a/pkg/docgen/test/single_library_test.dart
+++ b/pkg/docgen/test/single_library_test.dart
@@ -6,6 +6,8 @@
import 'package:unittest/unittest.dart';
import '../lib/docgen.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart'
+ as dart2js_util;
const String DART_LIBRARY = '''
library test;
@@ -48,8 +50,8 @@
file.writeAsStringSync(DART_LIBRARY);
getMirrorSystem([new Uri.file(fileName)])
.then(expectAsync1((mirrorSystem) {
- var testLibraryUri = new Uri(scheme: 'file',
- path: path.absolute(fileName));
+ var testLibraryUri = new Uri.file(path.absolute(fileName),
+ windows: Platform.isWindows);
var library = new Library(mirrorSystem.libraries[testLibraryUri]);
expect(library is Library, isTrue);
@@ -99,12 +101,14 @@
/// Testing fixReference
// Testing Doc comment for class [A].
var libraryMirror = mirrorSystem.libraries[testLibraryUri];
- var classMirror = libraryMirror.classes.values.first;
+ var classMirror =
+ dart2js_util.classesOf(libraryMirror.declarations).first;
var classDocComment = library.fixReference('A').children.first.text;
expect(classDocComment, 'test.A');
// Test for linking to parameter [A]
- var method = Indexable.getDocgenObject(classMirror.methods['doThis']);
+ var method = Indexable.getDocgenObject(
+ classMirror.declarations[dart2js_util.symbolOf('doThis')]);
var methodParameterDocComment = method.fixReference(
'A').children.first.text;
expect(methodParameterDocComment, 'test.A.doThis.A');
diff --git a/pkg/intl/example/basic/basic_example.dart b/pkg/intl/example/basic/basic_example.dart
index 41a63a0..4a8c5c3 100644
--- a/pkg/intl/example/basic/basic_example.dart
+++ b/pkg/intl/example/basic/basic_example.dart
@@ -69,5 +69,5 @@
var dayFormat = intl.date().add_yMMMMEEEEd();
var time = hmsFormat.format(aDate);
var day = dayFormat.format(aDate);
- Intl.withLocale(intl.locale, () => doThisWithTheOutput(operation(time,day)));
+ Intl.withLocale(intl.locale, () => doThisWithTheOutput(operation(time, day)));
}
diff --git a/pkg/intl/example/basic/basic_example_runner.dart b/pkg/intl/example/basic/basic_example_runner.dart
index 91bbfdd..805d4f7 100644
--- a/pkg/intl/example/basic/basic_example_runner.dart
+++ b/pkg/intl/example/basic/basic_example_runner.dart
@@ -11,4 +11,4 @@
main() {
setup(runProgram, print);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/example/basic/messages_all.dart b/pkg/intl/example/basic/messages_all.dart
index 78cb5f0..9265784 100644
--- a/pkg/intl/example/basic/messages_all.dart
+++ b/pkg/intl/example/basic/messages_all.dart
@@ -35,4 +35,4 @@
var actualLocale = Intl.verifiedLocale(locale, (x) => _findExact(x) != null);
if (actualLocale == null) return null;
return _findExact(actualLocale);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/example/basic/messages_de.dart b/pkg/intl/example/basic/messages_de.dart
index d18c981..c0145c4 100644
--- a/pkg/intl/example/basic/messages_de.dart
+++ b/pkg/intl/example/basic/messages_de.dart
@@ -18,7 +18,7 @@
get localeName => 'de';
final messages = {
- "runAt" : (time, day) => Intl.message("Ausgedruckt am $time am $day.")
+ "runAt": (time, day) => Intl.message("Ausgedruckt am $time am $day.")
};
}
diff --git a/pkg/intl/example/basic/messages_th_th.dart b/pkg/intl/example/basic/messages_th_th.dart
index 59c98dc..5d3813e 100644
--- a/pkg/intl/example/basic/messages_th_th.dart
+++ b/pkg/intl/example/basic/messages_th_th.dart
@@ -18,6 +18,6 @@
get localeName => 'th_TH';
final messages = {
- "runAt" : (time, day) => Intl.message('วิ่ง $time on $day.')
+ "runAt": (time, day) => Intl.message('วิ่ง $time on $day.')
};
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/bidi_formatter.dart b/pkg/intl/lib/bidi_formatter.dart
index 048a9de..5f23d3f 100644
--- a/pkg/intl/lib/bidi_formatter.dart
+++ b/pkg/intl/lib/bidi_formatter.dart
@@ -108,11 +108,11 @@
if (directionChange) {
spanDirection = ' dir=${direction.spanText}';
}
- result= '<span$spanDirection>$text</span>';
+ result = '<span$spanDirection>$text</span>';
} else {
result = text;
}
- return result + (resetDir? _resetDir(text, direction, isHtml) : '');
+ return result + (resetDir ? _resetDir(text, direction, isHtml) : '');
}
/**
@@ -143,7 +143,7 @@
result = "${marker}$text${Bidi.PDF}";
}
- return result + (resetDir? _resetDir(text, direction, isHtml) : '');
+ return result + (resetDir ? _resetDir(text, direction, isHtml) : '');
}
/**
@@ -172,11 +172,7 @@
(contextDirection == TextDirection.RTL &&
(direction == TextDirection.LTR ||
Bidi.endsWithLtr(text, isHtml)))) {
- if (contextDirection == TextDirection.LTR) {
- return Bidi.LRM;
- } else {
- return Bidi.RLM;
- }
+ return contextDirection == TextDirection.LTR ? Bidi.LRM : Bidi.RLM;
} else {
return '';
}
diff --git a/pkg/intl/lib/bidi_utils.dart b/pkg/intl/lib/bidi_utils.dart
index e4599da..3ef2c80 100644
--- a/pkg/intl/lib/bidi_utils.dart
+++ b/pkg/intl/lib/bidi_utils.dart
@@ -45,9 +45,8 @@
* Returns true if [otherDirection] is known to be different from this
* direction.
*/
- bool isDirectionChange(TextDirection otherDirection) {
- return otherDirection != TextDirection.UNKNOWN && this != otherDirection;
- }
+ bool isDirectionChange(TextDirection otherDirection) =>
+ otherDirection != TextDirection.UNKNOWN && this != otherDirection;
}
/**
@@ -198,17 +197,14 @@
* will override existing one in behavior (should work on Chrome, FF, and IE
* since this was ported directly from the Closure version).
*/
- static String enforceRtlInHtml(String html) {
- return _enforceInHtmlHelper(html, 'rtl');
- }
+ static String enforceRtlInHtml(String html) =>
+ _enforceInHtmlHelper(html, 'rtl');
/**
* Enforce RTL on both end of the given [text] using unicode BiDi formatting
* characters RLE and PDF.
*/
- static String enforceRtlInText(String text) {
- return '$RLE$text$PDF';
- }
+ static String enforceRtlInText(String text) => '$RLE$text$PDF';
/**
* Enforce the [html] snippet in LTR directionality regardless of overall
@@ -218,17 +214,14 @@
* the whole piece. If the tag already has a direction specified, this new one
* will override existing one in behavior (tested on FF and IE).
*/
- static String enforceLtrInHtml(String html) {
- return _enforceInHtmlHelper(html, 'ltr');
- }
+ static String enforceLtrInHtml(String html) =>
+ _enforceInHtmlHelper(html, 'ltr');
/**
* Enforce LTR on both end of the given [text] using unicode BiDi formatting
* characters LRE and PDF.
*/
- static String enforceLtrInText(String text) {
- return '$LRE$text$PDF';
- }
+ static String enforceLtrInText(String text) => '$LRE$text$PDF';
/**
* Enforce the [html] snippet in the desired [direction] regardless of overall
@@ -294,16 +287,15 @@
// See Issue 2979.
static String _guardBracketHelper(String str, RegExp regexp, [String before,
String after]) {
- StringBuffer buffer = new StringBuffer();
+ var buffer = new StringBuffer();
var startIndex = 0;
- Iterable matches = regexp.allMatches(str);
- for (Match match in matches) {
+ regexp.allMatches(str).forEach((match) {
buffer..write(str.substring(startIndex, match.start))
..write(before)
..write(str.substring(match.start, match.end))
..write(after);
startIndex = match.end;
- }
+ });
return (buffer..write(str.substring(startIndex))).toString();
}
@@ -371,7 +363,7 @@
&& new RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
buf.write('\u05f3');
} else {
- buf.write(str.substring(i, i+1));
+ buf.write(str.substring(i, i + 1));
}
}
return buf.toString();
@@ -382,7 +374,6 @@
* text should be laid out in RTL direction. If [isHtml] is true, the string
* is HTML or HTML-escaped.
*/
- static bool detectRtlDirectionality(String str, {bool isHtml: false}) {
- return estimateDirectionOfText(str, isHtml: isHtml) == TextDirection.RTL;
- }
+ static bool detectRtlDirectionality(String str, {bool isHtml: false}) =>
+ estimateDirectionOfText(str, isHtml: isHtml) == TextDirection.RTL;
}
diff --git a/pkg/intl/lib/date_format.dart b/pkg/intl/lib/date_format.dart
index 0a53f48..d2889ec 100644
--- a/pkg/intl/lib/date_format.dart
+++ b/pkg/intl/lib/date_format.dart
@@ -237,18 +237,14 @@
* something has happened or how long in the future something will happen
* given a [reference] DateTime relative to the current time.
*/
- String formatDuration(DateTime reference) {
- return '';
- }
+ String formatDuration(DateTime reference) => '';
/**
* Formats a string indicating how long ago (negative [duration]) or how far
* in the future (positive [duration]) some time is with respect to a
* reference [date].
*/
- String formatDurationFrom(Duration duration, DateTime date) {
- return '';
- }
+ String formatDurationFrom(Duration duration, DateTime date) => '';
/**
* Given user input, attempt to parse the [inputString] into the anticipated
@@ -259,10 +255,9 @@
// TODO(alanknight): The Closure code refers to special parsing of numeric
// values with no delimiters, which we currently don't do. Should we?
var dateFields = new _DateBuilder();
- if (utc) dateFields.utc=true;
+ if (utc) dateFields.utc = true;
var stream = new _Stream(inputString);
- _formatFields.forEach(
- (each) => each.parse(stream, dateFields));
+ _formatFields.forEach((f) => f.parse(stream, dateFields));
return dateFields.asDate();
}
@@ -270,9 +265,7 @@
* Given user input, attempt to parse the [inputString] into the anticipated
* format, treating it as being in UTC.
*/
- DateTime parseUTC(String inputString) {
- return parse(inputString, true);
- }
+ DateTime parseUTC(String inputString) => parse(inputString, true);
/**
* Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
@@ -497,11 +490,9 @@
* space to separate the two.
*/
_appendPattern(String inputPattern, [String separator = ' ']) {
- if (_pattern == null) {
- _pattern = inputPattern;
- } else {
- _pattern = "$_pattern$separator$inputPattern";
- }
+ _pattern = _pattern == null ?
+ inputPattern :
+ "$_pattern$separator$inputPattern";
}
/**
@@ -530,9 +521,7 @@
get pattern => _pattern;
/** Return the skeletons for our current locale. */
- Map get _availableSkeletons {
- return dateTimePatterns[locale];
- }
+ Map get _availableSkeletons => dateTimePatterns[locale];
/**
* Return the [DateSymbol] information for the locale. This can be useful
@@ -582,7 +571,7 @@
if (matched == null) return [];
var parsed = _parsePatternHelper(
- pattern.substring(matched.fullPattern().length));
+ pattern.substring(matched.fullPattern().length));
parsed.add(matched);
return parsed;
}
diff --git a/pkg/intl/lib/date_symbol_data_file.dart b/pkg/intl/lib/date_symbol_data_file.dart
index a418a9c..a4a67fe 100644
--- a/pkg/intl/lib/date_symbol_data_file.dart
+++ b/pkg/intl/lib/date_symbol_data_file.dart
@@ -40,6 +40,5 @@
}
/** Defines how new date symbol entries are created. */
-DateSymbols _createDateSymbol(Map map) {
- return new DateSymbols.deserializeFromMap(map);
-}
+DateSymbols _createDateSymbol(Map map) =>
+ new DateSymbols.deserializeFromMap(map);
diff --git a/pkg/intl/lib/date_symbol_data_http_request.dart b/pkg/intl/lib/date_symbol_data_http_request.dart
index 20d35a1..3fe56c6 100644
--- a/pkg/intl/lib/date_symbol_data_http_request.dart
+++ b/pkg/intl/lib/date_symbol_data_http_request.dart
@@ -41,6 +41,5 @@
}
/** Defines how new date symbol entries are created. */
-DateSymbols _createDateSymbol(Map map) {
- return new DateSymbols.deserializeFromMap(map);
-}
+DateSymbols _createDateSymbol(Map map) =>
+ new DateSymbols.deserializeFromMap(map);
diff --git a/pkg/intl/lib/date_symbols.dart b/pkg/intl/lib/date_symbols.dart
index cd0b9d2..aa76c41 100644
--- a/pkg/intl/lib/date_symbols.dart
+++ b/pkg/intl/lib/date_symbols.dart
@@ -82,34 +82,32 @@
FIRSTWEEKCUTOFFDAY = map["FIRSTWEEKCUTOFFDAY"];
}
- Map serializeToMap() {
- var map = new Map();
- map["NAME"] = NAME;
- map["ERAS"] = ERAS;
- map["ERANAMES"] = ERANAMES;
- map["NARROWMONTHS"] = NARROWMONTHS;
- map["STANDALONENARROWMONTHS"] = STANDALONENARROWMONTHS;
- map["MONTHS"] = MONTHS;
- map["STANDALONEMONTHS"] = STANDALONEMONTHS;
- map["SHORTMONTHS"] = SHORTMONTHS;
- map["STANDALONESHORTMONTHS"] = STANDALONESHORTMONTHS;
- map["WEEKDAYS"] = WEEKDAYS;
- map["STANDALONEWEEKDAYS"] = STANDALONEWEEKDAYS;
- map["SHORTWEEKDAYS"] = SHORTWEEKDAYS;
- map["STANDALONESHORTWEEKDAYS"] = STANDALONESHORTWEEKDAYS;
- map["NARROWWEEKDAYS"] = NARROWWEEKDAYS;
- map["STANDALONENARROWWEEKDAYS"] = STANDALONENARROWWEEKDAYS;
- map["SHORTQUARTERS"] = SHORTQUARTERS;
- map["QUARTERS"] = QUARTERS;
- map["AMPMS"] = AMPMS;
- map["DATEFORMATS"] = DATEFORMATS;
- map["TIMEFORMATS"] = TIMEFORMATS;
- map["AVAILABLEFORMATS"] = AVAILABLEFORMATS;
- map["FIRSTDAYOFWEEK"] = FIRSTDAYOFWEEK;
- map["WEEKENDRANGE"] = WEEKENDRANGE;
- map["FIRSTWEEKCUTOFFDAY"] = FIRSTWEEKCUTOFFDAY;
- return map;
- }
+ Map serializeToMap() => {
+ "NAME": NAME,
+ "ERAS": ERAS,
+ "ERANAMES": ERANAMES,
+ "NARROWMONTHS": NARROWMONTHS,
+ "STANDALONENARROWMONTHS": STANDALONENARROWMONTHS,
+ "MONTHS": MONTHS,
+ "STANDALONEMONTHS": STANDALONEMONTHS,
+ "SHORTMONTHS": SHORTMONTHS,
+ "STANDALONESHORTMONTHS": STANDALONESHORTMONTHS,
+ "WEEKDAYS": WEEKDAYS,
+ "STANDALONEWEEKDAYS": STANDALONEWEEKDAYS,
+ "SHORTWEEKDAYS": SHORTWEEKDAYS,
+ "STANDALONESHORTWEEKDAYS": STANDALONESHORTWEEKDAYS,
+ "NARROWWEEKDAYS": NARROWWEEKDAYS,
+ "STANDALONENARROWWEEKDAYS": STANDALONENARROWWEEKDAYS,
+ "SHORTQUARTERS": SHORTQUARTERS,
+ "QUARTERS": QUARTERS,
+ "AMPMS": AMPMS,
+ "DATEFORMATS": DATEFORMATS,
+ "TIMEFORMATS": TIMEFORMATS,
+ "AVAILABLEFORMATS": AVAILABLEFORMATS,
+ "FIRSTDAYOFWEEK": FIRSTDAYOFWEEK,
+ "WEEKENDRANGE": WEEKENDRANGE,
+ "FIRSTWEEKCUTOFFDAY": FIRSTWEEKCUTOFFDAY
+ };
toString() => NAME;
}
@@ -201,4 +199,4 @@
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
-};
\ No newline at end of file
+};
diff --git a/pkg/intl/lib/date_time_patterns.dart b/pkg/intl/lib/date_time_patterns.dart
index 8c92c70..d392a22 100644
--- a/pkg/intl/lib/date_time_patterns.dart
+++ b/pkg/intl/lib/date_time_patterns.dart
@@ -20,7 +20,7 @@
/**
* Extended set of localized date/time patterns for locale af.
*/
- 'af' : const {
+ 'af': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -64,13 +64,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale am.
*/
- 'am' : const {
+ 'am': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -114,13 +114,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ar.
*/
- 'ar' : const {
+ 'ar': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -164,13 +164,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale bg.
*/
- 'bg' : const {
+ 'bg': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -214,13 +214,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale bn.
*/
- 'bn' : const {
+ 'bn': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -264,13 +264,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ca.
*/
- 'ca' : const {
+ 'ca': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -314,13 +314,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale cs.
*/
- 'cs' : const {
+ 'cs': const {
'd': 'd.', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -364,13 +364,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale da.
*/
- 'da' : const {
+ 'da': const {
'd': 'd.', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -414,13 +414,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale de.
*/
- 'de' : const {
+ 'de': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -464,13 +464,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale de_AT.
*/
- 'de_AT' : const {
+ 'de_AT': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -514,13 +514,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale de_CH.
*/
- 'de_CH' : const {
+ 'de_CH': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -564,13 +564,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale el.
*/
- 'el' : const {
+ 'el': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -614,13 +614,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en.
*/
- 'en' : const {
+ 'en': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -664,13 +664,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_AU.
*/
- 'en_AU' : const {
+ 'en_AU': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -714,13 +714,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_GB.
*/
- 'en_GB' : const {
+ 'en_GB': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -764,13 +764,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_IE.
*/
- 'en_IE' : const {
+ 'en_IE': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -814,13 +814,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_IN.
*/
- 'en_IN' : const {
+ 'en_IN': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -864,13 +864,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_SG.
*/
- 'en_SG' : const {
+ 'en_SG': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -914,13 +914,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_US.
*/
- 'en_US' : const {
+ 'en_US': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -964,13 +964,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_ISO.
*/
- 'en_ISO' : const {
+ 'en_ISO': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1014,13 +1014,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale en_ZA.
*/
- 'en_ZA' : const {
+ 'en_ZA': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1064,13 +1064,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale es.
*/
- 'es' : const {
+ 'es': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1114,13 +1114,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale es_419.
*/
- 'es_419' : const {
+ 'es_419': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1164,13 +1164,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale et.
*/
- 'et' : const {
+ 'et': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1214,13 +1214,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale eu.
*/
- 'eu' : const {
+ 'eu': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1264,13 +1264,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale fa.
*/
- 'fa' : const {
+ 'fa': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1314,13 +1314,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale fi.
*/
- 'fi' : const {
+ 'fi': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1364,13 +1364,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale fil.
*/
- 'fil' : const {
+ 'fil': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1414,13 +1414,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale fr.
*/
- 'fr' : const {
+ 'fr': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1464,13 +1464,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale fr_CA.
*/
- 'fr_CA' : const {
+ 'fr_CA': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1514,13 +1514,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale gl.
*/
- 'gl' : const {
+ 'gl': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1564,13 +1564,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale gsw.
*/
- 'gsw' : const {
+ 'gsw': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1614,13 +1614,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale gu.
*/
- 'gu' : const {
+ 'gu': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1664,13 +1664,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale he.
*/
- 'he' : const {
+ 'he': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1714,13 +1714,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale hi.
*/
- 'hi' : const {
+ 'hi': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1764,13 +1764,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale hr.
*/
- 'hr' : const {
+ 'hr': const {
'd': 'd.', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1814,13 +1814,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale hu.
*/
- 'hu' : const {
+ 'hu': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1864,13 +1864,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale id.
*/
- 'id' : const {
+ 'id': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1914,13 +1914,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale in.
*/
- 'in' : const {
+ 'in': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -1964,13 +1964,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale is.
*/
- 'is' : const {
+ 'is': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2014,13 +2014,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale it.
*/
- 'it' : const {
+ 'it': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2064,13 +2064,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale iw.
*/
- 'iw' : const {
+ 'iw': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2114,13 +2114,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ja.
*/
- 'ja' : const {
+ 'ja': const {
'd': 'd日', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2164,13 +2164,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale kn.
*/
- 'kn' : const {
+ 'kn': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2214,13 +2214,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ko.
*/
- 'ko' : const {
+ 'ko': const {
'd': 'd일', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2264,13 +2264,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ln.
*/
- 'ln' : const {
+ 'ln': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2314,13 +2314,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale lt.
*/
- 'lt' : const {
+ 'lt': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2364,13 +2364,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale lv.
*/
- 'lv' : const {
+ 'lv': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2414,13 +2414,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ml.
*/
- 'ml' : const {
+ 'ml': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2464,13 +2464,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale mr.
*/
- 'mr' : const {
+ 'mr': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2514,13 +2514,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ms.
*/
- 'ms' : const {
+ 'ms': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2564,13 +2564,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale mt.
*/
- 'mt' : const {
+ 'mt': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2614,13 +2614,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale nl.
*/
- 'nl' : const {
+ 'nl': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2664,13 +2664,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale no.
*/
- 'no' : const {
+ 'no': const {
'd': 'd.', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2714,13 +2714,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale or.
*/
- 'or' : const {
+ 'or': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2764,13 +2764,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale pl.
*/
- 'pl' : const {
+ 'pl': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2814,13 +2814,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale pt_BR.
*/
- 'pt_BR' : const {
+ 'pt_BR': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2864,13 +2864,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale pt_PT.
*/
- 'pt_PT' : const {
+ 'pt_PT': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2914,13 +2914,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale pt.
*/
- 'pt' : const {
+ 'pt': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -2964,13 +2964,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ro.
*/
- 'ro' : const {
+ 'ro': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3014,13 +3014,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ru.
*/
- 'ru' : const {
+ 'ru': const {
'd': 'd', // DAY
'E': 'ccc', // ABBR_WEEKDAY
'EEEE': 'cccc', // WEEKDAY
@@ -3064,13 +3064,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale sk.
*/
- 'sk' : const {
+ 'sk': const {
'd': 'd.', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3114,13 +3114,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale sl.
*/
- 'sl' : const {
+ 'sl': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3164,13 +3164,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale sq.
*/
- 'sq' : const {
+ 'sq': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3214,13 +3214,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale sr.
*/
- 'sr' : const {
+ 'sr': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3264,13 +3264,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale sv.
*/
- 'sv' : const {
+ 'sv': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3314,13 +3314,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale sw.
*/
- 'sw' : const {
+ 'sw': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3364,13 +3364,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ta.
*/
- 'ta' : const {
+ 'ta': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3414,13 +3414,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale te.
*/
- 'te' : const {
+ 'te': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3464,13 +3464,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale th.
*/
- 'th' : const {
+ 'th': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3514,13 +3514,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale tl.
*/
- 'tl' : const {
+ 'tl': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3564,13 +3564,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale tr.
*/
- 'tr' : const {
+ 'tr': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3614,13 +3614,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale uk.
*/
- 'uk' : const {
+ 'uk': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3664,13 +3664,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale ur.
*/
- 'ur' : const {
+ 'ur': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3714,13 +3714,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale vi.
*/
- 'vi' : const {
+ 'vi': const {
'd': '\'Ngày\' d', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3764,13 +3764,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale zh_TW.
*/
- 'zh_TW' : const {
+ 'zh_TW': const {
'd': 'd日', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3814,13 +3814,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale zh_CN.
*/
- 'zh_CN' : const {
+ 'zh_CN': const {
'd': 'd日', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3864,13 +3864,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale zh_HK.
*/
- 'zh_HK' : const {
+ 'zh_HK': const {
'd': 'd日', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3914,13 +3914,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale zh.
*/
- 'zh' : const {
+ 'zh': const {
'd': 'd日', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -3964,13 +3964,13 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
},
/**
* Extended set of localized date/time patterns for locale zu.
*/
- 'zu' : const {
+ 'zu': const {
'd': 'd', // DAY
'E': 'EEE', // ABBR_WEEKDAY
'EEEE': 'EEEE', // WEEKDAY
@@ -4014,6 +4014,6 @@
'v': 'v', // ABBR_GENERIC_TZ
'z': 'z', // ABBR_SPECIFIC_TZ
'zzzz': 'zzzz', // SPECIFIC_TZ
- 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
+ 'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
}
-};
\ No newline at end of file
+};
diff --git a/pkg/intl/lib/extract_messages.dart b/pkg/intl/lib/extract_messages.dart
index 66b2258..aca18da 100644
--- a/pkg/intl/lib/extract_messages.dart
+++ b/pkg/intl/lib/extract_messages.dart
@@ -113,8 +113,7 @@
if (!validNames.contains(node.methodName.name)) return false;
if (!(node.target is SimpleIdentifier)) return false;
SimpleIdentifier target = node.target;
- if (target.token.toString() != "Intl") return false;
- return true;
+ return target.token.toString() == "Intl";
}
Message _expectedInstance(String type) {
@@ -175,7 +174,7 @@
*/
void visitMethodInvocation(MethodInvocation node) {
if (!addIntlMessage(node)) {
- return super.visitMethodInvocation(node);
+ super.visitMethodInvocation(node);
}
}
@@ -190,10 +189,9 @@
var reason = checkValidity(node);
if (reason != null) {
if (!suppressWarnings) {
- var err = new StringBuffer();
- err.write("Skipping invalid Intl.message invocation\n <$node>\n");
- err.write(" reason: $reason\n");
- err.write(_reportErrorLocation(node));
+ var err = new StringBuffer()
+ ..write("Skipping invalid Intl.message invocation\n <$node>\n")
+ ..writeAll([" reason: $reason\n", _reportErrorLocation(node)]);
warnings.add(err.toString());
print(err);
}
@@ -252,10 +250,9 @@
message.messagePieces.addAll(interpolation.pieces);
} on IntlMessageExtractionException catch (e) {
message = null;
- var err = new StringBuffer();
- err.write("Error $e\n");
- err.write("Processing <$node>\n");
- err.write(_reportErrorLocation(node));
+ var err = new StringBuffer()
+ ..writeAll(["Error ", e, "\nProcessing <", node, ">\n"])
+ ..write(_reportErrorLocation(node));
print(err);
warnings.add(err);
}
@@ -304,7 +301,7 @@
* special-purpose visitor.
*/
class InterpolationVisitor extends SimpleASTVisitor {
- Message message;
+ final Message message;
InterpolationVisitor(this.message);
@@ -373,7 +370,7 @@
* A plural or gender always exists in the context of a parent message,
* which could in turn also be a plural or gender.
*/
- ComplexMessage parent;
+ final ComplexMessage parent;
/**
* The pieces of the message. We are given an initial version of this
@@ -381,11 +378,11 @@
*/
List pieces;
- PluralAndGenderVisitor(this.pieces, this.parent) : super() {}
-
/** This will be set to true if we find a plural or gender. */
bool foundPluralOrGender = false;
+ PluralAndGenderVisitor(this.pieces, this.parent) : super();
+
visitInterpolationExpression(InterpolationExpression node) {
// TODO(alanknight): Provide better errors for malformed expressions.
if (!looksLikePluralOrGender(node.expression)) return;
@@ -409,8 +406,7 @@
}
if (!(node.target is SimpleIdentifier)) return false;
SimpleIdentifier target = node.target;
- if (target.token.toString() != "Intl") return false;
- return true;
+ return target.token.toString() == "Intl";
}
/**
@@ -423,7 +419,7 @@
/**
* Create a MainMessage from [node] using the name and
- * parameters of the last function/method declaration we encountered
+ * parameters of the last function/method declaration we encountered e
* and the parameters to the Intl.message call.
*/
Message messageFromMethodInvocation(MethodInvocation node) {
@@ -445,10 +441,9 @@
message[key] = interpolation.pieces;
} on IntlMessageExtractionException catch (e) {
message = null;
- var err = new StringBuffer();
- err.write("Error $e");
- err.write("Processing <$node>");
- err.write(_reportErrorLocation(node));
+ var err = new StringBuffer()
+ ..writeAll(["Error ", e, "\nProcessing <", node, ">"])
+ ..write(_reportErrorLocation(node));
print(err);
warnings.add(err);
}
@@ -479,4 +474,4 @@
const IntlMessageExtractionException([this.message = ""]);
String toString() => "IntlMessageExtractionException: $message";
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 0095c89..0dbd4bc 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -66,10 +66,10 @@
* but it can be any identifier that this program and the output of the
* translation can agree on as identifying a message.
*/
- String id;
+ final String id;
/** Our translated version of [originalMessage]. */
- Message translated;
+ final Message translated;
/** The original message that we are a translation of. */
MainMessage originalMessage;
@@ -106,20 +106,21 @@
usableTranslations.sort((a, b) =>
a.originalMessage.name.compareTo(b.originalMessage.name));
for (var translation in usableTranslations) {
- result.write(" ");
- result.write(translation.originalMessage.toCodeForLocale(locale));
- result.write("\n\n");
+ result
+ .write(" ")
+ ..write(translation.originalMessage.toCodeForLocale(locale))
+ ..write("\n\n");
}
result.write("\n final messages = const {\n");
var entries = usableTranslations
.map((translation) => translation.originalMessage.name)
.map((name) => " \"$name\" : $name");
- result.write(entries.join(",\n"));
- result.write("\n };\n}");
+ result
+ ..write(entries.join(",\n"))
+ ..write("\n };\n}");
- var output = new File(path.join(targetDir,
- "${generatedFilePrefix}messages_$locale.dart"));
- output.writeAsStringSync(result.toString());
+ new File(path.join(targetDir,"${generatedFilePrefix}messages_$locale.dart"))
+ ..writeAsStringSync(result.toString());
}
/**
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index ba517d3..281d2fd 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -121,11 +121,7 @@
* preferences).
*/
Intl([String aLocale]) {
- if (aLocale != null) {
- _locale = aLocale;
- } else {
- _locale = getCurrentLocale();
- }
+ _locale = aLocale != null ? aLocale : getCurrentLocale();
}
/**
@@ -177,9 +173,7 @@
* Return true if the locale exists, or if it is null. The null case
* is interpreted to mean that we use the default locale.
*/
- static bool _localeExists(localeName) {
- return DateFormat.localeExists(localeName);
- }
+ static bool _localeExists(localeName) => DateFormat.localeExists(localeName);
/**
* Given [newLocale] return a locale that we have data for that is similar
diff --git a/pkg/intl/lib/message_lookup_by_library.dart b/pkg/intl/lib/message_lookup_by_library.dart
index c4107dc..58e4115 100644
--- a/pkg/intl/lib/message_lookup_by_library.dart
+++ b/pkg/intl/lib/message_lookup_by_library.dart
@@ -115,4 +115,4 @@
String get localeName;
toString() => localeName;
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/number_format.dart b/pkg/intl/lib/number_format.dart
index a7acbaf..72f3154 100644
--- a/pkg/intl/lib/number_format.dart
+++ b/pkg/intl/lib/number_format.dart
@@ -88,9 +88,8 @@
* Create a number format that prints using [newPattern] as it applies in
* [locale].
*/
- factory NumberFormat([String newPattern, String locale]) {
- return new NumberFormat._forPattern(locale, (x) => newPattern);
- }
+ factory NumberFormat([String newPattern, String locale]) =>
+ new NumberFormat._forPattern(locale, (x) => newPattern);
/** Create a number format that prints as DECIMAL_PATTERN. */
NumberFormat.decimalPattern([String locale]) :
@@ -136,9 +135,7 @@
* Return the symbols which are used in our locale. Cache them to avoid
* repeated lookup.
*/
- NumberSymbols get symbols {
- return _symbols;
- }
+ NumberSymbols get symbols => _symbols;
/**
* Format [number] according to our pattern and return the formatted string.
@@ -307,9 +304,8 @@
* because we have digits left of the decimal point, or because there are
* a minimum number of printable digits greater than 1.
*/
- bool _hasPrintableIntegerPart(int intValue) {
- return intValue > 0 || minimumIntegerDigits > 0;
- }
+ bool _hasPrintableIntegerPart(int intValue) =>
+ intValue > 0 || minimumIntegerDigits > 0;
/**
* Create a new empty buffer. See comment on [_buffer] variable for why
@@ -364,17 +360,13 @@
* Returns the prefix for [x] based on whether it's positive or negative.
* In en_US this would be '' and '-' respectively.
*/
- String _signPrefix(num x) {
- return x.isNegative ? _negativePrefix : _positivePrefix;
- }
+ String _signPrefix(num x) => x.isNegative ? _negativePrefix : _positivePrefix;
/**
* Returns the suffix for [x] based on wether it's positive or negative.
* In en_US there are no suffixes for positive or negative.
*/
- String _signSuffix(num x) {
- return x.isNegative ? _negativeSuffix : _positiveSuffix;
- }
+ String _signSuffix(num x) => x.isNegative ? _negativeSuffix : _positiveSuffix;
void _setPattern(String newPattern) {
if (newPattern == null) return;
@@ -466,10 +458,7 @@
String _parseAffix() {
var affix = new StringBuffer();
inQuote = false;
- var loop = true;
- while (loop) {
- loop = parseCharacterAffix(affix) && pattern.moveNext();
- }
+ while (parseCharacterAffix(affix) && pattern.moveNext());
return affix.toString();
}
@@ -482,8 +471,7 @@
var ch = pattern.current;
if (ch == null) return false;
if (ch == _QUOTE) {
- var nextChar = pattern.peek;
- if (nextChar == _QUOTE) {
+ if (pattern.peek == _QUOTE) {
pattern.moveNext();
affix.write(_QUOTE); // 'don''t'
} else {
@@ -554,10 +542,8 @@
if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
// Handle '###.###' and '###.' and '.###'
- var n = decimalPos;
- if (n == 0) { // Handle '.###'
- n++;
- }
+ // Handle '.###'
+ var n = decimalPos == 0 ? 1 : decimalPos;
digitRightCount = digitLeftCount - n;
digitLeftCount = n - 1;
zeroDigitCount = 1;
@@ -702,8 +688,7 @@
class _StringIterable extends IterableBase<String> {
final Iterator<String> iterator;
- _StringIterable(String s)
- : iterator = _iterator(s);
+ _StringIterable(String s) : iterator = _iterator(s);
}
/**
@@ -711,8 +696,8 @@
* gives us a lookahead of one via the [peek] method.
*/
class _StringIterator implements Iterator<String> {
- String input;
- var index = -1;
+ final String input;
+ int index = -1;
inBounds(i) => i >= 0 && i < input.length;
_StringIterator(this.input);
String get current => inBounds(index) ? input[index] : null;
diff --git a/pkg/intl/lib/number_symbols.dart b/pkg/intl/lib/number_symbols.dart
index f45cb2c..1f389f1 100644
--- a/pkg/intl/lib/number_symbols.dart
+++ b/pkg/intl/lib/number_symbols.dart
@@ -33,4 +33,4 @@
this.DEF_CURRENCY_CODE});
toString() => NAME;
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/src/date_format_field.dart b/pkg/intl/lib/src/date_format_field.dart
index 14990e6..bf8f810 100644
--- a/pkg/intl/lib/src/date_format_field.dart
+++ b/pkg/intl/lib/src/date_format_field.dart
@@ -88,7 +88,7 @@
}
void patchQuotes() {
- if (pattern == "''") {
+ if (pattern == "''") {
pattern = "'";
} else {
pattern = pattern.substring(1, pattern.length - 1);
@@ -109,7 +109,7 @@
/** Format date according to our specification and return the result. */
String format(DateTime date) {
- return formatField(date);
+ return formatField(date);
}
/**
@@ -418,7 +418,7 @@
throw new UnimplementedError();
}
- /**
+ /**
* Return a string representation of the object padded to the left with
* zeros. Primarily useful for numbers.
*/
@@ -428,7 +428,7 @@
var buffer = new StringBuffer();
for (var i = 0; i < width - basicString.length; i++) {
buffer.write('0');
- }
+ }
buffer.write(basicString);
return buffer.toString();
}
diff --git a/pkg/intl/lib/src/temporary_debugging.dart b/pkg/intl/lib/src/temporary_debugging.dart
index f96b56d..29740c4 100644
--- a/pkg/intl/lib/src/temporary_debugging.dart
+++ b/pkg/intl/lib/src/temporary_debugging.dart
@@ -7,4 +7,4 @@
bool debugLogDateCreation = false;
-StringBuffer debugDateCreationLog = new StringBuffer();
\ No newline at end of file
+StringBuffer debugDateCreationLog = new StringBuffer();
diff --git a/pkg/intl/test/data_directory.dart b/pkg/intl/test/data_directory.dart
index df76575..3194364 100644
--- a/pkg/intl/test/data_directory.dart
+++ b/pkg/intl/test/data_directory.dart
@@ -53,4 +53,4 @@
'Cannot find ${path.join('pkg','intl')} directory.');
}
-String get datesRelativeToIntl => path.join('lib', 'src', 'data', 'dates');
\ No newline at end of file
+String get datesRelativeToIntl => path.join('lib', 'src', 'data', 'dates');
diff --git a/pkg/intl/test/date_time_format_test_stub.dart b/pkg/intl/test/date_time_format_test_stub.dart
index 0a70535..4b75747 100644
--- a/pkg/intl/test/date_time_format_test_stub.dart
+++ b/pkg/intl/test/date_time_format_test_stub.dart
@@ -31,7 +31,7 @@
* Return a set of a few locales to run just the tests on a small sample.
*/
List smallSetOfLocales() {
- return allLocales().sublist(0,10);
+ return allLocales().sublist(0, 10);
}
/**
@@ -52,7 +52,7 @@
bool initialized = false;
setUp(() {
- if(initialized) {
+ if (initialized) {
return null;
}
return initFunction("en_US", dir)
diff --git a/pkg/intl/test/find_default_locale_standalone_test.dart b/pkg/intl/test/find_default_locale_standalone_test.dart
index 2518133..f0df693 100644
--- a/pkg/intl/test/find_default_locale_standalone_test.dart
+++ b/pkg/intl/test/find_default_locale_standalone_test.dart
@@ -17,7 +17,7 @@
Intl.systemLocale = "xx_YY";
var callback = expectAsync1(verifyLocale);
findSystemLocale().then(callback);
- });
+ });
}
verifyLocale(_) {
diff --git a/pkg/intl/test/intl_test.dart b/pkg/intl/test/intl_test.dart
index 5533896..d357188 100644
--- a/pkg/intl/test/intl_test.dart
+++ b/pkg/intl/test/intl_test.dart
@@ -10,11 +10,11 @@
main() {
test("Locale setting doesn't verify the core locale", () {
- var de = new Intl('de_DE');
- expect(de.locale, equals('de_DE'));
+ var de = new Intl('de_DE');
+ expect(de.locale, equals('de_DE'));
});
- test('DateFormat creation does verify the locale', (){
+ test('DateFormat creation does verify the locale', () {
// TODO(alanknight): We need to make the locale verification be on a per
// usage basis rather than once for the entire Intl object. The set of
// locales covered for messages may be different from that for date
@@ -23,7 +23,7 @@
var de = new Intl('de_DE');
var format = de.date().add_d();
expect(format.locale, equals('de'));
- });
+ });
});
test("Canonicalizing locales", () {
diff --git a/pkg/intl/test/message_extraction/examples_parsing_test.dart b/pkg/intl/test/message_extraction/examples_parsing_test.dart
index 8a336db..661f622 100644
--- a/pkg/intl/test/message_extraction/examples_parsing_test.dart
+++ b/pkg/intl/test/message_extraction/examples_parsing_test.dart
@@ -22,4 +22,4 @@
var messages = parseFile(new File(file));
expect(messages['message2'].examples, {"x" : 3});
});
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/foo_messages_de_DE.dart b/pkg/intl/test/message_extraction/foo_messages_de_DE.dart
index 18f321c..c790ed5 100644
--- a/pkg/intl/test/message_extraction/foo_messages_de_DE.dart
+++ b/pkg/intl/test/message_extraction/foo_messages_de_DE.dart
@@ -80,4 +80,4 @@
"types" : types,
"whereTheyWentMessage" : whereTheyWentMessage
};
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/foo_messages_fr.dart b/pkg/intl/test/message_extraction/foo_messages_fr.dart
index 723d362..58c71ce 100644
--- a/pkg/intl/test/message_extraction/foo_messages_fr.dart
+++ b/pkg/intl/test/message_extraction/foo_messages_fr.dart
@@ -83,4 +83,4 @@
"types" : types,
"whereTheyWentMessage" : whereTheyWentMessage
};
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/message_extraction_test.dart b/pkg/intl/test/message_extraction/message_extraction_test.dart
index f64153d..b2de632 100644
--- a/pkg/intl/test/message_extraction/message_extraction_test.dart
+++ b/pkg/intl/test/message_extraction/message_extraction_test.dart
@@ -48,7 +48,8 @@
var files = [dir('intl_messages.json'), dir('translation_fr.json'),
dir('translation_de_DE.json')];
files.map((name) => new File(name)).forEach((x) {
- if (x.existsSync()) x.deleteSync();});
+ if (x.existsSync()) x.deleteSync();
+ });
}
/**
diff --git a/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart b/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart
index 085459c..b3728fd 100644
--- a/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart
+++ b/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart
@@ -72,4 +72,4 @@
args: [names, number, combinedGender, place]);
return nestedMessage(names, number, combinedGender, place);
}
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/print_to_list.dart b/pkg/intl/test/message_extraction/print_to_list.dart
index e718fc4..f5446d4 100644
--- a/pkg/intl/test/message_extraction/print_to_list.dart
+++ b/pkg/intl/test/message_extraction/print_to_list.dart
@@ -7,4 +7,4 @@
void printOut(String s) {
lines.add(s);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/sample_with_messages.dart b/pkg/intl/test/message_extraction/sample_with_messages.dart
index b978ca8..e1a9ac3 100644
--- a/pkg/intl/test/message_extraction/sample_with_messages.dart
+++ b/pkg/intl/test/message_extraction/sample_with_messages.dart
@@ -186,4 +186,4 @@
var f2 = initializeMessages(de.locale).then((_) => printStuff(de));
printStuff(english);
return Future.wait([f1, f2]);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/verify_messages.dart b/pkg/intl/test/message_extraction/verify_messages.dart
index 2203be6..d368c36 100644
--- a/pkg/intl/test/message_extraction/verify_messages.dart
+++ b/pkg/intl/test/message_extraction/verify_messages.dart
@@ -145,4 +145,4 @@
verify('5 einige Währung oder anderen.');
verify('1 Kanadischer dollar');
verify('2 Kanadischen dollar');
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/number_format_test.dart b/pkg/intl/test/number_format_test.dart
index 3b9aed6..07f1db1 100644
--- a/pkg/intl/test/number_format_test.dart
+++ b/pkg/intl/test/number_format_test.dart
@@ -16,7 +16,7 @@
* Tests the Numeric formatting library in dart.
*/
var testNumbers = {
- "0.001": 0.001,
+ "0.001": 0.001,
"0.01": 0.01,
"0.1": 0.1,
"1": 1,
@@ -94,4 +94,4 @@
expect(formatted, x);
}
});
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/tool/generate_locale_data_files.dart b/pkg/intl/tool/generate_locale_data_files.dart
index 4934d66..f60f515 100644
--- a/pkg/intl/tool/generate_locale_data_files.dart
+++ b/pkg/intl/tool/generate_locale_data_files.dart
@@ -69,9 +69,7 @@
void writePatterns(locale, patterns) {
var file = new File(path.join(dataDirectory, 'patterns', '${locale}.json'));
- var output = file.openWrite();
- output.write(JSON.encode(patterns));
- output.close();
+ file.openWrite()..write(JSON.encode(patterns))..close();
}
void writeToJSON(dynamic data, IOSink out) {
diff --git a/pkg/observe/lib/html.dart b/pkg/observe/lib/html.dart
index abf333a..2627531 100644
--- a/pkg/observe/lib/html.dart
+++ b/pkg/observe/lib/html.dart
@@ -51,7 +51,12 @@
}
}
-/** Add or remove CSS class [className] based on the [value]. */
+/**
+ * *Deprecated* use [CssClassSet.toggle] instead.
+ *
+ * Add or remove CSS class [className] based on the [value].
+ */
+@deprecated
void updateCssClass(Element element, String className, bool value) {
if (value == true) {
element.classes.add(className);
@@ -60,11 +65,21 @@
}
}
-/** Bind a CSS class to the observable [object] and property [path]. */
+/**
+ * *Deprecated* use `class="{{ binding }}"` in your HTML instead. It will also
+ * work on a `<polymer-element>`.
+ *
+ * Bind a CSS class to the observable [object] and property [path].
+ */
+@deprecated
PathObserver bindCssClass(Element element, String className,
Observable object, String path) {
- return new PathObserver(object, path)..bindSync((value) {
+ callback(value) {
updateCssClass(element, className, value);
- });
+ }
+
+ var obs = new PathObserver(object, path);
+ callback(obs.open(callback));
+ return obs;
}
diff --git a/pkg/observe/lib/observe.dart b/pkg/observe/lib/observe.dart
index 218a036..1dd83b8 100644
--- a/pkg/observe/lib/observe.dart
+++ b/pkg/observe/lib/observe.dart
@@ -76,25 +76,16 @@
* form into the second form automatically, to get the best of both worlds.
*/
library observe;
-import 'src/bind_property.dart';
-import 'src/change_notifier.dart';
-import 'src/change_record.dart';
-import 'src/compound_path_observer.dart';
-import 'src/list_path_observer.dart';
-import 'src/list_diff.dart';
-import 'src/metadata.dart';
-import 'src/observable.dart';
-import 'src/observable_box.dart';
-import 'src/observable_list.dart';
-import 'src/observable_map.dart';
-import 'src/path_observer.dart';
-import 'src/to_observable.dart';
+// This library contains code ported from observe-js:
+// https://github.com/Polymer/observe-js/blob/0152d542350239563d0f2cad39d22d3254bd6c2a/src/observe.js
+// We port what is needed for data bindings. Most of the functionality is
+// ported, except where differences are needed for Dart's Observable type.
+export 'src/bindable.dart';
export 'src/bind_property.dart';
export 'src/change_notifier.dart';
export 'src/change_record.dart';
-export 'src/compound_path_observer.dart';
export 'src/list_path_observer.dart';
export 'src/list_diff.dart' show ListChangeRecord;
export 'src/metadata.dart';
@@ -102,5 +93,6 @@
export 'src/observable_box.dart';
export 'src/observable_list.dart';
export 'src/observable_map.dart';
+export 'src/observer_transform.dart';
export 'src/path_observer.dart';
export 'src/to_observable.dart';
diff --git a/pkg/observe/lib/src/bindable.dart b/pkg/observe/lib/src/bindable.dart
new file mode 100644
index 0000000..636ef30
--- /dev/null
+++ b/pkg/observe/lib/src/bindable.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, 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 observe.src.bindable;
+
+/// An object that can be data bound.
+// Normally this is used with 'package:template_binding'.
+// TODO(jmesserly): Node.bind polyfill calls this "observable"
+abstract class Bindable {
+ // TODO(jmesserly): since we have "value", should open be a void method?
+ // TODO(jmesserly): not sure how I feel about open taking a variable number
+ // of arguments, but it's the easiest way to make CompoundObserver work.
+
+ /// Initiates observation and returns the initial value.
+ /// The callback will be called with the updated [value].
+ ///
+ /// Some subtypes may chose to provide additional arguments, such as
+ /// [PathObserver] providing the old value as the second argument.
+ /// However, they must support callbacks with as few as 0 or 1 argument.
+ /// This can be implemented by performing an "is" type test on the callback.
+ open(callback);
+
+ /// Stops future notifications and frees the reference to the callback passed
+ /// to [open], so its memory can be collected even if this Bindable is alive.
+ void close();
+
+ /// Gets the current value of the bindings.
+ get value;
+
+ /// This can be implemented for two-way bindings. By default does nothing.
+ /// Note: setting the value of a [Bindable] must not call the [callback] with
+ /// the new value. Any pending change notifications must be discarded.
+ set value(newValue) {}
+}
diff --git a/pkg/observe/lib/src/compound_path_observer.dart b/pkg/observe/lib/src/compound_path_observer.dart
deleted file mode 100644
index 1594e08..0000000
--- a/pkg/observe/lib/src/compound_path_observer.dart
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2013, 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 observe.src.compound_path_observer;
-
-import 'dart:async';
-import 'package:observe/observe.dart';
-
-/**
- * CompoundPathObserver is an object which knows how to listen to multiple path
- * values (registered via [addPath]) and invoke a function when one or more
- * of the values have changed. The result of this function will be set into the
- * [value] property. When any value has changed, all current values are provided
- * to the function in the single `values` argument.
- *
- * For example:
- *
- * var binding = new CompoundPathObserver(computeValue: (values) {
- * var combinedValue;
- * // compute combinedValue based on the current values which are provided
- * return combinedValue;
- * });
- * binding.addPath(obj1, path1);
- * binding.addPath(obj2, path2);
- * //...
- * binding.addPath(objN, pathN);
- */
-// TODO(jmesserly): this isn't a full port of CompoundPathObserver. It is only
-// what was needed for TemplateBinding.
-class CompoundPathObserver extends ChangeNotifier {
- List<PathObserver> _observers = [];
- List<StreamSubscription> _subs = [];
- Object _value; // the last computed value
-
- // TODO(jmesserly): this is public in observe.js
- final Function _computeValue;
-
- bool _started = false;
-
- /** True if [start] has been called, otherwise false. */
- bool get started => _started;
-
- bool _scheduled = false;
-
- /**
- * Creates a new observer, optionally proving the [computeValue] function
- * for computing the value. You can also set [schedule] to true if you plan
- * to invoke [resolve] manually after initial construction of the binding.
- */
- CompoundPathObserver({computeValue(List values)})
- : _computeValue = computeValue;
-
- int get length => _observers.length;
-
- @reflectable get value => _value;
-
- void addPath(model, String path) {
- if (_started) {
- throw new StateError('Cannot add more paths once started.');
- }
-
- _observers.add(new PathObserver(model, path));
- }
-
- void start() {
- if (_started) return;
- _started = true;
-
- final scheduleResolve = _scheduleResolve;
- for (var observer in _observers) {
- _subs.add(observer.changes.listen(scheduleResolve));
- }
- _resolve();
- }
-
- // TODO(rafaelw): Is this the right processing model?
- // TODO(rafaelw): Consider having a seperate ChangeSummary for
- // CompoundBindings so to excess dirtyChecks.
- void _scheduleResolve(_) {
- if (_scheduled) return;
- _scheduled = true;
- scheduleMicrotask(_resolve);
- }
-
- void _resolve() {
- _scheduled = false;
- if (_observers.isEmpty) return;
- var newValue = _observers.map((o) => o.value).toList();
- if (_computeValue != null) newValue = _computeValue(newValue);
- _value = notifyPropertyChange(#value, _value, newValue);
- }
-
- /**
- * Closes the observer.
- *
- * This happens automatically if the [value] property is no longer observed,
- * but this can also be called explicitly.
- */
- void close() {
- if (_observers.isEmpty) return;
-
- if (_started) {
- for (StreamSubscription sub in _subs) {
- sub.cancel();
- }
- }
- _observers.clear();
- _subs.clear();
- _value = null;
- }
-
- observed() => start();
- unobserved() => close();
-}
diff --git a/pkg/observe/lib/src/list_diff.dart b/pkg/observe/lib/src/list_diff.dart
index 6acef80..67a9ff1 100644
--- a/pkg/observe/lib/src/list_diff.dart
+++ b/pkg/observe/lib/src/list_diff.dart
@@ -381,7 +381,7 @@
*/
List<ListChangeRecord> projectListSplices(List list,
List<ListChangeRecord> records) {
- if (records.length == 1) return records;
+ if (records.length <= 1) return records;
var splices = [];
for (var splice in _createInitialSplices(list, records)) {
diff --git a/pkg/observe/lib/src/microtask.dart b/pkg/observe/lib/src/microtask.dart
deleted file mode 100644
index e4ed2d9..0000000
--- a/pkg/observe/lib/src/microtask.dart
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2013, 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.
-
-/**
- * *Warning*: this library is **internal**, and APIs are subject to change.
- *
- * Wraps a callback using [wrapMicrotask] and provides the ability to pump all
- * observable objects and [scheduleMicrotask] calls via
- * [performMicrotaskCheckpoint].
- */
-library observe.src.microtask;
-
-import 'dart:async' show Completer, runZoned, ZoneSpecification;
-import 'dart:collection';
-import 'package:observe/observe.dart' show Observable;
-
-// TODO(jmesserly): remove "microtask" from these names and instead import
-// the library "as microtask"?
-
-/**
- * This change pumps events relevant to observers and data-binding tests.
- * This must be used inside an [observeTest].
- *
- * Executes all pending [scheduleMicrotask] calls on the event loop, as well as
- * performing [Observable.dirtyCheck], until there are no more pending events.
- * It will always dirty check at least once.
- */
-// TODO(jmesserly): do we want to support nested microtasks similar to nested
-// zones? Instead of a single pending list we'd need one per wrapMicrotask,
-// and [performMicrotaskCheckpoint] would only run pending callbacks
-// corresponding to the innermost wrapMicrotask body.
-void performMicrotaskCheckpoint() {
- Observable.dirtyCheck();
-
- while (_pending.isNotEmpty) {
-
- for (int len = _pending.length; len > 0 && _pending.isNotEmpty; len--) {
- final callback = _pending.removeFirst();
- try {
- callback();
- } catch (e, s) {
- new Completer().completeError(e, s);
- }
- }
-
- Observable.dirtyCheck();
- }
-}
-
-final Queue<Function> _pending = new Queue<Function>();
-
-/**
- * Wraps the [body] in a zone that supports [performMicrotaskCheckpoint],
- * and returns the body.
- */
-// TODO(jmesserly): deprecate? this doesn't add much over runMicrotask.
-wrapMicrotask(body()) => () => runMicrotask(body);
-
-/**
- * Runs the [body] in a zone that supports [performMicrotaskCheckpoint],
- * and returns the result.
- */
-runMicrotask(body()) => runZoned(() {
- try {
- return body();
- } finally {
- performMicrotaskCheckpoint();
- }
-}, zoneSpecification: new ZoneSpecification(
- scheduleMicrotask: (self, parent, zone, callback) => _pending.add(callback))
-);
diff --git a/pkg/observe/lib/src/observable_list.dart b/pkg/observe/lib/src/observable_list.dart
index be25afa..f7052ff 100644
--- a/pkg/observe/lib/src/observable_list.dart
+++ b/pkg/observe/lib/src/observable_list.dart
@@ -255,12 +255,17 @@
notifyPropertyChange(#isNotEmpty, oldValue != 0, newValue != 0);
}
+ void discardListChages() {
+ // Leave _listRecords set so we don't schedule another delivery.
+ if (_listRecords != null) _listRecords = [];
+ }
+
bool deliverListChanges() {
if (_listRecords == null) return false;
var records = projectListSplices(this, _listRecords);
_listRecords = null;
- if (_hasListObservers) {
+ if (_hasListObservers && !records.isEmpty) {
_listChanges.add(new UnmodifiableListView<ListChangeRecord>(records));
return true;
}
@@ -284,4 +289,24 @@
static List<ListChangeRecord> calculateChangeRecords(
List<Object> oldValue, List<Object> newValue) =>
calcSplices(newValue, 0, newValue.length, oldValue, 0, oldValue.length);
+
+ /**
+ * Updates the [previous] list using the change [records]. For added items,
+ * the [current] list is used to find the current value.
+ */
+ static void applyChangeRecords(List<Object> previous, List<Object> current,
+ List<ListChangeRecord> changeRecords) {
+
+ if (identical(previous, current)) {
+ throw new ArgumentError("can't use same list for previous and current");
+ }
+
+ for (var change in changeRecords) {
+ int addEnd = change.index + change.addedCount;
+ int removeEnd = change.index + change.removed.length;
+
+ var addedItems = current.getRange(change.index, addEnd);
+ previous.replaceRange(change.index, removeEnd, addedItems);
+ }
+ }
}
diff --git a/pkg/observe/lib/src/observer_transform.dart b/pkg/observe/lib/src/observer_transform.dart
new file mode 100644
index 0000000..0587cd9
--- /dev/null
+++ b/pkg/observe/lib/src/observer_transform.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2013, 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 observe.src.observer_transform;
+
+import 'package:observe/observe.dart';
+
+/// ObserverTransform is used to dynamically transform observed value(s).
+///
+/// var obj = new ObservableBox(10);
+/// var observer = new PathObserver(obj, 'value');
+/// var transform = new ObserverTransform(observer,
+/// (x) => x * 2, setValue: (x) => x ~/ 2);
+///
+/// // Open returns the current value of 20.
+/// transform.open((newValue) => print('new: $newValue'));
+///
+/// obj.value = 20; // prints 'new: 40' async
+/// new Future(() {
+/// transform.value = 4; // obj.value will be 2
+/// });
+///
+/// ObserverTransform can also be used to reduce a set of observed values to a
+/// single value:
+///
+/// var obj = new ObservableMap.from({'a': 1, 'b': 2, 'c': 3});
+/// var observer = new CompoundObserver()
+/// ..addPath(obj, 'a')
+/// ..addPath(obj, 'b')
+/// ..addPath(obj, 'c');
+///
+/// var transform = new ObserverTransform(observer,
+/// (values) => values.fold(0, (x, y) => x + y));
+///
+/// // Open returns the current value of 6.
+/// transform.open((newValue) => print('new: $newValue'));
+///
+/// obj['a'] = 2;
+/// obj['c'] = 10; // will print 'new 14' asynchronously
+///
+class ObserverTransform extends Bindable {
+ Bindable _bindable;
+ Function _getTransformer, _setTransformer;
+ Function _notifyCallback;
+ var _value;
+
+ ObserverTransform(Bindable bindable, computeValue(value), {setValue(value)})
+ : _bindable = bindable,
+ _getTransformer = computeValue,
+ _setTransformer = setValue;
+
+ open(callback(value)) {
+ _notifyCallback = callback;
+ _value = _getTransformer(_bindable.open(_observedCallback));
+ return _value;
+ }
+
+ _observedCallback(newValue) {
+ final value = _getTransformer(newValue);
+ if (value == _value) return null;
+ _value = value;
+ return _notifyCallback(value);
+ }
+
+ void close() {
+ if (_bindable != null) _bindable.close();
+ _bindable = null;
+ _getTransformer = null;
+ _setTransformer = null;
+ _notifyCallback = null;
+ _value = null;
+ }
+
+ get value => _value = _getTransformer(_bindable.value);
+
+ set value(newValue) {
+ if (_setTransformer != null) {
+ newValue = _setTransformer(newValue);
+ }
+ _bindable.value = newValue;
+ }
+}
diff --git a/pkg/observe/lib/src/path_observer.dart b/pkg/observe/lib/src/path_observer.dart
index 5e59b80..8054a3a 100644
--- a/pkg/observe/lib/src/path_observer.dart
+++ b/pkg/observe/lib/src/path_observer.dart
@@ -5,6 +5,8 @@
library observe.src.path_observer;
import 'dart:async';
+import 'dart:collection';
+import 'dart:math' show min;
@MirrorsUsed(metaTargets: const [Reflectable, ObservableProperty],
override: 'observe.src.path_observer')
import 'dart:mirrors';
@@ -12,209 +14,216 @@
import 'package:observe/observe.dart';
import 'package:observe/src/observable.dart' show objectType;
-// This code is inspired by ChangeSummary:
-// https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js
-// ...which underlies MDV. Since we don't need the functionality of
-// ChangeSummary, we just implement what we need for data bindings.
-// This allows our implementation to be much simpler.
+/// A data-bound path starting from a view-model or model object, for example
+/// `foo.bar.baz`.
+///
+/// When [open] is called, this will observe changes to the object and any
+/// intermediate object along the path, and send updated values accordingly.
+/// When [close] is called it will stop observing the objects.
+///
+/// This class is used to implement `Node.bind` and similar functionality in
+/// the [template_binding](pub.dartlang.org/packages/template_binding) package.
+class PathObserver extends _Observer implements Bindable {
+ PropertyPath _path;
+ Object _object;
+ _ObservedSet _directObserver;
-/**
- * A data-bound path starting from a view-model or model object, for example
- * `foo.bar.baz`.
- *
- * When the [values] stream is being listened to, this will observe changes to
- * the object and any intermediate object along the path, and send [values]
- * accordingly. When all listeners are unregistered it will stop observing
- * the objects.
- *
- * This class is used to implement [Node.bind] and similar functionality.
- */
+ /// Observes [path] on [object] for changes. This returns an object
+ /// that can be used to get the changes and get/set the value at this path.
+ ///
+ /// The path can be a [PropertyPath], or a [String] used to construct it.
+ ///
+ /// See [open] and [value].
+ PathObserver(Object object, [path])
+ : _object = object,
+ _path = path is PropertyPath ? path : new PropertyPath(path);
+
+ bool get _isClosed => _path == null;
+
+ /// Sets the value at this path.
+ @reflectable void set value(Object newValue) {
+ if (_path != null) _path.setValueFrom(_object, newValue);
+ }
+
+ int get _reportArgumentCount => 2;
+
+ /// Initiates observation and returns the initial value.
+ /// The callback will be passed the updated [value], and may optionally be
+ /// declared to take a second argument, which will contain the previous value.
+ open(callback) => super.open(callback);
+
+ void _connect() {
+ _directObserver = new _ObservedSet(this, _object);
+ _check(skipChanges: true);
+ }
+
+ void _disconnect() {
+ _value = null;
+ if (_directObserver != null) {
+ _directObserver.close(this);
+ _directObserver = null;
+ }
+ // Dart note: the JS impl does not do this, but it seems consistent with
+ // CompoundObserver. After closing the PathObserver can't be reopened.
+ _path = null;
+ _object = null;
+ }
+
+ void _iterateObjects(void observe(obj)) {
+ _path._iterateObjects(_object, observe);
+ }
+
+ bool _check({bool skipChanges: false}) {
+ var oldValue = _value;
+ _value = _path.getValueFrom(_object);
+ if (skipChanges || _value == oldValue) return false;
+
+ _report(_value, oldValue);
+ return true;
+ }
+}
+
+/// A dot-delimieted property path such as "foo.bar" or "foo.10.bar".
+/// The path specifies how to get a particular value from an object graph, where
+/// the graph can include arrays.
// TODO(jmesserly): consider specialized subclasses for:
// * empty path
// * "value"
// * single token in path, e.g. "foo"
-class PathObserver extends ChangeNotifier {
- /** The path string. */
- final String path;
-
- /** True if the path is valid, otherwise false. */
- final bool _isValid;
-
+class PropertyPath {
+ /// The segments of the path.
final List<Object> _segments;
- List<Object> _values;
- List<StreamSubscription> _subs;
- final Function _computeValue;
-
- /**
- * Observes [path] on [object] for changes. This returns an object that can be
- * used to get the changes and get/set the value at this path.
- *
- * You can optionally use [computeValue] to apply a function to the result of
- * evaluating the path. The function should be pure, as PathObserver will not
- * know to observe any of its dependencies. If you need to observe mutliple
- * values, use [CompoundPathObserver] instead.
- *
- * See [PathObserver.bindSync] and [PathObserver.value].
- */
- PathObserver(Object object, String path, {computeValue(newValue)})
- : path = path,
- _computeValue = computeValue,
- _isValid = _isPathValid(path),
- _segments = <Object>[] {
-
- if (_isValid) {
- for (var segment in path.trim().split('.')) {
- if (segment == '') continue;
- var index = int.parse(segment, radix: 10, onError: (_) => null);
- _segments.add(index != null ? index : new Symbol(segment));
- }
- }
-
- // Initialize arrays.
- // Note that the path itself can't change after it is initially
- // constructed, even though the objects along the path can change.
- _values = new List<Object>(_segments.length + 1);
-
- // If we have an empty path, we need to apply the transformation function
- // to the value. The "value" property should always show the transformed
- // value.
- if (_segments.isEmpty && computeValue != null) {
- object = computeValue(object);
- }
-
- _values[0] = object;
- _subs = new List<StreamSubscription>(_segments.length);
- }
-
- /** The object being observed. If the path is empty this will be [value]. */
- get object => _values[0];
-
- /** Gets the last reported value at this path. */
- @reflectable get value {
- if (!_isValid) return null;
- if (!hasObservers) _updateValues();
- return _values.last;
- }
-
- /** Sets the value at this path. */
- @reflectable void set value(Object newValue) {
- int len = _segments.length;
-
- // TODO(jmesserly): throw if property cannot be set?
- // MDV seems tolerant of these errors.
- if (len == 0) return;
- if (!hasObservers) _updateValues(end: len - 1);
-
- if (_setObjectProperty(_values[len - 1], _segments[len - 1], newValue)) {
- // Technically, this would get updated asynchronously via a change record.
- // However, it is nice if calling the getter will yield the same value
- // that was just set. So we use this opportunity to update our cache.
- _values[len] = newValue;
- }
- }
-
- /**
- * Invokes the [callback] immediately with the current [value], and every time
- * the value changes. This is useful for bindings, which want to be up-to-date
- * immediately and stay bound to the value of the path.
- */
- StreamSubscription bindSync(void callback(value)) {
- var result = changes.listen((records) { callback(value); });
- callback(value);
- return result;
- }
-
- void observed() {
- super.observed();
- _updateValues();
- _observePath();
- }
-
- void unobserved() {
- for (int i = 0; i < _subs.length; i++) {
- if (_subs[i] != null) {
- _subs[i].cancel();
- _subs[i] = null;
- }
- }
- super.unobserved();
- }
-
- // TODO(jmesserly): should we be caching these values if not observing?
- void _updateValues({int end}) {
- if (end == null) end = _segments.length;
- int last = _segments.length - 1;
- for (int i = 0; i < end; i++) {
- var newValue = _getObjectProperty(_values[i], _segments[i]);
- if (i == last && _computeValue != null) {
- newValue = _computeValue(newValue);
- }
- _values[i + 1] = newValue;
- }
- }
-
- void _updateObservedValues({int start: 0}) {
- var oldValue, newValue;
- for (int i = start, last = _segments.length - 1; i <= last; i++) {
- oldValue = _values[i + 1];
- newValue = _getObjectProperty(_values[i], _segments[i]);
- if (i == last && _computeValue != null) {
- newValue = _computeValue(newValue);
- }
- if (identical(oldValue, newValue)) {
- _observePath(start, i);
- return;
- }
- _values[i + 1] = newValue;
- }
-
- _observePath(start);
- notifyPropertyChange(#value, oldValue, newValue);
- }
-
- void _observePath([int start = 0, int end]) {
- if (end == null) end = _segments.length;
-
- for (int i = start; i < end; i++) {
- if (_subs[i] != null) _subs[i].cancel();
- _observeIndex(i);
- }
- }
-
- void _observeIndex(int i) {
- final object = _values[i];
- final segment = _segments[i];
- if (segment is int) {
- if (object is ObservableList) {
- _subs[i] = object.listChanges.listen((List<ListChangeRecord> records) {
- for (var record in records) {
- if (record.indexChanged(segment)) {
- _updateObservedValues(start: i);
- return;
- }
- }
- });
- }
- } else if (object is Observable) {
- // TODO(jmesserly): rather than allocating a new closure for each
- // property, we could try and have one for the entire path. However we'd
- // need to do a linear scan to find the index as soon as we got a change.
- // Also we need to fix ListChangeRecord and MapChangeRecord to contain
- // the target. Not sure if it's worth it.
-
- _subs[i] = object.changes.listen((List<ChangeRecord> records) {
- for (var record in records) {
- if (_changeRecordMatches(record, segment)) {
- _updateObservedValues(start: i);
- return;
- }
+ /// Creates a new [PropertyPath]. These can be stored to avoid excessive
+ /// parsing of path strings.
+ ///
+ /// The provided [path] should be a String or a List. If it is a list it
+ /// should contain only Symbols and integers. This can be used to avoid
+ /// parsing.
+ ///
+ /// Note that this constructor will canonicalize identical paths in some cases
+ /// to save memory, but this is not guaranteed. Use [==] for comparions
+ /// purposes instead of [identical].
+ factory PropertyPath([path]) {
+ if (path is List) {
+ var copy = new List.from(path, growable: false);
+ for (var segment in copy) {
+ if (segment is! int && segment is! Symbol) {
+ throw new ArgumentError('List must contain only ints and Symbols');
}
- });
+ }
+ return new PropertyPath._(copy);
+ }
+
+ if (path == null) path = '';
+
+ var pathObj = _pathCache[path];
+ if (pathObj != null) return pathObj;
+
+ if (!_isPathValid(path)) return _InvalidPropertyPath._instance;
+
+ final segments = [];
+ for (var segment in path.trim().split('.')) {
+ if (segment == '') continue;
+ var index = int.parse(segment, radix: 10, onError: (_) => null);
+ segments.add(index != null ? index : new Symbol(segment));
+ }
+
+ // TODO(jmesserly): we could use an UnmodifiableListView here, but that adds
+ // memory overhead.
+ pathObj = new PropertyPath._(segments.toList(growable: false));
+ if (_pathCache.length >= _pathCacheLimit) {
+ _pathCache.remove(_pathCache.keys.first);
+ }
+ _pathCache[path] = pathObj;
+ return pathObj;
+ }
+
+ PropertyPath._(this._segments);
+
+ int get length => _segments.length;
+ bool get isEmpty => _segments.isEmpty;
+ bool get isValid => true;
+
+ String toString() {
+ if (!isValid) return '<invalid path>';
+ return _segments
+ .map((s) => s is Symbol ? MirrorSystem.getName(s) : s)
+ .join('.');
+ }
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! PropertyPath) return false;
+ if (isValid != other.isValid) return false;
+
+ int len = _segments.length;
+ if (len != other._segments.length) return false;
+ for (int i = 0; i < len; i++) {
+ if (_segments[i] != other._segments[i]) return false;
+ }
+ return true;
+ }
+
+ /// This is the [Jenkins hash function][1] but using masking to keep
+ /// values in SMI range.
+ /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+ // TODO(jmesserly): should reuse this instead, see
+ // https://code.google.com/p/dart/issues/detail?id=11617
+ int get hashCode {
+ int hash = 0;
+ for (int i = 0, len = _segments.length; i < len; i++) {
+ hash = 0x1fffffff & (hash + _segments[i].hashCode);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ hash = hash ^ (hash >> 6);
+ }
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ /// Returns the current of the path from the provided [obj]ect.
+ getValueFrom(Object obj) {
+ if (!isValid) return null;
+ for (var segment in _segments) {
+ if (obj == null) return null;
+ obj = _getObjectProperty(obj, segment);
+ }
+ return obj;
+ }
+
+ /// Attempts to set the [value] of the path from the provided [obj]ect.
+ /// Returns true if and only if the path was reachable and set.
+ bool setValueFrom(Object obj, Object value) {
+ var end = _segments.length - 1;
+ if (end < 0) return false;
+ for (int i = 0; i < end; i++) {
+ if (obj == null) return false;
+ obj = _getObjectProperty(obj, _segments[i]);
+ }
+ return _setObjectProperty(obj, _segments[end], value);
+ }
+
+ void _iterateObjects(Object obj, void observe(obj)) {
+ if (!isValid || isEmpty) return;
+
+ int i = 0, last = _segments.length - 1;
+ while (obj != null) {
+ observe(obj);
+
+ if (i >= last) break;
+ obj = _getObjectProperty(obj, _segments[i++]);
}
}
}
+class _InvalidPropertyPath extends PropertyPath {
+ static final _instance = new _InvalidPropertyPath();
+
+ bool get isValid => false;
+ _InvalidPropertyPath() : super._([]);
+}
+
bool _changeRecordMatches(record, key) {
if (record is PropertyChangeRecord) {
return (record as PropertyChangeRecord).name == key;
@@ -318,10 +327,8 @@
return false;
}
-/**
- * True if the type has a method, other than on Object.
- * Doesn't consider noSuchMethod, unless [name] is `#noSuchMethod`.
- */
+/// True if the type has a method, other than on Object.
+/// Doesn't consider noSuchMethod, unless [name] is `#noSuchMethod`.
bool _hasMethod(ClassMirror type, Symbol name) {
while (type != objectType) {
final member = type.declarations[name];
@@ -356,14 +363,376 @@
return new RegExp('^$path\$');
}();
-final _spacesRegExp = new RegExp(r'\s');
-
bool _isPathValid(String s) {
- s = s.replaceAll(_spacesRegExp, '');
-
+ s = s.trim();
if (s == '') return true;
if (s[0] == '.') return false;
return _pathRegExp.hasMatch(s);
}
final Logger _logger = new Logger('observe.PathObserver');
+
+
+/// This is a simple cache. It's like LRU but we don't update an item on a
+/// cache hit, because that would require allocation. Better to let it expire
+/// and reallocate the PropertyPath.
+// TODO(jmesserly): this optimization is from observe-js, how valuable is it in
+// practice?
+final _pathCache = new LinkedHashMap<String, PropertyPath>();
+
+/// The size of a path like "foo.bar" is approximately 160 bytes, so this
+/// reserves ~16Kb of memory for recently used paths. Since paths are frequently
+/// reused, the theory is that this ends up being a good tradeoff in practice.
+// (Note: the 160 byte estimate is from Dart VM 1.0.0.10_r30798 on x64 without
+// using UnmodifiableListView in PropertyPath)
+const int _pathCacheLimit = 100;
+
+/// [CompoundObserver] is a [Bindable] object which knows how to listen to
+/// multiple values (registered via [addPath] or [addObserver]) and invoke a
+/// callback when one or more of the values have changed.
+///
+/// var obj = new ObservableMap.from({'a': 1, 'b': 2});
+/// var otherObj = new ObservableMap.from({'c': 3});
+///
+/// var observer = new CompoundObserver()
+/// ..addPath(obj, 'a');
+/// ..addObserver(new PathObserver(obj, 'b'));
+/// ..addPath(otherObj, 'c');
+/// ..open((values) {
+/// for (int i = 0; i < values.length; i++) {
+/// print('The value at index $i is now ${values[i]}');
+/// }
+/// });
+///
+/// obj['a'] = 10; // print will be triggered async
+///
+class CompoundObserver extends _Observer implements Bindable {
+ _ObservedSet _directObserver;
+ List _observed = [];
+
+ bool get _isClosed => _observed == null;
+
+ CompoundObserver() {
+ _value = [];
+ }
+
+ int get _reportArgumentCount => 3;
+
+ /// Initiates observation and returns the initial value.
+ /// The callback will be passed the updated [value], and may optionally be
+ /// declared to take a second argument, which will contain the previous value.
+ ///
+ /// Implementation note: a third argument can also be declared, which will
+ /// receive a list of objects and paths, such that `list[2 * i]` will access
+ /// the object and `list[2 * i + 1]` will access the path, where `i` is the
+ /// order of the [addPath] call. This parameter is only used by
+ /// `package:polymer` as a performance optimization, and should not be relied
+ /// on in new code.
+ open(callback) => super.open(callback);
+
+ void _connect() {
+ _check(skipChanges: true);
+
+ for (var i = 0; i < _observed.length; i += 2) {
+ var object = _observed[i];
+ if (!identical(object, _observerSentinel)) {
+ _directObserver = new _ObservedSet(this, object);
+ break;
+ }
+ }
+ }
+
+ void _disconnect() {
+ _value = null;
+
+ if (_directObserver != null) {
+ _directObserver.close(this);
+ _directObserver = null;
+ }
+
+ for (var i = 0; i < _observed.length; i += 2) {
+ if (identical(_observed[i], _observerSentinel)) {
+ _observed[i + 1].close();
+ }
+ }
+ _observed = null;
+ }
+
+ /// Adds a dependency on the property [path] accessed from [object].
+ /// [path] can be a [PropertyPath] or a [String]. If it is omitted an empty
+ /// path will be used.
+ void addPath(Object object, [path]) {
+ if (_isOpen || _isClosed) {
+ throw new StateError('Cannot add paths once started.');
+ }
+
+ if (path is! PropertyPath) path = new PropertyPath(path);
+ _observed..add(object)..add(path);
+ }
+
+ void addObserver(Bindable observer) {
+ if (_isOpen || _isClosed) {
+ throw new StateError('Cannot add observers once started.');
+ }
+
+ observer.open(_deliver);
+ _observed..add(_observerSentinel)..add(observer);
+ }
+
+ void _iterateObjects(void observe(obj)) {
+ for (var i = 0; i < _observed.length; i += 2) {
+ var object = _observed[i];
+ if (!identical(object, _observerSentinel)) {
+ (_observed[i + 1] as PropertyPath)._iterateObjects(object, observe);
+ }
+ }
+ }
+
+ bool _check({bool skipChanges: false}) {
+ bool changed = false;
+ _value.length = _observed.length ~/ 2;
+ var oldValues = null;
+ for (var i = 0; i < _observed.length; i += 2) {
+ var pathOrObserver = _observed[i + 1];
+ var object = _observed[i];
+ var value = identical(object, _observerSentinel) ?
+ (pathOrObserver as Bindable).value :
+ (pathOrObserver as PropertyPath).getValueFrom(object);
+
+ if (skipChanges) {
+ _value[i ~/ 2] = value;
+ continue;
+ }
+
+ if (value == _value[i ~/ 2]) continue;
+
+ // don't allocate this unless necessary.
+ if (_notifyArgumentCount >= 2) {
+ if (oldValues == null) oldValues = new Map();
+ oldValues[i ~/ 2] = _value[i ~/ 2];
+ }
+
+ changed = true;
+ _value[i ~/ 2] = value;
+ }
+
+ if (!changed) return false;
+
+ // TODO(rafaelw): Having _observed as the third callback arg here is
+ // pretty lame API. Fix.
+ _report(_value, oldValues, _observed);
+ return true;
+ }
+}
+
+const _observerSentinel = const _ObserverSentinel();
+class _ObserverSentinel { const _ObserverSentinel(); }
+
+// A base class for the shared API implemented by PathObserver and
+// CompoundObserver and used in _ObservedSet.
+abstract class _Observer extends Bindable {
+ static int _nextBirthId = 0;
+
+ /// A number indicating when the object was created.
+ final int _birthId = _nextBirthId++;
+
+ Function _notifyCallback;
+ int _notifyArgumentCount;
+ var _value;
+
+ // abstract members
+ void _iterateObjects(void observe(obj));
+ void _connect();
+ void _disconnect();
+ bool get _isClosed;
+ _check({bool skipChanges: false});
+
+ bool get _isOpen => _notifyCallback != null;
+
+ /// The number of arguments the subclass will pass to [_report].
+ int get _reportArgumentCount;
+
+ open(callback) {
+ if (_isOpen || _isClosed) {
+ throw new StateError('Observer has already been opened.');
+ }
+
+ if (_minArgumentCount(callback) > _reportArgumentCount) {
+ throw new ArgumentError('callback should take $_reportArgumentCount or '
+ 'fewer arguments');
+ }
+
+ _notifyCallback = callback;
+ _notifyArgumentCount = min(_reportArgumentCount,
+ _maxArgumentCount(callback));
+
+ _connect();
+ return _value;
+ }
+
+ @reflectable get value {
+ _check(skipChanges: true);
+ return _value;
+ }
+
+ void close() {
+ if (!_isOpen) return;
+
+ _disconnect();
+ _value = null;
+ _notifyCallback = null;
+ }
+
+ void _deliver(_) {
+ if (_isOpen) _dirtyCheck();
+ }
+
+ bool _dirtyCheck() {
+ var cycles = 0;
+ while (cycles < _MAX_DIRTY_CHECK_CYCLES && _check()) {
+ cycles++;
+ }
+ return cycles > 0;
+ }
+
+ void _report(newValue, oldValue, [extraArg]) {
+ try {
+ switch (_notifyArgumentCount) {
+ case 0: _notifyCallback(); break;
+ case 1: _notifyCallback(newValue); break;
+ case 2: _notifyCallback(newValue, oldValue); break;
+ case 3: _notifyCallback(newValue, oldValue, extraArg); break;
+ }
+ } catch (e, s) {
+ // Deliver errors async, so if a single callback fails it doesn't prevent
+ // other things from working.
+ new Completer().completeError(e, s);
+ }
+ }
+}
+
+typedef _Func0();
+typedef _Func1(a);
+typedef _Func2(a, b);
+typedef _Func3(a, b, c);
+
+int _minArgumentCount(fn) {
+ if (fn is _Func0) return 0;
+ if (fn is _Func1) return 1;
+ if (fn is _Func2) return 2;
+ if (fn is _Func3) return 3;
+ return 4; // at least 4 arguments are required.
+}
+
+int _maxArgumentCount(fn) {
+ if (fn is _Func3) return 3;
+ if (fn is _Func2) return 2;
+ if (fn is _Func1) return 1;
+ if (fn is _Func0) return 0;
+ return -1;
+}
+
+class _ObservedSet {
+ /// To prevent sequential [PathObserver]s and [CompoundObserver]s from
+ /// observing the same object, we check if they are observing the same root
+ /// as the most recently created observer, and if so merge it into the
+ /// existing _ObservedSet.
+ ///
+ /// See <https://github.com/Polymer/observe-js/commit/f0990b1> and
+ /// <https://codereview.appspot.com/46780044/>.
+ static _ObservedSet _lastSet;
+
+ /// The root object for a [PathObserver]. For a [CompoundObserver], the root
+ /// object of the first path observed. This is used by the constructor to
+ /// reuse an [_ObservedSet] that starts from the same object.
+ Object _rootObject;
+
+ /// Observers associated with this root object, in birth order.
+ final Map<int, _Observer> _observers = new SplayTreeMap();
+
+ // Dart note: the JS implementation is O(N^2) because Array.indexOf is used
+ // for lookup in these two arrays. We use HashMap to avoid this problem. It
+ // also gives us a nice way of tracking the StreamSubscription.
+ Map<Object, StreamSubscription> _objects;
+ Map<Object, StreamSubscription> _toRemove;
+
+ bool _resetNeeded = false;
+
+ factory _ObservedSet(_Observer observer, Object rootObj) {
+ if (_lastSet == null || !identical(_lastSet._rootObject, rootObj)) {
+ _lastSet = new _ObservedSet._(rootObj);
+ }
+ _lastSet.open(observer);
+ }
+
+ _ObservedSet._(this._rootObject);
+
+ void open(_Observer obs) {
+ _observers[obs._birthId] = obs;
+ obs._iterateObjects(observe);
+ }
+
+ void close(_Observer obs) {
+ var anyLeft = false;
+
+ _observers.remove(obs._birthId);
+
+ if (_observers.isNotEmpty) {
+ _resetNeeded = true;
+ scheduleMicrotask(reset);
+ return;
+ }
+ _resetNeeded = false;
+
+ if (_objects != null) {
+ for (var sub in _objects) sub.cancel();
+ _objects = null;
+ }
+ }
+
+ void observe(Object obj) {
+ if (obj is ObservableList) _observeStream(obj.listChanges);
+ if (obj is Observable) _observeStream(obj.changes);
+ }
+
+ void _observeStream(Stream stream) {
+ // TODO(jmesserly): we hash on streams as we have two separate change
+ // streams for ObservableList. Not sure if that is the design we will use
+ // going forward.
+
+ if (_objects == null) _objects = new HashMap();
+ StreamSubscription sub = null;
+ if (_toRemove != null) sub = _toRemove.remove(stream);
+ if (sub != null) {
+ _objects[stream] = sub;
+ } else if (!_objects.containsKey(stream)) {
+ _objects[stream] = stream.listen(_callback);
+ }
+ }
+
+ void reset() {
+ if (!_resetNeeded) return;
+
+ var objs = _toRemove == null ? new HashMap() : _toRemove;
+ _toRemove = _objects;
+ _objects = objs;
+ for (var observer in _observers.values) {
+ if (observer._isOpen) observer._iterateObjects(observe);
+ }
+
+ for (var sub in _toRemove.values) sub.cancel();
+
+ _toRemove = null;
+ }
+
+ void _callback(records) {
+ for (var observer in _observers.values.toList(growable: false)) {
+ if (observer._isOpen) observer._check();
+ }
+
+ _resetNeeded = true;
+ scheduleMicrotask(reset);
+ }
+}
+
+const int _MAX_DIRTY_CHECK_CYCLES = 1000;
diff --git a/pkg/observe/lib/transformer.dart b/pkg/observe/lib/transformer.dart
index 7e29672..035cff5 100644
--- a/pkg/observe/lib/transformer.dart
+++ b/pkg/observe/lib/transformer.dart
@@ -10,7 +10,6 @@
import 'dart:async';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart';
@@ -116,7 +115,7 @@
/** Parse [code] using analyzer. */
CompilationUnit _parseCompilationUnit(String code) {
var errorListener = new _ErrorCollector();
- var reader = new CharSequenceReader(new CharSequence(code));
+ var reader = new CharSequenceReader(code);
var scanner = new Scanner(null, reader, errorListener);
var token = scanner.tokenize();
var parser = new Parser(null, errorListener);
diff --git a/pkg/observe/pubspec.yaml b/pkg/observe/pubspec.yaml
index 87c8727..3b0407c 100644
--- a/pkg/observe/pubspec.yaml
+++ b/pkg/observe/pubspec.yaml
@@ -1,5 +1,5 @@
name: observe
-version: 0.9.3
+version: 0.10.0-dev
author: Polymer.dart Authors <web-ui-dev@dartlang.org>
description: >
Observable properties and objects for use in Model-Driven-Views (MDV).
diff --git a/pkg/observe/test/list_change_test.dart b/pkg/observe/test/list_change_test.dart
index 6aeac7c..30afb60 100644
--- a/pkg/observe/test/list_change_test.dart
+++ b/pkg/observe/test/list_change_test.dart
@@ -10,10 +10,7 @@
// This file contains code ported from:
// https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
-main() {
- // TODO(jmesserly): rename this? Is summarizeListChanges coming back?
- group('summarizeListChanges', listChangeTests);
-}
+main() => dirtyCheckZone().run(listChangeTests);
// TODO(jmesserly): port or write array fuzzer tests
listChangeTests() {
@@ -27,7 +24,7 @@
_delta(i, r, a) => new ListChangeRecord(model, i, removed: r, addedCount: a);
- observeTest('sequential adds', () {
+ test('sequential adds', () {
model = toObservable([]);
model.add(0);
@@ -38,12 +35,10 @@
model.add(2);
expect(summary, null);
- performMicrotaskCheckpoint();
-
- expectChanges(summary, [_delta(1, [], 2)]);
+ return new Future(() => expectChanges(summary, [_delta(1, [], 2)]));
});
- observeTest('List Splice Truncate And Expand With Length', () {
+ test('List Splice Truncate And Expand With Length', () {
model = toObservable(['a', 'b', 'c', 'd', 'e']);
var summary;
@@ -51,28 +46,20 @@
model.length = 2;
- performMicrotaskCheckpoint();
- expectChanges(summary, [_delta(2, ['c', 'd', 'e'], 0)]);
- summary = null;
+ return new Future(() {
+ expectChanges(summary, [_delta(2, ['c', 'd', 'e'], 0)]);
+ summary = null;
+ model.length = 5;
- model.length = 5;
+ }).then(newMicrotask).then((_) {
- performMicrotaskCheckpoint();
- expectChanges(summary, [_delta(2, [], 3)]);
+ expectChanges(summary, [_delta(2, [], 3)]);
+ });
});
group('List deltas can be applied', () {
- var summary = null;
-
- observeArray(model) {
- sub = model.listChanges.listen((r) { summary = r; });
- }
-
- applyAndCheckDeltas(model, copy) {
- summary = null;
- performMicrotaskCheckpoint();
-
+ applyAndCheckDeltas(model, copy, changes) => changes.then((summary) {
// apply deltas to the copy
for (var delta in summary) {
copy.removeRange(delta.index, delta.index + delta.removed.length);
@@ -83,75 +70,75 @@
// Note: compare strings for easier debugging.
expect('$copy', '$model', reason: 'summary $summary');
- }
+ });
- observeTest('Contained', () {
+ test('Contained', () {
var model = toObservable(['a', 'b']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeAt(1);
model.insertAll(0, ['c', 'd', 'e']);
model.removeRange(1, 3);
model.insert(1, 'f');
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Delete Empty', () {
+ test('Delete Empty', () {
var model = toObservable([1]);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeAt(0);
model.insertAll(0, ['a', 'b', 'c']);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Right Non Overlap', () {
+ test('Right Non Overlap', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeRange(0, 1);
model.insert(0, 'e');
model.removeRange(2, 3);
model.insertAll(2, ['f', 'g']);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Left Non Overlap', () {
+ test('Left Non Overlap', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeRange(3, 4);
model.insertAll(3, ['f', 'g']);
model.removeRange(0, 1);
model.insert(0, 'e');
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Right Adjacent', () {
+ test('Right Adjacent', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeRange(1, 2);
model.insert(3, 'e');
model.removeRange(2, 3);
model.insertAll(0, ['f', 'g']);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Left Adjacent', () {
+ test('Left Adjacent', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeRange(2, 4);
model.insert(2, 'e');
@@ -159,26 +146,26 @@
model.removeAt(1);
model.insertAll(1, ['f', 'g']);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Right Overlap', () {
+ test('Right Overlap', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeAt(1);
model.insert(1, 'e');
model.removeAt(1);
model.insertAll(1, ['f', 'g']);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Left Overlap', () {
+ test('Left Overlap', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeAt(2);
model.insertAll(2, ['e', 'f', 'g']);
@@ -187,105 +174,95 @@
model.insertAll(1, ['h', 'i', 'j']);
// a [h i j] f g d
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Prefix And Suffix One In', () {
+ test('Prefix And Suffix One In', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.insert(0, 'z');
model.add('z');
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Remove First', () {
+ test('Remove First', () {
var model = toObservable([16, 15, 15]);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeAt(0);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Update Remove', () {
+ test('Update Remove', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeAt(2);
model.insertAll(2, ['e', 'f', 'g']); // a b [e f g] d
model[0] = 'h';
model.removeAt(1);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
- observeTest('Remove Mid List', () {
+ test('Remove Mid List', () {
var model = toObservable(['a', 'b', 'c', 'd']);
var copy = model.toList();
- observeArray(model);
+ var changes = model.listChanges.first;
model.removeAt(2);
- applyAndCheckDeltas(model, copy);
+ return applyAndCheckDeltas(model, copy, changes);
});
});
group('edit distance', () {
- var summary = null;
- observeArray(model) {
- sub = model.listChanges.listen((r) { summary = r; });
- }
-
- assertEditDistance(orig, expectDistance) {
- summary = null;
- performMicrotaskCheckpoint();
+ assertEditDistance(orig, changes, expectedDist) => changes.then((summary) {
var actualDistance = 0;
-
- if (summary != null) {
- for (var delta in summary) {
- actualDistance += delta.addedCount + delta.removed.length;
- }
+ for (var delta in summary) {
+ actualDistance += delta.addedCount + delta.removed.length;
}
- expect(actualDistance, expectDistance);
- }
-
- observeTest('add items', () {
- var model = toObservable([]);
- observeArray(model);
- model.addAll([1, 2, 3]);
- assertEditDistance(model, 3);
+ expect(actualDistance, expectedDist);
});
- observeTest('trunacte and add, sharing a contiguous block', () {
+ test('add items', () {
+ var model = toObservable([]);
+ var changes = model.listChanges.first;
+ model.addAll([1, 2, 3]);
+ return assertEditDistance(model, changes, 3);
+ });
+
+ test('trunacte and add, sharing a contiguous block', () {
var model = toObservable(['x', 'x', 'x', 'x', '1', '2', '3']);
- observeArray(model);
+ var changes = model.listChanges.first;
model.length = 0;
model.addAll(['1', '2', '3', 'y', 'y', 'y', 'y']);
- assertEditDistance(model, 8);
+ return assertEditDistance(model, changes, 8);
});
- observeTest('truncate and add, sharing a discontiguous block', () {
+ test('truncate and add, sharing a discontiguous block', () {
var model = toObservable(['1', '2', '3', '4', '5']);
- observeArray(model);
+ var changes = model.listChanges.first;
model.length = 0;
model.addAll(['a', '2', 'y', 'y', '4', '5', 'z', 'z']);
- assertEditDistance(model, 7);
+ return assertEditDistance(model, changes, 7);
});
- observeTest('insert at beginning and end', () {
+ test('insert at beginning and end', () {
var model = toObservable([2, 3, 4]);
- observeArray(model);
+ var changes = model.listChanges.first;
model.insert(0, 5);
model[2] = 6;
model.add(7);
- assertEditDistance(model, 4);
+ return assertEditDistance(model, changes, 4);
});
});
}
diff --git a/pkg/observe/test/observable_list_test.dart b/pkg/observe/test/observable_list_test.dart
index 66a03d3..81ca45f 100644
--- a/pkg/observe/test/observable_list_test.dart
+++ b/pkg/observe/test/observable_list_test.dart
@@ -7,7 +7,9 @@
import 'package:unittest/unittest.dart';
import 'observe_test_utils.dart';
-main() {
+main() => dirtyCheckZone().run(_runTests);
+
+_runTests() {
// TODO(jmesserly): need all standard List API tests.
StreamSubscription sub, sub2;
@@ -36,48 +38,54 @@
tearDown(sharedTearDown);
- observeTest('add changes length', () {
+ test('add changes length', () {
list.add(4);
expect(list, [1, 2, 3, 4]);
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(3, 4)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(3, 4)]);
+ });
});
- observeTest('removeObject', () {
+ test('removeObject', () {
list.remove(2);
expect(list, orderedEquals([1, 3]));
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(3, 2)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(3, 2)]);
+ });
});
- observeTest('removeRange changes length', () {
+ test('removeRange changes length', () {
list.add(4);
list.removeRange(1, 3);
expect(list, [1, 4]);
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(3, 4), _lengthChange(4, 2)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(3, 4), _lengthChange(4, 2)]);
+ });
});
- observeTest('length= changes length', () {
+ test('length= changes length', () {
list.length = 5;
expect(list, [1, 2, 3, null, null]);
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(3, 5)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(3, 5)]);
+ });
});
- observeTest('[]= does not change length', () {
+ test('[]= does not change length', () {
list[2] = 9000;
expect(list, [1, 2, 9000]);
- performMicrotaskCheckpoint();
- expectChanges(changes, null);
+ return new Future(() {
+ expectChanges(changes, null);
+ });
});
- observeTest('clear changes length', () {
+ test('clear changes length', () {
list.clear();
expect(list, []);
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(3, 0)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(3, 0)]);
+ });
});
});
@@ -94,71 +102,79 @@
tearDown(sharedTearDown);
- observeTest('add does not change existing items', () {
+ test('add does not change existing items', () {
list.add(4);
expect(list, [1, 2, 3, 4]);
- performMicrotaskCheckpoint();
- expectChanges(changes, []);
+ return new Future(() {
+ expectChanges(changes, []);
+ });
});
- observeTest('[]= changes item', () {
+ test('[]= changes item', () {
list[1] = 777;
expect(list, [1, 777, 3]);
- performMicrotaskCheckpoint();
- expectChanges(changes, [_change(1, addedCount: 1, removed: [2])]);
+ return new Future(() {
+ expectChanges(changes, [_change(1, addedCount: 1, removed: [2])]);
+ });
});
- observeTest('[]= on a different item does not fire change', () {
+ test('[]= on a different item does not fire change', () {
list[2] = 9000;
expect(list, [1, 2, 9000]);
- performMicrotaskCheckpoint();
- expectChanges(changes, []);
+ return new Future(() {
+ expectChanges(changes, []);
+ });
});
- observeTest('set multiple times results in one change', () {
+ test('set multiple times results in one change', () {
list[1] = 777;
list[1] = 42;
expect(list, [1, 42, 3]);
- performMicrotaskCheckpoint();
- expectChanges(changes, [
- _change(1, addedCount: 1, removed: [2]),
- ]);
+ return new Future(() {
+ expectChanges(changes, [
+ _change(1, addedCount: 1, removed: [2]),
+ ]);
+ });
});
- observeTest('set length without truncating item means no change', () {
+ test('set length without truncating item means no change', () {
list.length = 2;
expect(list, [1, 2]);
- performMicrotaskCheckpoint();
- expectChanges(changes, []);
+ return new Future(() {
+ expectChanges(changes, []);
+ });
});
- observeTest('truncate removes item', () {
+ test('truncate removes item', () {
list.length = 1;
expect(list, [1]);
- performMicrotaskCheckpoint();
- expectChanges(changes, [_change(1, removed: [2, 3])]);
+ return new Future(() {
+ expectChanges(changes, [_change(1, removed: [2, 3])]);
+ });
});
- observeTest('truncate and add new item', () {
+ test('truncate and add new item', () {
list.length = 1;
list.add(42);
expect(list, [1, 42]);
- performMicrotaskCheckpoint();
- expectChanges(changes, [
- _change(1, removed: [2, 3], addedCount: 1)
- ]);
+ return new Future(() {
+ expectChanges(changes, [
+ _change(1, removed: [2, 3], addedCount: 1)
+ ]);
+ });
});
- observeTest('truncate and add same item', () {
+ test('truncate and add same item', () {
list.length = 1;
list.add(2);
expect(list, [1, 2]);
- performMicrotaskCheckpoint();
- expectChanges(changes, []);
+ return new Future(() {
+ expectChanges(changes, []);
+ });
});
});
- observeTest('toString', () {
+ test('toString', () {
var list = toObservable([1, 2, 3]);
expect(list.toString(), '[1, 2, 3]');
});
@@ -178,7 +194,7 @@
tearDown(sharedTearDown);
- observeTest('read operations', () {
+ test('read operations', () {
expect(list.length, 6);
expect(list[0], 1);
expect(list.indexOf(4), 5);
@@ -189,76 +205,82 @@
var copy = new List<int>();
list.forEach((i) { copy.add(i); });
expect(copy, orderedEquals([1, 2, 3, 1, 3, 4]));
- performMicrotaskCheckpoint();
-
- // no change from read-only operators
- expectChanges(propRecords, null);
- expectChanges(listRecords, null);
+ return new Future(() {
+ // no change from read-only operators
+ expectChanges(propRecords, null);
+ expectChanges(listRecords, null);
+ });
});
- observeTest('add', () {
+ test('add', () {
list.add(5);
list.add(6);
expect(list, orderedEquals([1, 2, 3, 1, 3, 4, 5, 6]));
- performMicrotaskCheckpoint();
- expectChanges(propRecords, [
- _lengthChange(6, 7),
- _lengthChange(7, 8),
- ]);
- expectChanges(listRecords, [ _change(6, addedCount: 2) ]);
+ return new Future(() {
+ expectChanges(propRecords, [
+ _lengthChange(6, 7),
+ _lengthChange(7, 8),
+ ]);
+ expectChanges(listRecords, [ _change(6, addedCount: 2) ]);
+ });
});
- observeTest('[]=', () {
+ test('[]=', () {
list[1] = list.last;
expect(list, orderedEquals([1, 4, 3, 1, 3, 4]));
- performMicrotaskCheckpoint();
- expectChanges(propRecords, null);
- expectChanges(listRecords, [ _change(1, addedCount: 1, removed: [2]) ]);
+ return new Future(() {
+ expectChanges(propRecords, null);
+ expectChanges(listRecords, [ _change(1, addedCount: 1, removed: [2]) ]);
+ });
});
- observeTest('removeLast', () {
+ test('removeLast', () {
expect(list.removeLast(), 4);
expect(list, orderedEquals([1, 2, 3, 1, 3]));
- performMicrotaskCheckpoint();
- expectChanges(propRecords, [_lengthChange(6, 5)]);
- expectChanges(listRecords, [_change(5, removed: [4])]);
+ return new Future(() {
+ expectChanges(propRecords, [_lengthChange(6, 5)]);
+ expectChanges(listRecords, [_change(5, removed: [4])]);
+ });
});
- observeTest('removeRange', () {
+ test('removeRange', () {
list.removeRange(1, 4);
expect(list, orderedEquals([1, 3, 4]));
- performMicrotaskCheckpoint();
- expectChanges(propRecords, [_lengthChange(6, 3)]);
- expectChanges(listRecords, [_change(1, removed: [2, 3, 1])]);
+ return new Future(() {
+ expectChanges(propRecords, [_lengthChange(6, 3)]);
+ expectChanges(listRecords, [_change(1, removed: [2, 3, 1])]);
+ });
});
- observeTest('sort', () {
+ test('sort', () {
list.sort((x, y) => x - y);
expect(list, orderedEquals([1, 1, 2, 3, 3, 4]));
- performMicrotaskCheckpoint();
- expectChanges(propRecords, null);
- expectChanges(listRecords, [
- _change(1, addedCount: 1),
- _change(4, removed: [1])
- ]);
+ return new Future(() {
+ expectChanges(propRecords, null);
+ expectChanges(listRecords, [
+ _change(1, addedCount: 1),
+ _change(4, removed: [1])
+ ]);
+ });
});
- observeTest('clear', () {
+ test('clear', () {
list.clear();
expect(list, []);
- performMicrotaskCheckpoint();
- expectChanges(propRecords, [
- _lengthChange(6, 0),
- new PropertyChangeRecord(list, #isEmpty, false, true),
- new PropertyChangeRecord(list, #isNotEmpty, true, false),
- ]);
- expectChanges(listRecords, [_change(0, removed: [1, 2, 3, 1, 3, 4])]);
+ return new Future(() {
+ expectChanges(propRecords, [
+ _lengthChange(6, 0),
+ new PropertyChangeRecord(list, #isEmpty, false, true),
+ new PropertyChangeRecord(list, #isNotEmpty, true, false),
+ ]);
+ expectChanges(listRecords, [_change(0, removed: [1, 2, 3, 1, 3, 4])]);
+ });
});
});
}
diff --git a/pkg/observe/test/observable_map_test.dart b/pkg/observe/test/observable_map_test.dart
index c7ac0cf..063287e 100644
--- a/pkg/observe/test/observable_map_test.dart
+++ b/pkg/observe/test/observable_map_test.dart
@@ -7,7 +7,9 @@
import 'package:unittest/unittest.dart';
import 'observe_test_utils.dart';
-main() {
+main() => dirtyCheckZone().run(_runTests);
+
+_runTests() {
// TODO(jmesserly): need all standard Map API tests.
StreamSubscription sub;
@@ -33,50 +35,56 @@
tearDown(sharedTearDown);
- observeTest('add item changes length', () {
+ test('add item changes length', () {
map['d'] = 4;
expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(map, 3, 4)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(map, 3, 4)]);
+ });
});
- observeTest('putIfAbsent changes length', () {
+ test('putIfAbsent changes length', () {
map.putIfAbsent('d', () => 4);
expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(map, 3, 4)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(map, 3, 4)]);
+ });
});
- observeTest('remove changes length', () {
+ test('remove changes length', () {
map.remove('c');
map.remove('a');
expect(map, {'b': 2});
- performMicrotaskCheckpoint();
- expectChanges(changes, [
- _lengthChange(map, 3, 2),
- _lengthChange(map, 2, 1)
- ]);
+ return new Future(() {
+ expectChanges(changes, [
+ _lengthChange(map, 3, 2),
+ _lengthChange(map, 2, 1)
+ ]);
+ });
});
- observeTest('remove non-existent item does not change length', () {
+ test('remove non-existent item does not change length', () {
map.remove('d');
expect(map, {'a': 1, 'b': 2, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes, null);
+ return new Future(() {
+ expectChanges(changes, null);
+ });
});
- observeTest('set existing item does not change length', () {
+ test('set existing item does not change length', () {
map['c'] = 9000;
expect(map, {'a': 1, 'b': 2, 'c': 9000});
- performMicrotaskCheckpoint();
- expectChanges(changes, []);
+ return new Future(() {
+ expectChanges(changes, []);
+ });
});
- observeTest('clear changes length', () {
+ test('clear changes length', () {
map.clear();
expect(map, {});
- performMicrotaskCheckpoint();
- expectChanges(changes, [_lengthChange(map, 3, 0)]);
+ return new Future(() {
+ expectChanges(changes, [_lengthChange(map, 3, 0)]);
+ });
});
});
@@ -96,77 +104,86 @@
tearDown(sharedTearDown);
- observeTest('putIfAbsent new item does not change existing item', () {
+ test('putIfAbsent new item does not change existing item', () {
map.putIfAbsent('d', () => 4);
expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
- performMicrotaskCheckpoint();
- expectChanges(changes, []);
+ return new Future(() {
+ expectChanges(changes, []);
+ });
});
- observeTest('set item to null', () {
+ test('set item to null', () {
map['b'] = null;
expect(map, {'a': 1, 'b': null, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes, [_changeKey('b', 2, null)]);
+ return new Future(() {
+ expectChanges(changes, [_changeKey('b', 2, null)]);
+ });
});
- observeTest('set item to value', () {
+ test('set item to value', () {
map['b'] = 777;
expect(map, {'a': 1, 'b': 777, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes, [_changeKey('b', 2, 777)]);
+ return new Future(() {
+ expectChanges(changes, [_changeKey('b', 2, 777)]);
+ });
});
- observeTest('putIfAbsent does not change if already there', () {
+ test('putIfAbsent does not change if already there', () {
map.putIfAbsent('b', () => 1234);
expect(map, {'a': 1, 'b': 2, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes, null);
+ return new Future(() {
+ expectChanges(changes, null);
+ });
});
- observeTest('change a different item', () {
+ test('change a different item', () {
map['c'] = 9000;
expect(map, {'a': 1, 'b': 2, 'c': 9000});
- performMicrotaskCheckpoint();
+ return new Future(() {
expectChanges(changes, []);
+ });
});
- observeTest('change the item', () {
+ test('change the item', () {
map['b'] = 9001;
map['b'] = 42;
expect(map, {'a': 1, 'b': 42, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes, [
- _changeKey('b', 2, 9001),
- _changeKey('b', 9001, 42)
- ]);
+ return new Future(() {
+ expectChanges(changes, [
+ _changeKey('b', 2, 9001),
+ _changeKey('b', 9001, 42)
+ ]);
+ });
});
- observeTest('remove other items', () {
+ test('remove other items', () {
map.remove('a');
expect(map, {'b': 2, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes, []);
+ return new Future(() {
+ expectChanges(changes, []);
+ });
});
- observeTest('remove the item', () {
+ test('remove the item', () {
map.remove('b');
expect(map, {'a': 1, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes, [_removeKey('b', 2)]);
+ return new Future(() {
+ expectChanges(changes, [_removeKey('b', 2)]);
+ });
});
- observeTest('remove and add back', () {
+ test('remove and add back', () {
map.remove('b');
map['b'] = 2;
expect(map, {'a': 1, 'b': 2, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(changes,
- [_removeKey('b', 2), _insertKey('b', 2)]);
+ return new Future(() {
+ expectChanges(changes,
+ [_removeKey('b', 2), _insertKey('b', 2)]);
+ });
});
});
- observeTest('toString', () {
+ test('toString', () {
var map = toObservable({'a': 1, 'b': 2});
expect(map.toString(), '{a: 1, b: 2}');
});
@@ -183,7 +200,7 @@
tearDown(sharedTearDown);
- observeTest('read operations', () {
+ test('read operations', () {
expect(map.length, 2);
expect(map.isEmpty, false);
expect(map['a'], 1);
@@ -195,65 +212,69 @@
var copy = {};
map.forEach((k, v) { copy[k] = v; });
expect(copy, {'a': 1, 'b': 2});
- performMicrotaskCheckpoint();
+ return new Future(() {
+ // no change from read-only operators
+ expect(records, null);
- // no change from read-only operators
- expect(records, null);
-
- // Make a change so the subscription gets unregistered.
- map.clear();
+ // Make a change so the subscription gets unregistered.
+ map.clear();
+ });
});
- observeTest('putIfAbsent', () {
+ test('putIfAbsent', () {
map.putIfAbsent('a', () => 42);
expect(map, {'a': 1, 'b': 2});
map.putIfAbsent('c', () => 3);
expect(map, {'a': 1, 'b': 2, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(records, [
- _lengthChange(map, 2, 3),
- _insertKey('c', 3),
- ]);
+ return new Future(() {
+ expectChanges(records, [
+ _lengthChange(map, 2, 3),
+ _insertKey('c', 3),
+ ]);
+ });
});
- observeTest('[]=', () {
+ test('[]=', () {
map['a'] = 42;
expect(map, {'a': 42, 'b': 2});
map['c'] = 3;
expect(map, {'a': 42, 'b': 2, 'c': 3});
- performMicrotaskCheckpoint();
- expectChanges(records, [
- _changeKey('a', 1, 42),
- _lengthChange(map, 2, 3),
- _insertKey('c', 3)
- ]);
+ return new Future(() {
+ expectChanges(records, [
+ _changeKey('a', 1, 42),
+ _lengthChange(map, 2, 3),
+ _insertKey('c', 3)
+ ]);
+ });
});
- observeTest('remove', () {
+ test('remove', () {
map.remove('b');
expect(map, {'a': 1});
- performMicrotaskCheckpoint();
- expectChanges(records, [
- _removeKey('b', 2),
- _lengthChange(map, 2, 1),
- ]);
+ return new Future(() {
+ expectChanges(records, [
+ _removeKey('b', 2),
+ _lengthChange(map, 2, 1),
+ ]);
+ });
});
- observeTest('clear', () {
+ test('clear', () {
map.clear();
expect(map, {});
- performMicrotaskCheckpoint();
- expectChanges(records, [
- _removeKey('a', 1),
- _removeKey('b', 2),
- _lengthChange(map, 2, 0),
- ]);
+ return new Future(() {
+ expectChanges(records, [
+ _removeKey('a', 1),
+ _removeKey('b', 2),
+ _lengthChange(map, 2, 0),
+ ]);
+ });
});
});
}
diff --git a/pkg/observe/test/observe_test.dart b/pkg/observe/test/observe_test.dart
index 9376ed3..f973db9 100644
--- a/pkg/observe/test/observe_test.dart
+++ b/pkg/observe/test/observe_test.dart
@@ -9,11 +9,13 @@
import 'package:unittest/unittest.dart';
import 'observe_test_utils.dart';
-void main() {
+main() => dirtyCheckZone().run(_tests);
+
+void _tests() {
// Note: to test the basic Observable system, we use ObservableBox due to its
// simplicity. We also test a variant that is based on dirty-checking.
- observeTest('no observers at the start', () {
+ test('no observers at the start', () {
expect(dirty_check.allObservablesCount, 0);
});
@@ -73,18 +75,18 @@
tearDown(() {
for (var sub in subs) sub.cancel();
- performMicrotaskCheckpoint();
-
- expect(dirty_check.allObservablesCount, initialObservers,
- reason: 'Observable object leaked');
+ return new Future(() {
+ expect(dirty_check.allObservablesCount, initialObservers,
+ reason: 'Observable object leaked');
+ });
});
- observeTest('handle future result', () {
+ test('handle future result', () {
var callback = expectAsync0((){});
return new Future(callback);
});
- observeTest('no observers', () {
+ test('no observers', () {
var t = createModel(123);
expect(t.value, 123);
t.value = 42;
@@ -92,7 +94,7 @@
expect(t.hasObservers, false);
});
- observeTest('listen adds an observer', () {
+ test('listen adds an observer', () {
var t = createModel(123);
expect(t.hasObservers, false);
@@ -100,7 +102,7 @@
expect(t.hasObservers, true);
});
- observeTest('changes delived async', () {
+ test('changes delived async', () {
var t = createModel(123);
int called = 0;
@@ -114,7 +116,7 @@
expect(called, 0);
});
- observeTest('cause changes in handler', () {
+ test('cause changes in handler', () {
var t = createModel(123);
int called = 0;
@@ -130,7 +132,7 @@
t.value = 42;
});
- observeTest('multiple observers', () {
+ test('multiple observers', () {
var t = createModel(123);
verifyRecords(records) {
@@ -144,7 +146,7 @@
t.value = 42;
});
- observeTest('performMicrotaskCheckpoint', () {
+ test('async processing model', () {
var t = createModel(123);
var records = [];
subs.add(t.changes.listen((r) { records.addAll(r); }));
@@ -152,22 +154,23 @@
t.value = 42;
expectChanges(records, [], reason: 'changes delived async');
- performMicrotaskCheckpoint();
- expectPropertyChanges(records, watch ? 1 : 2);
- records.clear();
+ return new Future(() {
+ expectPropertyChanges(records, watch ? 1 : 2);
+ records.clear();
- t.value = 777;
- expectChanges(records, [], reason: 'changes delived async');
+ t.value = 777;
+ expectChanges(records, [], reason: 'changes delived async');
- performMicrotaskCheckpoint();
- expectPropertyChanges(records, 1);
+ }).then(newMicrotask).then((_) {
+ expectPropertyChanges(records, 1);
- // Has no effect if there are no changes
- performMicrotaskCheckpoint();
- expectPropertyChanges(records, 1);
+ // Has no effect if there are no changes
+ Observable.dirtyCheck();
+ expectPropertyChanges(records, 1);
+ });
});
- observeTest('cancel listening', () {
+ test('cancel listening', () {
var t = createModel(123);
var sub;
sub = t.changes.listen(expectAsync1((records) {
@@ -179,7 +182,7 @@
t.value = 42;
});
- observeTest('cancel and reobserve', () {
+ test('cancel and reobserve', () {
var t = createModel(123);
var sub;
sub = t.changes.listen(expectAsync1((records) {
@@ -197,47 +200,50 @@
t.value = 42;
});
- observeTest('cannot modify changes list', () {
+ test('cannot modify changes list', () {
var t = createModel(123);
var records = null;
subs.add(t.changes.listen((r) { records = r; }));
t.value = 42;
- performMicrotaskCheckpoint();
- expectPropertyChanges(records, 1);
+ return new Future(() {
+ expectPropertyChanges(records, 1);
- // Verify that mutation operations on the list fail:
+ // Verify that mutation operations on the list fail:
- expect(() {
- records[0] = new PropertyChangeRecord(t, #value, 0, 1);
- }, throwsUnsupportedError);
+ expect(() {
+ records[0] = new PropertyChangeRecord(t, #value, 0, 1);
+ }, throwsUnsupportedError);
- expect(() { records.clear(); }, throwsUnsupportedError);
+ expect(() { records.clear(); }, throwsUnsupportedError);
- expect(() { records.length = 0; }, throwsUnsupportedError);
+ expect(() { records.length = 0; }, throwsUnsupportedError);
+ });
});
- observeTest('notifyChange', () {
+ test('notifyChange', () {
var t = createModel(123);
var records = [];
subs.add(t.changes.listen((r) { records.addAll(r); }));
t.notifyChange(new PropertyChangeRecord(t, #value, 123, 42));
- performMicrotaskCheckpoint();
- expectPropertyChanges(records, 1);
- expect(t.value, 123, reason: 'value did not actually change.');
+ return new Future(() {
+ expectPropertyChanges(records, 1);
+ expect(t.value, 123, reason: 'value did not actually change.');
+ });
});
- observeTest('notifyPropertyChange', () {
+ test('notifyPropertyChange', () {
var t = createModel(123);
var records = null;
subs.add(t.changes.listen((r) { records = r; }));
expect(t.notifyPropertyChange(#value, t.value, 42), 42,
reason: 'notifyPropertyChange returns newValue');
- performMicrotaskCheckpoint();
- expectPropertyChanges(records, 1);
- expect(t.value, 123, reason: 'value did not actually change.');
+ return new Future(() {
+ expectPropertyChanges(records, 1);
+ expect(t.value, 123, reason: 'value did not actually change.');
+ });
});
}
diff --git a/pkg/observe/test/observe_test_utils.dart b/pkg/observe/test/observe_test_utils.dart
index af447dc..02a88e2 100644
--- a/pkg/observe/test/observe_test_utils.dart
+++ b/pkg/observe/test/observe_test_utils.dart
@@ -4,12 +4,16 @@
library observe.test.observe_test_utils;
+import 'dart:async';
import 'package:observe/observe.dart';
-
import 'package:unittest/unittest.dart';
+export 'package:observe/src/dirty_check.dart' show dirtyCheckZone;
-import 'package:observe/src/microtask.dart';
-export 'package:observe/src/microtask.dart';
+/// A small method to help readability. Used to cause the next "then" in a chain
+/// to happen in the next microtask:
+///
+/// future.then(newMicrotask).then(...)
+newMicrotask(_) => new Future.value();
// TODO(jmesserly): use matchers when we have a way to compare ChangeRecords.
// For now just use the toString.
@@ -21,13 +25,3 @@
List getPropertyChangeRecords(List changes, Symbol property) => changes
.where((c) => c is PropertyChangeRecord && c.name == property).toList();
-
-/**
- * This is a special kind of unit [test], that supports
- * calling [performMicrotaskCheckpoint] during the test to pump events
- * that original from observable objects.
- */
-observeTest(name, testCase) => test(name, wrapMicrotask(testCase));
-
-/** The [solo_test] version of [observeTest]. */
-solo_observeTest(name, testCase) => solo_test(name, wrapMicrotask(testCase));
diff --git a/pkg/observe/test/path_observer_test.dart b/pkg/observe/test/path_observer_test.dart
index dcb8853..0993c69 100644
--- a/pkg/observe/test/path_observer_test.dart
+++ b/pkg/observe/test/path_observer_test.dart
@@ -2,6 +2,7 @@
// 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 'package:observe/observe.dart';
import 'package:unittest/unittest.dart';
import 'observe_test_utils.dart';
@@ -9,240 +10,293 @@
// This file contains code ported from:
// https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
-main() {
+main() => dirtyCheckZone().run(() {
group('PathObserver', observePathTests);
-}
-observePath(obj, path) => new PathObserver(obj, path);
+ group('PropertyPath', () {
+ test('toString length', () {
+ expectPath(p, str, len) {
+ var path = new PropertyPath(p);
+ expect(path.toString(), str);
+ expect(path.length, len, reason: 'expected path length $len for $path');
+ }
+
+ expectPath('/foo', '<invalid path>', 0);
+ expectPath('abc', 'abc', 1);
+ expectPath('a.b.c', 'a.b.c', 3);
+ expectPath('a.b.c ', 'a.b.c', 3);
+ expectPath(' a.b.c', 'a.b.c', 3);
+ expectPath(' a.b.c ', 'a.b.c', 3);
+ expectPath('1.abc', '1.abc', 2);
+ expectPath([#qux], 'qux', 1);
+ expectPath([1, #foo, #bar], '1.foo.bar', 3);
+ });
+
+ test('caching and ==', () {
+ var start = new PropertyPath('abc.0');
+ for (int i = 1; i <= 100; i++) {
+ expect(identical(new PropertyPath('abc.0'), start), true,
+ reason: 'should return identical path');
+
+ var p = new PropertyPath('abc.$i');
+ expect(identical(p, start), false,
+ reason: 'different paths should not be merged');
+ }
+ var end = new PropertyPath('abc.0');
+ expect(identical(end, start), false,
+ reason: 'first entry expired');
+ expect(end, start, reason: 'different instances are equal');
+ });
+
+ test('hashCode equal', () {
+ var a = new PropertyPath([#foo, 2, #bar]);
+ var b = new PropertyPath('foo.2.bar');
+ expect(identical(a, b), false, reason: 'only strings cached');
+ expect(a, b, reason: 'same paths are equal');
+ expect(a.hashCode, b.hashCode, reason: 'equal hashCodes');
+ });
+
+ test('hashCode not equal', () {
+ expect(2.hashCode, isNot(3.hashCode),
+ reason: 'test depends on 2 and 3 having different hashcodes');
+
+ var a = new PropertyPath([2]);
+ var b = new PropertyPath([3]);
+ expect(a, isNot(b), reason: 'different paths');
+ expect(a.hashCode, isNot(b.hashCode), reason: 'different hashCodes');
+ });
+ });
+});
+
observePathTests() {
- observeTest('Degenerate Values', () {
- expect(observePath(null, '').value, null);
- expect(observePath(123, '').value, 123);
- expect(observePath(123, 'foo.bar.baz').value, null);
+ test('Degenerate Values', () {
+ expect(new PathObserver(null, '').value, null);
+ expect(new PathObserver(123, '').value, 123);
+ expect(new PathObserver(123, 'foo.bar.baz').value, null);
// shouldn't throw:
- observePath(123, '').changes.listen((_) {}).cancel();
- observePath(null, '').value = null;
- observePath(123, '').value = 42;
- observePath(123, 'foo.bar.baz').value = 42;
+ new PathObserver(123, '')..open((_) {})..close();
+ new PropertyPath('').setValueFrom(null, null);
+ new PropertyPath('').setValueFrom(123, 42);
+ new PropertyPath('foo.bar.baz').setValueFrom(123, 42);
var foo = {};
- expect(observePath(foo, '').value, foo);
+ expect(new PathObserver(foo, '').value, foo);
foo = new Object();
- expect(observePath(foo, '').value, foo);
+ expect(new PathObserver(foo, '').value, foo);
- expect(observePath(foo, 'a/3!').value, null);
+ expect(new PathObserver(foo, 'a/3!').value, null);
});
- observeTest('get value at path ObservableBox', () {
+ test('get value at path ObservableBox', () {
var obj = new ObservableBox(new ObservableBox(new ObservableBox(1)));
- expect(observePath(obj, '').value, obj);
- expect(observePath(obj, 'value').value, obj.value);
- expect(observePath(obj, 'value.value').value, obj.value.value);
- expect(observePath(obj, 'value.value.value').value, 1);
+ expect(new PathObserver(obj, '').value, obj);
+ expect(new PathObserver(obj, 'value').value, obj.value);
+ expect(new PathObserver(obj, 'value.value').value, obj.value.value);
+ expect(new PathObserver(obj, 'value.value.value').value, 1);
obj.value.value.value = 2;
- expect(observePath(obj, 'value.value.value').value, 2);
+ expect(new PathObserver(obj, 'value.value.value').value, 2);
obj.value.value = new ObservableBox(3);
- expect(observePath(obj, 'value.value.value').value, 3);
+ expect(new PathObserver(obj, 'value.value.value').value, 3);
obj.value = new ObservableBox(4);
- expect(observePath(obj, 'value.value.value').value, null);
- expect(observePath(obj, 'value.value').value, 4);
+ expect(new PathObserver(obj, 'value.value.value').value, null);
+ expect(new PathObserver(obj, 'value.value').value, 4);
});
- observeTest('get value at path ObservableMap', () {
+ test('get value at path ObservableMap', () {
var obj = toObservable({'a': {'b': {'c': 1}}});
- expect(observePath(obj, '').value, obj);
- expect(observePath(obj, 'a').value, obj['a']);
- expect(observePath(obj, 'a.b').value, obj['a']['b']);
- expect(observePath(obj, 'a.b.c').value, 1);
+ expect(new PathObserver(obj, '').value, obj);
+ expect(new PathObserver(obj, 'a').value, obj['a']);
+ expect(new PathObserver(obj, 'a.b').value, obj['a']['b']);
+ expect(new PathObserver(obj, 'a.b.c').value, 1);
obj['a']['b']['c'] = 2;
- expect(observePath(obj, 'a.b.c').value, 2);
+ expect(new PathObserver(obj, 'a.b.c').value, 2);
obj['a']['b'] = toObservable({'c': 3});
- expect(observePath(obj, 'a.b.c').value, 3);
+ expect(new PathObserver(obj, 'a.b.c').value, 3);
obj['a'] = toObservable({'b': 4});
- expect(observePath(obj, 'a.b.c').value, null);
- expect(observePath(obj, 'a.b').value, 4);
+ expect(new PathObserver(obj, 'a.b.c').value, null);
+ expect(new PathObserver(obj, 'a.b').value, 4);
});
- observeTest('set value at path', () {
+ test('set value at path', () {
var obj = toObservable({});
- observePath(obj, 'foo').value = 3;
+ new PropertyPath('foo').setValueFrom(obj, 3);
expect(obj['foo'], 3);
var bar = toObservable({ 'baz': 3 });
- observePath(obj, 'bar').value = bar;
+ new PropertyPath('bar').setValueFrom(obj, bar);
expect(obj['bar'], bar);
- observePath(obj, 'bar.baz.bat').value = 'not here';
- expect(observePath(obj, 'bar.baz.bat').value, null);
+ new PropertyPath('bar.baz.bat').setValueFrom(obj, 'not here');
+ expect(new PathObserver(obj, 'bar.baz.bat').value, null);
});
- observeTest('set value back to same', () {
+ test('set value back to same', () {
var obj = toObservable({});
- var path = observePath(obj, 'foo');
+ var path = new PathObserver(obj, 'foo');
var values = [];
- path.changes.listen((_) { values.add(path.value); });
+ path.open((x) {
+ expect(x, path.value, reason: 'callback should get current value');
+ values.add(x);
+ });
path.value = 3;
expect(obj['foo'], 3);
expect(path.value, 3);
- observePath(obj, 'foo').value = 2;
- performMicrotaskCheckpoint();
- expect(path.value, 2);
- expect(observePath(obj, 'foo').value, 2);
+ new PropertyPath('foo').setValueFrom(obj, 2);
+ return new Future(() {
+ expect(path.value, 2);
+ expect(new PathObserver(obj, 'foo').value, 2);
- observePath(obj, 'foo').value = 3;
- performMicrotaskCheckpoint();
- expect(path.value, 3);
+ new PropertyPath('foo').setValueFrom(obj, 3);
+ }).then(newMicrotask).then((_) {
+ expect(path.value, 3);
- performMicrotaskCheckpoint();
- expect(values, [2, 3]);
+ }).then(newMicrotask).then((_) {
+ expect(values, [2, 3]);
+ });
});
- observeTest('Observe and Unobserve - Paths', () {
+ test('Observe and Unobserve - Paths', () {
var arr = toObservable({});
arr['foo'] = 'bar';
var fooValues = [];
- var fooPath = observePath(arr, 'foo');
- var fooSub = fooPath.changes.listen((_) {
- fooValues.add(fooPath.value);
- });
+ var fooPath = new PathObserver(arr, 'foo');
+ fooPath.open(fooValues.add);
arr['foo'] = 'baz';
arr['bat'] = 'bag';
var batValues = [];
- var batPath = observePath(arr, 'bat');
- var batSub = batPath.changes.listen((_) {
- batValues.add(batPath.value);
+ var batPath = new PathObserver(arr, 'bat');
+ batPath.open(batValues.add);
+
+ return new Future(() {
+ expect(fooValues, ['baz']);
+ expect(batValues, []);
+
+ arr['foo'] = 'bar';
+ fooPath.close();
+ arr['bat'] = 'boo';
+ batPath.close();
+ arr['bat'] = 'boot';
+
+ }).then(newMicrotask).then((_) {
+ expect(fooValues, ['baz']);
+ expect(batValues, []);
});
-
- performMicrotaskCheckpoint();
- expect(fooValues, ['baz']);
- expect(batValues, []);
-
- arr['foo'] = 'bar';
- fooSub.cancel();
- arr['bat'] = 'boo';
- batSub.cancel();
- arr['bat'] = 'boot';
-
- performMicrotaskCheckpoint();
- expect(fooValues, ['baz']);
- expect(batValues, []);
});
- observeTest('Path Value With Indices', () {
+ test('Path Value With Indices', () {
var model = toObservable([]);
- var path = observePath(model, '0');
- path.changes.listen(expectAsync1((_) {
+ var path = new PathObserver(model, '0');
+ path.open(expectAsync1((x) {
expect(path.value, 123);
+ expect(x, 123);
}));
model.add(123);
});
group('ObservableList', () {
- observeTest('isNotEmpty', () {
+ test('isNotEmpty', () {
var model = new ObservableList();
- var path = observePath(model, 'isNotEmpty');
+ var path = new PathObserver(model, 'isNotEmpty');
expect(path.value, false);
- var future = path.changes.first.then((_) {
+ path.open(expectAsync1((_) {
expect(path.value, true);
- });
+ }));
model.add(123);
-
- return future;
});
- observeTest('isEmpty', () {
+ test('isEmpty', () {
var model = new ObservableList();
- var path = observePath(model, 'isEmpty');
+ var path = new PathObserver(model, 'isEmpty');
expect(path.value, true);
- var future = path.changes.first.then((_) {
+ path.open(expectAsync1((_) {
expect(path.value, false);
- });
+ }));
model.add(123);
-
- return future;
});
});
for (var createModel in [() => new TestModel(), () => new WatcherModel()]) {
- observeTest('Path Observation - ${createModel().runtimeType}', () {
+ test('Path Observation - ${createModel().runtimeType}', () {
var model = createModel()..a =
(createModel()..b = (createModel()..c = 'hello, world'));
- var path = observePath(model, 'a.b.c');
+ var path = new PathObserver(model, 'a.b.c');
var lastValue = null;
- var sub = path.changes.listen((_) { lastValue = path.value; });
+ path.open((x) { lastValue = x; });
model.a.b.c = 'hello, mom';
expect(lastValue, null);
- performMicrotaskCheckpoint();
- expect(lastValue, 'hello, mom');
+ return new Future(() {
+ expect(lastValue, 'hello, mom');
- model.a.b = createModel()..c = 'hello, dad';
- performMicrotaskCheckpoint();
- expect(lastValue, 'hello, dad');
+ model.a.b = createModel()..c = 'hello, dad';
+ }).then(newMicrotask).then((_) {
+ expect(lastValue, 'hello, dad');
- model.a = createModel()..b =
- (createModel()..c = 'hello, you');
- performMicrotaskCheckpoint();
- expect(lastValue, 'hello, you');
+ model.a = createModel()..b =
+ (createModel()..c = 'hello, you');
+ }).then(newMicrotask).then((_) {
+ expect(lastValue, 'hello, you');
- model.a.b = 1;
- performMicrotaskCheckpoint();
- expect(lastValue, null);
+ model.a.b = 1;
+ }).then(newMicrotask).then((_) {
+ expect(lastValue, null);
- // Stop observing
- sub.cancel();
+ // Stop observing
+ path.close();
- model.a.b = createModel()..c = 'hello, back again -- but not observing';
- performMicrotaskCheckpoint();
- expect(lastValue, null);
+ model.a.b = createModel()..c = 'hello, back again -- but not observing';
+ }).then(newMicrotask).then((_) {
+ expect(lastValue, null);
- // Resume observing
- sub = path.changes.listen((_) { lastValue = path.value; });
+ // Resume observing
+ new PathObserver(model, 'a.b.c').open((x) { lastValue = x; });
- model.a.b.c = 'hello. Back for reals';
- performMicrotaskCheckpoint();
- expect(lastValue, 'hello. Back for reals');
+ model.a.b.c = 'hello. Back for reals';
+ }).then(newMicrotask).then((_) {
+ expect(lastValue, 'hello. Back for reals');
+ });
});
}
- observeTest('observe map', () {
+ test('observe map', () {
var model = toObservable({'a': 1});
- var path = observePath(model, 'a');
+ var path = new PathObserver(model, 'a');
var values = [path.value];
- var sub = path.changes.listen((_) { values.add(path.value); });
+ path.open(values.add);
expect(values, [1]);
model['a'] = 2;
- performMicrotaskCheckpoint();
- expect(values, [1, 2]);
+ return new Future(() {
+ expect(values, [1, 2]);
- sub.cancel();
- model['a'] = 3;
- performMicrotaskCheckpoint();
- expect(values, [1, 2]);
+ path.close();
+ model['a'] = 3;
+ }).then(newMicrotask).then((_) {
+ expect(values, [1, 2]);
+ });
});
- observeTest('errors thrown from getter/setter', () {
+ test('errors thrown from getter/setter', () {
var model = new ObjectWithErrors();
var observer = new PathObserver(model, 'foo');
@@ -253,7 +307,7 @@
expect(model.setFooCalled, [123]);
});
- observeTest('object with noSuchMethod', () {
+ test('object with noSuchMethod', () {
var model = new NoSuchMethodModel();
var observer = new PathObserver(model, 'foo');
@@ -271,7 +325,7 @@
expect(observer.value, null, reason: 'path not found');
});
- observeTest('object with indexer', () {
+ test('object with indexer', () {
var model = new IndexerModel();
var observer = new PathObserver(model, 'foo');
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 90c23d2..83dce91 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -41,6 +41,9 @@
collection/test/priority_queue_test: Pass, Slow # Issue 16426
serialization/test/serialization_test: Skip
+[ $runtime == jsshell ]
+analyzer/test/generated/element_test: Pass, Slow # Issue 16473
+
[ $runtime == d8 || $runtime == jsshell ]
unittest/test/unittest_nested_groups_setup_teardown_test: RuntimeError # http://dartbug.com/10109
stack_trace/test/vm_test: RuntimeError, OK # VM-specific traces
@@ -66,6 +69,7 @@
polymer/test/prop_attr_bind_reflection_test: Skip #uses dart:html
polymer/test/prop_attr_reflection_test: Skip #uses dart:html
polymer/test/property_change_test: Skip # uses dart:html
+polymer/test/property_observe_test: Skip #uses dart:html
polymer/test/publish_attributes_test: Skip #uses dart:html
polymer/test/publish_inherited_properties_test: Skip #uses dart:html
polymer/test/register_test: Skip #uses dart:html
@@ -96,7 +100,7 @@
mime/test/mime_multipart_transformer_test: Skip # No typed_data on IE9.
typed_data/test/typed_buffers_test: Fail, Crash # No typed_data on IE9.
polymer/test/instance_attrs_test: Pass, Fail # Issue 14167
-polymer/test/bind_mdv_test: Pass, Fail # Issue 16441
+polymer/test/bind_mdv_test: Slow, Pass
[ $runtime == safari ]
fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
@@ -106,7 +110,7 @@
[ $runtime == ie9 || $runtime == ie10 ]
polymer/test/bind_mdv_test: RuntimeError # Issue 14412, 13260
-polymer/test/noscript_test: RuntimeError # Issue 13260
+polymer/test/noscript_test: RuntimeError, Pass # Issue 13260
# Skip browser-specific tests on VM
[ $runtime == vm ]
@@ -115,7 +119,6 @@
intl/test/date_time_format_http_request_test: Skip
[ $runtime == vm && $system == windows ]
-docgen/test/single_library_test: Fail # Issue 11985
intl/test/find_default_locale_standalone_test: Fail # Issue 8110
[ $compiler == dartanalyzer ]
@@ -256,9 +259,12 @@
unittest/test/unittest_correct_callback_test: Fail # 13921
unittest/test/unittest_exception_test: Fail # 13921
unittest/test/unittest_excess_callback_test: Fail # 13921
+unittest/test/unittest_group_name_test: Fail # 13921
+unittest/test/unittest_invalid_ops_test: Fail # 13921
unittest/test/unittest_late_exception_test: Fail # 13921
unittest/test/unittest_middle_exception_test: Fail # 13921
unittest/test/unittest_nested_groups_setup_teardown_test: Fail # 13921
+unittest/test/unittest_protect_async_test: Fail # 13921
unittest/test/unittest_runtests_without_tests_test: Fail # 13921
unittest/test/unittest_setup_and_teardown_test: Fail # 13921
unittest/test/unittest_setup_test: Fail # 13921
@@ -269,7 +275,6 @@
unittest/test/unittest_test_returning_future_test: Fail # 13921
unittest/test/unittest_test_returning_future_using_runasync_test: Fail # 13921
unittest/test/unittest_testcases_immutable_test: Fail # 13921
-unittest/test/unitttest_group_name_test: Fail # 13921
polymer/test/custom_event_test: Pass, Crash # 14360
polymer/example/canonicalization/test/deploy_test: Fail, OK # tests deploy only behavior
polymer/example/canonicalization/test/deploy2_test: Fail, OK # tests deploy only behavior
@@ -290,6 +295,9 @@
polymer_expressions/test/bindings_test: Skip
third_party/html5lib/test/browser/browser_test: Skip
+[ $runtime == safari || $runtime == ie9 || $runtime == ie10 ]
+polymer_expressions/test/globals_test: Fail # Issue 16568
+
[ $runtime == safari || $runtime == chrome || $runtime == ie9 || $runtime == ff || $runtime == dartium || $runtime == drt ]
docgen/test/single_library_test: Skip # Uses dart:io
docgen/test/multi_library_test: Skip # Uses dart:io
@@ -301,7 +309,6 @@
[ $compiler == none && ($runtime == dartium || $runtime == drt) ]
source_maps/test/parser_test: Pass, Timeout # Issue 13719: Please triage this failure.
-polymer_expressions/test/bindings_test: Fail, Pass # Issue 14445.
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
docgen/test/single_library_test: StaticWarning
diff --git a/pkg/pkgbuild.status b/pkg/pkgbuild.status
index cfcca4d..8ee3ed75 100644
--- a/pkg/pkgbuild.status
+++ b/pkg/pkgbuild.status
@@ -4,6 +4,7 @@
third_party/pkg/route_hierarchical: Fail
+samples/third_party/angular_todo: Pass, Slow
samples/third_party/pop-pop-win: Pass, Slow
samples/searchable_list: Pass, Slow
pkg/docgen: Pass, Slow
@@ -17,6 +18,7 @@
[ $use_public_packages ]
pkg/watcher: PubGetError # Issue 16026
+pkg/template_binding: Pass, PubGetError # Issue 16026
[ $builder_tag == russian ]
samples/third_party/pop-pop-win: Fail # Issue 16356
diff --git a/pkg/polymer/CHANGELOG.md b/pkg/polymer/CHANGELOG.md
index 01e65d6..d732a88 100644
--- a/pkg/polymer/CHANGELOG.md
+++ b/pkg/polymer/CHANGELOG.md
@@ -5,6 +5,15 @@
impact polymer: custom_element, html_import, observe, shadow_dom,
and template_binding.
+#### Pub version 0.10.0-dev
+ * Deploy step removes use of mirrors to initialize polymer elements. Mirrors
+ are still used for @published and for polymer-expressions.
+ **breaking change**: @initMethod and @CustomTag are only supported on
+ public classes/methods.
+
+#### Pub version 0.9.5
+ * Improvements on how to handle cross-package HTML imports.
+
#### Pub version 0.9.4
* Removes unused dependency on csslib.
diff --git a/pkg/polymer/example/canonicalization/lib/a.dart b/pkg/polymer/example/canonicalization/lib/a.dart
index 78426db..dfbe3ca 100644
--- a/pkg/polymer/example/canonicalization/lib/a.dart
+++ b/pkg/polymer/example/canonicalization/lib/a.dart
@@ -9,7 +9,7 @@
import 'd.dart';
int a = 0;
-@initMethod _init() {
+@initMethod initA() {
a++;
c++;
d++;
diff --git a/pkg/polymer/example/canonicalization/lib/b.dart b/pkg/polymer/example/canonicalization/lib/b.dart
index 0a3a29d..fbdccf6 100644
--- a/pkg/polymer/example/canonicalization/lib/b.dart
+++ b/pkg/polymer/example/canonicalization/lib/b.dart
@@ -9,7 +9,7 @@
import 'd.dart';
int b = 0;
-@initMethod _init() {
+@initMethod initB() {
b++;
c++;
d++;
diff --git a/pkg/polymer/example/canonicalization2/lib/a.dart b/pkg/polymer/example/canonicalization2/lib/a.dart
index 78426db..dfbe3ca 100644
--- a/pkg/polymer/example/canonicalization2/lib/a.dart
+++ b/pkg/polymer/example/canonicalization2/lib/a.dart
@@ -9,7 +9,7 @@
import 'd.dart';
int a = 0;
-@initMethod _init() {
+@initMethod initA() {
a++;
c++;
d++;
diff --git a/pkg/polymer/example/canonicalization2/lib/b.dart b/pkg/polymer/example/canonicalization2/lib/b.dart
index 0a3a29d..fbdccf6 100644
--- a/pkg/polymer/example/canonicalization2/lib/b.dart
+++ b/pkg/polymer/example/canonicalization2/lib/b.dart
@@ -9,7 +9,7 @@
import 'd.dart';
int b = 0;
-@initMethod _init() {
+@initMethod initB() {
b++;
c++;
d++;
diff --git a/pkg/polymer/example/canonicalization3/lib/a.dart b/pkg/polymer/example/canonicalization3/lib/a.dart
index 78426db..dfbe3ca 100644
--- a/pkg/polymer/example/canonicalization3/lib/a.dart
+++ b/pkg/polymer/example/canonicalization3/lib/a.dart
@@ -9,7 +9,7 @@
import 'd.dart';
int a = 0;
-@initMethod _init() {
+@initMethod initA() {
a++;
c++;
d++;
diff --git a/pkg/polymer/example/canonicalization3/lib/b.dart b/pkg/polymer/example/canonicalization3/lib/b.dart
index 0a3a29d..fbdccf6 100644
--- a/pkg/polymer/example/canonicalization3/lib/b.dart
+++ b/pkg/polymer/example/canonicalization3/lib/b.dart
@@ -9,7 +9,7 @@
import 'd.dart';
int b = 0;
-@initMethod _init() {
+@initMethod initB() {
b++;
c++;
d++;
diff --git a/pkg/polymer/lib/polymer.dart b/pkg/polymer/lib/polymer.dart
index ff80921..8ccfaff 100644
--- a/pkg/polymer/lib/polymer.dart
+++ b/pkg/polymer/lib/polymer.dart
@@ -40,7 +40,7 @@
library polymer;
import 'dart:async';
-import 'dart:collection' show HashMap;
+import 'dart:collection' show HashMap, HashSet;
import 'dart:html';
import 'dart:js' as js;
diff --git a/pkg/polymer/lib/src/build/code_extractor.dart b/pkg/polymer/lib/src/build/code_extractor.dart
index e6c6445..a349f08 100644
--- a/pkg/polymer/lib/src/build/code_extractor.dart
+++ b/pkg/polymer/lib/src/build/code_extractor.dart
@@ -7,7 +7,6 @@
import 'dart:async';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart';
@@ -73,7 +72,7 @@
/** Parse [code] and determine whether it has a library directive. */
bool _hasLibraryDirective(String code) {
var errorListener = new _ErrorCollector();
- var reader = new CharSequenceReader(new CharSequence(code));
+ var reader = new CharSequenceReader(code);
var scanner = new Scanner(null, reader, errorListener);
var token = scanner.tokenize();
var unit = new Parser(null, errorListener).parseCompilationUnit(token);
diff --git a/pkg/polymer/lib/src/build/common.dart b/pkg/polymer/lib/src/build/common.dart
index 1b27f55..516c02c 100644
--- a/pkg/polymer/lib/src/build/common.dart
+++ b/pkg/polymer/lib/src/build/common.dart
@@ -117,13 +117,26 @@
String toString() => 'polymer ($runtimeType)';
}
-/** Create an [AssetId] for a [url] seen in the [source] asset. */
+/**
+ * Create an [AssetId] for a [url] seen in the [source] asset. By default this
+ * is used to resolve relative urls that occur in HTML assets, including
+ * cross-package urls of the form "packages/foo/bar.html". Dart-style "package:"
+ * urls are not resolved unless [source] is Dart file (has a .dart extension).
+ */
// TODO(sigmund): delete once this is part of barback (dartbug.com/12610)
AssetId resolve(AssetId source, String url, TransformLogger logger, Span span) {
if (url == null || url == '') return null;
var uri = Uri.parse(url);
var urlBuilder = path.url;
if (uri.host != '' || uri.scheme != '' || urlBuilder.isAbsolute(url)) {
+ if (source.extension == '.dart' && uri.scheme == 'package') {
+ var index = uri.path.indexOf('/');
+ if (index != -1) {
+ return new AssetId(uri.path.substring(0, index),
+ 'lib${uri.path.substring(index)}');
+ }
+ }
+
logger.error('absolute paths not allowed: "$url"', span: span);
return null;
}
diff --git a/pkg/polymer/lib/src/build/script_compactor.dart b/pkg/polymer/lib/src/build/script_compactor.dart
index e869a2c..335fcb0 100644
--- a/pkg/polymer/lib/src/build/script_compactor.dart
+++ b/pkg/polymer/lib/src/build/script_compactor.dart
@@ -8,9 +8,14 @@
import 'dart:async';
import 'dart:convert';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/scanner.dart';
import 'package:barback/barback.dart';
import 'package:html5lib/parser.dart' show parseFragment;
import 'package:path/path.dart' as path;
+import 'package:source_maps/span.dart' show SourceFile;
import 'code_extractor.dart'; // import just for documentation.
import 'common.dart';
@@ -77,6 +82,7 @@
return null;
}
+ // Emit the bootstrap .dart file
var bootstrapId = id.addExtension('_bootstrap.dart');
mainScriptTag.attributes['src'] =
path.url.basename(bootstrapId.path);
@@ -92,20 +98,187 @@
buffer..write('\n')
..writeln('void main() {')
- ..writeln(' configureForDeployment([')
- ..writeAll(urls.map((url) => " '$url',\n"))
- ..writeln(' ]);')
- ..writeln(' i${i - 1}.main();')
- ..writeln('}');
+ ..writeln(' configureForDeployment([');
- transform.addOutput(new Asset.fromString(
- bootstrapId, buffer.toString()));
- transform.addOutput(new Asset.fromString(id, document.outerHtml));
+ // Inject @CustomTag and @initMethod initializations for each library
+ // that is sourced in a script tag.
+ i = 0;
+ return Future.forEach(libraries, (lib) {
+ return _initializersOf(lib, transform, logger).then((initializers) {
+ for (var init in initializers) {
+ var code = init.asCode('i$i');
+ buffer.write(" $code,\n");
+ }
+ i++;
+ });
+ }).then((_) {
+ buffer..writeln(' ]);')
+ ..writeln(' i${urls.length - 1}.main();')
+ ..writeln('}');
+
+ transform.addOutput(new Asset.fromString(
+ bootstrapId, buffer.toString()));
+ transform.addOutput(new Asset.fromString(id, document.outerHtml));
+ });
});
});
}
+
+ /**
+ * Computes the initializers of [dartLibrary]. That is, a closure that calls
+ * Polymer.register for each @CustomTag, and any public top-level methods
+ * labeled with @initMethod.
+ */
+ Future<List<_Initializer>> _initializersOf(
+ AssetId dartLibrary, Transform transform, TransformLogger logger) {
+ var initializers = [];
+ return transform.readInputAsString(dartLibrary).then((code) {
+ var file = new SourceFile.text(_simpleUriForSource(dartLibrary), code);
+ var unit = _parseCompilationUnit(code);
+
+ return Future.forEach(unit.directives, (directive) {
+ // Include anything from parts.
+ if (directive is PartDirective) {
+ var targetId = resolve(dartLibrary, directive.uri.stringValue,
+ logger, _getSpan(file, directive));
+ return _initializersOf(targetId, transform, logger)
+ .then(initializers.addAll);
+ }
+
+ // Similarly, include anything from exports except what's filtered by
+ // the show/hide combinators.
+ if (directive is ExportDirective) {
+ var targetId = resolve(dartLibrary, directive.uri.stringValue,
+ logger, _getSpan(file, directive));
+ return _initializersOf(targetId, transform, logger)
+ .then((r) => _processExportDirective(directive, r, initializers));
+ }
+ }).then((_) {
+ // Scan the code for classes and top-level functions.
+ for (var node in unit.declarations) {
+ if (node is ClassDeclaration) {
+ _processClassDeclaration(node, initializers, file, logger);
+ } else if (node is FunctionDeclaration &&
+ node.metadata.any(_isInitMethodAnnotation)) {
+ _processFunctionDeclaration(node, initializers, file, logger);
+ }
+ }
+ return initializers;
+ });
+ });
+ }
+
+ static String _simpleUriForSource(AssetId source) =>
+ source.path.startsWith('lib/')
+ ? 'package:${source.package}/${source.path.substring(4)}' : source.path;
+
+ /**
+ * Filter [exportedInitializers] according to [directive]'s show/hide
+ * combinators and add the result to [initializers].
+ */
+ // TODO(sigmund): call the analyzer's resolver instead?
+ static _processExportDirective(ExportDirective directive,
+ List<_Initializer> exportedInitializers,
+ List<_Initializer> initializers) {
+ for (var combinator in directive.combinators) {
+ if (combinator is ShowCombinator) {
+ var show = combinator.shownNames.map((n) => n.name).toSet();
+ exportedInitializers.retainWhere((e) => show.contains(e.symbolName));
+ } else if (combinator is HideCombinator) {
+ var hide = combinator.hiddenNames.map((n) => n.name).toSet();
+ exportedInitializers.removeWhere((e) => hide.contains(e.symbolName));
+ }
+ }
+ initializers.addAll(exportedInitializers);
+ }
+
+ /**
+ * Add an initializer to register [node] as a polymer element if it contains
+ * an appropriate [CustomTag] annotation.
+ */
+ static _processClassDeclaration(ClassDeclaration node,
+ List<_Initializer> initializers, SourceFile file,
+ TransformLogger logger) {
+ for (var meta in node.metadata) {
+ if (!_isCustomTagAnnotation(meta)) continue;
+ var args = meta.arguments.arguments;
+ if (args == null || args.length == 0) {
+ logger.error('Missing argument in @CustomTag annotation',
+ span: _getSpan(file, meta));
+ continue;
+ }
+
+ var tagName = args[0].stringValue;
+ var typeName = node.name.name;
+ if (typeName.startsWith('_')) {
+ logger.error('@CustomTag is no longer supported on private '
+ 'classes: $tagName', span: _getSpan(file, node.name));
+ continue;
+ }
+ initializers.add(new _CustomTagInitializer(tagName, typeName));
+ }
+ }
+
+ /** a method initializer for [function]. */
+ static _processFunctionDeclaration(FunctionDeclaration function,
+ List<_Initializer> initializers, SourceFile file,
+ TransformLogger logger) {
+ var name = function.name.name;
+ if (name.startsWith('_')) {
+ logger.error('@initMethod is no longer supported on private '
+ 'functions: $name', span: _getSpan(file, function.name));
+ return;
+ }
+ initializers.add(new _InitMethodInitializer(name));
+ }
}
+/** Parse [code] using analyzer. */
+CompilationUnit _parseCompilationUnit(String code) {
+ var errorListener = new _ErrorCollector();
+ var reader = new CharSequenceReader(code);
+ var scanner = new Scanner(null, reader, errorListener);
+ var token = scanner.tokenize();
+ var parser = new Parser(null, errorListener);
+ return parser.parseCompilationUnit(token);
+}
+
+class _ErrorCollector extends AnalysisErrorListener {
+ final errors = <AnalysisError>[];
+ onError(error) => errors.add(error);
+}
+
+// TODO(sigmund): consider support for importing annotations with prefixes.
+bool _isInitMethodAnnotation(Annotation node) =>
+ node.name.name == 'initMethod' && node.constructorName == null &&
+ node.arguments == null;
+bool _isCustomTagAnnotation(Annotation node) => node.name.name == 'CustomTag';
+
+abstract class _Initializer {
+ String get symbolName;
+ String asCode(String prefix);
+}
+
+class _InitMethodInitializer implements _Initializer {
+ String methodName;
+ String get symbolName => methodName;
+ _InitMethodInitializer(this.methodName);
+
+ String asCode(String prefix) => "$prefix.$methodName";
+}
+
+class _CustomTagInitializer implements _Initializer {
+ String tagName;
+ String typeName;
+ String get symbolName => typeName;
+ _CustomTagInitializer(this.tagName, this.typeName);
+
+ String asCode(String prefix) =>
+ "() => Polymer.register('$tagName', $prefix.$typeName)";
+}
+
+_getSpan(SourceFile file, ASTNode node) => file.span(node.offset, node.end);
+
const MAIN_HEADER = """
library app_bootstrap;
diff --git a/pkg/polymer/lib/src/declaration.dart b/pkg/polymer/lib/src/declaration.dart
index 7eaf11a..d120340 100644
--- a/pkg/polymer/lib/src/declaration.dart
+++ b/pkg/polymer/lib/src/declaration.dart
@@ -41,23 +41,29 @@
PolymerDeclaration _super;
PolymerDeclaration get superDeclaration => _super;
+ String _extendsName;
+
String _name;
String get name => _name;
/**
* Map of publish properties. Can be a [VariableMirror] or a [MethodMirror]
* representing a getter. If it is a getter, there will also be a setter.
+ *
+ * Note: technically these are always single properties, so we could use
+ * a Symbol instead of a PropertyPath. However there are lookups between
+ * this map and [_observe] so it is easier to just track paths.
*/
- Map<Symbol, DeclarationMirror> _publish;
+ Map<PropertyPath, DeclarationMirror> _publish;
/** The names of published properties for this polymer-element. */
- Iterable<Symbol> get publishedProperties =>
- _publish != null ? _publish.keys : const [];
+ Iterable<String> get publishedProperties =>
+ _publish != null ? _publish.keys.map((p) => '$p') : const [];
/** Same as [_publish] but with lower case names. */
Map<String, DeclarationMirror> _publishLC;
- Map<Symbol, Symbol> _observe;
+ Map<PropertyPath, List<Symbol>> _observe;
Map<String, Object> _instanceAttributes;
@@ -83,6 +89,8 @@
PolymerDeclaration.created() : super.created() {
// fetch the element name
_name = attributes['name'];
+ // fetch our extendee name
+ _extendsName = attributes['extends'];
// install element definition, if ready
registerWhenReady();
}
@@ -92,9 +100,7 @@
if (waitingForType(name)) {
return;
}
- // fetch our extendee name
- var extendee = attributes['extends'];
- if (waitingForExtendee(extendee)) {
+ if (waitingForExtendee(_extendsName)) {
//console.warn(name + ': waitingForExtendee:' + extendee);
return;
}
@@ -106,7 +112,7 @@
// finalizing elements in the main document
// TODO(jmesserly): Polymer.dart waits for HTMLImportsLoaded, so I've
// removed "whenImportsLoaded" for now. Restore the workaround if needed.
- _register(extendee);
+ _register(_extendsName);
}
void _register(extendee) {
@@ -188,10 +194,13 @@
// transcribe `attributes` declarations onto own prototype's `publish`
publishAttributes(cls, _super);
- publishProperties(type);
+ publishProperties(_type);
inferObservers(cls);
+ // desugar compound observer syntax, e.g. @ObserveProperty('a b c')
+ explodeObservers(cls);
+
// Skip the rest in Dart:
// chain various meta-data objects to inherited versions
// chain custom api to inherited
@@ -209,6 +218,8 @@
// install external stylesheets as if they are inline
installSheets();
+ adjustShadowElement();
+
// TODO(sorvell): install a helper method this.resolvePath to aid in
// setting resource paths. e.g.
// this.$.image.src = this.resolvePath('images/foo.png')
@@ -231,6 +242,22 @@
}
}
+ // TODO(sorvell): remove when spec addressed:
+ // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22460
+ // make <shadow></shadow> be <shadow><content></content></shadow>
+ void adjustShadowElement() {
+ // TODO(sorvell): avoid under SD polyfill until this bug is addressed:
+ // https://github.com/Polymer/ShadowDOM/issues/297
+ if (!_hasShadowDomPolyfill) {
+ final content = templateContent;
+ if (content == null) return;
+
+ for (var s in content.querySelectorAll('shadow')) {
+ if (s.nodes.isEmpty) s.append(new ContentElement());
+ }
+ }
+ }
+
void registerType(String name) {
var baseTag;
var decl = this;
@@ -257,16 +284,19 @@
if (attrs != null) {
// names='a b c' or names='a,b,c'
// record each name for publishing
- for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) {
+ for (var attr in attrs.split(_ATTRIBUTES_REGEX)) {
// remove excess ws
attr = attr.trim();
// do not override explicit entries
- if (attr != '' && _publish != null && _publish.containsKey(attr)) {
+ if (attr == '') continue;
+
+ var property = new Symbol(attr);
+ var path = new PropertyPath([property]);
+ if (_publish != null && _publish.containsKey(path)) {
continue;
}
- var property = new Symbol(attr);
var mirror = _getProperty(cls, property);
if (mirror == null) {
window.console.warn('property for attribute $attr of polymer-element '
@@ -274,7 +304,7 @@
continue;
}
if (_publish == null) _publish = {};
- _publish[property] = mirror;
+ _publish[path] = mirror;
}
}
@@ -378,7 +408,7 @@
var nodes = this.querySelectorAll(selector).toList();
var content = templateContent;
if (content != null) {
- nodes = nodes..addAll(content.queryAll(selector));
+ nodes = nodes..addAll(content.querySelectorAll(selector));
}
if (matcher != null) return nodes.where(matcher).toList();
return nodes;
@@ -408,7 +438,7 @@
}
// handle cached style elements
for (var style in styles.where(matcher)) {
- cssText..write(style.textContent)..write('\n\n');
+ cssText..write(style.text)..write('\n\n');
}
return cssText.toString();
}
@@ -427,14 +457,11 @@
}
/**
- * fetch a list of all observable properties names in our inheritance chain
- * above Polymer.
+ * Fetch a list of all *Changed methods so we can observe the associated
+ * properties.
*/
- // TODO(sjmiles): perf: reflection is slow, relatively speaking
- // If an element may take 6us to create, getCustomPropertyNames might
- // cost 1.6us more.
void inferObservers(ClassMirror cls) {
- if (cls == _objectType) return;
+ if (cls == _htmlElementType) return;
inferObservers(cls.superclass);
for (var method in cls.declarations.values) {
if (method is! MethodMirror || method.isStatic
@@ -442,9 +469,36 @@
String name = MirrorSystem.getName(method.simpleName);
if (name.endsWith(_OBSERVE_SUFFIX) && name != 'attributeChanged') {
- if (_observe == null) _observe = new Map();
+ // TODO(jmesserly): now that we have a better system, should we
+ // deprecate *Changed methods?
+ if (_observe == null) _observe = new HashMap();
name = name.substring(0, name.length - 7);
- _observe[new Symbol(name)] = method.simpleName;
+ _observe[new PropertyPath(name)] = [method.simpleName];
+ }
+ }
+ }
+
+ /**
+ * Fetch a list of all methods annotated with [ObserveProperty] so we can
+ * observe the associated properties.
+ */
+ void explodeObservers(ClassMirror cls) {
+ if (cls == _htmlElementType) return;
+
+ explodeObservers(cls.superclass);
+ for (var method in cls.declarations.values) {
+ if (method is! MethodMirror || method.isStatic
+ || !method.isRegularMethod) continue;
+
+ for (var meta in _safeGetMetadata(method)) {
+ if (meta.reflectee is! ObserveProperty) continue;
+
+ if (_observe == null) _observe = new HashMap();
+
+ for (String name in meta.reflectee.names) {
+ _observe.putIfAbsent(new PropertyPath(name), () => [])
+ .add(method.simpleName);
+ }
}
}
}
@@ -454,10 +508,10 @@
if (_publish != null) _publishLC = _lowerCaseMap(_publish);
}
- Map<String, dynamic> _lowerCaseMap(Map<Symbol, dynamic> properties) {
+ Map<String, dynamic> _lowerCaseMap(Map<PropertyPath, dynamic> properties) {
final map = new Map<String, dynamic>();
- properties.forEach((name, value) {
- map[MirrorSystem.getName(name).toLowerCase()] = value;
+ properties.forEach((PropertyPath path, value) {
+ map['$path'.toLowerCase()] = value;
});
return map;
}
@@ -495,10 +549,10 @@
PolymerDeclaration _getDeclaration(String name) => _declarations[name];
final _objectType = reflectClass(Object);
-
+final _htmlElementType = reflectClass(HtmlElement);
Map _getPublishedProperties(ClassMirror cls, Map props) {
- if (cls == _objectType) return props;
+ if (cls == _htmlElementType) return props;
props = _getPublishedProperties(cls.superclass, props);
for (var member in cls.declarations.values) {
if (member.isStatic || member.isPrivate) continue;
@@ -512,7 +566,7 @@
// it's a tad expensive.
if (member is! MethodMirror || _hasSetter(cls, member)) {
if (props == null) props = {};
- props[member.simpleName] = member;
+ props[new PropertyPath([member.simpleName])] = member;
}
break;
}
@@ -545,6 +599,19 @@
return null;
}
+List _safeGetMetadata(MethodMirror method) {
+ // TODO(jmesserly): dart2js blows up getting metadata from methods in some
+ // cases. Why does this happen? It seems like the culprit might be named
+ // arguments. Unfortunately even calling method.parameters also
+ // triggers the bug in computeFunctionRti. For now we guard against it
+ // with this check.
+ try {
+ return method.metadata;
+ } catch (e) {
+ return [];
+ }
+}
+
bool _hasSetter(ClassMirror cls, MethodMirror getter) {
var setterName = new Symbol('${MirrorSystem.getName(getter.simpleName)}=');
var mirror = cls.declarations[setterName];
@@ -565,8 +632,7 @@
*/
void _shimShadowDomStyling(DocumentFragment template, String name,
String extendee) {
- if (js.context == null || template == null) return;
- if (!js.context.hasProperty('ShadowDOMPolyfill')) return;
+ if (template == null || !_hasShadowDomPolyfill) return;
var platform = js.context['Platform'];
if (platform == null) return;
@@ -575,6 +641,9 @@
shadowCss.callMethod('shimStyling', [template, name, extendee]);
}
+final bool _hasShadowDomPolyfill = js.context != null &&
+ js.context.hasProperty('ShadowDOMPolyfill');
+
const _STYLE_SELECTOR = 'style';
const _SHEET_SELECTOR = '[rel=stylesheet]';
const _STYLE_GLOBAL_SCOPE = 'global';
@@ -627,6 +696,7 @@
'domfocusout': 'DOMFocusOut',
'domfocusin': 'DOMFocusIn',
+ 'dommousescroll': 'DOMMouseScroll',
// TODO(jmesserly): Dart specific renames. Reconcile with Polymer.js
'animationend': 'webkitAnimationEnd',
@@ -657,3 +727,5 @@
final result = _reverseEventTranslations[eventType];
return result != null ? result : eventType;
}
+
+final _ATTRIBUTES_REGEX = new RegExp(r'\s|,');
diff --git a/pkg/polymer/lib/src/instance.dart b/pkg/polymer/lib/src/instance.dart
index c0af66c..abc2a0c 100644
--- a/pkg/polymer/lib/src/instance.dart
+++ b/pkg/polymer/lib/src/instance.dart
@@ -13,7 +13,6 @@
* @published double volume;
* }
*/
-// TODO(jmesserly): does @published imply @observable or vice versa?
const published = const PublishedProperty();
/** An annotation used to publish a field as an attribute. See [published]. */
@@ -22,6 +21,37 @@
}
/**
+ * Use this type to observe a property and have the method be called when it
+ * changes. For example:
+ *
+ * @ObserveProperty('foo.bar baz qux')
+ * validate() {
+ * // use this.foo.bar, this.baz, and this.qux in validation
+ * ...
+ * }
+ *
+ * Note that you can observe a property path, and more than a single property
+ * can be specified in a space-delimited list or as a constant List.
+ */
+class ObserveProperty {
+ final _names;
+
+ List<String> get names {
+ var n = _names;
+ // TODO(jmesserly): the bogus '$n' is to workaround a dart2js bug, otherwise
+ // it generates an incorrect call site.
+ if (n is String) return '$n'.split(' ');
+ if (n is! Iterable) {
+ throw new UnsupportedError('ObserveProperty takes either an Iterable of '
+ 'names, or a space separated String, instead of `$n`.');
+ }
+ return n;
+ }
+
+ const ObserveProperty(this._names);
+}
+
+/**
* The mixin class for Polymer elements. It provides convenience features on top
* of the custom elements web standard.
*
@@ -30,7 +60,7 @@
*/
abstract class Polymer implements Element, Observable, NodeBindExtension {
// Fully ported from revision:
- // https://github.com/Polymer/polymer/blob/b7200854b2441a22ce89f6563963f36c50f5150d
+ // https://github.com/Polymer/polymer/blob/37eea00e13b9f86ab21c85a955585e8e4237e3d2
//
// src/boot.js (static APIs on "Polymer" object)
// src/instance/attributes.js
@@ -88,7 +118,7 @@
bool _unbound; // lazy-initialized
_Job _unbindAllJob;
- StreamSubscription _propertyObserver;
+ CompoundObserver _propertyObserver;
bool get _elementPrepared => _declaration != null;
@@ -217,7 +247,7 @@
* Return a shadow-root template (if desired), override for custom behavior.
*/
Element fetchTemplate(Element elementElement) =>
- elementElement.query('template');
+ elementElement.querySelector('template');
/**
* Utility function that stamps a `<template>` into light-dom.
@@ -379,29 +409,29 @@
if (value is bool) {
return _toBoolean(value) ? '' : null;
- } else if (value is String || value is int || value is double) {
+ } else if (value is String || value is num) {
return '$value';
}
return null;
}
- void reflectPropertyToAttribute(Symbol name) {
+ void reflectPropertyToAttribute(PropertyPath path) {
+ if (path.length != 1) throw new ArgumentError('path must be length 1');
+
// TODO(sjmiles): consider memoizing this
- final self = reflect(this);
// try to intelligently serialize property value
- // TODO(jmesserly): cache symbol?
- final propValue = self.getField(name).reflectee;
+ final propValue = path.getValueFrom(this);
final serializedValue = serializeValue(propValue);
// boolean properties must reflect as boolean attributes
if (serializedValue != null) {
- attributes[MirrorSystem.getName(name)] = serializedValue;
+ attributes['$path'] = serializedValue;
// TODO(sorvell): we should remove attr for all properties
// that have undefined serialization; however, we will need to
// refine the attr reflection system to achieve this; pica, for example,
// relies on having inferredType object properties not removed as
// attrs.
} else if (propValue is bool) {
- attributes.remove(MirrorSystem.getName(name));
+ attributes.remove('$path');
}
}
@@ -421,7 +451,9 @@
DocumentFragment instanceTemplate(Element template) =>
templateBind(template).createInstance(this, syntax);
- NodeBinding bind(String name, model, [String path]) {
+ // TODO(jmesserly): Polymer does not seem to implement the oneTime flag
+ // correctly. File bug.
+ Bindable bind(String name, Bindable bindable, {bool oneTime: false}) {
// note: binding is a prepare signal. This allows us to be sure that any
// property changes that occur as a result of binding will be observed.
if (!_elementPrepared) prepareElement();
@@ -429,23 +461,27 @@
var property = propertyForAttribute(name);
if (property == null) {
// Cannot call super.bind because template_binding is its own package
- return nodeBindFallback(this).bind(name, model, path);
+ return nodeBindFallback(this).bind(name, bindable, oneTime: oneTime);
} else {
// clean out the closets
unbind(name);
// use n-way Polymer binding
- var observer = bindProperty(property.simpleName, model, path);
+ var observer = bindProperty(property.simpleName, bindable);
+
// reflect bound property to attribute when binding
// to ensure binding is not left on attribute if property
// does not update due to not changing.
// Dart note: we include this patch:
// https://github.com/Polymer/polymer/pull/319
- reflectPropertyToAttribute(property.simpleName);
+
+ // TODO(jmesserly): polymer has the path_ in their observer object, should
+ // we use that too instead of allocating it here?
+ reflectPropertyToAttribute(new PropertyPath([property.simpleName]));
return bindings[name] = observer;
}
}
- Map<String, NodeBinding> get bindings => nodeBindFallback(this).bindings;
+ Map<String, Bindable> get bindings => nodeBindFallback(this).bindings;
TemplateInstance get templateInstance =>
nodeBindFallback(this).templateInstance;
@@ -508,65 +544,72 @@
/** Set up property observers. */
void observeProperties() {
- // TODO(jmesserly): we don't have CompoundPathObserver, so this
- // implementation is a little bit different. We also don't expose the
- // "generateCompoundPathObserver" method.
final observe = _declaration._observe;
final publish = _declaration._publish;
- if (observe != null) {
- for (var name in observe.keys) {
- observeArrayValue(name, reflect(this).getField(name), null);
+ // TODO(jmesserly): workaround for a dart2js compiler bug
+ bool hasObserved = observe != null;
+
+ if (hasObserved || publish != null) {
+ var o = _propertyObserver = new CompoundObserver();
+ if (hasObserved) {
+ for (var path in observe.keys) {
+ o.addPath(this, path);
+
+ // TODO(jmesserly): on the Polymer side it doesn't look like they
+ // will observe arrays unless it is a length == 1 path.
+ observeArrayValue(path, path.getValueFrom(this), null);
+ }
}
- }
- if (observe != null || publish != null) {
- // Instead of using CompoundPathObserver, set up a binding using normal
- // change records.
- _propertyObserver = changes.listen(notifyPropertyChanges);
+ if (publish != null) {
+ for (var path in publish.keys) {
+
+ if (!hasObserved || !observe.containsKey(path)) {
+ o.addPath(this, path);
+ }
+ }
+ }
+ o.open(notifyPropertyChanges);
}
}
+
/** Responds to property changes on this element. */
- // Dart note: this takes a list of changes rather than trying to deal with
- // what CompoundPathObserver would give us. Simpler and probably faster too.
- void notifyPropertyChanges(Iterable<ChangeRecord> changes) {
+ void notifyPropertyChanges(List newValues, Map oldValues, List paths) {
final observe = _declaration._observe;
final publish = _declaration._publish;
+ final called = new HashSet();
- // Summarize old and new values, so we only handle each change once.
- final valuePairs = new Map<Symbol, _PropertyValue>();
- for (var c in changes) {
- if (c is! PropertyChangeRecord) continue;
-
- valuePairs.putIfAbsent(c.name, () => new _PropertyValue(c.oldValue))
- .newValue = c.newValue;
- }
-
- valuePairs.forEach((name, pair) {
- if (publish != null && publish.containsKey(name)) {
- reflectPropertyToAttribute(name);
+ oldValues.forEach((i, oldValue) {
+ // note: paths is of form [object, path, object, path]
+ var path = paths[2 * i + 1];
+ if (publish != null && publish.containsKey(path)) {
+ reflectPropertyToAttribute(path);
}
if (observe == null) return;
- var method = observe[name];
- if (method != null) {
+ var methods = observe[path];
+ if (methods == null) return;
+
+ for (var method in methods) {
+ if (!called.add(method)) continue; // don't invoke more than once.
+
+ final newValue = newValues[i];
// observes the value if it is an array
- observeArrayValue(name, pair.newValue, pair.oldValue);
- // TODO(jmesserly): the JS code tries to avoid calling the same method
- // twice, but I don't see how that is possible.
- // Dart note: JS also passes "arguments", so we pass all change records.
- invokeMethod(method, [pair.oldValue, pair.newValue, changes]);
+ observeArrayValue(path, newValue, oldValue);
+ // Dart note: JS passes "arguments", so we pass along our args.
+ invokeMethod(method, [oldValue, newValue, newValues, oldValues, paths]);
}
});
}
- void observeArrayValue(Symbol name, Object value, Object old) {
+ void observeArrayValue(PropertyPath name, Object value, Object old) {
final observe = _declaration._observe;
if (observe == null) return;
// we only care if there are registered side-effects
- var callbackName = observe[name];
- if (callbackName == null) return;
+ var callbacks = observe[name];
+ if (callbacks == null) return;
// if we are observing the previous value, stop
if (old is ObservableList) {
@@ -575,7 +618,7 @@
'$name');
}
- unregisterObserver('${MirrorSystem.getName(name)}__array');
+ unregisterObserver('${name}__array');
}
// if the new value is an array, being observing it
if (value is ObservableList) {
@@ -584,9 +627,11 @@
'$name');
}
var sub = value.listChanges.listen((changes) {
- invokeMethod(callbackName, [old]);
+ for (var callback in callbacks) {
+ invokeMethod(callback, [old]);
+ }
});
- registerObserver('${MirrorSystem.getName(name)}__array', sub);
+ registerObserver('${name}__array', sub);
}
}
@@ -594,7 +639,7 @@
void unbindAllProperties() {
if (_propertyObserver != null) {
- _propertyObserver.cancel();
+ _propertyObserver.close();
_propertyObserver = null;
}
unregisterObservers();
@@ -633,37 +678,29 @@
* bindProperty(#myProperty, this, 'myModel.path.to.otherProp');
* }
*/
- // TODO(jmesserly): replace with something more localized, like:
- // @ComputedField('myModel.path.to.otherProp');
- NodeBinding bindProperty(Symbol name, Object model, [String path]) =>
- // apply Polymer two-way reference binding
- _bindProperties(this, name, model, path);
-
- /**
- * bind a property in A to a path in B by converting A[property] to a
- * getter/setter pair that accesses B[...path...]
- */
- static NodeBinding _bindProperties(Polymer inA, Symbol inProperty,
- Object inB, String inPath) {
-
- if (_bindLog.isLoggable(Level.FINE)) {
- _bindLog.fine('[$inB]: bindProperties: [$inPath] to '
- '[${inA.localName}].[$inProperty]');
- }
-
+ Bindable bindProperty(Symbol name, Bindable bindable) {
// Dart note: normally we only reach this code when we know it's a
// property, but if someone uses bindProperty directly they might get a
// NoSuchMethodError either from the getField below, or from the setField
// inside PolymerBinding. That doesn't seem unreasonable, but it's a slight
// difference from Polymer.js behavior.
+ if (_bindLog.isLoggable(Level.FINE)) {
+ _bindLog.fine('bindProperty: [$bindable] to [${localName}].[name]');
+ }
+
// capture A's value if B's value is null or undefined,
// otherwise use B's value
- var path = new PathObserver(inB, inPath);
- if (path.value == null) {
- path.value = reflect(inA).getField(inProperty).reflectee;
+ // TODO(sorvell): need to review, can do with ObserverTransform
+ var v = bindable.value;
+ if (v == null) {
+ bindable.value = reflect(this).getField(name).reflectee;
}
- return new _PolymerBinding(inA, inProperty, inB, inPath);
+
+ // TODO(jmesserly): this will create another subscription.
+ // It would be nice to have this reuse our existing _propertyObserver
+ // created by observeProperties, to avoid more observation overhead.
+ return new _PolymerBinding(this, name, bindable);
}
/** Attach event listeners on the host (this) element. */
@@ -702,8 +739,7 @@
var h = findEventDelegate(event);
if (h != null) {
if (log) _eventsLog.fine('[$localName] found host handler name [$h]');
- var detail = event is CustomEvent ?
- (event as CustomEvent).detail : null;
+ var detail = event is CustomEvent ? event.detail : null;
// TODO(jmesserly): cache the symbols?
dispatchMethod(this, h, [event, detail, this]);
}
@@ -745,16 +781,10 @@
* the bound path at event execution time.
*/
// from src/instance/event.js#prepareBinding
- // TODO(sorvell): we're patching the syntax while evaluating
- // event bindings. we'll move this to a better spot when that's done
- static PrepareBindingFunction prepareBinding(String path, String name, node,
- originalPrepareBinding) {
-
- // if lhs an event prefix,
- if (!_hasEventPrefix(name)) return originalPrepareBinding(path, name, node);
+ static PrepareBindingFunction prepareBinding(String path, String name, node) {
// provide an event-binding callback.
- return (model, node) {
+ return (model, node, oneTime) {
if (_eventsLog.isLoggable(Level.FINE)) {
_eventsLog.fine('event: [$node].$name => [$model].$path())');
}
@@ -763,46 +793,17 @@
var translated = _eventTranslations[eventName];
eventName = translated != null ? translated : eventName;
- // TODO(jmesserly): we need a place to unregister this. See:
- // https://code.google.com/p/dart/issues/detail?id=15574
- node.on[eventName].listen((event) {
- var ctrlr = _findController(node);
- if (ctrlr is! Polymer) return;
- var obj = ctrlr;
- var method = path;
- if (path[0] == '@') {
- obj = model;
- method = new PathObserver(model, path.substring(1)).value;
- }
- var detail = event is CustomEvent ?
- (event as CustomEvent).detail : null;
- ctrlr.dispatchMethod(obj, method, [event, detail, node]);
- });
-
- // TODO(jmesserly): this return value is bogus. Returning null here causes
- // the wrong thing to happen in template_binding.
- return new ObservableBox();
+ return new _EventBindable(node, eventName, model, path);
};
}
- // TODO(jmesserly): this won't find the correct host unless the ShadowRoot
- // was created on a PolymerElement.
- static Polymer _findController(Node node) {
- while (node.parentNode != null) {
- node = node.parentNode;
- }
- return _shadowHost[node];
- }
-
/** Call [methodName] method on this object with [args]. */
invokeMethod(Symbol methodName, List args) =>
_invokeMethod(this, methodName, args);
/** Call [methodName] method on [receiver] with [args]. */
static _invokeMethod(receiver, Symbol methodName, List args) {
- // TODO(sigmund): consider making callbacks list all arguments
- // explicitly. Unless VM mirrors are optimized first, this will be expensive
- // once custom elements extend directly from Element (see issue 11108).
+ // TODO(jmesserly): use function type tests instead of mirrors for dispatch.
var receiverMirror = reflect(receiver);
var method = _findMethod(receiverMirror.type, methodName);
if (method != null) {
@@ -999,27 +1000,21 @@
// listen to changes on both sides and update the values.
// TODO(jmesserly): our approach leads to race conditions in the bindings.
// See http://code.google.com/p/dart/issues/detail?id=13567
-class _PolymerBinding extends NodeBinding {
+class _PolymerBinding extends Bindable {
final InstanceMirror _target;
final Symbol _property;
+ final Bindable _bindable;
StreamSubscription _sub;
Object _lastValue;
- _PolymerBinding(Polymer node, Symbol property, model, path)
- : _target = reflect(node),
- _property = property,
- super(node, MirrorSystem.getName(property), model, path) {
+ _PolymerBinding(Polymer node, this._property, this._bindable)
+ : _target = reflect(node) {
_sub = node.changes.listen(_propertyValueChanged);
+ _updateNode(open(_updateNode));
}
- void close() {
- if (closed) return;
- _sub.cancel();
- super.close();
- }
-
- void valueChanged(newValue) {
+ void _updateNode(newValue) {
_lastValue = newValue;
_target.setField(_property, newValue);
}
@@ -1029,19 +1024,30 @@
if (record is PropertyChangeRecord && record.name == _property) {
final newValue = _target.getField(_property).reflectee;
if (!identical(_lastValue, newValue)) {
- value = newValue;
+ this.value = newValue;
}
return;
}
}
}
+
+ open(callback(value)) => _bindable.open(callback);
+ get value => _bindable.value;
+ set value(newValue) => _bindable.value = newValue;
+
+ void close() {
+ if (_sub != null) {
+ _sub.cancel();
+ _sub = null;
+ }
+ _bindable.close();
+ }
}
bool _toBoolean(value) => null != value && false != value;
TypeMirror _propertyType(DeclarationMirror property) =>
- property is VariableMirror
- ? (property as VariableMirror).type
+ property is VariableMirror ? property.type
: (property as MethodMirror).returnType;
TypeMirror _inferPropertyType(Object value, DeclarationMirror property) {
@@ -1095,6 +1101,58 @@
}
class _PolymerExpressionsWithEventDelegate extends PolymerExpressions {
- prepareBinding(String path, name, node) =>
- Polymer.prepareBinding(path, name, node, super.prepareBinding);
+ prepareBinding(String path, name, node) {
+ if (_hasEventPrefix(name)) return Polymer.prepareBinding(path, name, node);
+ return super.prepareBinding(path, name, node);
+ }
}
+
+class _EventBindable extends Bindable {
+ final Node _node;
+ final String _eventName;
+ final _model;
+ final String _path;
+ StreamSubscription _sub;
+
+ _EventBindable(this._node, this._eventName, this._model, this._path);
+
+ _listener(event) {
+ var ctrlr = _findController(_node);
+ if (ctrlr is! Polymer) return;
+ var obj = ctrlr;
+ var method = _path;
+ if (_path.startsWith('@')) {
+ obj = _model;
+ method = new PropertyPath(_path.substring(1)).getValueFrom(_model);
+ }
+ var detail = event is CustomEvent ?
+ (event as CustomEvent).detail : null;
+ ctrlr.dispatchMethod(obj, method, [event, detail, _node]);
+ }
+
+ // TODO(jmesserly): this won't find the correct host unless the ShadowRoot
+ // was created on a PolymerElement.
+ static Polymer _findController(Node node) {
+ while (node.parentNode != null) {
+ node = node.parentNode;
+ }
+ return _shadowHost[node];
+ }
+
+ get value => null;
+
+ open(callback) {
+ _sub = _node.on[_eventName].listen(_listener);
+ }
+
+ close() {
+ if (_sub != null) {
+ if (_eventsLog.isLoggable(Level.FINE)) {
+ _eventsLog.fine(
+ 'event.remove: [$_node].$_eventName => [$_model].$_path())');
+ }
+ _sub.cancel();
+ _sub = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/pkg/polymer/lib/src/loader.dart b/pkg/polymer/lib/src/loader.dart
index 28adf3d..7a04ef1 100644
--- a/pkg/polymer/lib/src/loader.dart
+++ b/pkg/polymer/lib/src/loader.dart
@@ -21,78 +21,88 @@
* * set up up polling for observable changes
* * initialize Model-Driven Views
* * Include some style to prevent flash of unstyled content (FOUC)
- * * for each library in [libraries], register custom elements labeled with
- * [CustomTag] and invoke the initialization method on it. If [libraries]
- * is null, first find all libraries that need to be loaded by scanning for
- * HTML imports in the main document.
- *
- * The initialization on each library is a top-level function and annotated with
- * [initMethod].
- *
- * The urls in [libraries] can be absolute or relative to
- * `currentMirrorSystem().isolate.rootLibrary.uri`.
+ * * for each library included transitively from HTML and HTML imports,
+ * register custom elements declared there (labeled with [CustomTag]) and
+ * invoke the initialization method on it (top-level functions annotated with
+ * [initMethod]).
*/
Zone initPolymer() {
+ // We use this pattern, and not the inline lazy initialization pattern, so we
+ // can help dart2js detect that _discoverInitializers can be tree-shaken for
+ // deployment (and hence all uses of dart:mirrors from this loading logic).
+ // TODO(sigmund): fix polymer's transformers so they can replace initPolymer
+ // by initPolymerOptimized.
+ if (_initializers == null) _initializers = _discoverInitializers();
if (_useDirtyChecking) {
- return dirtyCheckZone()..run(_initPolymerOptimized);
+ return dirtyCheckZone()..run(initPolymerOptimized);
}
- _initPolymerOptimized();
- return Zone.current;
+ return initPolymerOptimized();
}
/**
* Same as [initPolymer], but runs the version that is optimized for deployment
* to the internet. The biggest difference is it omits the [Zone] that
- * automatically invokes [Observable.dirtyCheck], and the list of libraries must
- * be supplied instead of being dynamically searched for at runtime.
+ * automatically invokes [Observable.dirtyCheck], and the list of initializers
+ * must be supplied instead of being dynamically searched for at runtime using
+ * mirrors.
*/
-// TODO(jmesserly): change the Polymer build step to call this directly.
-void _initPolymerOptimized() {
+Zone initPolymerOptimized() {
+ // TODO(jmesserly): there is some code in src/declaration/polymer-element.js,
+ // git version 37eea00e13b9f86ab21c85a955585e8e4237e3d2, right before
+ // it registers polymer-element, which uses Platform.deliverDeclarations to
+ // coordinate with HTML Imports. I don't think we need it so skipping.
document.register(PolymerDeclaration._TAG, PolymerDeclaration);
- _loadLibraries();
+ for (var initializer in _initializers) {
+ initializer();
+ }
// Run this after user code so they can add to Polymer.veiledElements
_preventFlashOfUnstyledContent();
customElementsReady.then((_) => Polymer._ready.complete());
+ return Zone.current;
}
/**
* Configures [initPolymer] making it optimized for deployment to the internet.
- * With this setup the list of libraries to initialize is supplied instead of
- * being dynamically searched for at runtime. Additionally, after this method is
- * called, [initPolymer] omits the [Zone] that automatically invokes
+ * With this setup the initializer list is supplied instead of being dynamically
+ * searched for at runtime. Additionally, after this method is called,
+ * [initPolymer] omits the [Zone] that automatically invokes
* [Observable.dirtyCheck].
*/
-void configureForDeployment(List<String> libraries) {
- _librariesToLoad = libraries;
+void configureForDeployment(List<Function> initializers) {
+ _initializers = initializers;
_useDirtyChecking = false;
}
/**
- * Libraries that will be initialized. For each library, the intialization
- * registers any type tagged with a [CustomTag] annotation and calls any
+ * List of initializers that by default will be executed when calling
+ * initPolymer. If null, initPolymer will compute the list of initializers by
+ * crawling HTML imports, searchfing for script tags, and including an
+ * initializer for each type tagged with a [CustomTag] annotation and for each
* top-level method annotated with [initMethod]. The value of this field is
* assigned programatically by the code generated from the polymer deploy
- * scripts. During development, the libraries are inferred by crawling HTML
- * imports and searching for script tags.
+ * scripts.
*/
-List<String> _librariesToLoad =
- _discoverScripts(document, window.location.href);
+List<Function> _initializers;
+
bool _useDirtyChecking = true;
-void _loadLibraries() {
- for (var lib in _librariesToLoad) {
+List<Function> _discoverInitializers() {
+ var initializers = [];
+ var librariesToLoad = _discoverScripts(document, window.location.href);
+ for (var lib in librariesToLoad) {
try {
- _loadLibrary(lib);
+ _loadLibrary(lib, initializers);
} catch (e, s) {
// Deliver errors async, so if a single library fails it doesn't prevent
// other things from loading.
new Completer().completeError(e, s);
}
}
+ return initializers;
}
/**
@@ -159,7 +169,7 @@
* * Registers any [PolymerElement] that is marked with the [CustomTag]
* annotation.
*/
-void _loadLibrary(String uriString) {
+void _loadLibrary(String uriString, List<Function> initializers) {
var uri = _rootUri.resolve(uriString);
var lib = _libs[uri];
if (_isHttpStylePackageUrl(uri)) {
@@ -185,7 +195,7 @@
// Search top-level functions marked with @initMethod
for (var f in lib.declarations.values.where((d) => d is MethodMirror)) {
- _maybeInvoke(lib, f);
+ _addInitMethod(lib, f, initializers);
}
for (var c in lib.declarations.values.where((d) => d is ClassMirror)) {
@@ -193,7 +203,7 @@
for (var m in c.metadata) {
var meta = m.reflectee;
if (meta is CustomTag) {
- Polymer.register(meta.tagName, c.reflectedType);
+ initializers.add(() => Polymer.register(meta.tagName, c.reflectedType));
}
}
@@ -206,7 +216,8 @@
}
}
-void _maybeInvoke(ObjectMirror obj, MethodMirror method) {
+void _addInitMethod(ObjectMirror obj, MethodMirror method,
+ List<Function> initializers) {
var annotationFound = false;
for (var meta in method.metadata) {
if (identical(meta.reflectee, initMethod)) {
@@ -225,7 +236,7 @@
"arguments, ${method.simpleName} expects some.");
return;
}
- obj.invoke(method.simpleName, const []);
+ initializers.add(() => obj.invoke(method.simpleName, const []));
}
class _InitMethodAnnotation {
diff --git a/pkg/polymer/pubspec.yaml b/pkg/polymer/pubspec.yaml
index 7a3ab81..15475869 100644
--- a/pkg/polymer/pubspec.yaml
+++ b/pkg/polymer/pubspec.yaml
@@ -1,5 +1,5 @@
name: polymer
-version: 0.9.5-dev
+version: 0.10.0-dev
author: Polymer.dart Authors <web-ui-dev@dartlang.org>
description: >
Polymer.dart is a new type of library for the web, built on top of Web
diff --git a/pkg/polymer/test/attr_mustache_test.dart b/pkg/polymer/test/attr_mustache_test.dart
index 8f2cae1..45da525 100644
--- a/pkg/polymer/test/attr_mustache_test.dart
+++ b/pkg/polymer/test/attr_mustache_test.dart
@@ -17,8 +17,8 @@
Future get foundSrc => _found.future;
// force an mdv binding
- bind(name, model, [path]) =>
- nodeBindFallback(this).bind(name, model, path);
+ bind(name, value, {oneTime: false}) =>
+ nodeBindFallback(this).bind(name, value, oneTime: oneTime);
inserted() {
testSrcForMustache();
diff --git a/pkg/polymer/test/build/all_phases_test.dart b/pkg/polymer/test/build/all_phases_test.dart
index bb39a85..3f84593 100644
--- a/pkg/polymer/test/build/all_phases_test.dart
+++ b/pkg/polymer/test/build/all_phases_test.dart
@@ -49,7 +49,6 @@
void main() {
configureForDeployment([
- 'a.dart',
]);
i0.main();
}
@@ -77,7 +76,6 @@
void main() {
configureForDeployment([
- 'test.html.0.dart',
]);
i0.main();
}
@@ -119,7 +117,6 @@
void main() {
configureForDeployment([
- 'a.dart',
]);
i0.main();
}
@@ -158,8 +155,6 @@
void main() {
configureForDeployment([
- 'test2.html.0.dart',
- 'b.dart',
]);
i1.main();
}
diff --git a/pkg/polymer/test/build/script_compactor_test.dart b/pkg/polymer/test/build/script_compactor_test.dart
index e3ec79c..2d32a74 100644
--- a/pkg/polymer/test/build/script_compactor_test.dart
+++ b/pkg/polymer/test/build/script_compactor_test.dart
@@ -50,7 +50,6 @@
void main() {
configureForDeployment([
- 'a.dart',
]);
i0.main();
}
@@ -66,7 +65,52 @@
'</div>',
'a|web/test.html.scriptUrls':
'[["a", "web/a.dart"],["a", "web/b.dart"],["a", "web/c.dart"]]',
- 'a|web/d.dart': 'library d;\nmain(){}',
+ 'a|web/d.dart': 'library d;\nmain(){}\n@initMethod mD(){}',
+
+ 'a|web/a.dart':
+ 'import "package:polymer/polymer.dart";\n'
+ '@initMethod mA(){}\n',
+
+ 'a|web/b.dart':
+ 'export "e.dart";\n'
+ 'export "f.dart" show XF1, mF1;\n'
+ 'export "g.dart" hide XG1, mG1;\n'
+ 'export "h.dart" show XH1, mH1 hide mH1, mH2;\n'
+ '@initMethod mB(){}\n',
+
+ 'a|web/c.dart':
+ 'import "package:polymer/polymer.dart";\n'
+ 'part "c_part.dart"\n'
+ '@CustomTag("x-c2") class XC2 {}\n',
+
+ 'a|web/c_part.dart':
+ '@CustomTag("x-c1") class XC1 {}\n',
+
+ 'a|web/e.dart':
+ 'import "package:polymer/polymer.dart";\n'
+ '@CustomTag("x-e") class XE {}\n'
+ '@initMethod mE(){}\n',
+
+ 'a|web/f.dart':
+ 'import "package:polymer/polymer.dart";\n'
+ '@CustomTag("x-f1") class XF1 {}\n'
+ '@initMethod mF1(){}\n'
+ '@CustomTag("x-f2") class XF2 {}\n'
+ '@initMethod mF2(){}\n',
+
+ 'a|web/g.dart':
+ 'import "package:polymer/polymer.dart";\n'
+ '@CustomTag("x-g1") class XG1 {}\n'
+ '@initMethod mG1(){}\n'
+ '@CustomTag("x-g2") class XG2 {}\n'
+ '@initMethod mG2(){}\n',
+
+ 'a|web/h.dart':
+ 'import "package:polymer/polymer.dart";\n'
+ '@CustomTag("x-h1") class XH1 {}\n'
+ '@initMethod mH1(){}\n'
+ '@CustomTag("x-h2") class XH2 {}\n'
+ '@initMethod mH2(){}\n',
}, {
'a|web/test.html':
'<!DOCTYPE html><html><head></head><body><div>'
@@ -84,10 +128,18 @@
void main() {
configureForDeployment([
- 'a.dart',
- 'b.dart',
- 'c.dart',
- 'd.dart',
+ i0.mA,
+ () => Polymer.register('x-e', i1.XE),
+ i1.mE,
+ () => Polymer.register('x-f1', i1.XF1),
+ i1.mF1,
+ () => Polymer.register('x-g2', i1.XG2),
+ i1.mG2,
+ () => Polymer.register('x-h1', i1.XH1),
+ i1.mB,
+ () => Polymer.register('x-c1', i2.XC1),
+ () => Polymer.register('x-c2', i2.XC2),
+ i3.mD,
]);
i3.main();
}
diff --git a/pkg/polymer/test/custom_event_test.dart b/pkg/polymer/test/custom_event_test.dart
index eef68e0..08c45af 100644
--- a/pkg/polymer/test/custom_event_test.dart
+++ b/pkg/polymer/test/custom_event_test.dart
@@ -53,10 +53,10 @@
final fooBar = testComp.fooBar;
final binding = nodeBind(fooBar).bindings['on-barbaz'];
- expect(binding, isNotNull, reason: 'on-barbaz event should be bound');
+ expect(binding is Bindable, true,
+ reason: 'on-barbaz event should be bound');
- expect(binding.model is! StreamSubscription, true,
- reason: 'event bindings should not be a StreamSubscription');
+ expect(binding.value, null, reason: 'event bindings do not have value');
fooBar.fireFoo(123);
fooBar.fireBarBaz(42);
diff --git a/pkg/polymer/test/event_handlers_test.dart b/pkg/polymer/test/event_handlers_test.dart
index 0b65bf6..33d8631 100644
--- a/pkg/polymer/test/event_handlers_test.dart
+++ b/pkg/polymer/test/event_handlers_test.dart
@@ -109,7 +109,7 @@
initPolymer();
}
-@initMethod _init() {
+@initMethod init() {
useHtmlConfiguration();
setUp(() => Polymer.onReady);
diff --git a/pkg/polymer/test/event_path_declarative_test.dart b/pkg/polymer/test/event_path_declarative_test.dart
index a96779a..1c9495f 100644
--- a/pkg/polymer/test/event_path_declarative_test.dart
+++ b/pkg/polymer/test/event_path_declarative_test.dart
@@ -81,7 +81,7 @@
}
}
-@initMethod _init() {
+@initMethod init() {
useHtmlConfiguration();
// TODO(sigmund): switch back to use @CustomTag. We seem to be running into a
// problem where using @CustomTag doesn't guarantee that we register the tags
diff --git a/pkg/polymer/test/nested_binding_test.dart b/pkg/polymer/test/nested_binding_test.dart
index ab991d9..f4c4959 100644
--- a/pkg/polymer/test/nested_binding_test.dart
+++ b/pkg/polymer/test/nested_binding_test.dart
@@ -35,5 +35,6 @@
setUp(() => Polymer.onReady);
- test('ready called', () => (query('my-test') as MyTest)._testDone.future);
+ test('ready called',
+ () => (querySelector('my-test') as MyTest)._testDone.future);
}
diff --git a/pkg/polymer/test/property_observe_test.dart b/pkg/polymer/test/property_observe_test.dart
new file mode 100644
index 0000000..c3facc6
--- /dev/null
+++ b/pkg/polymer/test/property_observe_test.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2013, 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 polymer.test.property_change_test;
+
+import 'dart:async';
+import 'dart:html';
+import 'package:polymer/polymer.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/matcher.dart';
+
+var _changes = 0;
+final _done = new Completer();
+
+checkDone() {
+ if (6 == ++_changes) {
+ _done.complete();
+ }
+}
+
+@CustomTag('x-test')
+class XTest extends PolymerElement {
+ @observable String bar = '';
+ @observable String pie;
+ @observable Map a;
+
+ XTest.created() : super.created();
+
+ ready() {
+ bar = 'bar';
+ pie = 'pie';
+ a = {'b': {'c': 'exists'}};
+ }
+
+ barChanged() {
+ // Dart note: unlike polymer-js we support multiple observers, due to how
+ // our @ObserveProperty metadata translated.
+ // _done.completeError('barChanged should not be called.');
+ expect('bar', 'bar', reason: 'barChanged called');
+ checkDone();
+ }
+
+ @ObserveProperty('bar pie')
+ validate() {
+ window.console.log('validate');
+ expect('bar', 'bar', reason: 'custom change observer called');
+ expect('pie', 'pie', reason: 'custom change observer called');
+ checkDone();
+ }
+
+ // Dart note: test that we can observe "pie" twice.
+ @ObserveProperty('pie')
+ validateYummyPie() {
+ window.console.log('validateYummyPie');
+ expect('pie', 'pie', reason: 'validateYummyPie called');
+ checkDone();
+ }
+
+
+ @ObserveProperty('a.b.c')
+ validateSubPath(oldValue, newValue) {
+ window.console.log('validateSubPath $oldValue $newValue');
+ expect(newValue, 'exists', reason: 'subpath change observer called');
+ checkDone();
+ }
+}
+
+@CustomTag('x-test2')
+class XTest2 extends XTest {
+ @observable String noogle;
+
+ XTest2.created() : super.created();
+
+ @ObserveProperty('noogle')
+ validate() => super.validate();
+
+ ready() {
+ super.ready();
+ noogle = 'noogle';
+ }
+}
+
+main() => initPolymer().run(() {
+ useHtmlConfiguration();
+
+ setUp(() => Polymer.onReady);
+
+ test('changes detected', () => _done.future);
+});
diff --git a/pkg/polymer/test/property_observe_test.html b/pkg/polymer/test/property_observe_test.html
new file mode 100644
index 0000000..a71228e
--- /dev/null
+++ b/pkg/polymer/test/property_observe_test.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<!--
+Copyright (c) 2013, 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.
+-->
+<html>
+ <!--polymer-test: this comment is needed for test_suite.dart-->
+ <head>
+ <title>property.observe changes</title>
+ <script src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ </head>
+ <body>
+ <x-test id="test"></x-test>
+ <x-test2 id="test"></x-test2>
+
+ <polymer-element name="x-test"><template></template></polymer-element>
+ <polymer-element name="x-test2" extends="x-test">
+ <template></template>
+ </polymer-element>
+ <script type="application/dart" src="property_observe_test.dart"></script>
+ </body>
+</html>
diff --git a/pkg/polymer/test/publish_attributes_test.dart b/pkg/polymer/test/publish_attributes_test.dart
index 8701a7b..78bd593 100644
--- a/pkg/polymer/test/publish_attributes_test.dart
+++ b/pkg/polymer/test/publish_attributes_test.dart
@@ -62,10 +62,10 @@
published(tag) => (query('polymer-element[name=$tag]')
as PolymerDeclaration).publishedProperties;
- expect(published('x-foo'), [#Foo, #baz]);
- expect(published('x-bar'), [#Foo, #baz, #Bar]);
- expect(published('x-zot'), [#Foo, #baz, #Bar, #zot]);
- expect(published('x-squid'), [#Foo, #baz, #Bar, #zot, #squid]);
- expect(published('x-qux'), [#qux]);
+ expect(published('x-foo'), ['Foo', 'baz']);
+ expect(published('x-bar'), ['Foo', 'baz', 'Bar']);
+ expect(published('x-zot'), ['Foo', 'baz', 'Bar', 'zot']);
+ expect(published('x-squid'), ['Foo', 'baz', 'Bar', 'zot', 'squid']);
+ expect(published('x-qux'), ['qux']);
});
}
diff --git a/pkg/polymer/test/publish_inherited_properties_test.dart b/pkg/polymer/test/publish_inherited_properties_test.dart
index 7eec80a..24595c4 100644
--- a/pkg/polymer/test/publish_inherited_properties_test.dart
+++ b/pkg/polymer/test/publish_inherited_properties_test.dart
@@ -56,9 +56,9 @@
published(tag) => (query('polymer-element[name=$tag]')
as PolymerDeclaration).publishedProperties;
- expect(published('x-zot'), [#Foo, #Bar, #zot, #m]);
- expect(published('x-squid'), [#Foo, #Bar, #zot, #m, #baz, #squid]);
- expect(published('x-noscript'), [#Foo, #Bar, #zot, #m]);
+ expect(published('x-zot'), ['Foo', 'Bar', 'zot', 'm']);
+ expect(published('x-squid'), ['Foo', 'Bar', 'zot', 'm', 'baz', 'squid']);
+ expect(published('x-noscript'), ['Foo', 'Bar', 'zot', 'm']);
// TODO(sigmund): uncomment, see above
// expect(published('x-squid'), [#Foo, #Bar, #zot, #zap, #baz, #squid]);
});
diff --git a/pkg/polymer_expressions/example/streams/collect_key_press.html b/pkg/polymer_expressions/example/streams/collect_key_press.html
index 0bd7ffe..d2225f5 100644
--- a/pkg/polymer_expressions/example/streams/collect_key_press.html
+++ b/pkg/polymer_expressions/example/streams/collect_key_press.html
@@ -31,7 +31,7 @@
'collect': collect,
};
- templateBind(query('#test'))
+ templateBind(querySelector('#test'))
..bindingDelegate = new PolymerExpressions(globals: globals)
..model = null;
}
diff --git a/pkg/polymer_expressions/lib/eval.dart b/pkg/polymer_expressions/lib/eval.dart
index be2fdec..22851e6 100644
--- a/pkg/polymer_expressions/lib/eval.dart
+++ b/pkg/polymer_expressions/lib/eval.dart
@@ -249,6 +249,8 @@
ExpressionObserver(this._expr);
+ Expression get expression => _expr;
+
Object get currentValue => _value;
update(Scope scope) => _updateSelf(scope);
diff --git a/pkg/polymer_expressions/lib/polymer_expressions.dart b/pkg/polymer_expressions/lib/polymer_expressions.dart
index 0d4d061..36ea352 100644
--- a/pkg/polymer_expressions/lib/polymer_expressions.dart
+++ b/pkg/polymer_expressions/lib/polymer_expressions.dart
@@ -81,17 +81,23 @@
return null;
}
- return (model, node) {
+ return (model, node, oneTime) {
if (model is! Scope) {
model = new Scope(model: model, variables: globals);
}
+ var converter = null;
if (node is Element && name == "class") {
- return new _Binding(expr, model, _classAttributeConverter);
+ converter = _classAttributeConverter;
}
if (node is Element && name == "style") {
- return new _Binding(expr, model, _styleAttributeConverter);
+ converter = _styleAttributeConverter;
}
- return new _Binding(expr, model);
+
+ if (oneTime) {
+ return _Binding._oneTime(expr, model, converter);
+ }
+
+ return new _Binding(expr, model, converter);
};
}
@@ -99,50 +105,82 @@
model is Scope ? model : new Scope(model: model, variables: globals);
}
-class _Binding extends ChangeNotifier {
+class _Binding extends Bindable {
final Scope _scope;
- final ExpressionObserver _expr;
final _converter;
+ Expression _expr;
+ Function _callback;
+ StreamSubscription _sub;
var _value;
- _Binding(Expression expr, Scope scope, [this._converter])
- : _expr = observe(expr, scope),
- _scope = scope {
- _expr.onUpdate.listen(_setValue).onError((e) {
- _logger.warning("Error evaluating expression '$_expr': ${e.message}");
- });
+ _Binding(this._expr, this._scope, [this._converter]);
+
+ static _oneTime(Expression expr, Scope scope, [converter]) {
try {
- update(_expr, _scope);
- _setValue(_expr.currentValue);
+ return _convertValue(eval(expr, scope), scope, converter);
} on EvalException catch (e) {
- _logger.warning("Error evaluating expression '$_expr': ${e.message}");
+ _logger.warning("Error evaluating expression '$expr': ${e.message}");
+ return null;
}
}
_setValue(v) {
- var oldValue = _value;
+ _value = _convertValue(v, _scope, _converter);
+ if (_callback != null) _callback(_value);
+ }
+
+ static _convertValue(v, scope, converter) {
if (v is Comprehension) {
// convert the Comprehension into a list of scopes with the loop
// variable added to the scope
- _value = v.iterable.map((i) {
+ return v.iterable.map((i) {
var vars = new Map();
vars[v.identifier] = i;
- Scope childScope = new Scope(parent: _scope, variables: vars);
+ Scope childScope = new Scope(parent: scope, variables: vars);
return childScope;
}).toList(growable: false);
} else {
- _value = (_converter == null) ? v : _converter(v);
+ return converter == null ? v : converter(v);
}
- notifyPropertyChange(#value, oldValue, _value);
}
- @reflectable get value => _value;
+ get value {
+ if (_callback != null) return _value;
+ return _oneTime(_expr, _scope, _converter);
+ }
- @reflectable set value(v) {
+ set value(v) {
try {
assign(_expr, v, _scope);
} on EvalException catch (e) {
_logger.warning("Error evaluating expression '$_expr': ${e.message}");
}
}
+
+ open(callback(value)) {
+ if (_callback != null) throw new StateError('already open');
+
+ _callback = callback;
+ final expr = observe(_expr, _scope);
+ _expr = expr;
+ _sub = expr.onUpdate.listen(_setValue)..onError((e) {
+ _logger.warning("Error evaluating expression '$_expr': ${e.message}");
+ });
+ try {
+ update(expr, _scope);
+ _value = _convertValue(expr.currentValue, _scope, _converter);
+ } on EvalException catch (e) {
+ _logger.warning("Error evaluating expression '$_expr': ${e.message}");
+ }
+ return _value;
+ }
+
+ void close() {
+ if (_callback == null) return;
+
+ _sub.cancel();
+ _sub = null;
+ _expr = (_expr as ExpressionObserver).expression;
+ _callback = null;
+ }
}
diff --git a/pkg/polymer_expressions/test/bindings_test.dart b/pkg/polymer_expressions/test/bindings_test.dart
index 26a3a14..209012d 100644
--- a/pkg/polymer_expressions/test/bindings_test.dart
+++ b/pkg/polymer_expressions/test/bindings_test.dart
@@ -4,17 +4,18 @@
library bindings_test;
+import 'dart:async';
import 'dart:html';
import 'package:logging/logging.dart';
import 'package:observe/observe.dart';
-import 'package:observe/src/microtask.dart';
+import 'package:observe/src/dirty_check.dart' show dirtyCheckZone;
import 'package:polymer_expressions/polymer_expressions.dart';
import 'package:template_binding/template_binding.dart' show templateBind;
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
-main() {
+main() => dirtyCheckZone().run(() {
useHtmlConfiguration();
group('bindings', () {
@@ -34,89 +35,93 @@
messages = [];
});
- observeTest('should update binding when data changes', () {
+ test('should update binding when data changes', () {
var model = new NotifyModel();
var binding = new PolymerExpressions()
- .prepareBinding('x', null, null)(model, null);
+ .prepareBinding('x', null, null)(model, null, false);
expect(binding.value, isNull);
model.x = "hi";
- performMicrotaskCheckpoint();
- expect(binding.value, 'hi');
- expect(messages.length, 0);
+ return new Future(() {
+ expect(binding.value, 'hi');
+ expect(messages.length, 0);
+ });
});
- observeTest('should update text content when data changes', () {
+ test('should update text content when data changes', () {
var model = new NotifyModel('abcde');
var template = templateBind(new Element.html(
'<template><span>{{x}}</span></template>'));
testDiv.append(template.createInstance(model, new PolymerExpressions()));
- performMicrotaskCheckpoint();
- var el = testDiv.query("span");
- expect(el.text, 'abcde');
- expect(model.x, 'abcde');
- model.x = '___';
+ return new Future(() {
+ var el = testDiv.query("span");
+ expect(el.text, 'abcde');
+ expect(model.x, 'abcde');
+ model.x = '___';
- performMicrotaskCheckpoint();
- expect(model.x, '___');
- expect(el.text, '___');
+ return new Future(() {
+ expect(model.x, '___');
+ expect(el.text, '___');
+ });
+ });
});
- observeTest('should log eval exceptions', () {
+ test('should log eval exceptions', () {
var model = new NotifyModel('abcde');
var template = templateBind(new Element.html(
'<template><span>{{foo}}</span></template>'));
testDiv.append(template.createInstance(model, new PolymerExpressions()));
- performMicrotaskCheckpoint();
- expect(messages.length, 1);
- expect(messages[0].message,
- "Error evaluating expression 'foo': variable 'foo' not found");
+
+ return new Future(() {
+ expect(messages.length, 1);
+ expect(messages[0].message,
+ "Error evaluating expression 'foo': variable 'foo' not found");
+ });
});
- observeTest('should preserve the cursor position', () {
+ test('should preserve the cursor position', () {
var model = new NotifyModel('abcde');
var template = templateBind(new Element.html(
'<template><input id="i1" value={{x}}></template>'));
testDiv.append(template.createInstance(model, new PolymerExpressions()));
- performMicrotaskCheckpoint();
- var el = testDiv.query("#i1");
- var subscription = el.onInput.listen(expectAsync1((_) {
- performMicrotaskCheckpoint();
- }, count: 1));
- el.focus();
+ return new Future(() {
+ var el = testDiv.query("#i1");
+ var subscription = el.onInput.listen(expectAsync1((_) {}, count: 1));
+ el.focus();
- expect(el.value, 'abcde');
- expect(model.x, 'abcde');
+ expect(el.value, 'abcde');
+ expect(model.x, 'abcde');
- el.selectionStart = 3;
- el.selectionEnd = 3;
- expect(el.selectionStart, 3);
- expect(el.selectionEnd, 3);
+ el.selectionStart = 3;
+ el.selectionEnd = 3;
+ expect(el.selectionStart, 3);
+ expect(el.selectionEnd, 3);
- el.value = 'abc de';
- // Updating the input value programatically (even to the same value in
- // Chrome) loses the selection position.
- expect(el.selectionStart, 6);
- expect(el.selectionEnd, 6);
+ el.value = 'abc de';
+ // Updating the input value programatically (even to the same value in
+ // Chrome) loses the selection position.
+ expect(el.selectionStart, 6);
+ expect(el.selectionEnd, 6);
- el.selectionStart = 4;
- el.selectionEnd = 4;
+ el.selectionStart = 4;
+ el.selectionEnd = 4;
- expect(model.x, 'abcde');
- el.dispatchEvent(new Event('input'));
- expect(model.x, 'abc de');
- expect(el.value, 'abc de');
+ expect(model.x, 'abcde');
+ el.dispatchEvent(new Event('input'));
+ expect(model.x, 'abc de');
+ expect(el.value, 'abc de');
- // But propagating observable values through reassign the value and
- // selection will be preserved.
- expect(el.selectionStart, 4);
- expect(el.selectionEnd, 4);
+ // But propagating observable values through reassign the value and
+ // selection will be preserved.
+ expect(el.selectionStart, 4);
+ expect(el.selectionEnd, 4);
- subscription.cancel();
+ subscription.cancel();
+ });
});
});
-}
+});
@reflectable
class NotifyModel extends ChangeNotifier {
@@ -128,5 +133,3 @@
_x = notifyPropertyChange(#x, _x, value);
}
}
-
-observeTest(name, testCase) => test(name, wrapMicrotask(testCase));
diff --git a/pkg/polymer_expressions/test/globals_test.dart b/pkg/polymer_expressions/test/globals_test.dart
index 295aa11..9690baf 100644
--- a/pkg/polymer_expressions/test/globals_test.dart
+++ b/pkg/polymer_expressions/test/globals_test.dart
@@ -2,17 +2,17 @@
// 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:html';
import 'package:observe/observe.dart';
-import 'package:observe/src/microtask.dart';
import 'package:polymer_expressions/polymer_expressions.dart';
import 'package:template_binding/template_binding.dart';
import 'package:unittest/unittest.dart';
-import 'package:unittest/html_enhanced_config.dart';
+import 'package:unittest/html_config.dart';
main() {
- useHtmlEnhancedConfiguration();
+ useHtmlConfiguration();
var testDiv;
group('enumerate', () {
@@ -34,23 +34,23 @@
testDiv = null;
});
- test('should enumerate item and index', wrapMicrotask(() {
+ test('should enumerate item and index', () {
templateBind(testDiv.query('template'))
..bindingDelegate = new PolymerExpressions()
..model = toObservable(
['hello', 'from', 'polymer', 'expressions']);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ expect(testDiv.queryAll('div').map((n) => n.text), [
+ 'Item 0 is hello',
+ 'Item 1 is from',
+ 'Item 2 is polymer',
+ 'Item 3 is expressions',
+ ]);
+ });
+ });
- expect(testDiv.queryAll('div').map((n) => n.text), [
- 'Item 0 is hello',
- 'Item 1 is from',
- 'Item 2 is polymer',
- 'Item 3 is expressions',
- ]);
- }));
-
- test('should update after changes', wrapMicrotask(() {
+ test('should update after changes', () {
var model = toObservable(
['hello', 'from', 'polymer', 'expressions', 'a', 'b', 'c']);
@@ -58,34 +58,34 @@
..bindingDelegate = new PolymerExpressions()
..model = model;
- performMicrotaskCheckpoint();
+ return new Future(() {
+ expect(testDiv.queryAll('div').map((n) => n.text), [
+ 'Item 0 is hello',
+ 'Item 1 is from',
+ 'Item 2 is polymer',
+ 'Item 3 is expressions',
+ 'Item 4 is a',
+ 'Item 5 is b',
+ 'Item 6 is c',
+ ]);
- expect(testDiv.queryAll('div').map((n) => n.text), [
- 'Item 0 is hello',
- 'Item 1 is from',
- 'Item 2 is polymer',
- 'Item 3 is expressions',
- 'Item 4 is a',
- 'Item 5 is b',
- 'Item 6 is c',
- ]);
+ model.removeAt(1);
+ model[1] = 'world';
+ model[2] = '!';
+ model.insert(5, 'e');
- model.removeAt(1);
- model[1] = 'world';
- model[2] = '!';
- model.insert(5, 'e');
-
- performMicrotaskCheckpoint();
-
- expect(testDiv.queryAll('div').map((n) => n.text), [
- 'Item 0 is hello',
- 'Item 1 is world',
- 'Item 2 is !',
- 'Item 3 is a',
- 'Item 4 is b',
- 'Item 5 is e',
- 'Item 6 is c',
- ]);
- }));
+ return new Future(() {
+ expect(testDiv.queryAll('div').map((n) => n.text), [
+ 'Item 0 is hello',
+ 'Item 1 is world',
+ 'Item 2 is !',
+ 'Item 3 is a',
+ 'Item 4 is b',
+ 'Item 5 is e',
+ 'Item 6 is c',
+ ]);
+ });
+ });
+ });
});
}
diff --git a/pkg/polymer_expressions/test/syntax_test.dart b/pkg/polymer_expressions/test/syntax_test.dart
index b5dc01f..50972e3 100644
--- a/pkg/polymer_expressions/test/syntax_test.dart
+++ b/pkg/polymer_expressions/test/syntax_test.dart
@@ -9,11 +9,11 @@
import 'package:observe/observe.dart';
import 'package:polymer_expressions/polymer_expressions.dart';
import 'package:template_binding/template_binding.dart';
-import 'package:unittest/html_enhanced_config.dart';
+import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
main() {
- useHtmlEnhancedConfiguration();
+ useHtmlConfiguration();
group('PolymerExpressions', () {
var testDiv;
@@ -67,7 +67,9 @@
var logFuture = logger.onRecord.toList();
testDiv.nodes.add(new Element.html('''
<template id="test" bind>{{ foo }}</template>'''));
- templateBind(query('#test')).bindingDelegate = new PolymerExpressions();
+ templateBind(query('#test'))
+ ..bindingDelegate = new PolymerExpressions()
+ ..model = [];
return new Future(() {
logger.clearListeners();
return logFuture.then((records) {
diff --git a/pkg/scheduled_test/lib/scheduled_test.dart b/pkg/scheduled_test/lib/scheduled_test.dart
index bf47adb..6713054 100644
--- a/pkg/scheduled_test/lib/scheduled_test.dart
+++ b/pkg/scheduled_test/lib/scheduled_test.dart
@@ -238,17 +238,16 @@
return currentSchedule.run(() {
if (_setUpFn != null) _setUpFn();
body();
+ }).catchError((error, stackTrace) {
+ if (error is ScheduleError) {
+ assert(error.schedule.errors.contains(error));
+ assert(error.schedule == currentSchedule);
+ unittest.registerException(error.schedule.errorString());
+ } else {
+ unittest.registerException(error, new Chain.forTrace(stackTrace));
+ }
}).then(completer.complete);
- }, onError: (e, chain) {
- if (e is ScheduleError) {
- assert(e.schedule.errors.contains(e));
- assert(e.schedule == currentSchedule);
- unittest.registerException(e.schedule.errorString());
- } else {
- unittest.registerException(e, chain);
- }
- completer.complete();
- });
+ }, onError: (error, chain) => currentSchedule.signalError(error, chain));
return completer.future;
});
diff --git a/pkg/scheduled_test/test/scheduled_test/unhandled_error_test.dart b/pkg/scheduled_test/test/scheduled_test/unhandled_error_test.dart
new file mode 100644
index 0000000..aaf87f3
--- /dev/null
+++ b/pkg/scheduled_test/test/scheduled_test/unhandled_error_test.dart
@@ -0,0 +1,27 @@
+// 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.
+
+import 'dart:async';
+
+import 'package:scheduled_test/scheduled_test.dart';
+import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
+
+import '../metatest.dart';
+import '../utils.dart';
+
+void main(_, message) {
+ initMetatest(message);
+
+ setUpTimeout();
+
+ expectTestFails("a top-leveled error should be converted to a schedule error",
+ () {
+ schedule(() {
+ new Future.microtask(() => throw 'error');
+ return pumpEventQueue();
+ });
+ }, (errors) {
+ expect(errors.first.error, equals('error'));
+ });
+}
diff --git a/pkg/shadow_dom/pubspec.yaml b/pkg/shadow_dom/pubspec.yaml
index 0c3bb3e..fc1a529 100644
--- a/pkg/shadow_dom/pubspec.yaml
+++ b/pkg/shadow_dom/pubspec.yaml
@@ -1,5 +1,5 @@
name: shadow_dom
-version: 0.9.1
+version: 0.9.2
author: Polymer.dart Authors <web-ui-dev@dartlang.org>
homepage: https://www.dartlang.org/polymer-dart/
description: >
@@ -9,4 +9,4 @@
within a document, thus enabling better functional encapsulation within the
DOM.
environment:
- sdk: ">=1.0.0 <2.0.0"
+ sdk: ">=1.2.0-dev.3.0 <2.0.0"
diff --git a/pkg/template_binding/lib/src/binding_delegate.dart b/pkg/template_binding/lib/src/binding_delegate.dart
index 0a9cb51..4d9f8d2 100644
--- a/pkg/template_binding/lib/src/binding_delegate.dart
+++ b/pkg/template_binding/lib/src/binding_delegate.dart
@@ -66,7 +66,7 @@
Element template) => null;
}
-typedef PrepareBindingFunction(model, Node node);
+typedef PrepareBindingFunction(model, Node node, bool oneTime);
typedef PrepareInstanceModelFunction(model);
diff --git a/pkg/template_binding/lib/src/element.dart b/pkg/template_binding/lib/src/element.dart
index 1ee43f9..bf9a036 100644
--- a/pkg/template_binding/lib/src/element.dart
+++ b/pkg/template_binding/lib/src/element.dart
@@ -8,76 +8,63 @@
class _ElementExtension extends NodeBindExtension {
_ElementExtension(Element node) : super._(node);
- NodeBinding bind(String name, model, [String path]) {
+ bind(String name, value, {bool oneTime: false}) {
_self.unbind(name);
- var binding;
- if (_node is OptionElement && name == 'value') {
+ Element node = _node;
+
+ if (node is OptionElement && name == 'value') {
// Note: because <option> can be a semantic template, <option> will be
// a TemplateBindExtension sometimes. So we need to handle it here.
- (_node as OptionElement).attributes.remove(name);
- binding = new _OptionValueBinding(_node, model, path);
- } else {
- binding = new _AttributeBinding(_node, name, model, path);
- }
- return bindings[name] = binding;
- }
-}
-
-class _AttributeBinding extends NodeBinding {
- final bool conditional;
-
- _AttributeBinding._(node, name, model, path, this.conditional)
- : super(node, name, model, path);
-
- factory _AttributeBinding(Element node, name, model, path) {
- bool conditional = name.endsWith('?');
- if (conditional) {
node.attributes.remove(name);
- name = name.substring(0, name.length - 1);
- }
- return new _AttributeBinding._(node, name, model, path, conditional);
- }
- Element get node => super.node;
-
- void valueChanged(value) {
- if (conditional) {
- if (_toBoolean(value)) {
- node.attributes[property] = '';
- } else {
- node.attributes.remove(property);
- }
+ if (oneTime) return _updateOption(value);
+ _open(value, _updateOption);
} else {
- // TODO(jmesserly): escape value if needed to protect against XSS.
- // See https://github.com/polymer-project/mdv/issues/58
- node.attributes[property] = sanitizeBoundValue(value);
+ bool conditional = name.endsWith('?');
+ if (conditional) {
+ node.attributes.remove(name);
+ name = name.substring(0, name.length - 1);
+ }
+
+ if (oneTime) return _updateAttribute(_node, name, conditional, value);
+
+ _open(value, (x) => _updateAttribute(_node, name, conditional, x));
}
+ return bindings[name] = value;
}
-}
-class _OptionValueBinding extends _ValueBinding {
- _OptionValueBinding(node, model, path) : super(node, model, path);
-
- OptionElement get node => super.node;
-
- void valueChanged(newValue) {
+ void _updateOption(newValue) {
+ OptionElement node = _node;
var oldValue = null;
var selectBinding = null;
- var select = node.parent;
+ var select = node.parentNode;
if (select is SelectElement) {
var valueBinding = nodeBind(select).bindings['value'];
- if (valueBinding is _SelectBinding) {
+ if (valueBinding is _InputBinding) {
selectBinding = valueBinding;
oldValue = select.value;
}
}
- super.valueChanged(newValue);
+ node.value = _sanitizeValue(newValue);
- if (selectBinding != null && !selectBinding.closed &&
- select.value != oldValue) {
- selectBinding.nodeValueChanged(null);
+ if (selectBinding != null && select.value != oldValue) {
+ selectBinding.value = select.value;
}
}
}
+
+void _updateAttribute(Element node, String name, bool conditional, value) {
+ if (conditional) {
+ if (_toBoolean(value)) {
+ node.attributes[name] = '';
+ } else {
+ node.attributes.remove(name);
+ }
+ } else {
+ // TODO(jmesserly): escape value if needed to protect against XSS.
+ // See https://github.com/polymer-project/mdv/issues/58
+ node.attributes[name] = _sanitizeValue(value);
+ }
+}
diff --git a/pkg/template_binding/lib/src/input_bindings.dart b/pkg/template_binding/lib/src/input_bindings.dart
index 06b744f..6292527 100644
--- a/pkg/template_binding/lib/src/input_bindings.dart
+++ b/pkg/template_binding/lib/src/input_bindings.dart
@@ -4,21 +4,79 @@
part of template_binding;
-abstract class _InputBinding extends NodeBinding {
- StreamSubscription _eventSub;
- _InputBinding(node, name, model, path): super(node, name, model, path) {
- _eventSub = _getStreamForInputType(node).listen(nodeValueChanged);
+// Note: the JavaScript version monkeypatches(!!) the close method of the passed
+// in Bindable. We use a wrapper instead.
+class _InputBinding extends Bindable {
+ // Note: node can be an InputElement or TextAreaElement. Both have "value".
+ var _node;
+ StreamSubscription _eventSub;
+ Bindable _bindable;
+ String _propertyName;
+
+ _InputBinding(this._node, this._bindable, this._propertyName) {
+ _eventSub = _getStreamForInputType(_node).listen(_nodeChanged);
+ _updateNode(open(_updateNode));
}
- void valueChanged(newValue);
+ void _updateNode(newValue) => _updateProperty(_node, newValue, _propertyName);
- void nodeValueChanged(e);
+ static void _updateProperty(node, newValue, String propertyName) {
+ switch (propertyName) {
+ case 'checked':
+ node.checked = _toBoolean(newValue);
+ return;
+ case 'selectedIndex':
+ node.selectedIndex = _toInt(newValue);
+ return;
+ case 'value':
+ node.value = _sanitizeValue(newValue);
+ return;
+ }
+ }
+
+ void _nodeChanged(e) {
+ switch (_propertyName) {
+ case 'value':
+ value = _node.value;
+ break;
+ case 'checked':
+ value = _node.checked;
+
+ // Only the radio button that is getting checked gets an event. We
+ // therefore find all the associated radio buttons and update their
+ // checked binding manually.
+ if (_node is InputElement && _node.type == 'radio') {
+ for (var r in _getAssociatedRadioButtons(_node)) {
+ var checkedBinding = nodeBind(r).bindings['checked'];
+ if (checkedBinding != null) {
+ // Set the value directly to avoid an infinite call stack.
+ checkedBinding.value = false;
+ }
+ }
+ }
+ break;
+ case 'selectedIndex':
+ value = _node.selectedIndex;
+ break;
+ }
+
+ Observable.dirtyCheck();
+ }
+
+ open(callback(value)) => _bindable.open(callback);
+ get value => _bindable.value;
+ set value(newValue) => _bindable.value = newValue;
void close() {
- if (closed) return;
- _eventSub.cancel();
- super.close();
+ if (_eventSub != null) {
+ _eventSub.cancel();
+ _eventSub = null;
+ }
+ if (_bindable != null) {
+ _bindable.close();
+ _bindable = null;
+ }
}
static EventStreamProvider<Event> _checkboxEventType = () {
@@ -53,51 +111,6 @@
return element.onInput;
}
}
-}
-
-class _ValueBinding extends _InputBinding {
- _ValueBinding(node, model, path) : super(node, 'value', model, path);
-
- get node => super.node;
-
- void valueChanged(newValue) {
- // Note: node can be an InputElement or TextAreaElement. Both have "value".
- node.value = sanitizeBoundValue(newValue);
- }
-
- void nodeValueChanged(e) {
- value = node.value;
- Observable.dirtyCheck();
- }
-}
-
-class _CheckedBinding extends _InputBinding {
- _CheckedBinding(node, model, path) : super(node, 'checked', model, path);
-
- InputElement get node => super.node;
-
- void valueChanged(newValue) {
- node.checked = _toBoolean(newValue);
- }
-
- void nodeValueChanged(e) {
- value = node.checked;
-
- // Only the radio button that is getting checked gets an event. We
- // therefore find all the associated radio buttons and update their
- // CheckedBinding manually.
- if (node is InputElement && node.type == 'radio') {
- for (var r in _getAssociatedRadioButtons(node)) {
- var checkedBinding = nodeBind(r).bindings['checked'];
- if (checkedBinding != null) {
- // Set the value directly to avoid an infinite call stack.
- checkedBinding.value = false;
- }
- }
- }
-
- Observable.dirtyCheck();
- }
// |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
// Returns an array containing all radio buttons other than |element| that
@@ -125,63 +138,6 @@
return radios.where((el) => el != element && el.form == null);
}
}
-}
-
-class _SelectBinding extends _InputBinding {
- MutationObserver _onMutation;
-
- _SelectBinding(node, property, model, path)
- : super(node, property, model, path);
-
- SelectElement get node => super.node;
-
- void valueChanged(newValue) {
- _cancelMutationObserver();
-
- if (_tryUpdateValue(newValue)) return;
-
- // It could be that a template will expand an <option> child (or grandchild,
- // if we have an <optgroup> in between). Since selected index cannot be set
- // if the children aren't created yet, we need to wait for them to be
- // created do this with a MutationObserver.
- // Dart note: unlike JS we use mutation observers to avoid:
- // https://github.com/Polymer/NodeBind/issues/5
-
- // Note: it doesn't matter when the children get added; even if they get
- // added much later, presumably we want the selected index data binding to
- // still take effect.
- _onMutation = new MutationObserver((x, y) {
- if (_tryUpdateValue(value)) _cancelMutationObserver();
- })..observe(node, childList: true, subtree: true);
- }
-
- bool _tryUpdateValue(newValue) {
- if (property == 'selectedIndex') {
- var intValue = _toInt(newValue);
- node.selectedIndex = intValue;
- return node.selectedIndex == intValue;
- } else if (property == 'value') {
- node.value = sanitizeBoundValue(newValue);
- return node.value == newValue;
- }
- }
-
- void _cancelMutationObserver() {
- if (_onMutation != null) {
- _onMutation.disconnect();
- _onMutation = null;
- }
- }
-
- void nodeValueChanged(e) {
- _cancelMutationObserver();
-
- if (property == 'selectedIndex') {
- value = node.selectedIndex;
- } else if (property == 'value') {
- value = node.value;
- }
- }
// TODO(jmesserly,sigmund): I wonder how many bindings typically convert from
// one type to another (e.g. value-as-number) and whether it is useful to
diff --git a/pkg/template_binding/lib/src/input_element.dart b/pkg/template_binding/lib/src/input_element.dart
index a599f24..e399435 100644
--- a/pkg/template_binding/lib/src/input_element.dart
+++ b/pkg/template_binding/lib/src/input_element.dart
@@ -10,15 +10,18 @@
InputElement get _node => super._node;
- NodeBinding bind(String name, model, [String path]) {
+ Bindable bind(String name, value, {bool oneTime: false}) {
if (name != 'value' && name != 'checked') {
- return super.bind(name, model, path);
+ return super.bind(name, value, oneTime: oneTime);
+ }
+
+ _node.attributes.remove(name);
+ if (oneTime) {
+ _InputBinding._updateProperty(_node, value, name);
+ return null;
}
_self.unbind(name);
- _node.attributes.remove(name);
- return bindings[name] = name == 'value' ?
- new _ValueBinding(_node, model, path) :
- new _CheckedBinding(_node, model, path);
+ return bindings[name] = new _InputBinding(_node, value, name);
}
}
diff --git a/pkg/template_binding/lib/src/instance_binding_map.dart b/pkg/template_binding/lib/src/instance_binding_map.dart
index 71b0c12..ad34b6e 100644
--- a/pkg/template_binding/lib/src/instance_binding_map.dart
+++ b/pkg/template_binding/lib/src/instance_binding_map.dart
@@ -6,66 +6,68 @@
class _InstanceBindingMap {
final List bindings;
- final Map<int, _InstanceBindingMap> children;
- final Node templateRef;
+ List<_InstanceBindingMap> children;
+ DocumentFragment content;
- // Workaround for:
- // https://github.com/Polymer/TemplateBinding/issues/150
- final int numChildren;
+ bool get isTemplate => false;
- _InstanceBindingMap._(this.bindings, this.children, this.templateRef,
- this.numChildren);
+ _InstanceBindingMap(this.bindings);
+
+ _InstanceBindingMap getChild(int index) {
+ if (children == null || index >= children.length) return null;
+ return children[index];
+ }
+}
+
+class _TemplateBindingMap extends _InstanceBindingMap {
+ bool get isTemplate => true;
+
+ MustacheTokens _if, _bind, _repeat;
+
+ _TemplateBindingMap(List bindings) : super(bindings);
}
_InstanceBindingMap _createInstanceBindingMap(Node node,
BindingDelegate delegate) {
- var bindings = _getBindings(node, delegate);
- Node templateRef = null;
+ _InstanceBindingMap map = _getBindings(node, delegate);
+ if (map == null) map = new _InstanceBindingMap([]);
- if (isSemanticTemplate(node)) templateRef = node;
-
- Map children = null;
- int i = 0;
- for (var c = node.firstChild; c != null; c = c.nextNode, i++) {
+ List children = null;
+ int index = 0;
+ for (var c = node.firstChild; c != null; c = c.nextNode, index++) {
var childMap = _createInstanceBindingMap(c, delegate);
if (childMap == null) continue;
- if (children == null) children = new HashMap();
- children[i] = childMap;
+ // TODO(jmesserly): use a sparse map instead?
+ if (children == null) children = new List(node.nodes.length);
+ children[index] = childMap;
}
+ map.children = children;
- if (bindings == null && children == null && templateRef == null) return null;
-
- return new _InstanceBindingMap._(bindings, children, templateRef, i);
+ return map;
}
-void _addMapBindings(Node node, _InstanceBindingMap map, model,
- BindingDelegate delegate, List bound) {
- if (map == null) return;
+Node _cloneAndBindInstance(Node node, Node parent, Document stagingDocument,
+ _InstanceBindingMap bindings, model, BindingDelegate delegate,
+ List instanceBindings, [TemplateInstance instanceRecord]) {
- if (map.templateRef != null) {
- TemplateBindExtension.decorate(node, map.templateRef);
+ var clone = parent.append(stagingDocument.importNode(node, false));
+
+ int i = 0;
+ for (var c = node.firstChild; c != null; c = c.nextNode, i++) {
+ var childMap = bindings != null ? bindings.getChild(i) : null;
+ _cloneAndBindInstance(c, clone, stagingDocument, childMap, model, delegate,
+ instanceBindings);
+ }
+
+ if (bindings.isTemplate) {
+ TemplateBindExtension.decorate(clone, node);
if (delegate != null) {
- templateBindFallback(node)._bindingDelegate = delegate;
+ templateBindFallback(clone).bindingDelegate = delegate;
}
}
- if (map.bindings != null) {
- _processBindings(map.bindings, node, model, bound);
- }
-
- if (map.children == null) return;
-
- // To workaround https://github.com/Polymer/TemplateBinding/issues/150,
- // we try and detect cases where creating a custom element resulted in extra
- // children compared to what we expected. We assume these new children are all
- // at the beginning, because _deepCloneIgnoreTemplateContent creates the
- // element then appends the template content's children to the end.
-
- int i = map.numChildren - node.nodes.length;
- for (var c = node.firstChild; c != null; c = c.nextNode, i++) {
- if (i < 0) continue;
- _addMapBindings(c, map.children[i], model, delegate, bound);
- }
+ _processBindings(clone, bindings, model, instanceBindings);
+ return clone;
}
diff --git a/pkg/template_binding/lib/src/mustache_tokens.dart b/pkg/template_binding/lib/src/mustache_tokens.dart
new file mode 100644
index 0000000..be84d26
--- /dev/null
+++ b/pkg/template_binding/lib/src/mustache_tokens.dart
@@ -0,0 +1,146 @@
+// Copyright (c) 2013, 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 template_binding.src.mustache_tokens;
+
+import 'package:observe/observe.dart';
+import 'package:template_binding/template_binding.dart';
+
+/**
+ * Represents a set of parsed tokens from a {{ mustache binding expression }}.
+ * This can be created by calling [parse].
+ *
+ * For performance reasons the data is stored in one linear array in [_tokens].
+ * This class wraps that array and provides accessors in an attempt to make the
+ * pattern easier to understand. See [length] and [getText] for example.
+ */
+class MustacheTokens {
+ // Constants for indexing into the exploded structs in [_tokens] .
+ static const _TOKEN_TEXT = 0;
+ static const _TOKEN_ONETIME = 1;
+ static const _TOKEN_PATH = 2;
+ static const _TOKEN_PREPAREFN = 3;
+ static const _TOKEN_SIZE = 4;
+
+ // There is 1 extra entry for the end text.
+ static const _TOKEN_ENDTEXT = 1;
+
+ bool get hasOnePath => _tokens.length == _TOKEN_SIZE + _TOKEN_ENDTEXT;
+ bool get isSimplePath => hasOnePath &&
+ _tokens[_TOKEN_TEXT] == '' && _tokens[_TOKEN_SIZE + _TOKEN_TEXT] == '';
+
+ /**
+ * [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one
+ * mustache.
+ */
+ final List _tokens;
+
+ final bool onlyOneTime;
+
+ // Dart note: I think this is cached in JavaScript to avoid an extra
+ // allocation per template instance. Seems reasonable, so we do the same.
+ Function _combinator;
+ Function get combinator => _combinator;
+
+ MustacheTokens._(this._tokens, this.onlyOneTime) {
+ // Should be: [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+].
+ assert((_tokens.length - _TOKEN_ENDTEXT) % _TOKEN_SIZE == 0);
+
+ _combinator = hasOnePath ? _singleCombinator : _listCombinator;
+ }
+
+ int get length => _tokens.length ~/ _TOKEN_SIZE;
+
+ /**
+ * Gets the [i]th text entry. Note that [length] can be passed to get the
+ * final text entry.
+ */
+ String getText(int i) => _tokens[i * _TOKEN_SIZE + _TOKEN_TEXT];
+
+ /** Gets the oneTime flag for the [i]th token. */
+ bool getOneTime(int i) => _tokens[i * _TOKEN_SIZE + _TOKEN_ONETIME];
+
+ /** Gets the path for the [i]th token. */
+ PropertyPath getPath(int i) => _tokens[i * _TOKEN_SIZE + _TOKEN_PATH];
+
+ /** Gets the prepareBinding function for the [i]th token. */
+ Function getPrepareBinding(int i) =>
+ _tokens[i * _TOKEN_SIZE + _TOKEN_PREPAREFN];
+
+
+ /**
+ * Parses {{ mustache }} bindings.
+ *
+ * Returns null if there are no matches. Otherwise returns the parsed tokens.
+ */
+ static MustacheTokens parse(String s, String name, node,
+ BindingDelegate delegate) {
+ if (s == null || s.isEmpty) return null;
+
+ var tokens = null;
+ var length = s.length;
+ var lastIndex = 0;
+ var onlyOneTime = true;
+ while (lastIndex < length) {
+ var startIndex = s.indexOf('{{', lastIndex);
+ var oneTimeStart = s.indexOf('[[', lastIndex);
+ var oneTime = false;
+ var terminator = '}}';
+
+ if (oneTimeStart >= 0 &&
+ (startIndex < 0 || oneTimeStart < startIndex)) {
+ startIndex = oneTimeStart;
+ oneTime = true;
+ terminator = ']]';
+ }
+
+ var endIndex = -1;
+ if (startIndex >= 0) {
+ endIndex = s.indexOf(terminator, startIndex + 2);
+ }
+
+ if (endIndex < 0) {
+ if (tokens == null) return null;
+
+ tokens.add(s.substring(lastIndex)); // TEXT
+ break;
+ }
+
+ if (tokens == null) tokens = [];
+ tokens.add(s.substring(lastIndex, startIndex)); // TEXT
+ var pathString = s.substring(startIndex + 2, endIndex).trim();
+ tokens.add(oneTime); // ONETIME?
+ onlyOneTime = onlyOneTime && oneTime;
+ tokens.add(new PropertyPath(pathString)); // PATH
+ var delegateFn = delegate == null ? null :
+ delegate.prepareBinding(pathString, name, node);
+ tokens.add(delegateFn);
+
+ lastIndex = endIndex + 2;
+ }
+
+ if (lastIndex == length) tokens.add('');
+
+ return new MustacheTokens._(tokens, onlyOneTime);
+ }
+
+
+ // Dart note: split "combinator" into the single/list variants, so the
+ // argument can be typed.
+ String _singleCombinator(Object value) {
+ if (value == null) value = '';
+ return '${getText(0)}$value${getText(length)}';
+ }
+
+ String _listCombinator(List<Object> values) {
+ var newValue = new StringBuffer(getText(0));
+ int len = this.length;
+ for (var i = 0; i < len; i++) {
+ var value = values[i];
+ if (value != null) newValue.write(value);
+ newValue.write(getText(i + 1));
+ }
+ return newValue.toString();
+ }
+}
diff --git a/pkg/template_binding/lib/src/node.dart b/pkg/template_binding/lib/src/node.dart
index a5fb835..595cbeb 100644
--- a/pkg/template_binding/lib/src/node.dart
+++ b/pkg/template_binding/lib/src/node.dart
@@ -7,18 +7,21 @@
/** Extensions to the [Node] API. */
class NodeBindExtension {
final Node _node;
- Map<String, NodeBinding> _bindings;
+ Map<String, Bindable> _bindings;
NodeBindExtension._(this._node);
/**
* Binds the attribute [name] to the [path] of the [model].
* Path is a String of accessors such as `foo.bar.baz`.
- * Returns the `NodeBinding` instance.
+ * Returns the `Bindable` instance.
*/
- NodeBinding bind(String name, model, [String path]) {
+ Bindable bind(String name, value, {bool oneTime: false}) {
+ // TODO(jmesserly): in Dart we could deliver an async error, which would
+ // have a similar affect but be reported as a test failure. Should we?
window.console.error('Unhandled binding to Node: '
- '$this $name $model $path');
+ '$this $name $value $oneTime');
+ return null;
}
/** Unbinds the attribute [name]. */
@@ -39,8 +42,8 @@
// TODO(jmesserly): we should return a read-only wrapper here.
/** Gets the data bindings that are associated with this node. */
- Map<String, NodeBinding> get bindings {
- if (_bindings == null) _bindings = new LinkedHashMap<String, NodeBinding>();
+ Map<String, Bindable> get bindings {
+ if (_bindings == null) _bindings = new LinkedHashMap<String, Bindable>();
return _bindings;
}
@@ -57,6 +60,9 @@
TemplateInstance get templateInstance =>
_templateInstance != null ? _templateInstance :
(_node.parent != null ? nodeBind(_node.parent).templateInstance : null);
+
+ _open(Bindable bindable, callback(value)) =>
+ callback(bindable.open(callback));
}
@@ -66,17 +72,19 @@
// in cases where script has modified the template instance boundary.
/** The first node of this template instantiation. */
- final Node firstNode;
+ Node get firstNode => _firstNode;
/**
* The last node of this template instantiation.
* This could be identical to [firstNode] if the template only expanded to a
* single node.
*/
- final Node lastNode;
+ Node get lastNode => _lastNode;
/** The model used to instantiate the template. */
final model;
- TemplateInstance(this.firstNode, this.lastNode, this.model);
+ Node _firstNode, _lastNode;
+
+ TemplateInstance(this.model);
}
diff --git a/pkg/template_binding/lib/src/node_binding.dart b/pkg/template_binding/lib/src/node_binding.dart
deleted file mode 100644
index 95c5e00..0000000
--- a/pkg/template_binding/lib/src/node_binding.dart
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2013, 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 template_binding.src.node_binding;
-
-import 'dart:async' show StreamSubscription;
-import 'dart:html' show Node;
-import 'package:observe/observe.dart' show PathObserver, CompoundPathObserver;
-
-/** Test only method. Not re-exported. */
-getObserverForTest(NodeBinding binding) => binding._observer;
-
-/**
- * A data binding on a [Node].
- * See [NodeBindExtension.bindings] and [NodeBindExtension.bind].
- */
-abstract class NodeBinding {
- Node _node;
- var _model;
-
- // TODO(jmesserly): need common interface for PathObserver,
- // CompoundPathObserver.
- var _observer;
- StreamSubscription _pathSub;
-
- /** The property of [node] which will be data bound. */
- final String property;
-
- /** The property of [node] which will be data bound. */
- final String path;
-
- /** The node that has [property] which will be data bound. */
- Node get node => _node;
-
- /** The bound data model. */
- get model => _model;
-
- /** True if this binding has been [closed]. */
- bool get closed => _node == null;
-
- /** The value at the [path] on [model]. */
- get value => _observer.value;
-
- set value(newValue) {
- _observer.value = newValue;
- }
-
- NodeBinding(this._node, this.property, this._model, [String path])
- : path = path != null ? path : '' {
-
- // Fast path if we're observing "value"
- if ((model is PathObserver || model is CompoundPathObserver) &&
- path == 'value') {
-
- _observer = model;
- } else {
- // Create the path observer
- _observer = new PathObserver(model, this.path);
- }
-
- _pathSub = _observer.changes.listen((r) => valueChanged(value));
- valueChanged(value);
- }
-
- /** Called when [value] changes to update the [node]. */
- // TODO(jmesserly): the impl in template_binding uses reflection to set the
- // property, but that isn't used except for specific known fields like
- // "textContent", so I'm overridding this in the subclasses instead.
- void valueChanged(newValue);
-
- /** Called to sanitize the value before it is assigned into the property. */
- sanitizeBoundValue(value) => value == null ? '' : '$value';
-
- /**
- * Called by [NodeBindExtension.unbind] to close this binding and unobserve
- * the [path].
- *
- * This can be overridden in subclasses, but they must call `super.close()`
- * to free associated resources. They must also check [closed] and return
- * immediately if already closed.
- */
- void close() {
- if (closed) return;
-
- if (_pathSub != null) _pathSub.cancel();
- _pathSub = null;
- _observer = null;
- _node = null;
- _model = null;
- }
-}
diff --git a/pkg/template_binding/lib/src/select_element.dart b/pkg/template_binding/lib/src/select_element.dart
index 432b049..f205a15 100644
--- a/pkg/template_binding/lib/src/select_element.dart
+++ b/pkg/template_binding/lib/src/select_element.dart
@@ -10,14 +10,21 @@
SelectElement get _node => super._node;
- NodeBinding bind(String name, model, [String path]) {
+ Bindable bind(String name, value, {bool oneTime: false}) {
if (name == 'selectedindex') name = 'selectedIndex';
if (name != 'selectedIndex' && name != 'value') {
- return super.bind(name, model, path);
+ return super.bind(name, value, oneTime: oneTime);
+ }
+
+ // TODO(jmesserly): merge logic here with InputElement, it's the same except
+ // for the addition of selectedIndex as a valid property name.
+ _node.attributes.remove(name);
+ if (oneTime) {
+ _InputBinding._updateProperty(_node, value, name);
+ return null;
}
_self.unbind(name);
- _node.attributes.remove(name);
- return bindings[name] = new _SelectBinding(_node, name, model, path);
+ return bindings[name] = new _InputBinding(_node, value, name);
}
}
diff --git a/pkg/template_binding/lib/src/template.dart b/pkg/template_binding/lib/src/template.dart
index 8df84d1..d085a89 100644
--- a/pkg/template_binding/lib/src/template.dart
+++ b/pkg/template_binding/lib/src/template.dart
@@ -9,7 +9,7 @@
var _model;
BindingDelegate _bindingDelegate;
_TemplateIterator _iterator;
- bool _scheduled = false;
+ bool _setModelScheduled = false;
Element _templateInstanceRef;
@@ -19,7 +19,7 @@
HtmlDocument _stagingDocument;
- var _bindingMap;
+ _InstanceBindingMap _bindingMap;
TemplateBindExtension._(Element node) : super(node);
@@ -28,106 +28,70 @@
TemplateBindExtension get _self => super._node is TemplateBindExtension
? _node : this;
- NodeBinding bind(String name, model, [String path]) {
- path = path != null ? path : '';
+ _TemplateIterator _processBindingDirectives(_TemplateBindingMap directives) {
+ if (_iterator != null) _iterator._closeDependencies();
+
+ if (directives._if == null &&
+ directives._bind == null &&
+ directives._repeat == null) {
+
+ if (_iterator != null) {
+ _iterator.close();
+ _iterator = null;
+ bindings.remove('iterator');
+ }
+ return null;
+ }
if (_iterator == null) {
- // TODO(jmesserly): since there's only one iterator, we could just
- // inline it into this object.
- _iterator = new _TemplateIterator(this);
+ bindings['iterator'] = _iterator = new _TemplateIterator(this);
}
- // Dart note: we return _TemplateBinding instead of _iterator.
- // See comment on _TemplateBinding class.
- switch (name) {
- case 'bind':
- _iterator..hasBind = true
- ..bindModel = model
- ..bindPath = path;
- _scheduleIterator();
- return bindings[name] = new _TemplateBinding(this, name, model, path);
- case 'repeat':
- _iterator..hasRepeat = true
- ..repeatModel = model
- ..repeatPath = path;
- _scheduleIterator();
- return bindings[name] = new _TemplateBinding(this, name, model, path);
- case 'if':
- _iterator..hasIf = true
- ..ifModel = model
- ..ifPath = path;
- _scheduleIterator();
- return bindings[name] = new _TemplateBinding(this, name, model, path);
- default:
- return super.bind(name, model, path);
- }
- }
-
- void unbind(String name) {
- switch (name) {
- case 'bind':
- if (_iterator == null) return;
- _iterator..hasBind = false
- ..bindModel = null
- ..bindPath = null;
- _scheduleIterator();
- bindings.remove(name);
- return;
- case 'repeat':
- if (_iterator == null) return;
- _iterator..hasRepeat = false
- ..repeatModel = null
- ..repeatPath = null;
- _scheduleIterator();
- bindings.remove(name);
- return;
- case 'if':
- if (_iterator == null) return;
- _iterator..hasIf = false
- ..ifModel = null
- ..ifPath = null;
- _scheduleIterator();
- bindings.remove(name);
- return;
- default:
- super.unbind(name);
- return;
- }
- }
-
- void _scheduleIterator() {
- if (!_iterator.depsChanging) {
- _iterator.depsChanging = true;
- scheduleMicrotask(_iterator.resolve);
- }
+ _iterator._updateDependencies(directives, model);
+ return _iterator;
}
/**
- * Creates an instance of the template, using the provided model and optional
- * binding delegate.
+ * Creates an instance of the template, using the provided [model] and
+ * optional binding [delegate].
+ *
+ * If [instanceBindings] is supplied, each [Bindable] in the returned
+ * instance will be added to the list. This makes it easy to close all of the
+ * bindings without walking the tree. This is not normally necesssary, but is
+ * used internally by the system.
*/
DocumentFragment createInstance([model, BindingDelegate delegate,
- List<NodeBinding> bound]) {
- var ref = templateBind(this.ref);
- var content = ref.content;
+ List<Bindable> instanceBindings]) {
+
+ final content = templateBind(ref).content;
// Dart note: we store _bindingMap on the TemplateBindExtension instead of
// the "content" because we already have an expando for it.
- var map = ref._bindingMap;
- if (map == null) {
+ var map = _bindingMap;
+ if (map == null || !identical(map.content, content)) {
// TODO(rafaelw): Setup a MutationObserver on content to detect
// when the instanceMap is invalid.
map = _createInstanceBindingMap(content, delegate);
- ref._bindingMap = map;
+ map.content = content;
+ _bindingMap = map;
}
- var staging = _getTemplateStagingDocument();
- var instance = _deepCloneIgnoreTemplateContent(content, staging);
+ final staging = _getTemplateStagingDocument();
+ final instance = _stagingDocument.createDocumentFragment();
+ _templateCreator[instance] = _node;
- _addMapBindings(instance, map, model, delegate, bound);
- // TODO(rafaelw): We can do this more lazily, but setting a sentinel
- // in the parent of the template element, and creating it when it's
- // asked for by walking back to find the iterating template.
- _addTemplateInstanceRecord(instance, model);
+ final instanceRecord = new TemplateInstance(model);
+
+ var i = 0;
+ for (var c = content.firstChild; c != null; c = c.nextNode, i++) {
+ final childMap = map != null ? map.getChild(i) : null;
+ var clone = _cloneAndBindInstance(c, instance, _stagingDocument,
+ childMap, model, delegate, instanceBindings);
+ nodeBindFallback(clone)._templateInstance = instanceRecord;
+ }
+
+ instanceRecord._firstNode = instance.firstChild;
+ instanceRecord._lastNode = instance.lastChild;
+
return instance;
}
@@ -157,19 +121,27 @@
void set bindingDelegate(BindingDelegate value) {
_bindingDelegate = value;
- _ensureSetModelScheduled();
+
+ // Clear cached state based on the binding delegate.
+ _bindingMap = null;
+ if (_iterator != null) {
+ _iterator._initPrepareFunctions = false;
+ _iterator._instanceModelFn = null;
+ _iterator._instancePositionChangedFn = null;
+ }
}
_ensureSetModelScheduled() {
- if (_scheduled) return;
+ if (_setModelScheduled) return;
_decorate();
- _scheduled = true;
+ _setModelScheduled = true;
scheduleMicrotask(_setModel);
}
void _setModel() {
- _scheduled = false;
- _addBindings(_node, _model, _bindingDelegate);
+ _setModelScheduled = false;
+ var map = _getBindings(_node, _bindingDelegate);
+ _processBindings(_node, map, _model);
}
/** Gets the template this node refers to. */
@@ -183,6 +155,15 @@
if (treeScope != null) {
result = treeScope.getElementById(refId);
}
+ if (result == null) {
+ var instanceRoot = _getInstanceRoot(_node);
+
+ // TODO(jmesserly): this won't work if refId is a number
+ // Similar to bug: https://github.com/Polymer/ShadowDOM/issues/340
+ if (instanceRoot != null) {
+ result = instanceRoot.querySelector('#$refId');
+ }
+ }
}
if (result == null) {
@@ -223,25 +204,32 @@
var templateElementExt = this;
_templateIsDecorated = true;
- var isNative = _node is TemplateElement;
- var bootstrapContents = isNative;
- var liftContents = !isNative;
+ var isNativeHtmlTemplate = _node is TemplateElement;
+ final bootstrapContents = isNativeHtmlTemplate;
+ final liftContents = !isNativeHtmlTemplate;
var liftRoot = false;
- if (!isNative && _isAttributeTemplate(_node)) {
- if (instanceRef != null) {
- // TODO(jmesserly): this is just an assert in TemplateBinding.
- throw new ArgumentError('instanceRef should not be supplied for '
- 'attribute templates.');
+ if (!isNativeHtmlTemplate) {
+ if (_isAttributeTemplate(_node)) {
+ if (instanceRef != null) {
+ // Dart note: this is just an assert in JS.
+ throw new ArgumentError('instanceRef should not be supplied for '
+ 'attribute templates.');
+ }
+ templateElementExt = templateBind(
+ _extractTemplateFromAttributeTemplate(_node));
+ templateElementExt._templateIsDecorated = true;
+ isNativeHtmlTemplate = templateElementExt._node is TemplateElement;
+ liftRoot = true;
+ } else if (_isSvgTemplate(_node)) {
+ templateElementExt = templateBind(
+ _extractTemplateFromSvgTemplate(_node));
+ templateElementExt._templateIsDecorated = true;
+ isNativeHtmlTemplate = templateElementExt._node is TemplateElement;
}
- templateElementExt = templateBind(
- _extractTemplateFromAttributeTemplate(_node));
- templateElementExt._templateIsDecorated = true;
- isNative = templateElementExt._node is TemplateElement;
- liftRoot = true;
- }
+ }
- if (!isNative) {
+ if (!isNativeHtmlTemplate) {
var doc = _getOrCreateTemplateContentsOwner(templateElementExt._node);
templateElementExt._content = doc.createDocumentFragment();
}
@@ -326,6 +314,16 @@
return template;
}
+ static Element _extractTemplateFromSvgTemplate(Element el) {
+ var template = el.ownerDocument.createElement('template');
+ el.parentNode.insertBefore(template, el);
+ template.attributes.addAll(el.attributes);
+
+ el.attributes.clear();
+ el.remove();
+ return template;
+ }
+
static void _liftNonNativeChildrenIntoContent(TemplateBindExtension template,
Element el, bool useRoot) {
@@ -386,58 +384,19 @@
}
}
-// TODO(jmesserly): https://github.com/polymer/templatebinding uses
-// TemplateIterator as the binding. This is a nice performance optimization,
-// however it means it doesn't share any of the reflective APIs with
-// NodeBinding: https://github.com/Polymer/TemplateBinding/issues/147
-class _TemplateBinding implements NodeBinding {
- TemplateBindExtension _ext;
- Object _model;
- final String property;
- final String path;
-
- Node get node => _ext._node;
-
- get model => _model;
-
- bool get closed => _ext == null;
-
- get value => _observer.value;
-
- set value(newValue) {
- _observer.value = newValue;
- }
-
- // No need to cache this since we only have it to support get/set value.
- get _observer {
- if ((_model is PathObserver || _model is CompoundPathObserver) &&
- path == 'value') {
- return _model;
- }
- return new PathObserver(_model, path);
- }
-
- _TemplateBinding(this._ext, this.property, this._model, this.path);
-
- void valueChanged(newValue) {}
-
- sanitizeBoundValue(value) => value == null ? '' : '$value';
-
- void close() {
- if (closed) return;
-
- // TODO(jmesserly): unlike normal NodeBinding.close methods this will remove
- // the binding from _node.bindings. Is that okay?
- _ext.unbind(property);
-
- _model = null;
- _ext = null;
- }
-}
+final _templateCreator = new Expando();
_getTreeScope(Node node) {
- while (node.parentNode != null) {
- node = node.parentNode;
+ while (true) {
+ var parent = node.parentNode;
+ if (parent != null) {
+ node = parent;
+ } else {
+ var creator = _templateCreator[node];
+ if (creator == null) break;
+
+ node = creator;
+ }
}
// Note: JS code tests that getElementById is present. We can't do that
@@ -447,3 +406,10 @@
}
return null;
}
+
+_getInstanceRoot(node) {
+ while (node.parentNode != null) {
+ node = node.parentNode;
+ }
+ return _templateCreator[node] != null ? node : null;
+}
diff --git a/pkg/template_binding/lib/src/template_iterator.dart b/pkg/template_binding/lib/src/template_iterator.dart
index c87306a..66d44f5 100644
--- a/pkg/template_binding/lib/src/template_iterator.dart
+++ b/pkg/template_binding/lib/src/template_iterator.dart
@@ -17,23 +17,23 @@
// See: https://github.com/polymer/TemplateBinding/issues/59
bool _toBoolean(value) => null != value && false != value;
-List _getBindings(Node node, BindingDelegate delegate) {
+_InstanceBindingMap _getBindings(Node node, BindingDelegate delegate) {
if (node is Element) {
return _parseAttributeBindings(node, delegate);
}
if (node is Text) {
- var tokens = _parseMustaches(node.text, 'text', node, delegate);
- if (tokens != null) return ['text', tokens];
+ var tokens = MustacheTokens.parse(node.text, 'text', node, delegate);
+ if (tokens != null) return new _InstanceBindingMap(['text', tokens]);
}
return null;
}
void _addBindings(Node node, model, [BindingDelegate delegate]) {
- var bindings = _getBindings(node, delegate);
+ final bindings = _getBindings(node, delegate);
if (bindings != null) {
- _processBindings(bindings, node, model);
+ _processBindings(node, bindings, model);
}
for (var c = node.firstChild; c != null; c = c.nextNode) {
@@ -41,8 +41,17 @@
}
}
+MustacheTokens _parseWithDefault(Element element, String name,
+ BindingDelegate delegate) {
-List _parseAttributeBindings(Element element, BindingDelegate delegate) {
+ var v = element.attributes[name];
+ if (v == '') v = '{{}}';
+ return MustacheTokens.parse(v, name, element, delegate);
+}
+
+_InstanceBindingMap _parseAttributeBindings(Element element,
+ BindingDelegate delegate) {
+
var bindings = null;
var ifFound = false;
var bindFound = false;
@@ -58,193 +67,157 @@
name = name.substring(1);
}
- if (isTemplateNode) {
- if (name == 'if') {
- ifFound = true;
- if (value == '') value = '{{}}'; // Accept 'naked' if.
- } else if (name == 'bind' || name == 'repeat') {
- bindFound = true;
- if (value == '') value = '{{}}'; // Accept 'naked' bind & repeat.
- }
+ if (isTemplateNode &&
+ (name == 'bind' || name == 'if' || name == 'repeat')) {
+ return;
}
- var tokens = _parseMustaches(value, name, element, delegate);
+ var tokens = MustacheTokens.parse(value, name, element, delegate);
if (tokens != null) {
if (bindings == null) bindings = [];
bindings..add(name)..add(tokens);
}
});
- // Treat <template if> as <template bind if>
- if (ifFound && !bindFound) {
+ if (isTemplateNode) {
if (bindings == null) bindings = [];
- bindings..add('bind')
- ..add(_parseMustaches('{{}}', 'bind', element, delegate));
+ var result = new _TemplateBindingMap(bindings)
+ .._if = _parseWithDefault(element, 'if', delegate)
+ .._bind = _parseWithDefault(element, 'bind', delegate)
+ .._repeat = _parseWithDefault(element, 'repeat', delegate);
+
+ // Treat <template if> as <template bind if>
+ if (result._if != null && result._bind == null && result._repeat == null) {
+ result._bind = MustacheTokens.parse('{{}}', 'bind', element, delegate);
+ }
+
+ return result;
}
- return bindings;
+ return bindings == null ? null : new _InstanceBindingMap(bindings);
}
-void _processBindings(List bindings, Node node, model,
- [List<NodeBinding> bound]) {
+_processOneTimeBinding(String name, MustacheTokens tokens, Node node, model) {
+ if (tokens.hasOnePath) {
+ var delegateFn = tokens.getPrepareBinding(0);
+ var value = delegateFn != null ? delegateFn(model, node, true) :
+ tokens.getPath(0).getValueFrom(model);
+ return tokens.isSimplePath ? value : tokens.combinator(value);
+ }
+
+ // Tokens uses a striding scheme to essentially store a sequence of structs in
+ // the list. See _MustacheTokens for more information.
+ var values = new List(tokens.length);
+ for (int i = 0; i < tokens.length; i++) {
+ Function delegateFn = tokens.getPrepareBinding(i);
+ values[i] = delegateFn != null ?
+ delegateFn(model, node, false) :
+ tokens.getPath(i).getValueFrom(model);
+ }
+ return tokens.combinator(values);
+}
+
+_processSinglePathBinding(String name, MustacheTokens tokens, Node node,
+ model) {
+ Function delegateFn = tokens.getPrepareBinding(0);
+ var observer = delegateFn != null ?
+ delegateFn(model, node, false) :
+ new PathObserver(model, tokens.getPath(0));
+
+ return tokens.isSimplePath ? observer :
+ new ObserverTransform(observer, tokens.combinator);
+}
+
+_processBinding(String name, MustacheTokens tokens, Node node, model) {
+ if (tokens.onlyOneTime) {
+ return _processOneTimeBinding(name, tokens, node, model);
+ }
+ if (tokens.hasOnePath) {
+ return _processSinglePathBinding(name, tokens, node, model);
+ }
+
+ var observer = new CompoundObserver();
+
+ for (int i = 0; i < tokens.length; i++) {
+ bool oneTime = tokens.getOneTime(i);
+ Function delegateFn = tokens.getPrepareBinding(i);
+
+ if (delegateFn != null) {
+ var value = delegateFn(model, node, oneTime);
+ if (oneTime) {
+ observer.addPath(value);
+ } else {
+ observer.addObserver(value);
+ }
+ continue;
+ }
+
+ PropertyPath path = tokens.getPath(i);
+ if (oneTime) {
+ observer.addPath(path.getValueFrom(model));
+ } else {
+ observer.addPath(model, path);
+ }
+ }
+
+ return new ObserverTransform(observer, tokens.combinator);
+}
+
+void _processBindings(Node node, _InstanceBindingMap map, model,
+ [List<Bindable> instanceBindings]) {
+
+ final bindings = map.bindings;
for (var i = 0; i < bindings.length; i += 2) {
var name = bindings[i];
var tokens = bindings[i + 1];
- var bindingModel = model;
- var bindingPath = tokens.tokens[1];
- if (tokens.hasOnePath) {
- var delegateFn = tokens.tokens[2];
- if (delegateFn != null) {
- var delegateBinding = delegateFn(model, node);
- if (delegateBinding != null) {
- bindingModel = delegateBinding;
- bindingPath = 'value';
- }
- }
- if (!tokens.isSimplePath) {
- bindingModel = new PathObserver(bindingModel, bindingPath,
- computeValue: tokens.combinator);
- bindingPath = 'value';
- }
- } else {
- var observer = new CompoundPathObserver(computeValue: tokens.combinator);
- for (var j = 1; j < tokens.tokens.length; j += 3) {
- var subModel = model;
- var subPath = tokens.tokens[j];
- var delegateFn = tokens.tokens[j + 1];
- var delegateBinding = delegateFn != null ?
- delegateFn(subModel, node) : null;
-
- if (delegateBinding != null) {
- subModel = delegateBinding;
- subPath = 'value';
- }
-
- observer.addPath(subModel, subPath);
- }
-
- observer.start();
- bindingModel = observer;
- bindingPath = 'value';
+ var value = _processBinding(name, tokens, node, model);
+ var binding = nodeBind(node).bind(name, value, oneTime: tokens.onlyOneTime);
+ if (binding != null && instanceBindings != null) {
+ instanceBindings.add(binding);
}
+ }
- var binding = nodeBind(node).bind(name, bindingModel, bindingPath);
- if (bound != null) bound.add(binding);
+ if (map is! _TemplateBindingMap) return;
+
+ final templateExt = nodeBindFallback(node);
+ templateExt._model = model;
+
+ var iter = templateExt._processBindingDirectives(map);
+ if (iter != null && instanceBindings != null) {
+ instanceBindings.add(iter);
}
}
-/**
- * Parses {{ mustache }} bindings.
- *
- * Returns null if there are no matches. Otherwise returns the parsed tokens.
- */
-_MustacheTokens _parseMustaches(String s, String name, Node node,
- BindingDelegate delegate) {
- if (s.isEmpty) return null;
- var tokens = null;
- var length = s.length;
- var startIndex = 0, lastIndex = 0, endIndex = 0;
- while (lastIndex < length) {
- startIndex = s.indexOf('{{', lastIndex);
- endIndex = startIndex < 0 ? -1 : s.indexOf('}}', startIndex + 2);
-
- if (endIndex < 0) {
- if (tokens == null) return null;
-
- tokens.add(s.substring(lastIndex)); // TEXT
- break;
- }
-
- if (tokens == null) tokens = [];
- tokens.add(s.substring(lastIndex, startIndex)); // TEXT
- var pathString = s.substring(startIndex + 2, endIndex).trim();
- tokens.add(pathString); // PATH
- var delegateFn = delegate == null ? null :
- delegate.prepareBinding(pathString, name, node);
- tokens.add(delegateFn);
-
- lastIndex = endIndex + 2;
- }
-
- if (lastIndex == length) tokens.add('');
-
- return new _MustacheTokens(tokens);
-}
-
-class _MustacheTokens {
- bool get hasOnePath => tokens.length == 4;
- bool get isSimplePath => hasOnePath && tokens[0] == '' && tokens[3] == '';
-
- /** [TEXT, (PATH, TEXT, DELEGATE_FN)+] if there is at least one mustache. */
- // TODO(jmesserly): clean up the type here?
- final List tokens;
-
- // Dart note: I think this is cached in JavaScript to avoid an extra
- // allocation per template instance. Seems reasonable, so we do the same.
- Function _combinator;
- Function get combinator => _combinator;
-
- _MustacheTokens(this.tokens) {
- // Should be: [TEXT, (PATH, TEXT, DELEGATE_FN)+].
- assert((tokens.length + 2) % 3 == 0);
-
- _combinator = hasOnePath ? _singleCombinator : _listCombinator;
- }
-
- // Dart note: split "combinator" into the single/list variants, so the
- // argument can be typed.
- String _singleCombinator(Object value) {
- if (value == null) value = '';
- return '${tokens[0]}$value${tokens[3]}';
- }
-
- String _listCombinator(List<Object> values) {
- var newValue = new StringBuffer(tokens[0]);
- for (var i = 1; i < tokens.length; i += 3) {
- var value = values[(i - 1) ~/ 3];
- if (value != null) newValue.write(value);
- newValue.write(tokens[i + 2]);
- }
-
- return newValue.toString();
- }
-}
-
-void _addTemplateInstanceRecord(fragment, model) {
- if (fragment.firstChild == null) {
- return;
- }
-
- var instanceRecord = new TemplateInstance(
- fragment.firstChild, fragment.lastChild, model);
-
- var node = instanceRecord.firstNode;
- while (node != null) {
- nodeBindFallback(node)._templateInstance = instanceRecord;
- node = node.nextNode;
- }
-}
-
-class _TemplateIterator {
+// Note: this doesn't really implement most of Bindable. See:
+// https://github.com/Polymer/TemplateBinding/issues/147
+class _TemplateIterator extends Bindable {
final TemplateBindExtension _templateExt;
/**
* Flattened array of tuples:
* <instanceTerminatorNode, [bindingsSetupByInstance]>
*/
- final List terminators = [];
- List iteratedValue;
- bool closed = false;
- bool depsChanging = false;
+ final List _terminators = [];
- bool hasRepeat = false, hasBind = false, hasIf = false;
- Object repeatModel, bindModel, ifModel;
- String repeatPath, bindPath, ifPath;
+ /** A copy of the last rendered [_presentValue] list state. */
+ final List _iteratedValue = [];
- StreamSubscription _valueSub, _listSub;
+ List _presentValue;
+
+ bool _closed = false;
+
+ // Dart note: instead of storing these in a Map like JS, or using a separate
+ // object (extra memory overhead) we just inline the fields.
+ var _ifValue, _value;
+
+ // TODO(jmesserly): lots of booleans in this object. Bitmask?
+ bool _hasIf, _hasRepeat;
+ bool _ifOneTime, _oneTime;
+
+ StreamSubscription _listSub;
bool _initPrepareFunctions = false;
PrepareInstanceModelFunction _instanceModelFn;
@@ -252,81 +225,106 @@
_TemplateIterator(this._templateExt);
+ open(callback) => throw new StateError('binding already opened');
+ get value => _value;
+
Element get _templateElement => _templateExt._node;
- resolve() {
- depsChanging = false;
-
- if (_valueSub != null) {
- _valueSub.cancel();
- _valueSub = null;
+ void _closeDependencies() {
+ if (_ifValue is Bindable) {
+ _ifValue.close();
+ _ifValue = null;
}
-
- if (!hasRepeat && !hasBind) {
- _valueChanged(null);
- return;
+ if (_value is Bindable) {
+ _value.close();
+ _value = null;
}
+ }
- final model = hasRepeat ? repeatModel : bindModel;
- final path = hasRepeat ? repeatPath : bindPath;
+ void _updateDependencies(_TemplateBindingMap directives, model) {
+ _closeDependencies();
- var valueObserver;
- if (!hasIf) {
- valueObserver = new PathObserver(model, path,
- computeValue: hasRepeat ? null : (x) => [x]);
- } else {
- // TODO(jmesserly): I'm not sure if closing over this is necessary for
- // correctness. It does seem useful if the valueObserver gets fired after
- // hasRepeat has changed, due to async nature of things.
- final isRepeat = hasRepeat;
+ final template = _templateElement;
- valueFn(List values) {
- var modelValue = values[0];
- var ifValue = values[1];
- if (!_toBoolean(ifValue)) return null;
- return isRepeat ? modelValue : [ modelValue ];
+ _hasIf = directives._if != null;
+ _hasRepeat = directives._repeat != null;
+
+ if (_hasIf) {
+ _ifOneTime = directives._if.onlyOneTime;
+ _ifValue = _processBinding('if', directives._if, template, model);
+
+ // oneTime if & predicate is false. nothing else to do.
+ if (_ifOneTime) {
+ if (!_toBoolean(_ifValue)) {
+ _updateIteratedValue(null);
+ return;
+ }
+ } else {
+ (_ifValue as Bindable).open(_updateIteratedValue);
}
-
- valueObserver = new CompoundPathObserver(computeValue: valueFn)
- ..addPath(model, path)
- ..addPath(ifModel, ifPath)
- ..start();
}
- _valueSub = valueObserver.changes.listen(
- (r) => _valueChanged(r.last.newValue));
- _valueChanged(valueObserver.value);
- }
-
- void _valueChanged(newValue) {
- var oldValue = iteratedValue;
- unobserve();
-
- if (newValue is List) {
- iteratedValue = newValue;
- } else if (newValue is Iterable) {
- // Dart note: we support Iterable by calling toList.
- // But we need to be careful to observe the original iterator if it
- // supports that.
- iteratedValue = (newValue as Iterable).toList();
+ if (_hasRepeat) {
+ _oneTime = directives._repeat.onlyOneTime;
+ _value = _processBinding('repeat', directives._repeat, template, model);
} else {
- iteratedValue = null;
+ _oneTime = directives._bind.onlyOneTime;
+ _value = _processBinding('bind', directives._bind, template, model);
}
- if (iteratedValue != null && newValue is ObservableList) {
- _listSub = newValue.listChanges.listen(_handleSplices);
- }
+ if (!_oneTime) _value.open(_updateIteratedValue);
- var splices = ObservableList.calculateChangeRecords(
- oldValue != null ? oldValue : [],
- iteratedValue != null ? iteratedValue : []);
-
- if (splices.isNotEmpty) _handleSplices(splices);
+ _updateIteratedValue(null);
}
- Node getTerminatorAt(int index) {
+ void _updateIteratedValue(_) {
+ if (_hasIf) {
+ var ifValue = _ifValue;
+ if (!_ifOneTime) ifValue = (ifValue as Bindable).value;
+ if (!_toBoolean(ifValue)) {
+ _valueChanged([]);
+ return;
+ }
+ }
+
+ var value = _value;
+ if (!_oneTime) value = (value as Bindable).value;
+ if (!_hasRepeat) value = [value];
+ _valueChanged(value);
+ }
+
+ void _valueChanged(Object value) {
+ if (value is! List) {
+ if (value is Iterable) {
+ // Dart note: we support Iterable by calling toList.
+ // But we need to be careful to observe the original iterator if it
+ // supports that.
+ value = (value as Iterable).toList();
+ } else {
+ value = [];
+ }
+ }
+
+ if (identical(value, _iteratedValue)) return;
+
+ _unobserve();
+ _presentValue = value;
+
+ if (value is ObservableList && _hasRepeat && !_oneTime) {
+ // Make sure any pending changes aren't delivered, since we're getting
+ // a snapshot at this point in time.
+ value.discardListChages();
+ _listSub = value.listChanges.listen(_handleSplices);
+ }
+
+ _handleSplices(ObservableList.calculateChangeRecords(
+ _iteratedValue != null ? _iteratedValue : [],
+ _presentValue != null ? _presentValue : []));
+ }
+
+ Node _getTerminatorAt(int index) {
if (index == -1) return _templateElement;
- var terminator = terminators[index * 2];
+ var terminator = _terminators[index * 2];
if (!isSemanticTemplate(terminator) ||
identical(terminator, _templateElement)) {
return terminator;
@@ -335,15 +333,15 @@
var subIter = templateBindFallback(terminator)._iterator;
if (subIter == null) return terminator;
- return subIter.getTerminatorAt(subIter.terminators.length ~/ 2 - 1);
+ return subIter._getTerminatorAt(subIter._terminators.length ~/ 2 - 1);
}
// TODO(rafaelw): If we inserting sequences of instances we can probably
- // avoid lots of calls to getTerminatorAt(), or cache its result.
- void insertInstanceAt(int index, DocumentFragment fragment,
- List<Node> instanceNodes, List<NodeBinding> bound) {
+ // avoid lots of calls to _getTerminatorAt(), or cache its result.
+ void _insertInstanceAt(int index, DocumentFragment fragment,
+ List<Node> instanceNodes, List<Bindable> instanceBindings) {
- var previousTerminator = getTerminatorAt(index - 1);
+ var previousTerminator = _getTerminatorAt(index - 1);
var terminator = null;
if (fragment != null) {
terminator = fragment.lastChild;
@@ -352,7 +350,7 @@
}
if (terminator == null) terminator = previousTerminator;
- terminators.insertAll(index * 2, [terminator, bound]);
+ _terminators.insertAll(index * 2, [terminator, instanceBindings]);
var parent = _templateElement.parentNode;
var insertBeforeNode = previousTerminator.nextNode;
@@ -365,12 +363,12 @@
}
}
- _BoundNodes extractInstanceAt(int index) {
+ _BoundNodes _extractInstanceAt(int index) {
var instanceNodes = <Node>[];
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = getTerminatorAt(index);
- var bound = terminators[index * 2 + 1];
- terminators.removeRange(index * 2, index * 2 + 2);
+ var previousTerminator = _getTerminatorAt(index - 1);
+ var terminator = _getTerminatorAt(index);
+ var instanceBindings = _terminators[index * 2 + 1];
+ _terminators.removeRange(index * 2, index * 2 + 2);
var parent = _templateElement.parentNode;
while (terminator != previousTerminator) {
@@ -379,24 +377,28 @@
node.remove();
instanceNodes.add(node);
}
- return new _BoundNodes(instanceNodes, bound);
+ return new _BoundNodes(instanceNodes, instanceBindings);
}
void _handleSplices(List<ListChangeRecord> splices) {
- if (closed) return;
+ if (_closed || splices.isEmpty) return;
final template = _templateElement;
- final delegate = _templateExt._self.bindingDelegate;
- if (template.parentNode == null || template.ownerDocument.window == null) {
+ if (template.parentNode == null) {
close();
return;
}
+ ObservableList.applyChangeRecords(_iteratedValue, _presentValue, splices);
+
+ final delegate = _templateExt.bindingDelegate;
+
// Dart note: the JavaScript code relies on the distinction between null
// and undefined to track whether the functions are prepared. We use a bool.
if (!_initPrepareFunctions) {
_initPrepareFunctions = true;
+ final delegate = _templateExt._self.bindingDelegate;
if (delegate != null) {
_instanceModelFn = delegate.prepareInstanceModel(template);
_instancePositionChangedFn =
@@ -408,7 +410,7 @@
var removeDelta = 0;
for (var splice in splices) {
for (var model in splice.removed) {
- instanceCache[model] = extractInstanceAt(splice.index + removeDelta);
+ instanceCache[model] = _extractInstanceAt(splice.index + removeDelta);
}
removeDelta -= splice.addedCount;
@@ -419,38 +421,39 @@
addIndex < splice.index + splice.addedCount;
addIndex++) {
- var model = iteratedValue[addIndex];
+ var model = _iteratedValue[addIndex];
var fragment = null;
var instance = instanceCache.remove(model);
- List bound;
+ List instanceBindings;
List instanceNodes = null;
if (instance != null && instance.nodes.isNotEmpty) {
- bound = instance.bound;
+ instanceBindings = instance.instanceBindings;
instanceNodes = instance.nodes;
} else {
- bound = [];
+ instanceBindings = [];
if (_instanceModelFn != null) {
model = _instanceModelFn(model);
}
if (model != null) {
- fragment = _templateExt.createInstance(model, delegate, bound);
+ fragment = _templateExt.createInstance(model, delegate,
+ instanceBindings);
}
}
- insertInstanceAt(addIndex, fragment, instanceNodes, bound);
+ _insertInstanceAt(addIndex, fragment, instanceNodes, instanceBindings);
}
}
for (var instance in instanceCache.values) {
- closeInstanceBindings(instance.bound);
+ _closeInstanceBindings(instance.instanceBindings);
}
- if (_instancePositionChangedFn != null) reportInstancesMoved(splices);
+ if (_instancePositionChangedFn != null) _reportInstancesMoved(splices);
}
- void reportInstanceMoved(int index) {
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = getTerminatorAt(index);
+ void _reportInstanceMoved(int index) {
+ var previousTerminator = _getTerminatorAt(index - 1);
+ var terminator = _getTerminatorAt(index);
if (identical(previousTerminator, terminator)) {
return; // instance has zero nodes.
}
@@ -463,13 +466,13 @@
_instancePositionChangedFn(instance, index);
}
- void reportInstancesMoved(List<ListChangeRecord> splices) {
+ void _reportInstancesMoved(List<ListChangeRecord> splices) {
var index = 0;
var offset = 0;
for (var splice in splices) {
if (offset != 0) {
while (index < splice.index) {
- reportInstanceMoved(index);
+ _reportInstanceMoved(index);
index++;
}
} else {
@@ -477,7 +480,7 @@
}
while (index < splice.index + splice.addedCount) {
- reportInstanceMoved(index);
+ _reportInstanceMoved(index);
index++;
}
@@ -486,44 +489,41 @@
if (offset == 0) return;
- var length = terminators.length ~/ 2;
+ var length = _terminators.length ~/ 2;
while (index < length) {
- reportInstanceMoved(index);
+ _reportInstanceMoved(index);
index++;
}
}
- void closeInstanceBindings(List<NodeBinding> bound) {
- for (var binding in bound) binding.close();
+ void _closeInstanceBindings(List<Bindable> instanceBindings) {
+ for (var binding in instanceBindings) binding.close();
}
- void unobserve() {
+ void _unobserve() {
if (_listSub == null) return;
_listSub.cancel();
_listSub = null;
}
void close() {
- if (closed) return;
+ if (_closed) return;
- unobserve();
- for (var i = 1; i < terminators.length; i += 2) {
- closeInstanceBindings(terminators[i]);
+ _unobserve();
+ for (var i = 1; i < _terminators.length; i += 2) {
+ _closeInstanceBindings(_terminators[i]);
}
- terminators.clear();
- if (_valueSub != null) {
- _valueSub.cancel();
- _valueSub = null;
- }
+ _terminators.clear();
+ _closeDependencies();
_templateExt._iterator = null;
- closed = true;
+ _closed = true;
}
}
// Dart note: the JavaScript version just puts an expando on the array.
class _BoundNodes {
final List<Node> nodes;
- final List<NodeBinding> bound;
- _BoundNodes(this.nodes, this.bound);
+ final List<Bindable> instanceBindings;
+ _BoundNodes(this.nodes, this.instanceBindings);
}
diff --git a/pkg/template_binding/lib/src/text.dart b/pkg/template_binding/lib/src/text.dart
index ecb2581..fd4c44a 100644
--- a/pkg/template_binding/lib/src/text.dart
+++ b/pkg/template_binding/lib/src/text.dart
@@ -8,20 +8,25 @@
class _TextExtension extends NodeBindExtension {
_TextExtension(Text node) : super._(node);
- NodeBinding bind(String name, model, [String path]) {
+ Bindable bind(String name, value, {bool oneTime: false}) {
// Dart note: 'text' instead of 'textContent' to match the DOM property.
if (name != 'text') {
- return super.bind(name, model, path);
+ return super.bind(name, value, oneTime: oneTime);
}
+ if (oneTime) {
+ _updateText(value);
+ return null;
+ }
+
unbind(name);
- return bindings[name] = new _TextBinding(_node, model, path);
+ _open(value, _updateText);
+ return bindings[name] = value;
+ }
+
+ _updateText(value) {
+ _node.text = _sanitizeValue(value);
}
}
-class _TextBinding extends NodeBinding {
- _TextBinding(node, model, path) : super(node, 'text', model, path);
-
- void valueChanged(newValue) {
- node.text = sanitizeBoundValue(newValue);
- }
-}
+/** Called to sanitize the value before it is assigned into the property. */
+_sanitizeValue(value) => value == null ? '' : '$value';
diff --git a/pkg/template_binding/lib/src/text_area_element.dart b/pkg/template_binding/lib/src/text_area_element.dart
index 0d462d1..361f7c1 100644
--- a/pkg/template_binding/lib/src/text_area_element.dart
+++ b/pkg/template_binding/lib/src/text_area_element.dart
@@ -10,11 +10,16 @@
TextAreaElement get _node => super._node;
- NodeBinding bind(String name, model, [String path]) {
- if (name != 'value') return super.bind(name, model, path);
+ Bindable bind(String name, value, {bool oneTime: false}) {
+ if (name != 'value') return super.bind(name, value, oneTime: oneTime);
+
+ if (oneTime) {
+ _InputBinding._updateProperty(_node, value, name);
+ return null;
+ }
_self.unbind(name);
_node.attributes.remove(name);
- return bindings[name] = new _ValueBinding(_node, model, path);
+ return bindings[name] = new _InputBinding(_node, value, name);
}
}
diff --git a/pkg/template_binding/lib/template_binding.dart b/pkg/template_binding/lib/template_binding.dart
index 61ec19d..97daeab 100644
--- a/pkg/template_binding/lib/template_binding.dart
+++ b/pkg/template_binding/lib/template_binding.dart
@@ -25,10 +25,9 @@
import 'package:observe/observe.dart';
import 'src/binding_delegate.dart';
-import 'src/node_binding.dart';
+import 'src/mustache_tokens.dart';
export 'src/binding_delegate.dart';
-export 'src/node_binding.dart' show NodeBinding;
part 'src/element.dart';
part 'src/input_bindings.dart';
@@ -45,6 +44,8 @@
// two packages, but this is not easy when we are faking extension methods.
// Since TemplateElement needs to override Node.bind, it seems like the
// Node.bind layer must have some innate knowledge of TemplateBinding.
+// NOTE: I've heard NodeBind might become an internal API, which is all the more
+// reason to have it in this package.
/**
* Provides access to the data binding APIs for the [node]. For example:
@@ -136,6 +137,12 @@
bool _isAttributeTemplate(Element n) => n.attributes.containsKey('template') &&
_SEMANTIC_TEMPLATE_TAGS.containsKey(n.localName);
+bool _isSvgTemplate(Element el) => el.tagName == 'template' &&
+ el.namespaceUri == 'http://www.w3.org/2000/svg';
+
+bool _isHtmlTemplate(Element el) => el.tagName == 'TEMPLATE' &&
+ el.namespaceUri == 'http://www.w3.org/1999/xhtml';
+
/**
* Returns true if this node is semantically a template.
*
@@ -146,7 +153,7 @@
* and COL), OPTION, and OPTGROUP.
*/
bool isSemanticTemplate(Node n) => n is Element &&
- (n.localName == 'template' || _isAttributeTemplate(n));
+ (_isHtmlTemplate(n) || _isAttributeTemplate(n) || _isSvgTemplate(n));
// TODO(jmesserly): const set would be better
const _SEMANTIC_TEMPLATE_TAGS = const {
diff --git a/pkg/template_binding/pubspec.yaml b/pkg/template_binding/pubspec.yaml
index 873e79d..b4a1685 100644
--- a/pkg/template_binding/pubspec.yaml
+++ b/pkg/template_binding/pubspec.yaml
@@ -1,5 +1,5 @@
name: template_binding
-version: 0.9.1
+version: 0.10.0-dev
author: Polymer.dart Team <web-ui-dev@dartlang.org>
description: >
Extends the capabilities of the HTML Template Element by enabling it to
@@ -8,7 +8,7 @@
dependencies:
logging: ">=0.9.0 <0.10.0"
mutation_observer: ">=0.9.0 <0.10.0"
- observe: ">=0.9.0 <0.10.0"
+ observe: ">=0.10.0-dev <0.11.0"
dev_dependencies:
custom_element: ">=0.9.1 <0.10.0"
unittest: ">=0.9.0 <0.10.0"
diff --git a/pkg/template_binding/test/binding_syntax.dart b/pkg/template_binding/test/binding_syntax.dart
index 384dbf9..f5e6afd9 100644
--- a/pkg/template_binding/test/binding_syntax.dart
+++ b/pkg/template_binding/test/binding_syntax.dart
@@ -4,18 +4,18 @@
library template_binding.test.binding_syntax;
+import 'dart:async';
import 'dart:collection';
import 'dart:html';
import 'package:template_binding/template_binding.dart';
import 'package:observe/observe.dart';
-import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
import 'utils.dart';
// Note: this test is executed by template_element_test.dart
syntaxTests(FooBarModel fooModel([foo, bar])) {
- observeTest('prepareBinding', () {
+ test('prepareBinding', () {
var model = fooModel('bar');
var testSyntax = new TestBindingSyntax();
var div = createTestHtml(
@@ -23,23 +23,24 @@
'<template bind>{{ foo }}</template>'
'</template>');
recursivelySetTemplateModel(div, model, testSyntax);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
- expect(div.nodes.last.text, 'bar');
- expect(div.nodes[2].tagName, 'TEMPLATE');
- expect(testSyntax.log, [
- ['prepare', '', 'bind', 'TEMPLATE'],
- ['bindFn', model, 'TEMPLATE', 0],
- ['prepare', 'foo', 'text', 'TEXT'],
- ['prepare', '', 'bind', 'TEMPLATE'],
- ['bindFn', model, 'TEXT', 2],
- ['bindFn', model, 'TEMPLATE', 3],
- ['prepare', 'foo', 'text', 'TEXT'],
- ['bindFn', model, 'TEXT', 6],
- ]);
+ return new Future(() {
+ expect(div.nodes.length, 4);
+ expect(div.nodes.last.text, 'bar');
+ expect(div.nodes[2].tagName, 'TEMPLATE');
+ expect(testSyntax.log, [
+ ['prepare', '', 'bind', 'TEMPLATE'],
+ ['bindFn', model, 'TEMPLATE', 0],
+ ['prepare', 'foo', 'text', 'TEXT'],
+ ['prepare', '', 'bind', 'TEMPLATE'],
+ ['bindFn', model, 'TEXT', 2],
+ ['bindFn', model, 'TEMPLATE', 3],
+ ['prepare', 'foo', 'text', 'TEXT'],
+ ['bindFn', model, 'TEXT', 6],
+ ]);
+ });
});
- observeTest('prepareInstanceModel', () {
+ test('prepareInstanceModel', () {
var model = toObservable([fooModel(1), fooModel(2), fooModel(3)]);
var testSyntax = new TestModelSyntax();
@@ -49,23 +50,24 @@
var template = div.nodes[0];
recursivelySetTemplateModel(div, model, testSyntax);
- performMicrotaskCheckpoint();
+ return new Future(() {
- expect(div.nodes.length, 4);
- expect(div.nodes[0].tagName, 'TEMPLATE');
- expect(div.nodes[1].text, 'a');
- expect(div.nodes[2].text, 'b');
- expect(div.nodes[3].text, 'c');
+ expect(div.nodes.length, 4);
+ expect(div.nodes[0].tagName, 'TEMPLATE');
+ expect(div.nodes[1].text, 'a');
+ expect(div.nodes[2].text, 'b');
+ expect(div.nodes[3].text, 'c');
- expect(testSyntax.log, [
- ['prepare', template],
- ['bindFn', model[0]],
- ['bindFn', model[1]],
- ['bindFn', model[2]],
- ]);
+ expect(testSyntax.log, [
+ ['prepare', template],
+ ['bindFn', model[0]],
+ ['bindFn', model[1]],
+ ['bindFn', model[2]],
+ ]);
+ });
});
- observeTest('prepareInstanceModel - reorder instances', () {
+ test('prepareInstanceModel - reorder instances', () {
var model = toObservable([0, 1, 2]);
var div = createTestHtml('<template repeat>{{}}</template>');
@@ -73,18 +75,19 @@
var delegate = new TestInstanceModelSyntax();
recursivelySetTemplateModel(div, model, delegate);
- performMicrotaskCheckpoint();
- expect(delegate.prepareCount, 1);
- expect(delegate.callCount, 3);
+ return new Future(() {
+ expect(delegate.prepareCount, 1);
+ expect(delegate.callCount, 3);
- // Note: intentionally mutate in place.
- model.replaceRange(0, model.length, model.reversed.toList());
- performMicrotaskCheckpoint();
- expect(delegate.prepareCount, 1);
- expect(delegate.callCount, 3);
+ // Note: intentionally mutate in place.
+ model.replaceRange(0, model.length, model.reversed.toList());
+ }).then(endOfMicrotask).then((_) {
+ expect(delegate.prepareCount, 1);
+ expect(delegate.callCount, 3);
+ });
});
- observeTest('prepareInstancePositionChanged', () {
+ test('prepareInstancePositionChanged', () {
var model = toObservable(['a', 'b', 'c']);
var div = createTestHtml('<template repeat>{{}}</template>');
@@ -92,45 +95,72 @@
var template = div.nodes[0];
recursivelySetTemplateModel(div, model, delegate);
- performMicrotaskCheckpoint();
+ return new Future(() {
- expect(div.nodes.length, 4);
- expect(div.nodes[0].tagName, 'TEMPLATE');
- expect(div.nodes[1].text, 'a');
- expect(div.nodes[2].text, 'b');
- expect(div.nodes[3].text, 'c');
+ expect(div.nodes.length, 4);
+ expect(div.nodes[0].tagName, 'TEMPLATE');
+ expect(div.nodes[1].text, 'a');
+ expect(div.nodes[2].text, 'b');
+ expect(div.nodes[3].text, 'c');
- expect(delegate.log, [
- ['prepare', template],
- ['bindFn', model[0], 0],
- ['bindFn', model[1], 1],
- ['bindFn', model[2], 2],
- ]);
+ expect(delegate.log, [
+ ['prepare', template],
+ ['bindFn', model[0], 0],
+ ['bindFn', model[1], 1],
+ ['bindFn', model[2], 2],
+ ]);
- delegate.log.clear();
+ delegate.log.clear();
- model.removeAt(1);
- performMicrotaskCheckpoint();
+ model.removeAt(1);
+ }).then(endOfMicrotask).then((_) {
- expect(delegate.log, [['bindFn', 'c', 1]], reason: 'removed item');
+ expect(delegate.log, [['bindFn', 'c', 1]], reason: 'removed item');
- expect(div.nodes.skip(1).map((n) => n.text), ['a', 'c']);
+ expect(div.nodes.skip(1).map((n) => n.text), ['a', 'c']);
+ });
});
- observeTest('Basic', () {
+
+ test('Update bindingDelegate with active template', () {
+ var model = toObservable([1, 2]);
+
+ var div = createTestHtml(
+ '<template repeat>{{ \$index }} - {{ \$ident }}</template>');
+ var template = templateBind(div.firstChild)
+ ..bindingDelegate = new UpdateBindingDelegateA()
+ ..model = model;
+
+ return new Future(() {
+ expect(div.nodes.length, 3);
+ expect(div.nodes[1].text, 'i:0 - a:1');
+ expect(div.nodes[2].text, 'i:1 - a:2');
+
+ template.bindingDelegate = new UpdateBindingDelegateB();
+ model.add(3);
+ }).then(nextMicrotask).then((_) {
+ expect(4, div.nodes.length);
+ expect(div.nodes[1].text, 'i:0 - a:1');
+ expect(div.nodes[2].text, 'i:1 - a:2');
+ expect(div.nodes[3].text, 'I:4 - A:3-narg');
+ });
+ });
+
+ test('Basic', () {
var model = fooModel(2, 4);
var div = createTestHtml(
'<template bind>'
'{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>');
recursivelySetTemplateModel(div, model, new TimesTwoSyntax());
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, '2 + 8 + ');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, '2 + 8 + ');
- model.foo = 4;
- model.bar = 8;
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, '4 + 16 + ');
+ model.foo = 4;
+ model.bar = 8;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, '4 + 16 + ');
+ });
});
// Note: issue-141 test not included here as it's not related to the
@@ -147,9 +177,11 @@
int id = log.length;
log.add(['prepare', path, name, tagName]);
final outerNode = node;
- return (model, node) {
+ return (model, node, oneTime) {
var tagName = node is Element ? node.tagName : 'TEXT';
log.add(['bindFn', model, tagName, id]);
+ return oneTime ? new PropertyPath(path).getValueFrom(model) :
+ new PathObserver(model, path);
};
}
}
@@ -199,8 +231,42 @@
if (!path.startsWith('2x:')) return null;
path = path.substring(3);
- return (model, _) {
- return new PathObserver(model, path, computeValue: (x) => 2 * x);
+ return (model, _, oneTime) {
+ return new ObserverTransform(new PathObserver(model, path), (x) => 2 * x);
};
}
}
+
+class UpdateBindingDelegateBase extends BindingDelegate {
+ bindingHandler(prefix, path) => (model, _, oneTime) =>
+ new ObserverTransform(new PathObserver(model, path), (x) => '$prefix:$x');
+}
+
+class UpdateBindingDelegateA extends UpdateBindingDelegateBase {
+ prepareBinding(path, name, node) {
+ if (path == '\$ident') return bindingHandler('a', 'id');
+ if (path == '\$index') return bindingHandler('i', 'index');
+ }
+
+ prepareInstanceModel(template) => (model) => toObservable({ 'id': model });
+
+ prepareInstancePositionChanged(template) => (templateInstance, index) {
+ templateInstance.model['index'] = index;
+ };
+}
+
+class UpdateBindingDelegateB extends UpdateBindingDelegateBase {
+ prepareBinding(path, name, node) {
+ if (path == '\$ident') return bindingHandler('A', 'id');
+ if (path == '\$index') return bindingHandler('I', 'index');
+ }
+
+ prepareInstanceModel(template) =>
+ (model) => toObservable({ 'id': '${model}-narg' });
+
+
+ prepareInstancePositionChanged(template) => (templateInstance, index) {
+ templateInstance.model['index'] = 2 * index;
+ };
+}
+
diff --git a/pkg/template_binding/test/custom_element_bindings_test.dart b/pkg/template_binding/test/custom_element_bindings_test.dart
index cc12875..d3c22c9 100644
--- a/pkg/template_binding/test/custom_element_bindings_test.dart
+++ b/pkg/template_binding/test/custom_element_bindings_test.dart
@@ -8,14 +8,14 @@
import 'dart:html';
import 'package:custom_element/polyfill.dart';
import 'package:template_binding/template_binding.dart';
-import 'package:observe/observe.dart' show toObservable;
+import 'package:observe/observe.dart';
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
import 'utils.dart';
Future _registered;
-main() {
+main() => dirtyCheckZone().run(() {
useHtmlConfiguration();
_registered = loadCustomElementPolyfill().then((_) {
@@ -24,7 +24,7 @@
});
group('Custom Element Bindings', customElementBindingsTest);
-}
+});
customElementBindingsTest() {
setUp(() {
@@ -37,13 +37,13 @@
testDiv = null;
});
- observeTest('override bind/unbind/unbindAll', () {
+ test('override bind/unbind/unbindAll', () {
var element = new MyCustomElement();
var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
nodeBind(element)
- ..bind('my-point', model, 'a')
- ..bind('scary-monster', model, 'b');
+ ..bind('my-point', new PathObserver(model, 'a'))
+ ..bind('scary-monster', new PathObserver(model, 'b'));
expect(element.attributes, isNot(contains('my-point')));
expect(element.attributes, isNot(contains('scary-monster')));
@@ -52,65 +52,67 @@
expect(element.scaryMonster, model['b']);
model['a'] = null;
- performMicrotaskCheckpoint();
- expect(element.myPoint, null);
- nodeBind(element).unbind('my-point');
+ return new Future(() {
+ expect(element.myPoint, null);
+ nodeBind(element).unbind('my-point');
- model['a'] = new Point(1, 2);
- model['b'] = new Monster(200);
- performMicrotaskCheckpoint();
- expect(element.scaryMonster, model['b']);
- expect(element.myPoint, null, reason: 'a was unbound');
+ model['a'] = new Point(1, 2);
+ model['b'] = new Monster(200);
+ }).then(endOfMicrotask).then((_) {
+ expect(element.scaryMonster, model['b']);
+ expect(element.myPoint, null, reason: 'a was unbound');
- nodeBind(element).unbindAll();
- model['b'] = null;
- performMicrotaskCheckpoint();
- expect(element.scaryMonster.health, 200);
+ nodeBind(element).unbindAll();
+ model['b'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(element.scaryMonster.health, 200);
+ });
});
- observeTest('override attribute setter', () {
+ test('override attribute setter', () {
var element = new WithAttrsCustomElement();
var model = toObservable({'a': 1, 'b': 2});
- nodeBind(element).bind('hidden?', model, 'a');
- nodeBind(element).bind('id', model, 'b');
+ nodeBind(element).bind('hidden?', new PathObserver(model, 'a'));
+ nodeBind(element).bind('id', new PathObserver(model, 'b'));
expect(element.attributes, contains('hidden'));
expect(element.attributes['hidden'], '');
expect(element.id, '2');
model['a'] = null;
- performMicrotaskCheckpoint();
- expect(element.attributes, isNot(contains('hidden')),
- reason: 'null is false-y');
+ return new Future(() {
+ expect(element.attributes, isNot(contains('hidden')),
+ reason: 'null is false-y');
- model['a'] = false;
- performMicrotaskCheckpoint();
- expect(element.attributes, isNot(contains('hidden')));
+ model['a'] = false;
+ }).then(endOfMicrotask).then((_) {
+ expect(element.attributes, isNot(contains('hidden')));
- model['a'] = 'foo';
- // TODO(jmesserly): this is here to force an ordering between the two
- // changes. Otherwise the order depends on what order StreamController
- // chooses to fire the two listeners in.
- performMicrotaskCheckpoint();
+ model['a'] = 'foo';
+ // TODO(jmesserly): this is here to force an ordering between the two
+ // changes. Otherwise the order depends on what order StreamController
+ // chooses to fire the two listeners in.
+ }).then(endOfMicrotask).then((_) {
- model['b'] = 'x';
- performMicrotaskCheckpoint();
- expect(element.attributes, contains('hidden'));
- expect(element.attributes['hidden'], '');
- expect(element.id, 'x');
+ model['b'] = 'x';
+ }).then(endOfMicrotask).then((_) {
+ expect(element.attributes, contains('hidden'));
+ expect(element.attributes['hidden'], '');
+ expect(element.id, 'x');
- expect(element.attributes.log, [
- ['remove', 'hidden?'],
- ['[]=', 'hidden', ''],
- ['[]=', 'id', '2'],
- ['remove', 'hidden'],
- ['remove', 'hidden'],
- ['[]=', 'hidden', ''],
- ['[]=', 'id', 'x'],
- ]);
+ expect(element.attributes.log, [
+ ['remove', 'hidden?'],
+ ['[]=', 'hidden', ''],
+ ['[]=', 'id', '2'],
+ ['remove', 'hidden'],
+ ['remove', 'hidden'],
+ ['[]=', 'hidden', ''],
+ ['[]=', 'id', 'x'],
+ ]);
+ });
});
- observeTest('template bind uses overridden custom element bind', () {
+ test('template bind uses overridden custom element bind', () {
var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
var div = createTestHtml('<template bind>'
@@ -119,34 +121,36 @@
'</template>');
templateBind(div.query('template')).model = model;
- performMicrotaskCheckpoint();
+ var element;
+ return new Future(() {
+ print('!!! running future');
+ element = div.nodes[1];
- var element = div.nodes[1];
+ expect(element is MyCustomElement, true,
+ reason: '$element should be a MyCustomElement');
- expect(element is MyCustomElement, true,
- reason: '$element should be a MyCustomElement');
+ expect(element.myPoint, model['a']);
+ expect(element.scaryMonster, model['b']);
- expect(element.myPoint, model['a']);
- expect(element.scaryMonster, model['b']);
+ expect(element.attributes, isNot(contains('my-point')));
+ expect(element.attributes, isNot(contains('scary-monster')));
- expect(element.attributes, isNot(contains('my-point')));
- expect(element.attributes, isNot(contains('scary-monster')));
+ model['a'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(element.myPoint, null);
- model['a'] = null;
- performMicrotaskCheckpoint();
- expect(element.myPoint, null);
+ templateBind(div.query('template')).model = null;
+ }).then(endOfMicrotask).then((_) {
- templateBind(div.query('template')).model = null;
- performMicrotaskCheckpoint();
+ expect(element.parentNode, null, reason: 'element was detached');
- expect(element.parentNode, null, reason: 'element was detached');
+ model['a'] = new Point(1, 2);
+ model['b'] = new Monster(200);
+ }).then(endOfMicrotask).then((_) {
- model['a'] = new Point(1, 2);
- model['b'] = new Monster(200);
- performMicrotaskCheckpoint();
-
- expect(element.myPoint, null, reason: 'model was unbound');
- expect(element.scaryMonster.health, 100, reason: 'model was unbound');
+ expect(element.myPoint, null, reason: 'model was unbound');
+ expect(element.scaryMonster.health, 100, reason: 'model was unbound');
+ });
});
}
@@ -165,35 +169,30 @@
MyCustomElement.created() : super.created();
- NodeBinding bind(String name, model, [String path]) {
+ Bindable bind(String name, value, {oneTime: false}) {
switch (name) {
case 'my-point':
case 'scary-monster':
attributes.remove(name);
+ if (oneTime) {
+ _setProperty(name, value);
+ return null;
+ }
unbind(name);
- return bindings[name] = new _MyCustomBinding(this, name, model, path);
+ _setProperty(name, value.open((x) => _setProperty(name, x)));
+ return bindings[name] = value;
}
- return nodeBindFallback(this).bind(name, model, path);
+ return nodeBindFallback(this).bind(name, value, oneTime: oneTime);
}
unbind(name) => nodeBindFallback(this).unbind(name);
unbindAll() => nodeBindFallback(this).unbindAll();
get bindings => nodeBindFallback(this).bindings;
get templateInstance => nodeBindFallback(this).templateInstance;
-}
-class _MyCustomBinding extends NodeBinding {
- _MyCustomBinding(MyCustomElement node, property, model, path)
- : super(node, property, model, path) {
-
- node.attributes.remove(property);
- }
-
- MyCustomElement get node => super.node;
-
- void valueChanged(newValue) {
- if (property == 'my-point') node.myPoint = newValue;
- if (property == 'scary-monster') node.scaryMonster = newValue;
+ void _setProperty(String property, newValue) {
+ if (property == 'my-point') myPoint = newValue;
+ if (property == 'scary-monster') scaryMonster = newValue;
}
}
diff --git a/pkg/template_binding/test/node_bind_test.dart b/pkg/template_binding/test/node_bind_test.dart
index fbedcfa..93bcd8f 100644
--- a/pkg/template_binding/test/node_bind_test.dart
+++ b/pkg/template_binding/test/node_bind_test.dart
@@ -4,11 +4,12 @@
library template_binding.test.node_bind_test;
+import 'dart:async';
import 'dart:html';
-import 'package:observe/observe.dart' show toObservable, PathObserver;
+import 'package:observe/observe.dart'
+ show toObservable, PathObserver, PropertyPath;
import 'package:template_binding/template_binding.dart' show nodeBind;
-import 'package:template_binding/src/node_binding.dart' show getObserverForTest;
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
@@ -17,7 +18,7 @@
// Note: this file ported from
// https://github.com/toolkitchen/mdv/blob/master/tests/node_bindings.js
-main() {
+main() => dirtyCheckZone().run(() {
useHtmlConfiguration();
setUp(() {
@@ -29,147 +30,162 @@
testDiv = null;
});
-
group('Text bindings', testBindings);
group('Element attribute bindings', elementBindings);
group('Form Element bindings', formBindings);
-}
+});
testBindings() {
- observeTest('Basic', () {
+ test('Basic', () {
var text = new Text('hi');
var model = toObservable({'a': 1});
- nodeBind(text).bind('text', model, 'a');
+ nodeBind(text).bind('text', new PathObserver(model, 'a'));
expect(text.text, '1');
model['a'] = 2;
- performMicrotaskCheckpoint();
- expect(text.text, '2');
+ return new Future(() {
+ expect(text.text, '2');
- nodeBind(text).unbind('text');
- model['a'] = 3;
- performMicrotaskCheckpoint();
- expect(text.text, '2');
-
- // TODO(rafaelw): Throw on binding to unavailable property?
+ nodeBind(text).unbind('text');
+ model['a'] = 3;
+ }).then(endOfMicrotask).then((_) {
+ // TODO(rafaelw): Throw on binding to unavailable property?
+ expect(text.text, '2');
+ });
});
- observeTest('No Path', () {
+ test('oneTime', () {
var text = new Text('hi');
- var model = 1;
- nodeBind(text).bind('text', model);
+ nodeBind(text).bind('text', 1, oneTime: true);
expect(text.text, '1');
});
- observeTest('Path unreachable', () {
+ test('No Path', () {
+ var text = new Text('hi');
+ var model = 1;
+ nodeBind(text).bind('text', new PathObserver(model));
+ expect(text.text, '1');
+ });
+
+ test('Path unreachable', () {
var text = testDiv.append(new Text('hi'));
var model = 1;
- nodeBind(text).bind('text', model, 'a');
+ nodeBind(text).bind('text', new PathObserver(model, 'a'));
expect(text.text, '');
});
- observeTest('Observer is Model', () {
+ test('Observer is Model', () {
var text = new Text('');
var model = toObservable({'a': {'b': {'c': 1}}});
var observer = new PathObserver(model, 'a.b.c');
- nodeBind(text).bind('text', observer, 'value');
+ nodeBind(text).bind('text', observer);
expect(text.text, '1');
var binding = nodeBind(text).bindings['text'];
- expect(binding, isNotNull);
- expect(getObserverForTest(binding), observer,
- reason: 'should reuse observer');
+ expect(binding, observer, reason: 'should reuse observer');
model['a']['b']['c'] = 2;
- performMicrotaskCheckpoint();
- expect(text.text, '2');
- nodeBind(text).unbind('text');
+ return new Future(() {
+ expect(text.text, '2');
+ nodeBind(text).unbind('text');
+ });
});
}
elementBindings() {
- observeTest('Basic', () {
+ test('Basic', () {
var el = new DivElement();
var model = toObservable({'a': '1'});
- nodeBind(el).bind('foo', model, 'a');
- performMicrotaskCheckpoint();
- expect(el.attributes['foo'], '1');
+ nodeBind(el).bind('foo', new PathObserver(model, 'a'));
- model['a'] = '2';
- performMicrotaskCheckpoint();
- expect(el.attributes['foo'], '2');
-
- model['a'] = 232.2;
- performMicrotaskCheckpoint();
- expect(el.attributes['foo'], '232.2');
-
- model['a'] = 232;
- performMicrotaskCheckpoint();
- expect(el.attributes['foo'], '232');
-
- model['a'] = null;
- performMicrotaskCheckpoint();
- expect(el.attributes['foo'], '');
+ return new Future(() {
+ expect(el.attributes['foo'], '1');
+ model['a'] = '2';
+ }).then(endOfMicrotask).then((_) {
+ expect(el.attributes['foo'], '2');
+ model['a'] = 232.2;
+ }).then(endOfMicrotask).then((_) {
+ expect(el.attributes['foo'], '232.2');
+ model['a'] = 232;
+ }).then(endOfMicrotask).then((_) {
+ expect(el.attributes['foo'], '232');
+ model['a'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(el.attributes['foo'], '');
+ });
});
- observeTest('No Path', () {
- var el = testDiv.append(new DivElement());
- var model = 1;
- nodeBind(el).bind('foo', model);
- expect(el.attributes['foo'], '1');
- });
-
- observeTest('Path unreachable', () {
- var el = testDiv.append(new DivElement());
- var model = toObservable({});
- nodeBind(el).bind('foo', model, 'bar');
- expect(el.attributes['foo'], '');
- });
-
- observeTest('Dashes', () {
+ test('oneTime', () {
var el = testDiv.append(new DivElement());
var model = toObservable({'a': '1'});
- nodeBind(el).bind('foo-bar', model, 'a');
- performMicrotaskCheckpoint();
- expect(el.attributes['foo-bar'], '1');
-
- model['a'] = '2';
- performMicrotaskCheckpoint();
- expect(el.attributes['foo-bar'], '2');
+ nodeBind(el).bind('foo', 1, oneTime: true);
+ expect('1', el.attributes['foo']);
});
- observeTest('Element.id, Element.hidden?', () {
+ test('No Path', () {
+ var el = testDiv.append(new DivElement());
+ var model = 1;
+ nodeBind(el).bind('foo', new PathObserver(model));
+ return new Future(() {
+ expect(el.attributes['foo'], '1');
+ });
+ });
+
+ test('Path unreachable', () {
+ var el = testDiv.append(new DivElement());
+ var model = toObservable({});
+ nodeBind(el).bind('foo', new PathObserver(model, 'bar'));
+ return new Future(() {
+ expect(el.attributes['foo'], '');
+ });
+ });
+
+ test('Dashes', () {
+ var el = testDiv.append(new DivElement());
+ var model = toObservable({'a': '1'});
+ nodeBind(el).bind('foo-bar', new PathObserver(model, 'a'));
+ return new Future(() {
+ expect(el.attributes['foo-bar'], '1');
+ model['a'] = '2';
+
+ }).then(endOfMicrotask).then((_) {
+ expect(el.attributes['foo-bar'], '2');
+ });
+ });
+
+ test('Element.id, Element.hidden?', () {
var element = new DivElement();
var model = toObservable({'a': 1, 'b': 2});
- nodeBind(element).bind('hidden?', model, 'a');
- nodeBind(element).bind('id', model, 'b');
+ nodeBind(element).bind('hidden?', new PathObserver(model, 'a'));
+ nodeBind(element).bind('id', new PathObserver(model, 'b'));
expect(element.attributes, contains('hidden'));
expect(element.attributes['hidden'], '');
expect(element.id, '2');
model['a'] = null;
- performMicrotaskCheckpoint();
- expect(element.attributes, isNot(contains('hidden')),
- reason: 'null is false-y');
+ return new Future(() {
+ expect(element.attributes, isNot(contains('hidden')),
+ reason: 'null is false-y');
- model['a'] = false;
- performMicrotaskCheckpoint();
- expect(element.attributes, isNot(contains('hidden')));
+ model['a'] = false;
+ }).then(endOfMicrotask).then((_) {
+ expect(element.attributes, isNot(contains('hidden')));
- model['a'] = 'foo';
- model['b'] = 'x';
- performMicrotaskCheckpoint();
- expect(element.attributes, contains('hidden'));
- expect(element.attributes['hidden'], '');
- expect(element.id, 'x');
+ model['a'] = 'foo';
+ model['b'] = 'x';
+ }).then(endOfMicrotask).then((_) {
+ expect(element.attributes, contains('hidden'));
+ expect(element.attributes['hidden'], '');
+ expect(element.id, 'x');
+ });
});
- observeTest('Element.id - path unreachable', () {
+ test('Element.id - path unreachable', () {
var element = testDiv.append(new DivElement());
var model = toObservable({});
- nodeBind(element).bind('id', model, 'a');
- expect(element.id, '');
+ nodeBind(element).bind('id', new PathObserver(model, 'a'));
+ return new Future(() => expect(element.id, ''));
});
}
@@ -178,237 +194,284 @@
var el = new Element.tag(tagName);
testDiv.nodes.add(el);
var model = toObservable({'x': 42});
- nodeBind(el).bind('value', model, 'x');
+ nodeBind(el).bind('value', new PathObserver(model, 'x'));
expect(el.value, '42');
model['x'] = 'Hi';
expect(el.value, '42', reason: 'changes delivered async');
- performMicrotaskCheckpoint();
- expect(el.value, 'Hi');
+ return new Future(() {
+ expect(el.value, 'Hi');
- el.value = 'changed';
- dispatchEvent('input', el);
- expect(model['x'], 'changed');
+ el.value = 'changed';
+ dispatchEvent('input', el);
+ expect(model['x'], 'changed');
- nodeBind(el).unbind('value');
+ nodeBind(el).unbind('value');
- el.value = 'changed again';
- dispatchEvent('input', el);
- expect(model['x'], 'changed');
+ el.value = 'changed again';
+ dispatchEvent('input', el);
+ expect(model['x'], 'changed');
- nodeBind(el).bind('value', model, 'x');
- model['x'] = null;
- performMicrotaskCheckpoint();
- expect(el.value, '');
+ nodeBind(el).bind('value', new PathObserver(model, 'x'));
+ model['x'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(el.value, '');
+ });
+ }
+
+ inputTextAreaValueOnetime(String tagName) {
+ var el = testDiv.append(new Element.tag(tagName));
+ nodeBind(el).bind('value', 42, oneTime: true);
+ expect(el.value, '42');
}
inputTextAreaNoPath(String tagName) {
var el = testDiv.append(new Element.tag(tagName));
var model = 42;
- nodeBind(el).bind('value', model);
+ nodeBind(el).bind('value', new PathObserver(model));
expect(el.value, '42');
}
inputTextAreaPathUnreachable(String tagName) {
var el = testDiv.append(new Element.tag(tagName));
var model = toObservable({});
- nodeBind(el).bind('value', model, 'a');
+ nodeBind(el).bind('value', new PathObserver(model, 'a'));
expect(el.value, '');
}
- observeTest('Input.value',
+ test('Input.value',
() => inputTextAreaValueTest('input'));
- observeTest('Input.value - no path',
+
+ test('Input.value - oneTime',
+ () => inputTextAreaValueOnetime('input'));
+
+ test('Input.value - no path',
() => inputTextAreaNoPath('input'));
- observeTest('Input.value - path unreachable',
+
+ test('Input.value - path unreachable',
() => inputTextAreaPathUnreachable('input'));
- observeTest('TextArea.value',
+
+ test('TextArea.value',
() => inputTextAreaValueTest('textarea'));
- observeTest('TextArea.value - no path',
+
+ test('TextArea.value - oneTime',
+ () => inputTextAreaValueOnetime('textarea'));
+
+ test('TextArea.value - no path',
() => inputTextAreaNoPath('textarea'));
- observeTest('TextArea.value - path unreachable',
+
+ test('TextArea.value - path unreachable',
() => inputTextAreaPathUnreachable('textarea'));
- observeTest('Radio Input', () {
+ test('Radio Input', () {
var input = new InputElement();
input.type = 'radio';
var model = toObservable({'x': true});
- nodeBind(input).bind('checked', model, 'x');
+ nodeBind(input).bind('checked', new PathObserver(model, 'x'));
expect(input.checked, true);
model['x'] = false;
expect(input.checked, true);
- performMicrotaskCheckpoint();
- expect(input.checked, false,reason: 'model change should update checked');
+ return new Future(() {
+ expect(input.checked, false,reason: 'model change should update checked');
- input.checked = true;
- dispatchEvent('change', input);
- expect(model['x'], true, reason: 'input.checked should set model');
+ input.checked = true;
+ dispatchEvent('change', input);
+ expect(model['x'], true, reason: 'input.checked should set model');
- nodeBind(input).unbind('checked');
+ nodeBind(input).unbind('checked');
- input.checked = false;
- dispatchEvent('change', input);
- expect(model['x'], true,
- reason: 'disconnected binding should not fire');
+ input.checked = false;
+ dispatchEvent('change', input);
+ expect(model['x'], true,
+ reason: 'disconnected binding should not fire');
+ });
});
- observeTest('Input.value - user value rejected', () {
+ test('Input.value - user value rejected', () {
var model = toObservable({'val': 'ping'});
var el = new InputElement();
- nodeBind(el).bind('value', model, 'val');
- performMicrotaskCheckpoint();
- expect(el.value, 'ping');
+ nodeBind(el).bind('value', new PathObserver(model, 'val'));
+ return new Future(() {
+ expect(el.value, 'ping');
- el.value = 'pong';
- dispatchEvent('input', el);
- expect(model['val'], 'pong');
+ el.value = 'pong';
+ dispatchEvent('input', el);
+ expect(model['val'], 'pong');
- // Try a deep path.
- model = toObservable({'a': {'b': {'c': 'ping'}}});
+ // Try a deep path.
+ model = toObservable({'a': {'b': {'c': 'ping'}}});
- nodeBind(el).bind('value', model, 'a.b.c');
- performMicrotaskCheckpoint();
- expect(el.value, 'ping');
+ nodeBind(el).bind('value', new PathObserver(model, 'a.b.c'));
+ }).then(endOfMicrotask).then((_) {
+ expect(el.value, 'ping');
- el.value = 'pong';
- dispatchEvent('input', el);
- expect(new PathObserver(model, 'a.b.c').value, 'pong');
+ el.value = 'pong';
+ dispatchEvent('input', el);
+ expect(new PropertyPath('a.b.c').getValueFrom(model), 'pong');
- // Start with the model property being absent.
- model['a']['b'].remove('c');
- performMicrotaskCheckpoint();
- expect(el.value, '');
+ // Start with the model property being absent.
+ model['a']['b'].remove('c');
+ }).then(endOfMicrotask).then((_) {
+ expect(el.value, '');
- el.value = 'pong';
- dispatchEvent('input', el);
- expect(new PathObserver(model, 'a.b.c').value, 'pong');
- performMicrotaskCheckpoint();
+ el.value = 'pong';
+ dispatchEvent('input', el);
+ expect(new PropertyPath('a.b.c').getValueFrom(model), 'pong');
+ }).then(endOfMicrotask).then((_) {
- // Model property unreachable (and unsettable).
- model['a'].remove('b');
- performMicrotaskCheckpoint();
- expect(el.value, '');
+ // Model property unreachable (and unsettable).
+ model['a'].remove('b');
+ }).then(endOfMicrotask).then((_) {
+ expect(el.value, '');
- el.value = 'pong';
- dispatchEvent('input', el);
- expect(new PathObserver(model, 'a.b.c').value, null);
+ el.value = 'pong';
+ dispatchEvent('input', el);
+ expect(new PropertyPath('a.b.c').getValueFrom(model), null);
+ });
});
- observeTest('(Checkbox)Input.checked', () {
+ test('Checkbox Input.checked', () {
var el = testDiv.append(new InputElement());
el.type = 'checkbox';
var model = toObservable({'x': true});
- nodeBind(el).bind('checked', model, 'x');
+ nodeBind(el).bind('checked', new PathObserver(model, 'x'));
expect(el.checked, true);
model['x'] = false;
expect(el.checked, true, reason: 'changes delivered async');
- performMicrotaskCheckpoint();
- expect(el.checked, false);
+ return new Future(() {
+ expect(el.checked, false);
- el.click();
- expect(model['x'], true);
- performMicrotaskCheckpoint();
+ el.click();
+ expect(model['x'], true);
+ }).then(endOfMicrotask).then((_) {
- el.click();
- expect(model['x'], false);
+ el.click();
+ expect(model['x'], false);
+ });
});
- observeTest('(Checkbox)Input.checked - path unreachable', () {
+ test('Checkbox Input.checked - oneTime', () {
+ var input = testDiv.append(new InputElement());
+ input.type = 'checkbox';
+ nodeBind(input).bind('checked', true, oneTime: true);
+ expect(input.checked, true, reason: 'checked was set');
+ });
+
+ test('Checkbox Input.checked - path unreachable', () {
var input = testDiv.append(new InputElement());
input.type = 'checkbox';
var model = toObservable({});
- nodeBind(input).bind('checked', model, 'x');
+ nodeBind(input).bind('checked', new PathObserver(model, 'x'));
expect(input.checked, false);
});
- observeTest('(Checkbox)Input.checked 2', () {
+ test('Checkbox Input.checked 2', () {
var model = toObservable({'val': true});
var el = testDiv.append(new InputElement());
el.type = 'checkbox';
- nodeBind(el).bind('checked', model, 'val');
- performMicrotaskCheckpoint();
- expect(el.checked, true);
+ nodeBind(el).bind('checked', new PathObserver(model, 'val'));
+ return new Future(() {
+ expect(el.checked, true);
- model['val'] = false;
- performMicrotaskCheckpoint();
- expect(el.checked, false);
+ model['val'] = false;
+ }).then(endOfMicrotask).then((_) {
+ expect(el.checked, false);
- el.click();
- expect(model['val'], true);
-
- el.click();
- expect(model['val'], false);
-
- el.onClick.listen((_) {
+ el.click();
expect(model['val'], true);
- });
- el.onChange.listen((_) {
- expect(model['val'], true);
- });
- el.dispatchEvent(new MouseEvent('click', view: window));
+ el.click();
+ expect(model['val'], false);
+
+ el.onClick.listen((_) {
+ expect(model['val'], true);
+ });
+ el.onChange.listen((_) {
+ expect(model['val'], true);
+ });
+
+ el.dispatchEvent(new MouseEvent('click', view: window));
+ });
});
- observeTest('(Checkbox)Input.checked - binding updated on click', () {
+ test('Checkbox Input.checked - binding updated on click', () {
var model = toObservable({'val': true});
var el = new InputElement();
testDiv.append(el);
el.type = 'checkbox';
- nodeBind(el).bind('checked', model, 'val');
- performMicrotaskCheckpoint();
- expect(el.checked, true);
+ nodeBind(el).bind('checked', new PathObserver(model, 'val'));
+ return new Future(() {
+ expect(el.checked, true);
- el.onClick.listen((_) {
- expect(model['val'], false);
+ int fired = 0;
+ el.onClick.listen((_) {
+ fired++;
+ expect(model['val'], false);
+ });
+
+ el.dispatchEvent(new MouseEvent('click', view: window));
+
+ expect(fired, 1, reason: 'events dispatched synchronously');
});
-
- el.dispatchEvent(new MouseEvent('click', view: window));
});
- observeTest('(Checkbox)Input.checked - binding updated on change', () {
+ test('Checkbox Input.checked - binding updated on change', () {
var model = toObservable({'val': true});
var el = new InputElement();
testDiv.append(el);
el.type = 'checkbox';
- nodeBind(el).bind('checked', model, 'val');
- performMicrotaskCheckpoint();
- expect(el.checked, true);
+ nodeBind(el).bind('checked', new PathObserver(model, 'val'));
+ return new Future(() {
+ expect(el.checked, true);
- el.onChange.listen((_) {
- expect(model['val'], false);
+ int fired = 0;
+ el.onChange.listen((_) {
+ fired++;
+ expect(model['val'], false);
+ });
+
+ el.dispatchEvent(new MouseEvent('click', view: window));
+
+ expect(fired, 1, reason: 'events dispatched synchronously');
});
-
- el.dispatchEvent(new MouseEvent('click', view: window));
});
- observeTest('(Radio)Input.checked', () {
+ test('Radio Input.checked', () {
var input = testDiv.append(new InputElement());
input.type = 'radio';
var model = toObservable({'x': true});
- nodeBind(input).bind('checked', model, 'x');
+ nodeBind(input).bind('checked', new PathObserver(model, 'x'));
expect(input.checked, true);
model['x'] = false;
expect(input.checked, true);
- performMicrotaskCheckpoint();
- expect(input.checked, false);
+ return new Future(() {
+ expect(input.checked, false);
- input.checked = true;
- dispatchEvent('change', input);
- expect(model['x'], true);
+ input.checked = true;
+ dispatchEvent('change', input);
+ expect(model['x'], true);
- nodeBind(input).unbind('checked');
+ nodeBind(input).unbind('checked');
- input.checked = false;
- dispatchEvent('change', input);
- expect(model['x'], true);
+ input.checked = false;
+ dispatchEvent('change', input);
+ expect(model['x'], true);
+ });
+ });
+
+ test('Radio Input.checked - oneTime', () {
+ var input = testDiv.append(new InputElement());
+ input.type = 'radio';
+ nodeBind(input).bind('checked', true, oneTime: true);
+ expect(input.checked, true, reason: 'checked was set');
});
radioInputChecked2(host) {
@@ -421,69 +484,67 @@
var el1 = container.append(new InputElement());
el1.type = 'radio';
el1.name = RADIO_GROUP_NAME;
- nodeBind(el1).bind('checked', model, 'val1');
+ nodeBind(el1).bind('checked', new PathObserver(model, 'val1'));
var el2 = container.append(new InputElement());
el2.type = 'radio';
el2.name = RADIO_GROUP_NAME;
- nodeBind(el2).bind('checked', model, 'val2');
+ nodeBind(el2).bind('checked', new PathObserver(model, 'val2'));
var el3 = container.append(new InputElement());
el3.type = 'radio';
el3.name = RADIO_GROUP_NAME;
- nodeBind(el3).bind('checked', model, 'val3');
+ nodeBind(el3).bind('checked', new PathObserver(model, 'val3'));
var el4 = container.append(new InputElement());
el4.type = 'radio';
el4.name = 'othergroup';
- nodeBind(el4).bind('checked', model, 'val4');
+ nodeBind(el4).bind('checked', new PathObserver(model, 'val4'));
- performMicrotaskCheckpoint();
- expect(el1.checked, true);
- expect(el2.checked, false);
- expect(el3.checked, false);
- expect(el4.checked, true);
+ return new Future(() {
+ expect(el1.checked, true);
+ expect(el2.checked, false);
+ expect(el3.checked, false);
+ expect(el4.checked, true);
- model['val1'] = false;
- model['val2'] = true;
- performMicrotaskCheckpoint();
- expect(el1.checked, false);
- expect(el2.checked, true);
- expect(el3.checked, false);
- expect(el4.checked, true);
+ model['val1'] = false;
+ model['val2'] = true;
+ }).then(endOfMicrotask).then((_) {
+ expect(el1.checked, false);
+ expect(el2.checked, true);
+ expect(el3.checked, false);
+ expect(el4.checked, true);
- el1.checked = true;
- dispatchEvent('change', el1);
- expect(model['val1'], true);
- expect(model['val2'], false);
- expect(model['val3'], false);
- expect(model['val4'], true);
+ el1.checked = true;
+ dispatchEvent('change', el1);
+ expect(model['val1'], true);
+ expect(model['val2'], false);
+ expect(model['val3'], false);
+ expect(model['val4'], true);
- el3.checked = true;
- dispatchEvent('change', el3);
- expect(model['val1'], false);
- expect(model['val2'], false);
- expect(model['val3'], true);
- expect(model['val4'], true);
+ el3.checked = true;
+ dispatchEvent('change', el3);
+ expect(model['val1'], false);
+ expect(model['val2'], false);
+ expect(model['val3'], true);
+ expect(model['val4'], true);
+ });
}
- observeTest('(Radio)Input.checked 2', () {
- radioInputChecked2(testDiv);
- });
+ test('Radio Input.checked 2', () => radioInputChecked2(testDiv));
- observeTest('(Radio)Input.checked 2 - ShadowRoot', () {
- if (!ShadowRoot.supported) return;
+ test('Radio Input.checked 2 - ShadowRoot', () {
+ if (!ShadowRoot.supported) return null;
- var div = new DivElement();
- var shadowRoot = div.createShadowRoot();
- radioInputChecked2(shadowRoot);
- unbindAll(shadowRoot);
+ var shadowRoot = new DivElement().createShadowRoot();
+ return radioInputChecked2(shadowRoot)
+ .whenComplete(() => unbindAll(shadowRoot));
});
radioInputCheckedMultipleForms(host) {
var model = toObservable({'val1': true, 'val2': false, 'val3': false,
'val4': true});
- var RADIO_GROUP_NAME = 'observeTest';
+ var RADIO_GROUP_NAME = 'test';
var container = testDiv.append(new DivElement());
var form1 = new FormElement();
@@ -495,64 +556,65 @@
form1.append(el1);
el1.type = 'radio';
el1.name = RADIO_GROUP_NAME;
- nodeBind(el1).bind('checked', model, 'val1');
+ nodeBind(el1).bind('checked', new PathObserver(model, 'val1'));
var el2 = new InputElement();
form1.append(el2);
el2.type = 'radio';
el2.name = RADIO_GROUP_NAME;
- nodeBind(el2).bind('checked', model, 'val2');
+ nodeBind(el2).bind('checked', new PathObserver(model, 'val2'));
var el3 = new InputElement();
form2.append(el3);
el3.type = 'radio';
el3.name = RADIO_GROUP_NAME;
- nodeBind(el3).bind('checked', model, 'val3');
+ nodeBind(el3).bind('checked', new PathObserver(model, 'val3'));
var el4 = new InputElement();
form2.append(el4);
el4.type = 'radio';
el4.name = RADIO_GROUP_NAME;
- nodeBind(el4).bind('checked', model, 'val4');
+ nodeBind(el4).bind('checked', new PathObserver(model, 'val4'));
- performMicrotaskCheckpoint();
- expect(el1.checked, true);
- expect(el2.checked, false);
- expect(el3.checked, false);
- expect(el4.checked, true);
+ return new Future(() {
+ expect(el1.checked, true);
+ expect(el2.checked, false);
+ expect(el3.checked, false);
+ expect(el4.checked, true);
- el2.checked = true;
- dispatchEvent('change', el2);
- expect(model['val1'], false);
- expect(model['val2'], true);
+ el2.checked = true;
+ dispatchEvent('change', el2);
+ expect(model['val1'], false);
+ expect(model['val2'], true);
- // Radio buttons in form2 should be unaffected
- expect(model['val3'], false);
- expect(model['val4'], true);
+ // Radio buttons in form2 should be unaffected
+ expect(model['val3'], false);
+ expect(model['val4'], true);
- el3.checked = true;
- dispatchEvent('change', el3);
- expect(model['val3'], true);
- expect(model['val4'], false);
+ el3.checked = true;
+ dispatchEvent('change', el3);
+ expect(model['val3'], true);
+ expect(model['val4'], false);
- // Radio buttons in form1 should be unaffected
- expect(model['val1'], false);
- expect(model['val2'], true);
+ // Radio buttons in form1 should be unaffected
+ expect(model['val1'], false);
+ expect(model['val2'], true);
+ });
}
- observeTest('(Radio)Input.checked - multiple forms', () {
- radioInputCheckedMultipleForms(testDiv);
+ test('Radio Input.checked - multiple forms', () {
+ return radioInputCheckedMultipleForms(testDiv);
});
- observeTest('(Radio)Input.checked 2 - ShadowRoot', () {
- if (!ShadowRoot.supported) return;
+ test('Radio Input.checked - multiple forms - ShadowRoot', () {
+ if (!ShadowRoot.supported) return null;
var shadowRoot = new DivElement().createShadowRoot();
- radioInputChecked2(shadowRoot);
- unbindAll(shadowRoot);
+ return radioInputCheckedMultipleForms(shadowRoot)
+ .whenComplete(() => unbindAll(shadowRoot));
});
- observeTest('Select.selectedIndex', () {
+ test('Select.selectedIndex', () {
var select = new SelectElement();
testDiv.append(select);
var option0 = select.append(new OptionElement());
@@ -561,16 +623,28 @@
var model = toObservable({'val': 2});
- nodeBind(select).bind('selectedIndex', model, 'val');
- performMicrotaskCheckpoint();
- expect(select.selectedIndex, 2);
+ nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val'));
+ return new Future(() {
+ expect(select.selectedIndex, 2);
- select.selectedIndex = 1;
- dispatchEvent('change', select);
- expect(model['val'], 1);
+ select.selectedIndex = 1;
+ dispatchEvent('change', select);
+ expect(model['val'], 1);
+ });
});
- observeTest('Select.selectedIndex - path NaN', () {
+ test('Select.selectedIndex - oneTime', () {
+ var select = new SelectElement();
+ testDiv.append(select);
+ var option0 = select.append(new OptionElement());
+ var option1 = select.append(new OptionElement());
+ var option2 = select.append(new OptionElement());
+
+ nodeBind(select).bind('selectedIndex', 2, oneTime: true);
+ return new Future(() => expect(select.selectedIndex, 2));
+ });
+
+ test('Select.selectedIndex - invalid path', () {
var select = new SelectElement();
testDiv.append(select);
var option0 = select.append(new OptionElement());
@@ -580,12 +654,11 @@
var model = toObservable({'val': 'foo'});
- nodeBind(select).bind('selectedIndex', model, 'val');
- performMicrotaskCheckpoint();
- expect(select.selectedIndex, 0);
+ nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val'));
+ return new Future(() => expect(select.selectedIndex, 0));
});
- observeTest('Select.selectedIndex - path unreachable', () {
+ test('Select.selectedIndex - path unreachable', () {
var select = new SelectElement();
testDiv.append(select);
var option0 = select.append(new OptionElement());
@@ -595,24 +668,28 @@
var model = toObservable({});
- nodeBind(select).bind('selectedIndex', model, 'val');
- performMicrotaskCheckpoint();
- expect(select.selectedIndex, 0);
+ nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val'));
+ return new Future(() => expect(select.selectedIndex, 0));
});
- observeTest('Option.value', () {
+ test('Option.value', () {
var option = testDiv.append(new OptionElement());
var model = toObservable({'x': 42});
- nodeBind(option).bind('value', model, 'x');
+ nodeBind(option).bind('value', new PathObserver(model, 'x'));
expect(option.value, '42');
model['x'] = 'Hi';
expect(option.value, '42');
- performMicrotaskCheckpoint();
- expect(option.value, 'Hi');
+ return new Future(() => expect(option.value, 'Hi'));
});
- observeTest('Select.value', () {
+ test('Option.value - oneTime', () {
+ var option = testDiv.append(new OptionElement());
+ nodeBind(option).bind('value', 42, oneTime: true);
+ expect(option.value, '42');
+ });
+
+ test('Select.value', () {
var select = testDiv.append(new SelectElement());
testDiv.append(select);
var option0 = select.append(new OptionElement());
@@ -626,25 +703,26 @@
'selected': 'b'
});
- nodeBind(option0).bind('value', model, 'opt0');
- nodeBind(option1).bind('value', model, 'opt1');
- nodeBind(option2).bind('value', model, 'opt2');
+ nodeBind(option0).bind('value', new PathObserver(model, 'opt0'));
+ nodeBind(option1).bind('value', new PathObserver(model, 'opt1'));
+ nodeBind(option2).bind('value', new PathObserver(model, 'opt2'));
- nodeBind(select).bind('value', model, 'selected');
- performMicrotaskCheckpoint();
- expect(select.value, 'b');
+ nodeBind(select).bind('value', new PathObserver(model, 'selected'));
+ return new Future(() {
+ expect(select.value, 'b');
- select.value = 'c';
- dispatchEvent('change', select);
- expect(model['selected'], 'c');
+ select.value = 'c';
+ dispatchEvent('change', select);
+ expect(model['selected'], 'c');
- model['opt2'] = 'X';
- performMicrotaskCheckpoint();
- expect(select.value, 'X');
- expect(model['selected'], 'X');
+ model['opt2'] = 'X';
+ }).then(endOfMicrotask).then((_) {
+ expect(select.value, 'X');
+ expect(model['selected'], 'X');
- model['selected'] = 'a';
- performMicrotaskCheckpoint();
- expect(select.value, 'a');
+ model['selected'] = 'a';
+ }).then(endOfMicrotask).then((_) {
+ expect(select.value, 'a');
+ });
});
}
diff --git a/pkg/template_binding/test/template_binding_test.dart b/pkg/template_binding/test/template_binding_test.dart
index 7639d76..c2ac5a9 100644
--- a/pkg/template_binding/test/template_binding_test.dart
+++ b/pkg/template_binding/test/template_binding_test.dart
@@ -5,7 +5,6 @@
library template_binding.test.template_binding_test;
import 'dart:async';
-import 'dart:collection';
import 'dart:html';
import 'dart:math' as math;
import 'package:observe/observe.dart';
@@ -18,13 +17,13 @@
import 'utils.dart';
// Note: this file ported from
-// https://github.com/Polymer/TemplateBinding/blob/ed3266266e751b5ab1f75f8e0509d0d5f0ef35d8/tests/tests.js
+// https://github.com/Polymer/TemplateBinding/blob/fcb7a502794f19544f2d4b77c96eebb70830591d/tests/tests.js
// TODO(jmesserly): submit a small cleanup patch to original. I fixed some
// cases where "div" and "t" were unintentionally using the JS global scope;
// look for "assertNodesAre".
-main() {
+main() => dirtyCheckZone().run(() {
useHtmlConfiguration();
// Load MutationObserver polyfill in case IE needs it.
@@ -46,7 +45,7 @@
expect(MutationObserver.supported, true, reason: 'polyfill was loaded.');
});
- group('Template Instantiation', templateInstantiationTests);
+ group('Template', templateInstantiationTests);
group('Binding Delegate API', () {
group('with Observable', () {
@@ -59,7 +58,7 @@
});
group('Compat', compatTests);
-}
+});
var expando = new Expando('test');
void addExpandos(node) {
@@ -78,237 +77,710 @@
}
templateInstantiationTests() {
+ // Dart note: renamed some of these tests to have unique names
- observeTest('Template', () {
+ test('Bind (simple)', () {
var div = createTestHtml('<template bind={{}}>text</template>');
templateBind(div.firstChild).model = {};
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, 'text');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'text');
- templateBind(div.firstChild).model = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ // Dart note: null is used instead of undefined to clear the template.
+ templateBind(div.firstChild).model = null;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ templateBind(div.firstChild).model = 123;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'text');
+ });
});
- observeTest('Template bind, no parent', () {
+ test('oneTime-Bind', () {
+ var div = createTestHtml('<template bind="[[ bound ]]">text</template>');
+ var model = toObservable({'bound': 1});
+ templateBind(div.firstChild).model = model;
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'text');
+
+ model['bound'] = false;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'text');
+ });
+ });
+
+ test('Bind - no parent', () {
var div = createTestHtml('<template bind>text</template>');
var template = div.firstChild;
template.remove();
templateBind(template).model = {};
- performMicrotaskCheckpoint();
- expect(template.nodes.length, 0);
- expect(template.nextNode, null);
+ return new Future(() {
+ expect(template.nodes.length, 0);
+ expect(template.nextNode, null);
+ });
});
- observeTest('Template bind, no defaultView', () {
+ test('Bind - no defaultView', () {
var div = createTestHtml('<template bind>text</template>');
var template = div.firstChild;
var doc = document.implementation.createHtmlDocument('');
doc.adoptNode(div);
recursivelySetTemplateModel(template, {});
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ return new Future(() => expect(div.nodes.length, 1));
});
- observeTest('Template-Empty Bind', () {
+ test('Empty Bind', () {
var div = createTestHtml('<template bind>text</template>');
var template = div.firstChild;
templateBind(template).model = {};
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, 'text');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'text');
+ });
});
- observeTest('Template Bind If', () {
- var div = createTestHtml('<template bind if="{{ foo }}">text</template>');
- // Note: changed this value from 0->null because zero is not falsey in Dart.
+ test('Bind If', () {
+ var div = createTestHtml(
+ '<template bind="{{ bound }}" if="{{ predicate }}">'
+ 'value:{{ value }}'
+ '</template>');
+ // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
// See https://code.google.com/p/dart/issues/detail?id=11956
- var m = toObservable({ 'foo': null });
+ // Changed bound from null->1 since null is equivalent to JS undefined,
+ // and would cause the template to not be expanded.
+ var m = toObservable({ 'predicate': null, 'bound': 1 });
var template = div.firstChild;
templateBind(template).model = m;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ return new Future(() {
+ expect(div.nodes.length, 1);
- m['foo'] = 1;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.lastChild.text, 'text');
+ m['predicate'] = 1;
- templateBind(template).model = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:');
+
+ m['bound'] = toObservable({ 'value': 2 });
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:2');
+
+ m['bound']['value'] = 3;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ templateBind(template).model = null;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
});
- observeTest('Template Bind If, 2', () {
+ test('Bind oneTime-If - predicate false', () {
+ var div = createTestHtml(
+ '<template bind="{{ bound }}" if="[[ predicate ]]">'
+ 'value:{{ value }}'
+ '</template>');
+ // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
+ // See https://code.google.com/p/dart/issues/detail?id=11956
+ // Changed bound from null->1 since null is equivalent to JS undefined,
+ // and would cause the template to not be expanded.
+ var m = toObservable({ 'predicate': null, 'bound': 1 });
+ var template = div.firstChild;
+ templateBind(template).model = m;
+
+ return new Future(() {
+ expect(div.nodes.length, 1);
+
+ m['predicate'] = 1;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+
+ m['bound'] = toObservable({ 'value': 2 });
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+
+ m['bound']['value'] = 3;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+
+ templateBind(template).model = null;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('Bind oneTime-If - predicate true', () {
+ var div = createTestHtml(
+ '<template bind="{{ bound }}" if="[[ predicate ]]">'
+ 'value:{{ value }}'
+ '</template>');
+
+ // Dart note: changed bound from null->1 since null is equivalent to JS
+ // undefined, and would cause the template to not be expanded.
+ var m = toObservable({ 'predicate': 1, 'bound': 1 });
+ var template = div.firstChild;
+ templateBind(template).model = m;
+
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:');
+
+ m['bound'] = toObservable({ 'value': 2 });
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:2');
+
+ m['bound']['value'] = 3;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ m['predicate'] = null; // will have no effect
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ templateBind(template).model = null;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('oneTime-Bind If', () {
+ var div = createTestHtml(
+ '<template bind="[[ bound ]]" if="{{ predicate }}">'
+ 'value:{{ value }}'
+ '</template>');
+
+ var m = toObservable({'predicate': null, 'bound': {'value': 2}});
+ var template = div.firstChild;
+ templateBind(template).model = m;
+
+ return new Future(() {
+ expect(div.nodes.length, 1);
+
+ m['predicate'] = 1;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:2');
+
+ m['bound']['value'] = 3;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ m['bound'] = toObservable({'value': 4 });
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ templateBind(template).model = null;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('oneTime-Bind oneTime-If', () {
+ var div = createTestHtml(
+ '<template bind="[[ bound ]]" if="[[ predicate ]]">'
+ 'value:{{ value }}'
+ '</template>');
+
+ var m = toObservable({'predicate': 1, 'bound': {'value': 2}});
+ var template = div.firstChild;
+ templateBind(template).model = m;
+
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:2');
+
+ m['bound']['value'] = 3;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ m['bound'] = toObservable({'value': 4 });
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ m['predicate'] = false;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'value:3');
+
+ templateBind(template).model = null;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('Bind If, 2', () {
var div = createTestHtml(
'<template bind="{{ foo }}" if="{{ bar }}">{{ bat }}</template>');
var m = toObservable({ 'bar': null, 'foo': { 'bat': 'baz' } });
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ return new Future(() {
+ expect(div.nodes.length, 1);
- m['bar'] = 1;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.lastChild.text, 'baz');
+ m['bar'] = 1;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'baz');
+ });
});
- observeTest('Template If', () {
+ test('If', () {
var div = createTestHtml('<template if="{{ foo }}">{{ value }}</template>');
- // Note: changed this value from 0->null because zero is not falsey in
- // Dart. See https://code.google.com/p/dart/issues/detail?id=11956
+ // Dart note: foo changed from 0->null because 0 isn't falsey in Dart.
+ // See https://code.google.com/p/dart/issues/detail?id=11956
var m = toObservable({ 'foo': null, 'value': 'foo' });
var template = div.firstChild;
templateBind(template).model = m;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ return new Future(() {
+ expect(div.nodes.length, 1);
- m['foo'] = 1;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.lastChild.text, 'foo');
+ m['foo'] = 1;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'foo');
- templateBind(template).model = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ templateBind(template).model = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
});
- observeTest('Template Empty-If', () {
+ test('Empty-If', () {
var div = createTestHtml('<template if>{{ value }}</template>');
var m = toObservable({ 'value': 'foo' });
recursivelySetTemplateModel(div, null);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ return new Future(() {
+ expect(div.nodes.length, 1);
- recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.lastChild.text, 'foo');
+ recursivelySetTemplateModel(div, m);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'foo');
+ });
});
- observeTest('Template Repeat If', () {
+ test('OneTime - simple text', () {
+ var div = createTestHtml('<template bind>[[ value ]]</template>');
+ var m = toObservable({ 'value': 'foo' });
+ recursivelySetTemplateModel(div, m);
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'foo');
+
+ m['value'] = 'bar';
+
+ }).then(endOfMicrotask).then((_) {
+ // unchanged.
+ expect(div.lastChild.text, 'foo');
+ });
+ });
+
+ test('OneTime - compound text', () {
var div = createTestHtml(
- '<template repeat="{{ foo }}" if="{{ bar }}">{{ }}</template>');
- // Note: changed this value from 0->null because zero is not falsey in Dart.
+ '<template bind>[[ foo ]] bar [[ baz ]]</template>');
+ var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' });
+ recursivelySetTemplateModel(div, m);
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'FOO bar BAZ');
+
+ m['foo'] = 'FI';
+ m['baz'] = 'BA';
+
+ }).then(endOfMicrotask).then((_) {
+ // unchanged.
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'FOO bar BAZ');
+ });
+ });
+
+ test('OneTime/Dynamic Mixed - compound text', () {
+ var div = createTestHtml(
+ '<template bind>[[ foo ]] bar {{ baz }}</template>');
+ var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' });
+ recursivelySetTemplateModel(div, m);
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'FOO bar BAZ');
+
+ m['foo'] = 'FI';
+ m['baz'] = 'BA';
+
+ }).then(endOfMicrotask).then((_) {
+ // unchanged [[ foo ]].
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.text, 'FOO bar BA');
+ });
+ });
+
+ test('OneTime - simple attribute', () {
+ var div = createTestHtml(
+ '<template bind><div foo="[[ value ]]"></div></template>');
+ var m = toObservable({ 'value': 'foo' });
+ recursivelySetTemplateModel(div, m);
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.attributes['foo'], 'foo');
+
+ m['value'] = 'bar';
+
+ }).then(endOfMicrotask).then((_) {
+ // unchanged.
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.attributes['foo'], 'foo');
+ });
+ });
+
+ test('OneTime - compound attribute', () {
+ var div = createTestHtml(
+ '<template bind>'
+ '<div foo="[[ value ]]:[[ otherValue ]]"></div>'
+ '</template>');
+ var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' });
+ recursivelySetTemplateModel(div, m);
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.attributes['foo'], 'foo:bar');
+
+ m['value'] = 'baz';
+ m['otherValue'] = 'bot';
+
+ }).then(endOfMicrotask).then((_) {
+ // unchanged.
+ expect(div.lastChild.attributes['foo'], 'foo:bar');
+ });
+ });
+
+ test('OneTime/Dynamic mixed - compound attribute', () {
+ var div = createTestHtml(
+ '<template bind>'
+ '<div foo="{{ value }}:[[ otherValue ]]"></div>'
+ '</template>');
+ var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' });
+ recursivelySetTemplateModel(div, m);
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.lastChild.attributes['foo'], 'foo:bar');
+
+ m['value'] = 'baz';
+ m['otherValue'] = 'bot';
+
+ }).then(endOfMicrotask).then((_) {
+ // unchanged [[ otherValue ]].
+ expect(div.lastChild.attributes['foo'], 'baz:bar');
+ });
+ });
+
+ test('Repeat If', () {
+ var div = createTestHtml(
+ '<template repeat="{{ items }}" if="{{ predicate }}">{{}}</template>');
+ // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
// See https://code.google.com/p/dart/issues/detail?id=11956
- var m = toObservable({ 'bar': null, 'foo': [1, 2, 3] });
+ var m = toObservable({ 'predicate': null, 'items': [1] });
var template = div.firstChild;
templateBind(template).model = m;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ return new Future(() {
+ expect(div.nodes.length, 1);
- m['bar'] = 1;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
- expect(div.nodes[1].text, '1');
- expect(div.nodes[2].text, '2');
- expect(div.nodes[3].text, '3');
+ m['predicate'] = 1;
- templateBind(template).model = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ m['items']..add(2)..add(3);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
+ expect(div.nodes[1].text, '1');
+ expect(div.nodes[2].text, '2');
+ expect(div.nodes[3].text, '3');
+
+ m['items'] = [4];
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '4');
+
+ templateBind(template).model = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
});
- observeTest('TextTemplateWithNullStringBinding', () {
+ test('Repeat oneTime-If (predicate false)', () {
+ var div = createTestHtml(
+ '<template repeat="{{ items }}" if="[[ predicate ]]">{{}}</template>');
+ // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
+ // See https://code.google.com/p/dart/issues/detail?id=11956
+ var m = toObservable({ 'predicate': null, 'items': [1] });
+ var template = div.firstChild;
+ templateBind(template).model = m;
+ return new Future(() {
+ expect(div.nodes.length, 1);
+
+ m['predicate'] = 1;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1, reason: 'unchanged');
+
+ m['items']..add(2)..add(3);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1, reason: 'unchanged');
+
+ m['items'] = [4];
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1, reason: 'unchanged');
+
+ templateBind(template).model = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('Repeat oneTime-If (predicate true)', () {
+ var div = createTestHtml(
+ '<template repeat="{{ items }}" if="[[ predicate ]]">{{}}</template>');
+
+ var m = toObservable({ 'predicate': true, 'items': [1] });
+ var template = div.firstChild;
+ templateBind(template).model = m;
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ m['items']..add(2)..add(3);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
+ expect(div.nodes[1].text, '1');
+ expect(div.nodes[2].text, '2');
+ expect(div.nodes[3].text, '3');
+
+ m['items'] = [4];
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '4');
+
+ m['predicate'] = false;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2, reason: 'unchanged');
+ expect(div.nodes[1].text, '4', reason: 'unchanged');
+
+ templateBind(template).model = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('oneTime-Repeat If', () {
+ var div = createTestHtml(
+ '<template repeat="[[ items ]]" if="{{ predicate }}">{{}}</template>');
+
+ var m = toObservable({ 'predicate': false, 'items': [1] });
+ var template = div.firstChild;
+ templateBind(template).model = m;
+ return new Future(() {
+ expect(div.nodes.length, 1);
+
+ m['predicate'] = true;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ m['items']..add(2)..add(3);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ m['items'] = [4];
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ templateBind(template).model = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('oneTime-Repeat oneTime-If', () {
+ var div = createTestHtml(
+ '<template repeat="[[ items ]]" if="[[ predicate ]]">{{}}</template>');
+
+ var m = toObservable({ 'predicate': true, 'items': [1] });
+ var template = div.firstChild;
+ templateBind(template).model = m;
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ m['items']..add(2)..add(3);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ m['items'] = [4];
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ m['predicate'] = false;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes[1].text, '1');
+
+ templateBind(template).model = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
+ });
+
+ test('TextTemplateWithNullStringBinding', () {
var div = createTestHtml('<template bind={{}}>a{{b}}c</template>');
var model = toObservable({'b': 'B'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, 'aBc');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'aBc');
- model['b'] = 'b';
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, 'abc');
+ model['b'] = 'b';
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, 'abc');
- model['b'] = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, 'ac');
+ model['b'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, 'ac');
- model = null;
- performMicrotaskCheckpoint();
- // setting model isn't observable.
- expect(div.nodes.last.text, 'ac');
+ model = null;
+ }).then(endOfMicrotask).then((_) {
+ // setting model isn't bindable.
+ expect(div.nodes.last.text, 'ac');
+ });
});
- observeTest('TextTemplateWithBindingPath', () {
+ test('TextTemplateWithBindingPath', () {
var div = createTestHtml(
'<template bind="{{ data }}">a{{b}}c</template>');
var model = toObservable({ 'data': {'b': 'B'} });
var template = div.firstChild;
templateBind(template).model = model;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, 'aBc');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'aBc');
- model['data']['b'] = 'b';
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, 'abc');
+ model['data']['b'] = 'b';
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, 'abc');
- model['data'] = toObservable({'b': 'X'});
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, 'aXc');
+ model['data'] = toObservable({'b': 'X'});
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, 'aXc');
- // Dart note: changed from `null` since our null means don't render a model.
- model['data'] = toObservable({});
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, 'ac');
+ // Dart note: changed from `null` since our null means don't render a model.
+ model['data'] = toObservable({});
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, 'ac');
- model['data'] = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ model['data'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
});
- observeTest('TextTemplateWithBindingAndConditional', () {
+ test('TextTemplateWithBindingAndConditional', () {
var div = createTestHtml(
'<template bind="{{}}" if="{{ d }}">a{{b}}c</template>');
var model = toObservable({'b': 'B', 'd': 1});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, 'aBc');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'aBc');
- model['b'] = 'b';
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, 'abc');
+ model['b'] = 'b';
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, 'abc');
- // TODO(jmesserly): MDV set this to empty string and relies on JS conversion
- // rules. Is that intended?
- // See https://github.com/toolkitchen/mdv/issues/59
- model['d'] = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ // TODO(jmesserly): MDV set this to empty string and relies on JS conversion
+ // rules. Is that intended?
+ // See https://github.com/Polymer/TemplateBinding/issues/59
+ model['d'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
- model['d'] = 'here';
- model['b'] = 'd';
+ model['d'] = 'here';
+ model['b'] = 'd';
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, 'adc');
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'adc');
+ });
});
- observeTest('TemplateWithTextBinding2', () {
+ test('TemplateWithTextBinding2', () {
var div = createTestHtml(
'<template bind="{{ b }}">a{{value}}c</template>');
expect(div.nodes.length, 1);
var model = toObservable({'b': {'value': 'B'}});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.text, 'aBc');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.text, 'aBc');
- model['b'] = toObservable({'value': 'b'});
- performMicrotaskCheckpoint();
- expect(div.nodes.last.text, 'abc');
+ model['b'] = toObservable({'value': 'b'});
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.text, 'abc');
+ });
});
- observeTest('TemplateWithAttributeBinding', () {
+ test('TemplateWithAttributeBinding', () {
var div = createTestHtml(
'<template bind="{{}}">'
'<div foo="a{{b}}c"></div>'
@@ -316,20 +788,21 @@
var model = toObservable({'b': 'B'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.attributes['foo'], 'aBc');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.attributes['foo'], 'aBc');
- model['b'] = 'b';
- performMicrotaskCheckpoint();
- expect(div.nodes.last.attributes['foo'], 'abc');
+ model['b'] = 'b';
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.attributes['foo'], 'abc');
- model['b'] = 'X';
- performMicrotaskCheckpoint();
- expect(div.nodes.last.attributes['foo'], 'aXc');
+ model['b'] = 'X';
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.attributes['foo'], 'aXc');
+ });
});
- observeTest('TemplateWithConditionalBinding', () {
+ test('TemplateWithConditionalBinding', () {
var div = createTestHtml(
'<template bind="{{}}">'
'<div foo?="{{b}}"></div>'
@@ -337,40 +810,91 @@
var model = toObservable({'b': 'b'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.attributes['foo'], '');
- expect(div.nodes.last.attributes, isNot(contains('foo?')));
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.attributes['foo'], '');
+ expect(div.nodes.last.attributes, isNot(contains('foo?')));
- model['b'] = null;
- performMicrotaskCheckpoint();
- expect(div.nodes.last.attributes, isNot(contains('foo')));
+ model['b'] = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.attributes, isNot(contains('foo')));
+ });
});
- observeTest('Repeat', () {
+ test('Repeat', () {
var div = createTestHtml(
- '<template repeat="{{}}"">text</template>');
+ '<template repeat="{{ array }}">{{}},</template>');
+
+ var model = toObservable({'array': [0, 1, 2]});
+ var template = templateBind(div.firstChild);
+ template.model = model;
+
+ return new Future(() {
+ expect(div.nodes.length, 4);
+ expect(div.text, '0,1,2,');
+
+ model['array'].length = 1;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
+ expect(div.text, '0,');
+
+ model['array'].addAll([3, 4]);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
+ expect(div.text, '0,3,4,');
+
+ model['array'].removeRange(1, 2);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 3);
+ expect(div.text, '0,4,');
+
+ model['array'].addAll([5, 6]);
+ model['array'] = toObservable(['x', 'y']);
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 3);
+ expect(div.text, 'x,y,');
+
+ template.model = null;
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ expect(div.text, '');
+ });
+ });
+
+ test('Repeat - oneTime', () {
+ var div = createTestHtml('<template repeat="[[]]">text</template>');
var model = toObservable([0, 1, 2]);
- recursivelySetTemplateModel(div, model);
+ var template = templateBind(div.firstChild);
+ template.model = model;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
+ return new Future(() {
+ expect(div.nodes.length, 4);
- model.length = 1;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
+ model.length = 1;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
- model.addAll(toObservable([3, 4]));
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
+ model.addAll([3, 4]);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
- model.removeRange(1, 2);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 3);
+ model.removeRange(1, 2);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
+
+ template.model = null;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
+ });
});
- observeTest('Repeat - Reuse Instances', () {
+ test('Repeat - Reuse Instances', () {
var div = createTestHtml('<template repeat>{{ val }}</template>');
var model = toObservable([
@@ -381,157 +905,164 @@
{'val': 1}
]);
recursivelySetTemplateModel(div, model);
-
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 6);
var template = div.firstChild;
- addExpandos(template.nextNode);
- checkExpandos(template.nextNode);
+ return new Future(() {
+ expect(div.nodes.length, 6);
- model.sort((a, b) => a['val'] - b['val']);
- performMicrotaskCheckpoint();
- checkExpandos(template.nextNode);
+ addExpandos(template.nextNode);
+ checkExpandos(template.nextNode);
- model = toObservable(model.reversed);
- recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- checkExpandos(template.nextNode);
+ model.sort((a, b) => a['val'] - b['val']);
+ }).then(endOfMicrotask).then((_) {
+ checkExpandos(template.nextNode);
- for (var item in model) {
- item['val'] += 1;
- }
+ model = toObservable(model.reversed);
+ recursivelySetTemplateModel(div, model);
+ }).then(endOfMicrotask).then((_) {
+ checkExpandos(template.nextNode);
- performMicrotaskCheckpoint();
- expect(div.nodes[1].text, "11");
- expect(div.nodes[2].text, "9");
- expect(div.nodes[3].text, "6");
- expect(div.nodes[4].text, "3");
- expect(div.nodes[5].text, "2");
+ for (var item in model) {
+ item['val'] += 1;
+ }
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes[1].text, "11");
+ expect(div.nodes[2].text, "9");
+ expect(div.nodes[3].text, "6");
+ expect(div.nodes[4].text, "3");
+ expect(div.nodes[5].text, "2");
+ });
});
- observeTest('Bind - Reuse Instance', () {
+ test('Bind - Reuse Instance', () {
var div = createTestHtml(
'<template bind="{{ foo }}">{{ bar }}</template>');
var model = toObservable({ 'foo': { 'bar': 5 }});
recursivelySetTemplateModel(div, model);
-
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
var template = div.firstChild;
- addExpandos(template.nextNode);
- checkExpandos(template.nextNode);
+ return new Future(() {
+ expect(div.nodes.length, 2);
- model = toObservable({'foo': model['foo']});
- recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- checkExpandos(template.nextNode);
+ addExpandos(template.nextNode);
+ checkExpandos(template.nextNode);
+
+ model = toObservable({'foo': model['foo']});
+ recursivelySetTemplateModel(div, model);
+ }).then(endOfMicrotask).then((_) {
+ checkExpandos(template.nextNode);
+ });
});
- observeTest('Repeat-Empty', () {
+ test('Repeat-Empty', () {
var div = createTestHtml(
'<template repeat>text</template>');
var model = toObservable([0, 1, 2]);
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
+ return new Future(() {
+ expect(div.nodes.length, 4);
- model.length = 1;
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
+ model.length = 1;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 2);
- model.addAll(toObservable([3, 4]));
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
+ model.addAll(toObservable([3, 4]));
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
- model.removeRange(1, 2);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 3);
+ model.removeRange(1, 2);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 3);
+ });
});
- observeTest('Removal from iteration needs to unbind', () {
+ test('Removal from iteration needs to unbind', () {
var div = createTestHtml(
'<template repeat="{{}}"><a>{{v}}</a></template>');
var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3},
{'v': 4}]);
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- var nodes = div.nodes.skip(1).toList();
- var vs = model.toList();
+ var nodes, vs;
+ return new Future(() {
- for (var i = 0; i < 5; i++) {
- expect(nodes[i].text, '$i');
- }
+ nodes = div.nodes.skip(1).toList();
+ vs = model.toList();
- model.length = 3;
- performMicrotaskCheckpoint();
- for (var i = 0; i < 5; i++) {
- expect(nodes[i].text, '$i');
- }
+ for (var i = 0; i < 5; i++) {
+ expect(nodes[i].text, '$i');
+ }
- vs[3]['v'] = 33;
- vs[4]['v'] = 44;
- performMicrotaskCheckpoint();
- for (var i = 0; i < 5; i++) {
- expect(nodes[i].text, '$i');
- }
+ model.length = 3;
+ }).then(endOfMicrotask).then((_) {
+ for (var i = 0; i < 5; i++) {
+ expect(nodes[i].text, '$i');
+ }
+
+ vs[3]['v'] = 33;
+ vs[4]['v'] = 44;
+ }).then(endOfMicrotask).then((_) {
+ for (var i = 0; i < 5; i++) {
+ expect(nodes[i].text, '$i');
+ }
+ });
});
- observeTest('DOM Stability on Iteration', () {
+ test('DOM Stability on Iteration', () {
var div = createTestHtml(
'<template repeat="{{}}">{{}}</template>');
var model = toObservable([1, 2, 3, 4, 5]);
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
+ var nodes;
+ return new Future(() {
+ // Note: the node at index 0 is the <template>.
+ nodes = div.nodes.toList();
+ expect(nodes.length, 6, reason: 'list has 5 items');
- // Note: the node at index 0 is the <template>.
- var nodes = div.nodes.toList();
- expect(nodes.length, 6, reason: 'list has 5 items');
+ model.removeAt(0);
+ model.removeLast();
- model.removeAt(0);
- model.removeLast();
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4, reason: 'list has 3 items');
+ expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed');
+ expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed');
+ expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed');
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4, reason: 'list has 3 items');
- expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed');
- expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed');
- expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed');
+ model.insert(0, 5);
+ model[2] = 6;
+ model.add(7);
- model.insert(0, 5);
- model[2] = 6;
- model.add(7);
+ }).then(endOfMicrotask).then((_) {
- performMicrotaskCheckpoint();
+ expect(div.nodes.length, 6, reason: 'list has 5 items');
+ expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node');
+ expect(identical(div.nodes[2], nodes[2]), true);
+ expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node');
+ expect(identical(div.nodes[4], nodes[4]), true);
+ expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node');
- expect(div.nodes.length, 6, reason: 'list has 5 items');
- expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node');
- expect(identical(div.nodes[2], nodes[2]), true);
- expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node');
- expect(identical(div.nodes[4], nodes[4]), true);
- expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node');
+ nodes = div.nodes.toList();
- nodes = div.nodes.toList();
+ model.insert(2, 8);
- model.insert(2, 8);
+ }).then(endOfMicrotask).then((_) {
- performMicrotaskCheckpoint();
-
- expect(div.nodes.length, 7, reason: 'list has 6 items');
- expect(identical(div.nodes[1], nodes[1]), true);
- expect(identical(div.nodes[2], nodes[2]), true);
- expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node');
- expect(identical(div.nodes[4], nodes[3]), true);
- expect(identical(div.nodes[5], nodes[4]), true);
- expect(identical(div.nodes[6], nodes[5]), true);
+ expect(div.nodes.length, 7, reason: 'list has 6 items');
+ expect(identical(div.nodes[1], nodes[1]), true);
+ expect(identical(div.nodes[2], nodes[2]), true);
+ expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node');
+ expect(identical(div.nodes[4], nodes[3]), true);
+ expect(identical(div.nodes[5], nodes[4]), true);
+ expect(identical(div.nodes[6], nodes[5]), true);
+ });
});
- observeTest('Repeat2', () {
+ test('Repeat2', () {
var div = createTestHtml(
'<template repeat="{{}}">{{value}}</template>');
expect(div.nodes.length, 1);
@@ -543,28 +1074,29 @@
]);
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
- expect(div.nodes[1].text, '0');
- expect(div.nodes[2].text, '1');
- expect(div.nodes[3].text, '2');
+ return new Future(() {
+ expect(div.nodes.length, 4);
+ expect(div.nodes[1].text, '0');
+ expect(div.nodes[2].text, '1');
+ expect(div.nodes[3].text, '2');
- model[1]['value'] = 'One';
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
- expect(div.nodes[1].text, '0');
- expect(div.nodes[2].text, 'One');
- expect(div.nodes[3].text, '2');
+ model[1]['value'] = 'One';
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
+ expect(div.nodes[1].text, '0');
+ expect(div.nodes[2].text, 'One');
+ expect(div.nodes[3].text, '2');
- model.replaceRange(0, 1, toObservable([{'value': 'Zero'}]));
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
- expect(div.nodes[1].text, 'Zero');
- expect(div.nodes[2].text, 'One');
- expect(div.nodes[3].text, '2');
+ model.replaceRange(0, 1, toObservable([{'value': 'Zero'}]));
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 4);
+ expect(div.nodes[1].text, 'Zero');
+ expect(div.nodes[2].text, 'One');
+ expect(div.nodes[3].text, '2');
+ });
});
- observeTest('TemplateWithInputValue', () {
+ test('TemplateWithInputValue', () {
var div = createTestHtml(
'<template bind="{{}}">'
'<input value="{{x}}">'
@@ -572,25 +1104,26 @@
var model = toObservable({'x': 'hi'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes.last.value, 'hi');
+ return new Future(() {
+ expect(div.nodes.length, 2);
+ expect(div.nodes.last.value, 'hi');
- model['x'] = 'bye';
- expect(div.nodes.last.value, 'hi');
- performMicrotaskCheckpoint();
- expect(div.nodes.last.value, 'bye');
+ model['x'] = 'bye';
+ expect(div.nodes.last.value, 'hi');
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.value, 'bye');
- div.nodes.last.value = 'hello';
- dispatchEvent('input', div.nodes.last);
- expect(model['x'], 'hello');
- performMicrotaskCheckpoint();
- expect(div.nodes.last.value, 'hello');
+ div.nodes.last.value = 'hello';
+ dispatchEvent('input', div.nodes.last);
+ expect(model['x'], 'hello');
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.last.value, 'hello');
+ });
});
//////////////////////////////////////////////////////////////////////////////
- observeTest('Decorated', () {
+ test('Decorated', () {
var div = createTestHtml(
'<template bind="{{ XX }}" id="t1">'
'<p>Crew member: {{name}}, Job title: {{title}}</p>'
@@ -604,24 +1137,24 @@
});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ var t1 = document.getElementById('t1');
+ var instance = t1.nextElementSibling;
+ expect(instance.text, 'Crew member: Leela, Job title: Captain');
- var t1 = document.getElementById('t1');
- var instance = t1.nextElementSibling;
- expect(instance.text, 'Crew member: Leela, Job title: Captain');
+ var t2 = document.getElementById('t2');
+ instance = t2.nextElementSibling;
+ expect(instance.text, 'Crew member: Fry, Job title: Delivery boy');
- var t2 = document.getElementById('t2');
- instance = t2.nextElementSibling;
- expect(instance.text, 'Crew member: Fry, Job title: Delivery boy');
+ expect(div.children.length, 4);
+ expect(div.nodes.length, 4);
- expect(div.children.length, 4);
- expect(div.nodes.length, 4);
-
- expect(div.nodes[1].tagName, 'P');
- expect(div.nodes[3].tagName, 'P');
+ expect(div.nodes[1].tagName, 'P');
+ expect(div.nodes[3].tagName, 'P');
+ });
});
- observeTest('DefaultStyles', () {
+ test('DefaultStyles', () {
var t = new Element.tag('template');
TemplateBindExtension.decorate(t);
@@ -632,40 +1165,24 @@
});
- observeTest('Bind', () {
+ test('Bind', () {
var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>');
var model = toObservable({'name': 'Leela'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes[1].text, 'Hi Leela');
+ return new Future(() => expect(div.nodes[1].text, 'Hi Leela'));
});
- observeTest('BindImperative', () {
- var div = createTestHtml(
- '<template>'
- 'Hi {{ name }}'
- '</template>');
- var t = div.nodes.first;
-
- var model = toObservable({'name': 'Leela'});
- nodeBind(t).bind('bind', model, '');
-
- performMicrotaskCheckpoint();
- expect(div.nodes[1].text, 'Hi Leela');
- });
-
- observeTest('BindPlaceHolderHasNewLine', () {
+ test('BindPlaceHolderHasNewLine', () {
var div = createTestHtml(
'<template bind="{{}}">Hi {{\nname\n}}</template>');
var model = toObservable({'name': 'Leela'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes[1].text, 'Hi Leela');
+ return new Future(() => expect(div.nodes[1].text, 'Hi Leela'));
});
- observeTest('BindWithRef', () {
+ test('BindWithRef', () {
var id = 't${new math.Random().nextInt(100)}';
var div = createTestHtml(
'<template id="$id">'
@@ -681,11 +1198,35 @@
var model = toObservable({'name': 'Fry'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(t2.nextNode.text, 'Hi Fry');
+ return new Future(() => expect(t2.nextNode.text, 'Hi Fry'));
});
- observeTest('BindWithDynamicRef', () {
+
+ test('Update Ref', () {
+ var div = createTestHtml(
+ '<template id=A>Hi, {{}}</template>'
+ '<template id=B>Hola, {{}}</template>'
+ '<template ref=A repeat></template>');
+
+ var model = new ObservableList.from(['Fry']);
+ recursivelySetTemplateModel(div, model);
+
+ return new Future(() {
+ expect(div.nodes.length, 4);
+ expect('Hi, Fry', div.nodes[3].text);
+
+ div.nodes[2].attributes['ref'] = 'B';
+ model.add('Leela');
+
+ }).then(endOfMicrotask).then((x) {
+ expect(div.nodes.length, 5);
+
+ expect('Hi, Fry', div.nodes[3].text);
+ expect('Hola, Leela', div.nodes[4].text);
+ });
+ });
+
+ test('BindWithDynamicRef', () {
var id = 't${new math.Random().nextInt(100)}';
var div = createTestHtml(
'<template id="$id">'
@@ -698,33 +1239,7 @@
var model = toObservable({'name': 'Fry', 'id': id });
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(t2.nextNode.text, 'Hi Fry');
- });
-
- observeTest('BindChanged', () {
- var model = toObservable({
- 'XX': {'name': 'Leela', 'title': 'Captain'},
- 'XY': {'name': 'Fry', 'title': 'Delivery boy'},
- 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'}
- });
-
- var div = createTestHtml(
- '<template bind="{{ XX }}">Hi {{ name }}</template>');
-
- recursivelySetTemplateModel(div, model);
-
- var t = div.nodes.first;
- performMicrotaskCheckpoint();
-
- expect(div.nodes.length, 2);
- expect(t.nextNode.text, 'Hi Leela');
-
- nodeBind(t).bind('bind', model, 'XZ');
- performMicrotaskCheckpoint();
-
- expect(div.nodes.length, 2);
- expect(t.nextNode.text, 'Hi Zoidberg');
+ return new Future(() => expect(t2.nextNode.text, 'Hi Fry'));
});
assertNodesAre(div, [arguments]) {
@@ -737,7 +1252,7 @@
}
}
- observeTest('Repeat3', () {
+ test('Repeat3', () {
var div = createTestHtml(
'<template repeat="{{ contacts }}">Hi {{ name }}</template>');
var t = div.nodes.first;
@@ -751,44 +1266,45 @@
});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
- assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+ assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
- m['contacts'].add(toObservable({'name': 'Alex'}));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
+ m['contacts'].add(toObservable({'name': 'Alex'}));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
- m['contacts'].replaceRange(0, 2,
- toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
+ m['contacts'].replaceRange(0, 2,
+ toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
- m['contacts'].removeRange(1, 3);
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
+ m['contacts'].removeRange(1, 3);
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
- m['contacts'].insertAll(1,
- toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
+ m['contacts'].insertAll(1,
+ toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
- m['contacts'].replaceRange(0, 1,
- toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
- 'Hi Alex']);
+ m['contacts'].replaceRange(0, 1,
+ toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
+ 'Hi Alex']);
- m['contacts'] = toObservable([{'name': 'Alex'}]);
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Alex']);
+ m['contacts'] = toObservable([{'name': 'Alex'}]);
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Alex']);
- m['contacts'].length = 0;
- performMicrotaskCheckpoint();
- assertNodesAre(div, []);
+ m['contacts'].length = 0;
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, []);
+ });
});
- observeTest('RepeatModelSet', () {
+ test('RepeatModelSet', () {
var div = createTestHtml(
'<template repeat="{{ contacts }}">'
'Hi {{ name }}'
@@ -801,14 +1317,13 @@
]
});
recursivelySetTemplateModel(div, m);
-
- performMicrotaskCheckpoint();
- var t = div.nodes.first;
-
- assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+ return new Future(() {
+ var t = div.nodes.first;
+ assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+ });
});
- observeTest('RepeatEmptyPath', () {
+ test('RepeatEmptyPath', () {
var div = createTestHtml(
'<template repeat="{{}}">Hi {{ name }}</template>');
var t = div.nodes.first;
@@ -819,39 +1334,39 @@
{'name': 'Neal'}
]);
recursivelySetTemplateModel(div, m);
+ return new Future(() {
- performMicrotaskCheckpoint();
+ assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
- assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+ m.add(toObservable({'name': 'Alex'}));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
- m.add(toObservable({'name': 'Alex'}));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
+ m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
- m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
+ m.removeRange(1, 3);
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
- m.removeRange(1, 3);
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
+ m.insertAll(1, toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
- m.insertAll(1, toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
+ m.replaceRange(0, 1, toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
+ 'Hi Alex']);
- m.replaceRange(0, 1, toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
- 'Hi Alex']);
-
- m.length = 0;
- m.add(toObservable({'name': 'Alex'}));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Alex']);
+ m.length = 0;
+ m.add(toObservable({'name': 'Alex'}));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Alex']);
+ });
});
- observeTest('RepeatNullModel', () {
+ test('RepeatNullModel', () {
var div = createTestHtml(
'<template repeat="{{}}">Hi {{ name }}</template>');
var t = div.nodes.first;
@@ -864,12 +1379,10 @@
t.attributes['iterate'] = '';
m = toObservable({});
recursivelySetTemplateModel(div, m);
-
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ return new Future(() => expect(div.nodes.length, 1));
});
- observeTest('RepeatReuse', () {
+ test('RepeatReuse', () {
var div = createTestHtml(
'<template repeat="{{}}">Hi {{ name }}</template>');
var t = div.nodes.first;
@@ -880,60 +1393,61 @@
{'name': 'Neal'}
]);
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
- var node1 = div.nodes[1];
- var node2 = div.nodes[2];
- var node3 = div.nodes[3];
+ var node1, node2, node3;
+ return new Future(() {
+ assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+ node1 = div.nodes[1];
+ node2 = div.nodes[2];
+ node3 = div.nodes[3];
- m.replaceRange(1, 2, toObservable([{'name': 'Erik'}]));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']);
- expect(div.nodes[1], node1,
- reason: 'model[0] did not change so the node should not have changed');
- expect(div.nodes[2], isNot(equals(node2)),
- reason: 'Should not reuse when replacing');
- expect(div.nodes[3], node3,
- reason: 'model[2] did not change so the node should not have changed');
+ m.replaceRange(1, 2, toObservable([{'name': 'Erik'}]));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']);
+ expect(div.nodes[1], node1,
+ reason: 'model[0] did not change so the node should not have changed');
+ expect(div.nodes[2], isNot(equals(node2)),
+ reason: 'Should not reuse when replacing');
+ expect(div.nodes[3], node3,
+ reason: 'model[2] did not change so the node should not have changed');
- node2 = div.nodes[2];
- m.insert(0, toObservable({'name': 'Alex'}));
- performMicrotaskCheckpoint();
- assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']);
+ node2 = div.nodes[2];
+ m.insert(0, toObservable({'name': 'Alex'}));
+ }).then(endOfMicrotask).then((_) {
+ assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']);
+ });
});
- observeTest('TwoLevelsDeepBug', () {
+ test('TwoLevelsDeepBug', () {
var div = createTestHtml(
'<template bind="{{}}"><span><span>{{ foo }}</span></span></template>');
var model = toObservable({'foo': 'bar'});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
-
- expect(div.nodes[1].nodes[0].nodes[0].text, 'bar');
+ return new Future(() {
+ expect(div.nodes[1].nodes[0].nodes[0].text, 'bar');
+ });
});
- observeTest('Checked', () {
+ test('Checked', () {
var div = createTestHtml(
- '<template>'
+ '<template bind>'
'<input type="checkbox" checked="{{a}}">'
'</template>');
var t = div.nodes.first;
- var m = toObservable({
- 'a': true
+ templateBind(t).model = toObservable({'a': true });
+
+ return new Future(() {
+
+ var instanceInput = t.nextNode;
+ expect(instanceInput.checked, true);
+
+ instanceInput.click();
+ expect(instanceInput.checked, false);
+
+ instanceInput.click();
+ expect(instanceInput.checked, true);
});
- nodeBind(t).bind('bind', m, '');
- performMicrotaskCheckpoint();
-
- var instanceInput = t.nextNode;
- expect(instanceInput.checked, true);
-
- instanceInput.click();
- expect(instanceInput.checked, false);
-
- instanceInput.click();
- expect(instanceInput.checked, true);
});
nestedHelper(s, start) {
@@ -947,40 +1461,37 @@
});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
- var i = start;
- expect(div.nodes[i++].text, '1');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, '2');
+ var i = start;
+ expect(div.nodes[i++].text, '1');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, '2');
- m['a']['b'] = 11;
- performMicrotaskCheckpoint();
- expect(div.nodes[start].text, '11');
+ m['a']['b'] = 11;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes[start].text, '11');
- m['a']['c'] = toObservable({'d': 22});
- performMicrotaskCheckpoint();
- expect(div.nodes[start + 2].text, '22');
+ m['a']['c'] = toObservable({'d': 22});
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes[start + 2].text, '22');
+ });
}
- observeTest('Nested', () {
- nestedHelper(
- '<template bind="{{a}}">'
- '{{b}}'
- '<template bind="{{c}}">'
- '{{d}}'
- '</template>'
- '</template>', 1);
- });
+ test('Nested', () => nestedHelper(
+ '<template bind="{{a}}">'
+ '{{b}}'
+ '<template bind="{{c}}">'
+ '{{d}}'
+ '</template>'
+ '</template>', 1));
- observeTest('NestedWithRef', () {
- nestedHelper(
+ test('NestedWithRef', () => nestedHelper(
'<template id="inner">{{d}}</template>'
'<template id="outer" bind="{{a}}">'
'{{b}}'
'<template ref="inner" bind="{{c}}"></template>'
- '</template>', 2);
- });
+ '</template>', 2));
nestedIterateInstantiateHelper(s, start) {
var div = createTestHtml(s);
@@ -999,46 +1510,43 @@
});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
- var i = start;
- expect(div.nodes[i++].text, '1');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, '11');
- expect(div.nodes[i++].text, '2');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, '22');
+ var i = start;
+ expect(div.nodes[i++].text, '1');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, '11');
+ expect(div.nodes[i++].text, '2');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, '22');
- m['a'][1] = toObservable({
- 'b': 3,
- 'c': {'d': 33}
+ m['a'][1] = toObservable({
+ 'b': 3,
+ 'c': {'d': 33}
+ });
+
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes[start + 3].text, '3');
+ expect(div.nodes[start + 5].text, '33');
});
-
- performMicrotaskCheckpoint();
- expect(div.nodes[start + 3].text, '3');
- expect(div.nodes[start + 5].text, '33');
}
- observeTest('NestedRepeatBind', () {
- nestedIterateInstantiateHelper(
- '<template repeat="{{a}}">'
- '{{b}}'
- '<template bind="{{c}}">'
- '{{d}}'
- '</template>'
- '</template>', 1);
- });
-
- observeTest('NestedRepeatBindWithRef', () {
- nestedIterateInstantiateHelper(
- '<template id="inner">'
+ test('NestedRepeatBind', () => nestedIterateInstantiateHelper(
+ '<template repeat="{{a}}">'
+ '{{b}}'
+ '<template bind="{{c}}">'
'{{d}}'
'</template>'
- '<template repeat="{{a}}">'
- '{{b}}'
- '<template ref="inner" bind="{{c}}"></template>'
- '</template>', 2);
- });
+ '</template>', 1));
+
+ test('NestedRepeatBindWithRef', () => nestedIterateInstantiateHelper(
+ '<template id="inner">'
+ '{{d}}'
+ '</template>'
+ '<template repeat="{{a}}">'
+ '{{b}}'
+ '<template ref="inner" bind="{{c}}"></template>'
+ '</template>', 2));
nestedIterateIterateHelper(s, start) {
var div = createTestHtml(s);
@@ -1057,53 +1565,50 @@
});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
- var i = start;
- expect(div.nodes[i++].text, '1');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, '11');
- expect(div.nodes[i++].text, '12');
- expect(div.nodes[i++].text, '2');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, '21');
- expect(div.nodes[i++].text, '22');
+ var i = start;
+ expect(div.nodes[i++].text, '1');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, '11');
+ expect(div.nodes[i++].text, '12');
+ expect(div.nodes[i++].text, '2');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, '21');
+ expect(div.nodes[i++].text, '22');
- m['a'][1] = toObservable({
- 'b': 3,
- 'c': [{'d': 31}, {'d': 32}, {'d': 33}]
+ m['a'][1] = toObservable({
+ 'b': 3,
+ 'c': [{'d': 31}, {'d': 32}, {'d': 33}]
+ });
+
+ i = start + 4;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes[start + 4].text, '3');
+ expect(div.nodes[start + 6].text, '31');
+ expect(div.nodes[start + 7].text, '32');
+ expect(div.nodes[start + 8].text, '33');
});
-
- i = start + 4;
- performMicrotaskCheckpoint();
- expect(div.nodes[start + 4].text, '3');
- expect(div.nodes[start + 6].text, '31');
- expect(div.nodes[start + 7].text, '32');
- expect(div.nodes[start + 8].text, '33');
}
- observeTest('NestedRepeatBind', () {
- nestedIterateIterateHelper(
- '<template repeat="{{a}}">'
- '{{b}}'
- '<template repeat="{{c}}">'
- '{{d}}'
- '</template>'
- '</template>', 1);
- });
-
- observeTest('NestedRepeatRepeatWithRef', () {
- nestedIterateIterateHelper(
- '<template id="inner">'
+ test('NestedRepeatBind', () => nestedIterateIterateHelper(
+ '<template repeat="{{a}}">'
+ '{{b}}'
+ '<template repeat="{{c}}">'
'{{d}}'
'</template>'
- '<template repeat="{{a}}">'
- '{{b}}'
- '<template ref="inner" repeat="{{c}}"></template>'
- '</template>', 2);
- });
+ '</template>', 1));
- observeTest('NestedRepeatSelfRef', () {
+ test('NestedRepeatRepeatWithRef', () => nestedIterateIterateHelper(
+ '<template id="inner">'
+ '{{d}}'
+ '</template>'
+ '<template repeat="{{a}}">'
+ '{{b}}'
+ '<template ref="inner" repeat="{{c}}"></template>'
+ '</template>', 2));
+
+ test('NestedRepeatSelfRef', () {
var div = createTestHtml(
'<template id="t" repeat="{{}}">'
'{{name}}'
@@ -1135,26 +1640,27 @@
]);
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
- var i = 1;
- expect(div.nodes[i++].text, 'Item 1');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, 'Item 1.1');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, 'Item 1.1.1');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, 'Item 1.2');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, 'Item 2');
+ int i = 1;
+ return new Future(() {
+ expect(div.nodes[i++].text, 'Item 1');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, 'Item 1.1');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, 'Item 1.1.1');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, 'Item 1.2');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, 'Item 2');
- m[0] = toObservable({'name': 'Item 1 changed'});
+ m[0] = toObservable({'name': 'Item 1 changed'});
- i = 1;
- performMicrotaskCheckpoint();
- expect(div.nodes[i++].text, 'Item 1 changed');
- expect(div.nodes[i++].tagName, 'TEMPLATE');
- expect(div.nodes[i++].text, 'Item 2');
+ i = 1;
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes[i++].text, 'Item 1 changed');
+ expect(div.nodes[i++].tagName, 'TEMPLATE');
+ expect(div.nodes[i++].text, 'Item 2');
+ });
});
// Note: we don't need a zone for this test, and we don't want to alter timing
@@ -1211,8 +1717,8 @@
return completer.future;
});
- observeTest('NestedIterateTableMixedSemanticNative', () {
- if (!parserHasNativeTemplate) return;
+ test('NestedIterateTableMixedSemanticNative', () {
+ if (!parserHasNativeTemplate) return null;
var div = createTestHtml(
'<table><tbody>'
@@ -1229,30 +1735,30 @@
]);
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ var tbody = div.nodes[0].nodes[0];
- var tbody = div.nodes[0].nodes[0];
+ // 1 for the <tr template>, 2 * (1 tr)
+ expect(tbody.nodes.length, 3);
- // 1 for the <tr template>, 2 * (1 tr)
- expect(tbody.nodes.length, 3);
+ // 1 for the <td template>, 2 * (1 td)
+ expect(tbody.nodes[1].nodes.length, 3);
- // 1 for the <td template>, 2 * (1 td)
- expect(tbody.nodes[1].nodes.length, 3);
+ expect(tbody.nodes[1].nodes[1].text, '0');
+ expect(tbody.nodes[1].nodes[2].text, '1');
- expect(tbody.nodes[1].nodes[1].text, '0');
- expect(tbody.nodes[1].nodes[2].text, '1');
+ // 1 for the <td template>, 2 * (1 td)
+ expect(tbody.nodes[2].nodes.length, 3);
+ expect(tbody.nodes[2].nodes[1].text, '2');
+ expect(tbody.nodes[2].nodes[2].text, '3');
- // 1 for the <td template>, 2 * (1 td)
- expect(tbody.nodes[2].nodes.length, 3);
- expect(tbody.nodes[2].nodes[1].text, '2');
- expect(tbody.nodes[2].nodes[2].text, '3');
-
- // Asset the 'class' binding is retained on the semantic template (just
- // check the last one).
- expect(tbody.nodes[2].nodes[2].attributes["class"], '3');
+ // Asset the 'class' binding is retained on the semantic template (just
+ // check the last one).
+ expect(tbody.nodes[2].nodes[2].attributes["class"], '3');
+ });
});
- observeTest('NestedIterateTable', () {
+ test('NestedIterateTable', () {
var div = createTestHtml(
'<table><tbody>'
'<tr template repeat="{{}}">'
@@ -1266,30 +1772,31 @@
]);
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
- var i = 1;
- var tbody = div.nodes[0].nodes[0];
+ var i = 1;
+ var tbody = div.nodes[0].nodes[0];
- // 1 for the <tr template>, 2 * (1 tr)
- expect(tbody.nodes.length, 3);
+ // 1 for the <tr template>, 2 * (1 tr)
+ expect(tbody.nodes.length, 3);
- // 1 for the <td template>, 2 * (1 td)
- expect(tbody.nodes[1].nodes.length, 3);
- expect(tbody.nodes[1].nodes[1].text, '0');
- expect(tbody.nodes[1].nodes[2].text, '1');
+ // 1 for the <td template>, 2 * (1 td)
+ expect(tbody.nodes[1].nodes.length, 3);
+ expect(tbody.nodes[1].nodes[1].text, '0');
+ expect(tbody.nodes[1].nodes[2].text, '1');
- // 1 for the <td template>, 2 * (1 td)
- expect(tbody.nodes[2].nodes.length, 3);
- expect(tbody.nodes[2].nodes[1].text, '2');
- expect(tbody.nodes[2].nodes[2].text, '3');
+ // 1 for the <td template>, 2 * (1 td)
+ expect(tbody.nodes[2].nodes.length, 3);
+ expect(tbody.nodes[2].nodes[1].text, '2');
+ expect(tbody.nodes[2].nodes[2].text, '3');
- // Asset the 'class' binding is retained on the semantic template (just
- // check the last one).
- expect(tbody.nodes[2].nodes[2].attributes['class'], '3');
+ // Asset the 'class' binding is retained on the semantic template (just
+ // check the last one).
+ expect(tbody.nodes[2].nodes[2].attributes['class'], '3');
+ });
});
- observeTest('NestedRepeatDeletionOfMultipleSubTemplates', () {
+ test('NestedRepeatDeletionOfMultipleSubTemplates', () {
var div = createTestHtml(
'<ul>'
'<template repeat="{{}}" id=t1>'
@@ -1313,13 +1820,10 @@
]);
recursivelySetTemplateModel(div, m);
-
- performMicrotaskCheckpoint();
- m.removeAt(0);
- performMicrotaskCheckpoint();
+ return new Future(() => m.removeAt(0));
});
- observeTest('DeepNested', () {
+ test('DeepNested', () {
var div = createTestHtml(
'<template bind="{{a}}">'
'<p>'
@@ -1337,34 +1841,36 @@
}
});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
-
- expect(div.nodes[1].tagName, 'P');
- expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE');
- expect(div.nodes[1].nodes[1].text, '42');
+ return new Future(() {
+ expect(div.nodes[1].tagName, 'P');
+ expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE');
+ expect(div.nodes[1].nodes[1].text, '42');
+ });
});
- observeTest('TemplateContentRemoved', () {
+ test('TemplateContentRemoved', () {
var div = createTestHtml('<template bind="{{}}">{{ }}</template>');
var model = 42;
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes[1].text, '42');
- expect(div.nodes[0].text, '');
+ return new Future(() {
+ expect(div.nodes[1].text, '42');
+ expect(div.nodes[0].text, '');
+ });
});
- observeTest('TemplateContentRemovedEmptyArray', () {
+ test('TemplateContentRemovedEmptyArray', () {
var div = createTestHtml('<template iterate>Remove me</template>');
var model = toObservable([]);
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
- expect(div.nodes[0].text, '');
+ return new Future(() {
+ expect(div.nodes.length, 1);
+ expect(div.nodes[0].text, '');
+ });
});
- observeTest('TemplateContentRemovedNested', () {
+ test('TemplateContentRemovedNested', () {
var div = createTestHtml(
'<template bind="{{}}">'
'{{ a }}'
@@ -1378,35 +1884,36 @@
'b': 2
});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
-
- expect(div.nodes[0].text, '');
- expect(div.nodes[1].text, '1');
- expect(div.nodes[2].text, '');
- expect(div.nodes[3].text, '2');
+ return new Future(() {
+ expect(div.nodes[0].text, '');
+ expect(div.nodes[1].text, '1');
+ expect(div.nodes[2].text, '');
+ expect(div.nodes[3].text, '2');
+ });
});
- observeTest('BindWithUndefinedModel', () {
+ test('BindWithUndefinedModel', () {
var div = createTestHtml(
'<template bind="{{}}" if="{{}}">{{ a }}</template>');
var model = toObservable({'a': 42});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes[1].text, '42');
+ return new Future(() {
+ expect(div.nodes[1].text, '42');
- model = null;
- recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 1);
+ model = null;
+ recursivelySetTemplateModel(div, model);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 1);
- model = toObservable({'a': 42});
- recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
- expect(div.nodes[1].text, '42');
+ model = toObservable({'a': 42});
+ recursivelySetTemplateModel(div, model);
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes[1].text, '42');
+ });
});
- observeTest('BindNested', () {
+ test('BindNested', () {
var div = createTestHtml(
'<template bind="{{}}">'
'Name: {{ name }}'
@@ -1425,24 +1932,24 @@
}
});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ expect(div.nodes.length, 5);
+ expect(div.nodes[1].text, 'Name: Hermes');
+ expect(div.nodes[3].text, 'Wife: LaBarbara');
- expect(div.nodes.length, 5);
- expect(div.nodes[1].text, 'Name: Hermes');
- expect(div.nodes[3].text, 'Wife: LaBarbara');
+ m['child'] = toObservable({'name': 'Dwight'});
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 6);
+ expect(div.nodes[5].text, 'Child: Dwight');
- m['child'] = toObservable({'name': 'Dwight'});
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 6);
- expect(div.nodes[5].text, 'Child: Dwight');
-
- m.remove('wife');
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 5);
- expect(div.nodes[4].text, 'Child: Dwight');
+ m.remove('wife');
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 5);
+ expect(div.nodes[4].text, 'Child: Dwight');
+ });
});
- observeTest('BindRecursive', () {
+ test('BindRecursive', () {
var div = createTestHtml(
'<template bind="{{}}" if="{{}}" id="t">'
'Name: {{ name }}'
@@ -1456,24 +1963,24 @@
}
});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ expect(div.nodes.length, 5);
+ expect(div.nodes[1].text, 'Name: Fry');
+ expect(div.nodes[3].text, 'Name: Bender');
- expect(div.nodes.length, 5);
- expect(div.nodes[1].text, 'Name: Fry');
- expect(div.nodes[3].text, 'Name: Bender');
+ m['friend']['friend'] = toObservable({'name': 'Leela'});
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 7);
+ expect(div.nodes[5].text, 'Name: Leela');
- m['friend']['friend'] = toObservable({'name': 'Leela'});
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 7);
- expect(div.nodes[5].text, 'Name: Leela');
-
- m['friend'] = toObservable({'name': 'Leela'});
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 5);
- expect(div.nodes[3].text, 'Name: Leela');
+ m['friend'] = toObservable({'name': 'Leela'});
+ }).then(endOfMicrotask).then((_) {
+ expect(div.nodes.length, 5);
+ expect(div.nodes[3].text, 'Name: Leela');
+ });
});
- observeTest('Template - Self is terminator', () {
+ test('Template - Self is terminator', () {
var div = createTestHtml(
'<template repeat>{{ foo }}'
'<template bind></template>'
@@ -1481,37 +1988,38 @@
var m = toObservable([{ 'foo': 'bar' }]);
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ return new Future(() {
- m.add(toObservable({ 'foo': 'baz' }));
- recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ m.add(toObservable({ 'foo': 'baz' }));
+ recursivelySetTemplateModel(div, m);
+ }).then(endOfMicrotask).then((_) {
- expect(div.nodes.length, 5);
- expect(div.nodes[1].text, 'bar');
- expect(div.nodes[3].text, 'baz');
+ expect(div.nodes.length, 5);
+ expect(div.nodes[1].text, 'bar');
+ expect(div.nodes[3].text, 'baz');
+ });
});
- observeTest('Template - Same Contents, Different Array has no effect', () {
- if (!MutationObserver.supported) return;
+ test('Template - Same Contents, Different Array has no effect', () {
+ if (!MutationObserver.supported) return null;
var div = createTestHtml('<template repeat>{{ foo }}</template>');
var m = toObservable([{ 'foo': 'bar' }, { 'foo': 'bat'}]);
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
+ var observer = new MutationObserver((x, y) {});
+ return new Future(() {
+ observer.observe(div, childList: true);
- var observer = new MutationObserver((records, _) {});
- observer.observe(div, childList: true);
-
- var template = div.firstChild;
- nodeBind(template).bind('repeat', toObservable(m.toList()), '');
- performMicrotaskCheckpoint();
- var records = observer.takeRecords();
- expect(records.length, 0);
+ var template = div.firstChild;
+ templateBind(template).model = new ObservableList.from(m);
+ }).then(endOfMicrotask).then((_) {
+ var records = observer.takeRecords();
+ expect(records.length, 0);
+ });
});
- observeTest('RecursiveRef', () {
+ test('RecursiveRef', () {
var div = createTestHtml(
'<template bind>'
'<template id=src>{{ foo }}</template>'
@@ -1520,54 +2028,13 @@
var m = toObservable({'foo': 'bar'});
recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
-
- expect(div.nodes.length, 4);
- expect(div.nodes[3].text, 'bar');
- });
-
- observeTest('ChangeFromBindToRepeat', () {
- var div = createTestHtml(
- '<template bind="{{a}}">'
- '{{ length }}'
- '</template>');
- var template = div.nodes.first;
-
- // Note: this test data is a little different from the JS version, because
- // we allow binding to the "length" field of the Map in preference to
- // binding keys.
- var m = toObservable({
- 'a': [
- [],
- { 'b': [1,2,3,4] },
- // Note: this will use the Map "length" property, not the "length" key.
- {'length': 42, 'c': 123}
- ]
+ return new Future(() {
+ expect(div.nodes.length, 4);
+ expect(div.nodes[3].text, 'bar');
});
- recursivelySetTemplateModel(div, m);
- performMicrotaskCheckpoint();
-
- expect(div.nodes.length, 2);
- expect(div.nodes[1].text, '3');
-
- nodeBind(template)
- ..unbind('bind')
- ..bind('repeat', m, 'a');
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 4);
- expect(div.nodes[1].text, '0');
- expect(div.nodes[2].text, '1');
- expect(div.nodes[3].text, '2');
-
- nodeBind(template).unbind('repeat');
- nodeBind(template).bind('bind', m, 'a.1.b');
-
- performMicrotaskCheckpoint();
- expect(div.nodes.length, 2);
- expect(div.nodes[1].text, '4');
});
- observeTest('ChangeRefId', () {
+ test('ChangeRefId', () {
var div = createTestHtml(
'<template id="a">a:{{ }}</template>'
'<template id="b">b:{{ }}</template>'
@@ -1576,22 +2043,22 @@
'</template>');
var model = toObservable([]);
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ expect(div.nodes.length, 3);
- expect(div.nodes.length, 3);
+ document.getElementById('a').id = 'old-a';
+ document.getElementById('b').id = 'a';
- document.getElementById('a').id = 'old-a';
- document.getElementById('b').id = 'a';
+ model..add(1)..add(2);
+ }).then(endOfMicrotask).then((_) {
- model..add(1)..add(2);
- performMicrotaskCheckpoint();
-
- expect(div.nodes.length, 7);
- expect(div.nodes[4].text, 'b:1');
- expect(div.nodes[6].text, 'b:2');
+ expect(div.nodes.length, 7);
+ expect(div.nodes[4].text, 'b:1');
+ expect(div.nodes[6].text, 'b:2');
+ });
});
- observeTest('Content', () {
+ test('Content', () {
var div = createTestHtml(
'<template><a></a></template>'
'<template><b></b></template>');
@@ -1620,7 +2087,7 @@
expect(contentB.nodes.first.tagName, 'B');
});
- observeTest('NestedContent', () {
+ test('NestedContent', () {
var div = createTestHtml(
'<template>'
'<template></template>'
@@ -1634,46 +2101,44 @@
templateBind(templateA).content.ownerDocument);
});
- observeTest('BindShadowDOM', () {
- if (ShadowRoot.supported) {
- var root = createShadowTestHtml(
- '<template bind="{{}}">Hi {{ name }}</template>');
- var model = toObservable({'name': 'Leela'});
- recursivelySetTemplateModel(root, model);
- performMicrotaskCheckpoint();
- expect(root.nodes[1].text, 'Hi Leela');
- }
+ test('BindShadowDOM', () {
+ if (!ShadowRoot.supported) return null;
+
+ var root = createShadowTestHtml(
+ '<template bind="{{}}">Hi {{ name }}</template>');
+ var model = toObservable({'name': 'Leela'});
+ recursivelySetTemplateModel(root, model);
+ return new Future(() => expect(root.nodes[1].text, 'Hi Leela'));
});
// Dart note: this test seems gone from JS. Keeping for posterity sake.
- observeTest('BindShadowDOM createInstance', () {
- if (ShadowRoot.supported) {
- var model = toObservable({'name': 'Leela'});
- var template = new Element.html('<template>Hi {{ name }}</template>');
- var root = createShadowTestHtml('');
- root.nodes.add(templateBind(template).createInstance(model));
+ test('BindShadowDOM createInstance', () {
+ if (!ShadowRoot.supported) return null;
- performMicrotaskCheckpoint();
+ var model = toObservable({'name': 'Leela'});
+ var template = new Element.html('<template>Hi {{ name }}</template>');
+ var root = createShadowTestHtml('');
+ root.nodes.add(templateBind(template).createInstance(model));
+
+ return new Future(() {
expect(root.text, 'Hi Leela');
model['name'] = 'Fry';
- performMicrotaskCheckpoint();
+ }).then(endOfMicrotask).then((_) {
expect(root.text, 'Hi Fry');
- }
+ });
});
- observeTest('BindShadowDOM Template Ref', () {
- if (ShadowRoot.supported) {
- var root = createShadowTestHtml(
- '<template id=foo>Hi</template><template bind ref=foo></template>');
- recursivelySetTemplateModel(root, toObservable({}));
- performMicrotaskCheckpoint();
- expect(root.nodes.length, 3);
- }
+ test('BindShadowDOM Template Ref', () {
+ if (!ShadowRoot.supported) return null;
+ var root = createShadowTestHtml(
+ '<template id=foo>Hi</template><template bind ref=foo></template>');
+ recursivelySetTemplateModel(root, toObservable({}));
+ return new Future(() => expect(root.nodes.length, 3));
});
- // https://github.com/toolkitchen/mdv/issues/8
- observeTest('UnbindingInNestedBind', () {
+ // https://github.com/Polymer/TemplateBinding/issues/8
+ test('UnbindingInNestedBind', () {
var div = createTestHtml(
'<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">'
'<template bind="{{inner}}" if="{{inner}}">'
@@ -1682,44 +2147,38 @@
'</template>');
var syntax = new UnbindingInNestedBindSyntax();
- var model = toObservable({
- 'outer': {
- 'inner': {
- 'age': 42
- }
- }
- });
+ var model = toObservable({'outer': {'inner': {'age': 42}}});
recursivelySetTemplateModel(div, model, syntax);
- performMicrotaskCheckpoint();
- expect(syntax.count, 1);
+ return new Future(() {
+ expect(syntax.count, 1);
- var inner = model['outer']['inner'];
- model['outer'] = null;
+ var inner = model['outer']['inner'];
+ model['outer'] = null;
- performMicrotaskCheckpoint();
- expect(syntax.count, 1);
+ }).then(endOfMicrotask).then((_) {
+ expect(syntax.count, 1);
- model['outer'] = toObservable({'inner': {'age': 2}});
- syntax.expectedAge = 2;
+ model['outer'] = toObservable({'inner': {'age': 2}});
+ syntax.expectedAge = 2;
- performMicrotaskCheckpoint();
- expect(syntax.count, 2);
+ }).then(endOfMicrotask).then((_) {
+ expect(syntax.count, 2);
+ });
});
// https://github.com/toolkitchen/mdv/issues/8
- observeTest('DontCreateInstancesForAbandonedIterators', () {
+ test('DontCreateInstancesForAbandonedIterators', () {
var div = createTestHtml(
'<template bind="{{}} {{}}">'
- '<template bind="{{}}">Foo'
- '</template>'
+ '<template bind="{{}}">Foo</template>'
'</template>');
recursivelySetTemplateModel(div, null);
- performMicrotaskCheckpoint();
+ return nextMicrotask;
});
- observeTest('CreateInstance', () {
+ test('CreateInstance', () {
var div = createTestHtml(
'<template bind="{{a}}">'
'<template bind="{{b}}">'
@@ -1735,11 +2194,35 @@
templateBind(instance.nodes.first).ref);
host.append(instance);
- performMicrotaskCheckpoint();
- expect(host.firstChild.nextNode.text, 'bar:replaced');
+ return new Future(() {
+ expect(host.firstChild.nextNode.text, 'bar:replaced');
+ });
});
- observeTest('Bootstrap', () {
+ test('Repeat - svg', () {
+ var div = createTestHtml(
+ '<svg width="400" height="110">'
+ '<template repeat>'
+ '<rect width="{{ width }}" height="{{ height }}" />'
+ '</template>'
+ '</svg>');
+
+ var model = toObservable([{ 'width': 10, 'height': 11 },
+ { 'width': 20, 'height': 21 }]);
+ var svg = div.firstChild;
+ var template = svg.firstChild;
+ templateBind(template).model = model;
+
+ return new Future(() {
+ expect(svg.nodes.length, 3);
+ expect(svg.nodes[1].attributes['width'], '10');
+ expect(svg.nodes[1].attributes['height'], '11');
+ expect(svg.nodes[2].attributes['width'], '20');
+ expect(svg.nodes[2].attributes['height'], '21');
+ });
+ });
+
+ test('Bootstrap', () {
var div = new DivElement();
div.innerHtml =
'<template>'
@@ -1773,7 +2256,7 @@
expect(template3.content.nodes.first.text, 'Hello');
});
- observeTest('issue-285', () {
+ test('issue-285', () {
var div = createTestHtml(
'<template>'
'<template bind if="{{show}}">'
@@ -1793,19 +2276,20 @@
div.append(templateBind(template).createInstance(model,
new Issue285Syntax()));
- performMicrotaskCheckpoint();
- expect(template.nextNode.nextNode.nextNode.text, '2');
- model['show'] = false;
- performMicrotaskCheckpoint();
- model['show'] = true;
- performMicrotaskCheckpoint();
- expect(template.nextNode.nextNode.nextNode.text, '2');
+ return new Future(() {
+ expect(template.nextNode.nextNode.nextNode.text, '2');
+ model['show'] = false;
+ }).then(endOfMicrotask).then((_) {
+ model['show'] = true;
+ }).then(endOfMicrotask).then((_) {
+ expect(template.nextNode.nextNode.nextNode.text, '2');
+ });
});
- observeTest('issue-141', () {
+ test('issue-141', () {
var div = createTestHtml(
- '<template bind>' +
- '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>' +
+ '<template bind>'
+ '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>'
'</template>');
var model = toObservable({
@@ -1815,14 +2299,40 @@
});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ expect(div.lastChild.attributes['bar'], 'barValue');
+ });
+ });
- expect(div.lastChild.attributes['bar'], 'barValue');
+ test('issue-18', () {
+ var delegate = new Issue18Syntax();
+
+ var div = createTestHtml(
+ '<template bind>'
+ '<div class="foo: {{ bar }}"></div>'
+ '</template>');
+
+ var model = toObservable({'bar': 2});
+
+ recursivelySetTemplateModel(div, model, delegate);
+
+ return new Future(() {
+ expect(div.lastChild.attributes['class'], 'foo: 2');
+ });
+ });
+
+ test('issue-152', () {
+ var div = createTestHtml('<template ref=notThere></template>');
+ var template = div.firstChild;
+
+ // if a ref cannot be located, a template will continue to use itself
+ // as the source of template instances.
+ expect(template, templateBind(template).ref);
});
}
compatTests() {
- observeTest('underbar bindings', () {
+ test('underbar bindings', () {
var div = createTestHtml(
'<template bind>'
'<div _style="color: {{ color }};"></div>'
@@ -1839,19 +2349,19 @@
});
recursivelySetTemplateModel(div, model);
- performMicrotaskCheckpoint();
+ return new Future(() {
+ var subDiv = div.firstChild.nextNode;
+ expect(subDiv.attributes['style'], 'color: red;');
- var subDiv = div.firstChild.nextNode;
- expect(subDiv.attributes['style'], 'color: red;');
+ var img = subDiv.nextNode;
+ expect(img.attributes['src'], 'pic.jpg');
- var img = subDiv.nextNode;
- expect(img.attributes['src'], 'pic.jpg');
+ var a = img.nextNode;
+ expect(a.attributes['href'], 'link.html');
- var a = img.nextNode;
- expect(a.attributes['href'], 'link.html');
-
- var input = a.nextNode;
- expect(input.value, '4');
+ var input = a.nextNode;
+ expect(input.value, '4');
+ });
});
}
@@ -1864,7 +2374,7 @@
class TestBindingSyntax extends BindingDelegate {
prepareBinding(String path, name, node) {
if (path.trim() == 'replaceme') {
- return (x, y) => new ObservableBox('replaced');
+ return (m, n, oneTime) => new PathObserver('replaced', '');
}
return null;
}
@@ -1877,10 +2387,18 @@
prepareBinding(path, name, node) {
if (name != 'text' || path != 'age') return null;
- return (model, node) {
+ return (model, _, oneTime) {
expect(model['age'], expectedAge);
count++;
- return model;
+ return new PathObserver(model, path);
};
}
}
+
+class Issue18Syntax extends BindingDelegate {
+ prepareBinding(path, name, node) {
+ if (name != 'class') return null;
+
+ return (model, _, oneTime) => new PathObserver(model, path);
+ }
+}
diff --git a/pkg/template_binding/test/utils.dart b/pkg/template_binding/test/utils.dart
index 92d63e4..11f7668 100644
--- a/pkg/template_binding/test/utils.dart
+++ b/pkg/template_binding/test/utils.dart
@@ -4,13 +4,23 @@
library template_binding.test.utils;
+import 'dart:async';
import 'dart:html';
import 'package:observe/observe.dart';
import 'package:template_binding/template_binding.dart';
-import 'package:unittest/unittest.dart';
+export 'package:observe/src/dirty_check.dart' show dirtyCheckZone;
-import 'package:observe/src/microtask.dart';
-export 'package:observe/src/microtask.dart';
+/// A small method to help readability. Used to cause the next "then" in a chain
+/// to happen in the next microtask:
+///
+/// future.then(newMicrotask).then(...)
+endOfMicrotask(_) => new Future.value();
+
+/// A small method to help readability. Used to cause the next "then" in a chain
+/// to happen in the next microtask, after a timer:
+///
+/// future.then(nextMicrotask).then(...)
+nextMicrotask(_) => new Future(() {});
final bool parserHasNativeTemplate = () {
var div = new DivElement()..innerHtml = '<table><template>';
@@ -57,10 +67,6 @@
}
}
-observeTest(name, testCase) => test(name, wrapMicrotask(testCase));
-
-solo_observeTest(name, testCase) => solo_test(name, wrapMicrotask(testCase));
-
DivElement testDiv;
createTestHtml(s) {
@@ -68,7 +74,7 @@
div.setInnerHtml(s, treeSanitizer: new NullTreeSanitizer());
testDiv.append(div);
- for (var node in div.queryAll('*')) {
+ for (var node in div.querySelectorAll('*')) {
if (isSemanticTemplate(node)) TemplateBindExtension.decorate(node);
}
diff --git a/pkg/unittest/CHANGELOG.md b/pkg/unittest/CHANGELOG.md
new file mode 100644
index 0000000..9392db2
--- /dev/null
+++ b/pkg/unittest/CHANGELOG.md
@@ -0,0 +1,19 @@
+# Changelog - unittest
+
+##0.10.0-dev
+
+* Each test is run in a seperate `Zone`. This ensures that any exceptions that
+occur is async operations are reported back to the source test case.
+* **DEPRECATED** `guardAsync`, `protectAsync0`, `protectAsync1`,
+and `protectAsync2`
+ * Running each test in a `Zone` addresses the need for these methods.
+* `TestCase`:
+ * Removed properties: `setUp`, `tearDown`, `testFunction`
+ * `enabled` is now get-only
+ * Removed methods: `pass`, `fail`, `error`
+* `interactive_html_config.dart` has been removed.
+* `runTests`, `tearDown`, `setUp`, `test`, `group`, `solo_test`, and
+ `solo_group` now throw a `StateError` if called while tests are running.
+* `rerunTests` has been removed.
+
+##0.9.3 - 2014-01-13
diff --git a/pkg/unittest/lib/html_config.dart b/pkg/unittest/lib/html_config.dart
index dd760bd..ef23d52 100644
--- a/pkg/unittest/lib/html_config.dart
+++ b/pkg/unittest/lib/html_config.dart
@@ -134,7 +134,7 @@
void onInit() {
// For Dart internal tests, we want to turn off stack frame
// filtering, which we do with this meta-header.
- var meta = query('meta[name="dart.unittest"]');
+ var meta = querySelector('meta[name="dart.unittest"]');
filterStacks = meta == null ? true :
!meta.content.contains('full-stack-traces');
_installHandlers();
diff --git a/pkg/unittest/lib/html_enhanced_config.dart b/pkg/unittest/lib/html_enhanced_config.dart
index f303f24..d434663 100644
--- a/pkg/unittest/lib/html_enhanced_config.dart
+++ b/pkg/unittest/lib/html_enhanced_config.dart
@@ -67,7 +67,7 @@
//initialize and load CSS
final String _CSSID = '_unittestcss_';
- var cssElement = document.head.query('#${_CSSID}');
+ var cssElement = document.head.querySelector('#${_CSSID}');
if (cssElement == null) {
cssElement = new StyleElement();
cssElement.id = _CSSID;
@@ -134,9 +134,9 @@
"""));
// handle the click event for the collapse all button
- te.query('#btnCollapseAll').onClick.listen((_){
+ te.querySelector('#btnCollapseAll').onClick.listen((_){
document
- .queryAll('.unittest-row')
+ .querySelectorAll('.unittest-row')
.forEach((el) => el.attributes['class'] = el.attributes['class']
.replaceAll('unittest-row ', 'unittest-row-hidden '));
});
@@ -207,16 +207,17 @@
</div>"""));
// 'safeGroup' could be empty
- var grp = (safeGroup == '') ? null : te.query('#${safeGroup}');
+ var grp = (safeGroup == '') ?
+ null : te.querySelector('#${safeGroup}');
if (grp != null) {
grp.onClick.listen((_) {
- var row = document.query('.unittest-row-${safeGroup}');
+ var row = document.querySelector('.unittest-row-${safeGroup}');
if (row.attributes['class'].contains('unittest-row ')){
- document.queryAll('.unittest-row-${safeGroup}').forEach(
+ document.querySelectorAll('.unittest-row-${safeGroup}').forEach(
(e) => e.attributes['class'] = e.attributes['class']
.replaceAll('unittest-row ', 'unittest-row-hidden '));
}else{
- document.queryAll('.unittest-row-${safeGroup}').forEach(
+ document.querySelectorAll('.unittest-row-${safeGroup}').forEach(
(e) => e.attributes['class'] = e.attributes['class']
.replaceAll('unittest-row-hidden', 'unittest-row'));
}
diff --git a/pkg/unittest/lib/interactive_html_config.dart b/pkg/unittest/lib/interactive_html_config.dart
deleted file mode 100644
index 46be199..0000000
--- a/pkg/unittest/lib/interactive_html_config.dart
+++ /dev/null
@@ -1,709 +0,0 @@
-// Copyright (c) 2013, 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.
-
-/**
- * This configuration can be used to rerun selected tests, as well
- * as see diagnostic output from tests. It runs each test in its own
- * IFrame, so the configuration consists of two parts - a 'parent'
- * config that manages all the tests, and a 'child' config for the
- * IFrame that runs the individual tests.
- *
- * Note: this unit test configuration will not work with the debugger (the tests
- * are executed in a separate IFrame).
- */
-library unittest.interactive_html_config;
-
-// TODO(gram) - add options for: remove IFrame on done/keep
-// IFrame for failed tests/keep IFrame for all tests.
-
-import 'dart:html';
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:stack_trace/stack_trace.dart';
-
-import 'unittest.dart';
-
-/** The messages exchanged between parent and child. */
-class _Message {
- static const START = 'start';
- static const LOG = 'log';
- static const STACK = 'stack';
- static const PASS = 'pass';
- static const FAIL = 'fail';
- static const ERROR = 'error';
- static const _PREFIX = 'TestMsg:';
-
- final String messageType;
- final int elapsed;
- final String body;
-
- static String text(String messageType,
- [int elapsed = 0, String body = '']) =>
- '$_PREFIX$messageType $elapsed $body';
-
- _Message(this.messageType, [this.elapsed = 0, this.body = '']);
-
- factory _Message.fromString(String msg) {
- if (!msg.startsWith(_PREFIX)) {
- return null;
- }
- int idx = msg.indexOf(' ', _PREFIX.length);
- var messageType = msg.substring(_PREFIX.length, idx);
- ++idx;
- int idx2 = msg.indexOf(' ', idx);
- var elapsed = int.parse(msg.substring(idx, idx2));
- ++idx2;
- var body = msg.substring(idx2);
-
- return new _Message(messageType, elapsed, body);
- }
-
- String toString() => text(messageType, elapsed, body);
-}
-
-
-class HtmlConfiguration extends SimpleConfiguration {
- StreamSubscription _errorSubscription;
-
- void _installErrorHandler() {
- if (_errorSubscription == null) {
- _errorSubscription = window.onError.listen((e) {
- handleExternalError(e, '(DOM callback has errors)');
- });
- }
- }
-
- void _uninstallErrorHandler() {
- if (_errorSubscription != null) {
- _errorSubscription.cancel();
- _errorSubscription = null;
- }
- }
-}
-
-/**
- * The child configuration that is used to run individual tests in
- * an IFrame and post the results back to the parent. In principle
- * this can run more than one test in the IFrame but currently only
- * one is used.
- */
-class ChildInteractiveHtmlConfiguration extends HtmlConfiguration {
-
- /** The window to which results must be posted. */
- WindowBase _parentWindow;
-
- /** The time at which tests start. */
- final Map<int, DateTime> _testStarts;
-
- ChildInteractiveHtmlConfiguration() :
- _testStarts = new Map<int,DateTime>();
-
- /** Don't start running tests automatically. */
- get autoStart => false;
-
- void onInit() {
- _installErrorHandler();
-
- /**
- * The parent posts a 'start' message to kick things off,
- * which is handled by this handler. It saves the parent
- * window, gets the test ID from the query parameter in the
- * IFrame URL, sets that as a solo test and starts test execution.
- */
- window.onMessage.listen((MessageEvent e) {
- // Get the result, do any logging, then do a pass/fail.
- var m = new _Message.fromString(e.data);
- if (m != null && m.messageType == _Message.START) {
- _parentWindow = e.source;
- String search = window.location.search;
- int pos = search.indexOf('t=');
- String ids = search.substring(pos + 2);
- int id = int.parse(ids);
- setSoloTest(id);
- runTests();
- }
- });
- }
-
- void onStart() {
- _installErrorHandler();
- }
-
- /** Record the start time of the test. */
- void onTestStart(TestCase testCase) {
- super.onTestStart(testCase);
- _testStarts[testCase.id] = new DateTime.now();
- }
-
- /**
- * Tests can call [logMessage] for diagnostic output. These log
- * messages in turn get passed to this method, which adds
- * a timestamp and posts them back to the parent window.
- */
- void onLogMessage(TestCase testCase, String message) {
- int elapsed;
- if (testCase == null) {
- elapsed = -1;
- } else {
- DateTime end = new DateTime.now();
- elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
- }
- _parentWindow.postMessage(
- _Message.text(_Message.LOG, elapsed, message).toString(), '*');
- }
-
- /**
- * Get the elapsed time for the test, and post the test result back to the
- * parent window. If the test failed due to an exception the stack is posted
- * back too (before the test result).
- */
- void onTestResult(TestCase testCase) {
- super.onTestResult(testCase);
- DateTime end = new DateTime.now();
- int elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
- if (testCase.stackTrace != null) {
- var message = JSON.encode(testCase.stackTrace.frames.map((frame) {
- return <String, dynamic> {
- "uri": frame.uri.toString(),
- "line": frame.line,
- "column": frame.column,
- "member": frame.member
- };
- }).toList());
- _parentWindow.postMessage(
- _Message.text(_Message.STACK, elapsed, message), '*');
- }
- _parentWindow.postMessage(
- _Message.text(testCase.result, elapsed, testCase.message), '*');
- }
- void onSummary(int passed, int failed, int errors, List<TestCase> results,
- String uncaughtError) {
- }
-
- void onDone(bool success) {
- _uninstallErrorHandler();
- }
-}
-
-/**
- * The parent configuration runs in the top-level window; it wraps the tests
- * in new functions that create child IFrames and run the real tests.
- */
-class ParentInteractiveHtmlConfiguration extends HtmlConfiguration {
- final Map<int, DateTime> _testStarts;
-
-
- /** The stack that was posted back from the child, if any. */
- Trace _stack;
-
- int _testTime;
- /**
- * Whether or not we have already wrapped the TestCase test functions
- * in new closures that instead create an IFrame and get it to run the
- * test.
- */
- bool _doneWrap = false;
-
- StreamSubscription _messageSubscription;
-
- ParentInteractiveHtmlConfiguration() :
- _testStarts = new Map<int,DateTime>();
-
- // We need to block until the test is done, so we make a
- // dummy async callback that we will use to flag completion.
- Function _completeTest = null;
-
- Function _wrapTest(TestCase testCase) {
- String baseUrl = window.location.toString();
- String url = '${baseUrl}?t=${testCase.id}';
- return () {
- // Rebuild the child IFrame.
- Element childDiv = document.query('#child');
- childDiv.nodes.clear();
- IFrameElement child = new Element.html("""
- <iframe id='childFrame${testCase.id}' src='$url' style='display:none'>
- </iframe>""");
- childDiv.nodes.add(child);
- _completeTest = expectAsync0((){ });
- // Kick off the test when the IFrame is loaded.
- child.onLoad.listen((e) {
- child.contentWindow.postMessage(_Message.text(_Message.START), '*');
- });
- };
- }
-
- void _handleMessage(MessageEvent e) {
- // Get the result, do any logging, then do a pass/fail.
- var msg = new _Message.fromString(e.data);
-
- if (msg == null) {
- return;
- }
- if (msg.messageType == _Message.LOG) {
- logMessage(e.data);
- } else if (msg.messageType == _Message.STACK) {
- _stack = new Trace(JSON.decode(msg.body).map((frame) {
- return new Frame(
- Uri.parse(frame['uri']),
- frame['line'],
- frame['column'],
- frame['member']);
- }));
- } else {
- _testTime = msg.elapsed;
- logMessage(_Message.text(_Message.LOG, _testTime, 'Complete'));
- if (msg.messageType == _Message.PASS) {
- currentTestCase.pass();
- } else if (msg.messageType == _Message.FAIL) {
- currentTestCase.fail(msg.body, _stack);
- } else if (msg.messageType == _Message.ERROR) {
- currentTestCase.error(msg.body, _stack);
- }
- _completeTest();
- }
- }
-
- void onInit() {
- _installErrorHandler();
- document.query('#group-divs').innerHtml = "";
- }
-
- void onStart() {
- _installErrorHandler();
- if (!_doneWrap) {
- _doneWrap = true;
- for (int i = 0; i < testCases.length; i++) {
- testCases[i].testFunction = _wrapTest(testCases[i]);
- testCases[i].setUp = null;
- testCases[i].tearDown = null;
- }
- }
- assert(_messageSubscription == null);
- _messageSubscription = window.onMessage.listen(_handleMessage);
- }
-
- static final _notAlphaNumeric = new RegExp('[^a-z0-9A-Z]');
-
- String _stringToDomId(String s) {
- if (s.length == 0) {
- return '-None-';
- }
- return s.trim().replaceAll(_notAlphaNumeric, '-');
- }
-
- // Used for DOM element IDs for tests result list entries.
- static const _testIdPrefix = 'test-';
- // Used for DOM element IDs for test log message lists.
- static const _actionIdPrefix = 'act-';
- // Used for DOM element IDs for test checkboxes.
- static const _selectedIdPrefix = 'selected-';
-
- void onTestStart(TestCase testCase) {
- var id = testCase.id;
- _testStarts[testCase.id] = new DateTime.now();
- super.onTestStart(testCase);
- _stack = null;
- // Convert the group name to a DOM id.
- String groupId = _stringToDomId(testCase.currentGroup);
- // Get the div for the group. If it doesn't exist,
- // create it.
- var groupDiv = document.query('#$groupId');
- if (groupDiv == null) {
- groupDiv = new Element.html("""
- <div class='test-describe' id='$groupId'>
- <h2>
- <input type='checkbox' checked='true' class='groupselect'>
- Group: ${testCase.currentGroup}
- </h2>
- <ul class='tests'>
- </ul>
- </div>""");
- document.query('#group-divs').nodes.add(groupDiv);
- groupDiv.query('.groupselect').onClick.listen((e) {
- var parent = document.query('#$groupId');
- InputElement cb = parent.query('.groupselect');
- var state = cb.checked;
- var tests = parent.query('.tests');
- for (Element t in tests.children) {
- cb = t.query('.testselect') as InputElement;
- cb.checked = state;
- var testId = int.parse(t.id.substring(_testIdPrefix.length));
- if (state) {
- enableTest(testId);
- } else {
- disableTest(testId);
- }
- }
- });
- }
- var list = groupDiv.query('.tests');
- var testItem = list.query('#$_testIdPrefix$id');
- if (testItem == null) {
- // Create the li element for the test.
- testItem = new Element.html("""
- <li id='$_testIdPrefix$id' class='test-it status-pending'>
- <div class='test-info'>
- <p class='test-title'>
- <input type='checkbox' checked='true' class='testselect'
- id='$_selectedIdPrefix$id'>
- <span class='test-label'>
- <span class='timer-result test-timer-result'></span>
- <span class='test-name closed'>${testCase.description}</span>
- </span>
- </p>
- </div>
- <div class='scrollpane'>
- <ol class='test-actions' id='$_actionIdPrefix$id'></ol>
- </div>
- </li>""");
- list.nodes.add(testItem);
- testItem.query('#$_selectedIdPrefix$id').onChange.listen((e) {
- InputElement cb = testItem.query('#$_selectedIdPrefix$id');
- testCase.enabled = cb.checked;
- });
- testItem.query('.test-label').onClick.listen((e) {
- var _testItem = document.query('#$_testIdPrefix$id');
- var _actions = _testItem.query('#$_actionIdPrefix$id');
- var _label = _testItem.query('.test-name');
- if (_actions.style.display == 'none') {
- _actions.style.display = 'table';
- _label.classes.remove('closed');
- _label.classes.add('open');
- } else {
- _actions.style.display = 'none';
- _label.classes.remove('open');
- _label.classes.add('closed');
- }
- });
- } else { // Reset the test element.
- testItem.classes.clear();
- testItem.classes.add('test-it');
- testItem.classes.add('status-pending');
- testItem.query('#$_actionIdPrefix$id').innerHtml = '';
- }
- }
-
- // Actually test logging is handled by the child, then posted
- // back to the parent. So here we know that the [message] argument
- // is in the format used by [_Message].
- void onLogMessage(TestCase testCase, String message) {
- var msg = new _Message.fromString(message);
- if (msg.elapsed < 0) { // No associated test case.
- document.query('#otherlogs').nodes.add(
- new Element.html('<p>${msg.body}</p>'));
- } else {
- var actions = document.query('#$_testIdPrefix${testCase.id}').
- query('.test-actions');
- String elapsedText = msg.elapsed >= 0 ? "${msg.elapsed}ms" : "";
- actions.nodes.add(new Element.html(
- "<li style='list-style-stype:none>"
- "<div class='timer-result'>${elapsedText}</div>"
- "<div class='test-title'>${msg.body}</div>"
- "</li>"));
- }
- }
-
- void onTestResult(TestCase testCase) {
- if (!testCase.enabled) return;
- super.onTestResult(testCase);
- if (testCase.message != '') {
- onLogMessage(testCase,
- _Message.text(_Message.LOG, -1, testCase.message));
- }
- int id = testCase.id;
- var testItem = document.query('#$_testIdPrefix$id');
- var timeSpan = testItem.query('.test-timer-result');
- timeSpan.text = '${_testTime}ms';
- // Convert status into what we need for our CSS.
- String result = 'status-error';
- if (testCase.result == 'pass') {
- result = 'status-success';
- } else if (testCase.result == 'fail') {
- result = 'status-failure';
- }
- testItem.classes.remove('status-pending');
- testItem.classes.add(result);
- // hide the actions
- var actions = testItem.query('.test-actions');
- for (Element e in actions.nodes) {
- e.classes.add(result);
- }
- actions.style.display = 'none';
- }
-
- void onSummary(int passed, int failed, int errors, List<TestCase> results,
- String uncaughtError) {
- }
-
- void onDone(bool success) {
- assert(_messageSubscription != null);
- _messageSubscription.cancel();
- _messageSubscription = null;
- _uninstallErrorHandler();
- document.query('#busy').style.display = 'none';
- InputElement startButton = document.query('#start');
- startButton.disabled = false;
- }
-}
-
-/**
- * Add the divs to the DOM if they are not present. We have a 'controls'
- * div for control, 'specs' div with test results, a 'busy' div for the
- * animated GIF used to indicate tests are running, and a 'child' div to
- * hold the iframe for the test.
- */
-void _prepareDom() {
- if (document.query('#control') == null) {
- // Use this as an opportunity for adding the CSS too.
- // I wanted to avoid having to include a css element explicitly
- // in the main html file. I considered moving all the styles
- // inline as attributes but that started getting very messy,
- // so we do it this way.
- document.body.nodes.add(new Element.html("<style>$_CSS</style>"));
- document.body.nodes.add(new Element.html(
- "<div id='control'>"
- "<input id='start' disabled='true' type='button' value='Run'>"
- "</div>"));
- document.query('#start').onClick.listen((e) {
- InputElement startButton = document.query('#start');
- startButton.disabled = true;
- rerunTests();
- });
- }
- if (document.query('#otherlogs') == null) {
- document.body.nodes.add(new Element.html(
- "<div id='otherlogs'></div>"));
- }
- if (document.query('#specs') == null) {
- document.body.nodes.add(new Element.html(
- "<div id='specs'><div id='group-divs'></div></div>"));
- }
- if (document.query('#busy') == null) {
- document.body.nodes.add(new Element.html(
- "<div id='busy' style='display:none'><img src='googleballs.gif'>"
- "</img></div>"));
- }
- if (document.query('#child') == null) {
- document.body.nodes.add(new Element.html("<div id='child'></div>"));
- }
-}
-
-/**
- * Allocate a Configuration. We allocate either a parent or child, depending on
- * whether the URL has a search part.
- *
- * Note: this unit test configuration will not work with the debugger (the tests
- * are executed in a separate IFrame).
- */
-void useInteractiveHtmlConfiguration() {
- if (window.location.search == '') { // This is the parent.
- _prepareDom();
- unittestConfiguration = _singletonParent;
- } else {
- unittestConfiguration = _singletonChild;
- }
-}
-
-final _singletonParent = new ParentInteractiveHtmlConfiguration();
-final _singletonChild = new ChildInteractiveHtmlConfiguration();
-
-const String _CSS = """
-body {
-font-family: Arial, sans-serif;
-margin: 0;
-font-size: 14px;
-}
-
-#application h2,
-#specs h2 {
-margin: 0;
-padding: 0.5em;
-font-size: 1.1em;
-}
-
-#header,
-#application,
-.test-info,
-.test-actions li {
-overflow: hidden;
-}
-
-#application {
-margin: 10px;
-}
-
-#application iframe {
-width: 100%;
-height: 758px;
-}
-
-#application iframe {
-border: none;
-}
-
-#specs {
-padding-top: 50px
-}
-
-.test-describe h2 {
-border-top: 2px solid #BABAD1;
-background-color: #efefef;
-}
-
-.tests,
-.test-it ol,
-.status-display {
-margin: 0;
-padding: 0;
-}
-
-.test-info {
-margin-left: 1em;
-margin-top: 0.5em;
-border-radius: 8px 0 0 8px;
--webkit-border-radius: 8px 0 0 8px;
--moz-border-radius: 8px 0 0 8px;
-cursor: pointer;
-}
-
-.test-info:hover .test-name {
-text-decoration: underline;
-}
-
-.test-info .closed:before {
-content: '\\25b8\\00A0';
-}
-
-.test-info .open:before {
-content: '\\25be\\00A0';
-font-weight: bold;
-}
-
-.test-it ol {
-margin-left: 2.5em;
-}
-
-.status-display,
-.status-display li {
-float: right;
-}
-
-.status-display li {
-padding: 5px 10px;
-}
-
-.timer-result,
-.test-title {
-display: inline-block;
-margin: 0;
-padding: 4px;
-}
-
-.test-actions .test-title,
-.test-actions .test-result {
-display: table-cell;
-padding-left: 0.5em;
-padding-right: 0.5em;
-}
-
-.test-it {
-list-style-type: none;
-}
-
-.test-actions {
-display: table;
-}
-
-.test-actions li {
-display: table-row;
-}
-
-.timer-result {
-width: 4em;
-padding: 0 10px;
-text-align: right;
-font-family: monospace;
-}
-
-.test-it pre,
-.test-actions pre {
-clear: left;
-color: black;
-margin-left: 6em;
-}
-
-.test-describe {
-margin: 5px 5px 10px 2em;
-border-left: 1px solid #BABAD1;
-border-right: 1px solid #BABAD1;
-border-bottom: 1px solid #BABAD1;
-padding-bottom: 0.5em;
-}
-
-.test-actions .status-pending .test-title:before {
-content: \\'\\\\00bb\\\\00A0\\';
-}
-
-.scrollpane {
- max-height: 20em;
- overflow: auto;
-}
-
-#busy {
-display: block;
-}
-/** Colors */
-
-#header {
-background-color: #F2C200;
-}
-
-#application {
-border: 1px solid #BABAD1;
-}
-
-.status-pending .test-info {
-background-color: #F9EEBC;
-}
-
-.status-success .test-info {
-background-color: #B1D7A1;
-}
-
-.status-failure .test-info {
-background-color: #FF8286;
-}
-
-.status-error .test-info {
-background-color: black;
-color: white;
-}
-
-.test-actions .status-success .test-title {
-color: #30B30A;
-}
-
-.test-actions .status-failure .test-title {
-color: #DF0000;
-}
-
-.test-actions .status-error .test-title {
-color: black;
-}
-
-.test-actions .timer-result {
-color: #888;
-}
-
-ul, menu, dir {
-display: block;
-list-style-type: disc;
--webkit-margin-before: 1em;
--webkit-margin-after: 1em;
--webkit-margin-start: 0px;
--webkit-margin-end: 0px;
--webkit-padding-start: 40px;
-}
-""";
diff --git a/pkg/unittest/lib/src/group_context.dart b/pkg/unittest/lib/src/group_context.dart
new file mode 100644
index 0000000..668fb47
--- /dev/null
+++ b/pkg/unittest/lib/src/group_context.dart
@@ -0,0 +1,67 @@
+part of unittest;
+
+/**
+ * Setup and teardown functions for a group and its parents, the latter
+ * for chaining.
+ */
+class _GroupContext {
+ final _GroupContext parent;
+
+ /** Description text of the current test group. */
+ final String _name;
+
+ /** Setup function called before each test in a group. */
+ Function _testSetup;
+
+ get testSetup => _testSetup;
+
+ get parentSetup => (parent == null) ? null : parent.testSetup;
+
+ set testSetup(Function setup) {
+ var preSetup = parentSetup;
+ if (preSetup == null) {
+ _testSetup = setup;
+ } else {
+ _testSetup = () {
+ var f = preSetup();
+ if (f is Future) {
+ return f.then((_) => setup());
+ } else {
+ return setup();
+ }
+ };
+ }
+ }
+
+ /** Teardown function called after each test in a group. */
+ Function _testTeardown;
+
+ get testTeardown => _testTeardown;
+
+ get parentTeardown => (parent == null) ? null : parent.testTeardown;
+
+ set testTeardown(Function teardown) {
+ var postTeardown = parentTeardown;
+ if (postTeardown == null) {
+ _testTeardown = teardown;
+ } else {
+ _testTeardown = () {
+ var f = teardown();
+ if (f is Future) {
+ return f.then((_) => postTeardown());
+ } else {
+ return postTeardown();
+ }
+ };
+ }
+ }
+
+ String get fullName => (parent == null || parent == _rootContext)
+ ? _name
+ : "${parent.fullName}$groupSep$_name";
+
+ _GroupContext([this.parent, this._name = '']) {
+ _testSetup = parentSetup;
+ _testTeardown = parentTeardown;
+ }
+}
diff --git a/pkg/unittest/lib/src/spread_args_helper.dart b/pkg/unittest/lib/src/spread_args_helper.dart
new file mode 100644
index 0000000..41411b9
--- /dev/null
+++ b/pkg/unittest/lib/src/spread_args_helper.dart
@@ -0,0 +1,133 @@
+part of unittest;
+
+/** Simulates spread arguments using named arguments. */
+// TODO(sigmund): remove this class and simply use a closure with named
+// arguments (if still applicable).
+class _SpreadArgsHelper {
+ final Function callback;
+ final int minExpectedCalls;
+ final int maxExpectedCalls;
+ final Function isDone;
+ final String id;
+ int actualCalls = 0;
+ final TestCase testCase;
+ bool complete;
+
+ _SpreadArgsHelper(Function callback, int minExpected, int maxExpected,
+ Function isDone, String id)
+ : this.callback = callback,
+ minExpectedCalls = minExpected,
+ maxExpectedCalls = (maxExpected == 0 && minExpected > 0)
+ ? minExpected
+ : maxExpected,
+ this.isDone = isDone,
+ this.testCase = currentTestCase,
+ this.id = _makeCallbackId(id, callback) {
+ ensureInitialized();
+ if (testCase == null) {
+ throw new StateError("No valid test. Did you forget to run your test "
+ "inside a call to test()?");
+ }
+
+ if (isDone != null || minExpected > 0) {
+ testCase._callbackFunctionsOutstanding++;
+ complete = false;
+ } else {
+ complete = true;
+ }
+ }
+
+ static String _makeCallbackId(String id, Function callback) {
+ // Try to create a reasonable id.
+ if (id != null) {
+ return "$id ";
+ } else {
+ // If the callback is not an anonymous closure, try to get the
+ // name.
+ var fname = callback.toString();
+ var prefix = "Function '";
+ var pos = fname.indexOf(prefix);
+ if (pos > 0) {
+ pos += prefix.length;
+ var epos = fname.indexOf("'", pos);
+ if (epos > 0) {
+ return "${fname.substring(pos, epos)} ";
+ }
+ }
+ }
+ return '';
+ }
+
+ bool shouldCallBack() {
+ ++actualCalls;
+ if (testCase.isComplete) {
+ // Don't run if the test is done. We don't throw here as this is not
+ // the current test, but we do mark the old test as having an error
+ // if it previously passed.
+ if (testCase.result == PASS) {
+ testCase._error(
+ 'Callback ${id}called ($actualCalls) after test case '
+ '${testCase.description} has already been marked as '
+ '${testCase.result}.');
+ }
+ return false;
+ } else if (maxExpectedCalls >= 0 && actualCalls > maxExpectedCalls) {
+ throw new TestFailure('Callback ${id}called more times than expected '
+ '($maxExpectedCalls).');
+ }
+ return true;
+ }
+
+ void after() {
+ if (!complete) {
+ if (minExpectedCalls > 0 && actualCalls < minExpectedCalls) return;
+ if (isDone != null && !isDone()) return;
+
+ // Mark this callback as complete and remove it from the testcase
+ // oustanding callback count; if that hits zero the testcase is done.
+ complete = true;
+ testCase._markCallbackComplete();
+ }
+ }
+
+ invoke0() {
+ return _guardAsync(
+ () {
+ if (shouldCallBack()) {
+ return callback();
+ }
+ },
+ after, testCase);
+ }
+
+ invoke1(arg1) {
+ return _guardAsync(
+ () {
+ if (shouldCallBack()) {
+ return callback(arg1);
+ }
+ },
+ after, testCase);
+ }
+
+ invoke2(arg1, arg2) {
+ return _guardAsync(
+ () {
+ if (shouldCallBack()) {
+ return callback(arg1, arg2);
+ }
+ },
+ after, testCase);
+ }
+
+ _guardAsync(Function tryBody, Function finallyBody, TestCase testCase) {
+ assert(testCase != null);
+ try {
+ return tryBody();
+ } catch (e, trace) {
+ _registerException(testCase, e, trace);
+ } finally {
+ if (finallyBody != null) finallyBody();
+ }
+ }
+}
diff --git a/pkg/unittest/lib/src/test_case.dart b/pkg/unittest/lib/src/test_case.dart
index 95068bd..d4802ea 100644
--- a/pkg/unittest/lib/src/test_case.dart
+++ b/pkg/unittest/lib/src/test_case.dart
@@ -17,13 +17,13 @@
final String description;
/** The setup function to call before the test, if any. */
- Function setUp;
+ final Function _setUp;
/** The teardown function to call after the test, if any. */
- Function tearDown;
+ final Function _tearDown;
/** The body of the test case. */
- TestFunction testFunction;
+ final TestFunction _testFunction;
/**
* Remaining number of callbacks functions that must reach a 'done' state
@@ -57,16 +57,18 @@
Duration _runningTime;
Duration get runningTime => _runningTime;
- bool enabled = true;
+ bool _enabled = true;
+
+ bool get enabled => _enabled;
bool _doneTeardown = false;
Completer _testComplete;
- TestCase._internal(this.id, this.description, this.testFunction)
+ TestCase._internal(this.id, this.description, this._testFunction)
: currentGroup = _currentContext.fullName,
- setUp = _currentContext.testSetup,
- tearDown = _currentContext.testTeardown;
+ _setUp = _currentContext.testSetup,
+ _tearDown = _currentContext.testTeardown;
bool get isComplete => !enabled || result != null;
@@ -76,9 +78,9 @@
}
if (result == null || result == PASS) {
if (e is TestFailure) {
- fail("$e", stack);
+ _fail("$e", stack);
} else {
- error("$stage failed: Caught $e", stack);
+ _error("$stage failed: Caught $e", stack);
}
}
};
@@ -97,7 +99,7 @@
// Avoid calling [new Future] to avoid issue 11911.
return new Future.value().then((_) {
- if (setUp != null) return setUp();
+ if (_setUp != null) return _setUp();
}).catchError(_errorHandler('Setup'))
.then((_) {
// Skip the test if setup failed.
@@ -106,7 +108,7 @@
_startTime = new DateTime.now();
_runningTime = null;
++_callbackFunctionsOutstanding;
- return testFunction();
+ return _testFunction();
})
.catchError(_errorHandler('Test'))
.then((_) {
@@ -115,12 +117,12 @@
// Outstanding callbacks exist; we need to return a Future.
_testComplete = new Completer();
return _testComplete.future.whenComplete(() {
- if (tearDown != null) {
- return tearDown();
+ if (_tearDown != null) {
+ return _tearDown();
}
}).catchError(_errorHandler('Teardown'));
- } else if (tearDown != null) {
- return tearDown();
+ } else if (_tearDown != null) {
+ return _tearDown();
}
})
.catchError(_errorHandler('Teardown'));
@@ -160,11 +162,11 @@
}
}
- void pass() {
+ void _pass() {
_complete(PASS);
}
- void fail(String messageText, [StackTrace stack]) {
+ void _fail(String messageText, [StackTrace stack]) {
if (result != null) {
String newMessage = (result == PASS)
? 'Test failed after initially passing: $messageText'
@@ -176,13 +178,13 @@
}
}
- void error(String messageText, [StackTrace stack]) {
+ void _error(String messageText, [StackTrace stack]) {
_complete(ERROR, messageText, stack);
}
void _markCallbackComplete() {
if (--_callbackFunctionsOutstanding == 0 && !isComplete) {
- pass();
+ _pass();
}
}
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index eae5a13..5fa2ae9 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -146,7 +146,9 @@
import 'src/utils.dart';
part 'src/configuration.dart';
+part 'src/group_context.dart';
part 'src/simple_configuration.dart';
+part 'src/spread_args_helper.dart';
part 'src/test_case.dart';
Configuration _config;
@@ -207,79 +209,19 @@
int _soloNestingLevel = 0;
bool _soloTestSeen = false;
-/**
- * Setup and teardown functions for a group and its parents, the latter
- * for chaining.
- */
-class _GroupContext {
- final _GroupContext parent;
-
- /** Description text of the current test group. */
- final String _name;
-
- /** Setup function called before each test in a group. */
- Function _testSetup;
-
- get testSetup => _testSetup;
-
- get parentSetup => (parent == null) ? null : parent.testSetup;
-
- set testSetup(Function setup) {
- var preSetup = parentSetup;
- if (preSetup == null) {
- _testSetup = setup;
- } else {
- _testSetup = () {
- var f = preSetup();
- if (f is Future) {
- return f.then((_) => setup());
- } else {
- return setup();
- }
- };
- }
- }
-
- /** Teardown function called after each test in a group. */
- Function _testTeardown;
-
- get testTeardown => _testTeardown;
-
- get parentTeardown => (parent == null) ? null : parent.testTeardown;
-
- set testTeardown(Function teardown) {
- var postTeardown = parentTeardown;
- if (postTeardown == null) {
- _testTeardown = teardown;
- } else {
- _testTeardown = () {
- var f = teardown();
- if (f is Future) {
- return f.then((_) => postTeardown());
- } else {
- return postTeardown();
- }
- };
- }
- }
-
- String get fullName => (parent == null || parent == _rootContext)
- ? _name
- : "${parent.fullName}$groupSep$_name";
-
- _GroupContext([this.parent, this._name = '']) {
- _testSetup = parentSetup;
- _testTeardown = parentTeardown;
- }
-}
-
// We use a 'dummy' context for the top level to eliminate null
// checks when querying the context. This allows us to easily
// support top-level setUp/tearDown functions as well.
final _rootContext = new _GroupContext();
_GroupContext _currentContext = _rootContext;
-int _currentTestCaseIndex = 0;
+/**
+ * Represents the index of the currently running test case
+ * == -1 implies the test system is not running
+ * == [number of test cases] is a short-lived state flagging that the last test
+ * has completed
+ */
+int _currentTestCaseIndex = -1;
/** [TestCase] currently being executed. */
TestCase get currentTestCase =>
@@ -293,7 +235,7 @@
String _uncaughtErrorMessage = null;
/** Time since we last gave non-sync code a chance to be scheduled. */
-var _lastBreath = new DateTime.now().millisecondsSinceEpoch;
+int _lastBreath = new DateTime.now().millisecondsSinceEpoch;
/* Test case result strings. */
// TODO(gram) we should change these constants to use a different string
@@ -313,6 +255,7 @@
* calls.
*/
void test(String spec, TestFunction body) {
+ _requireNotRunning();
ensureInitialized();
if (!_soloTestSeen || _soloNestingLevel > 0) {
var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
@@ -341,6 +284,7 @@
* fact that they are effectively no-ops.
*/
void solo_test(String spec, TestFunction body) {
+ _requireNotRunning();
ensureInitialized();
if (!_soloTestSeen) {
_soloTestSeen = true;
@@ -355,133 +299,6 @@
}
}
-/** Sentinel value for [_SpreadArgsHelper]. */
-class _Sentinel {
- const _Sentinel();
-}
-
-/** Simulates spread arguments using named arguments. */
-// TODO(sigmund): remove this class and simply use a closure with named
-// arguments (if still applicable).
-class _SpreadArgsHelper {
- final Function callback;
- final int minExpectedCalls;
- final int maxExpectedCalls;
- final Function isDone;
- final String id;
- int actualCalls = 0;
- final TestCase testCase;
- bool complete;
- static const sentinel = const _Sentinel();
-
- _SpreadArgsHelper(Function callback, int minExpected, int maxExpected,
- Function isDone, String id)
- : this.callback = callback,
- minExpectedCalls = minExpected,
- maxExpectedCalls = (maxExpected == 0 && minExpected > 0)
- ? minExpected
- : maxExpected,
- this.isDone = isDone,
- this.testCase = currentTestCase,
- this.id = _makeCallbackId(id, callback) {
- ensureInitialized();
- if (testCase == null) {
- throw new StateError("No valid test. Did you forget to run your test "
- "inside a call to test()?");
- }
-
- if (isDone != null || minExpected > 0) {
- testCase._callbackFunctionsOutstanding++;
- complete = false;
- } else {
- complete = true;
- }
- }
-
- static String _makeCallbackId(String id, Function callback) {
- // Try to create a reasonable id.
- if (id != null) {
- return "$id ";
- } else {
- // If the callback is not an anonymous closure, try to get the
- // name.
- var fname = callback.toString();
- var prefix = "Function '";
- var pos = fname.indexOf(prefix);
- if (pos > 0) {
- pos += prefix.length;
- var epos = fname.indexOf("'", pos);
- if (epos > 0) {
- return "${fname.substring(pos, epos)} ";
- }
- }
- }
- return '';
- }
-
- bool shouldCallBack() {
- ++actualCalls;
- if (testCase.isComplete) {
- // Don't run if the test is done. We don't throw here as this is not
- // the current test, but we do mark the old test as having an error
- // if it previously passed.
- if (testCase.result == PASS) {
- testCase.error(
- 'Callback ${id}called ($actualCalls) after test case '
- '${testCase.description} has already been marked as '
- '${testCase.result}.');
- }
- return false;
- } else if (maxExpectedCalls >= 0 && actualCalls > maxExpectedCalls) {
- throw new TestFailure('Callback ${id}called more times than expected '
- '($maxExpectedCalls).');
- }
- return true;
- }
-
- void after() {
- if (!complete) {
- if (minExpectedCalls > 0 && actualCalls < minExpectedCalls) return;
- if (isDone != null && !isDone()) return;
-
- // Mark this callback as complete and remove it from the testcase
- // oustanding callback count; if that hits zero the testcase is done.
- complete = true;
- testCase._markCallbackComplete();
- }
- }
-
- invoke0() {
- return _guardAsync(
- () {
- if (shouldCallBack()) {
- return callback();
- }
- },
- after, testCase);
- }
-
- invoke1(arg1) {
- return _guardAsync(
- () {
- if (shouldCallBack()) {
- return callback(arg1);
- }
- },
- after, testCase);
- }
-
- invoke2(arg1, arg2) {
- return _guardAsync(
- () {
- if (shouldCallBack()) {
- return callback(arg1, arg2);
- }
- },
- after, testCase);
- }
-}
-
/**
* Indicate that [callback] is expected to be called a [count] number of times
* (by default 1). The unittest framework will wait for the callback to run the
@@ -549,33 +366,39 @@
}
/**
- * Wraps the [callback] in a new function and returns that function. The new
- * function will be able to handle exceptions by directing them to the correct
- * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
- * might optionally be called but may never be called during the test.
- * [callback] should take 0 positional arguments (named arguments are not
- * supported). [id] can be used to identify the callback in error
- * messages (for example if it is called after the test case is complete).
+ * *Deprecated*
+ *
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
*/
-// TODO(sigmund): deprecate this API when issue 2706 is fixed.
+@deprecated
Function protectAsync0(Function callback, {String id}) {
- return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke0;
+ return callback;
}
/**
- * Like [protectAsync0] but [callback] should take 1 positional argument.
+ * *Deprecated*
+ *
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
*/
-// TODO(sigmund): deprecate this API when issue 2706 is fixed.
+@deprecated
Function protectAsync1(Function callback, {String id}) {
- return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke1;
+ return callback;
}
/**
- * Like [protectAsync0] but [callback] should take 2 positional arguments.
+ * *Deprecated*
+ *
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
*/
-// TODO(sigmund): deprecate this API when issue 2706 is fixed.
+@deprecated
Function protectAsync2(Function callback, {String id}) {
- return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2;
+ return callback;
}
/**
@@ -584,6 +407,7 @@
*/
void group(String description, void body()) {
ensureInitialized();
+ _requireNotRunning();
_currentContext = new _GroupContext(_currentContext, description);
try {
body();
@@ -601,6 +425,7 @@
/** Like [solo_test], but for groups. */
void solo_group(String description, void body()) {
+ _requireNotRunning();
ensureInitialized();
if (!_soloTestSeen) {
_soloTestSeen = true;
@@ -623,6 +448,7 @@
* case it must return a [Future].
*/
void setUp(Function setupTest) {
+ _requireNotRunning();
_currentContext.testSetup = setupTest;
}
@@ -635,6 +461,7 @@
* case it must return a [Future].
*/
void tearDown(Function teardownTest) {
+ _requireNotRunning();
_currentContext.testTeardown = teardownTest;
}
@@ -651,18 +478,12 @@
var msg = '$message\nCaught $e';
if (currentTestCase != null) {
- currentTestCase.error(msg, stack);
+ currentTestCase._error(msg, stack);
} else {
_uncaughtErrorMessage = "$msg: $stack";
}
}
-void rerunTests() {
- _uncaughtErrorMessage = null;
- _initialized = true; // We don't want to reset the test array.
- runTests();
-}
-
/**
* Filter the tests. [testFilter] can be a [RegExp], a [String] or a
* predicate function. This is different to enabling/disabling tests
@@ -683,6 +504,7 @@
/** Runs all queued tests, one at a time. */
void runTests() {
+ _requireNotRunning();
_ensureInitialized(false);
_currentTestCaseIndex = 0;
_config.onStart();
@@ -690,24 +512,15 @@
}
/**
- * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is
- * passed to the corresponding test.
+ * *Deprecated*
*
- * The value returned by [tryBody] (if any) is returned by [guardAsync].
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
*/
+@deprecated
guardAsync(Function tryBody) {
- return _guardAsync(tryBody, null, currentTestCase);
-}
-
-_guardAsync(Function tryBody, Function finallyBody, TestCase testCase) {
- assert(testCase != null);
- try {
- return tryBody();
- } catch (e, trace) {
- _registerException(testCase, e, trace);
- } finally {
- if (finallyBody != null) finallyBody();
- }
+ return tryBody();
}
/**
@@ -723,9 +536,9 @@
void _registerException(TestCase testCase, e, [trace]) {
String message = (e is TestFailure) ? e.message : 'Caught $e';
if (testCase.result == null) {
- testCase.fail(message, trace);
+ testCase._fail(message, trace);
} else {
- testCase.error(message, trace);
+ testCase._error(message, trace);
}
}
@@ -734,16 +547,23 @@
*/
void _runTest() {
if (_currentTestCaseIndex >= testCases.length) {
+ assert(_currentTestCaseIndex == testCases.length);
_completeTests();
} else {
- final testCase = testCases[_currentTestCaseIndex];
- var f = _guardAsync(testCase._run, null, testCase);
+ var testCase = testCases[_currentTestCaseIndex];
+ Future f = runZoned(testCase._run, onError: (error, stack) {
+ // TODO(kevmoo) Do a better job of flagging these are async errors.
+ // https://code.google.com/p/dart/issues/detail?id=16530
+ _registerException(testCase, error, stack);
+ });
+
+ var timeout = unittestConfiguration.timeout;
+
Timer timer;
- final Duration timeout = unittestConfiguration.timeout;
if (timeout != null) {
try {
timer = new Timer(timeout, () {
- testCase.error("Test timed out after ${timeout.inSeconds} seconds.");
+ testCase._error("Test timed out after ${timeout.inSeconds} seconds.");
_nextTestCase();
});
} on UnsupportedError catch (e) {
@@ -782,6 +602,7 @@
_config.onDone(passed > 0 && failed == 0 && errors == 0 &&
_uncaughtErrorMessage == null);
_initialized = false;
+ _currentTestCaseIndex = -1;
}
String _fullSpec(String spec) {
@@ -824,11 +645,11 @@
void _setTestEnabledState(int testId, bool state) {
// Try fast path first.
if (testCases.length > testId && testCases[testId].id == testId) {
- testCases[testId].enabled = state;
+ testCases[testId]._enabled = state;
} else {
for (var i = 0; i < testCases.length; i++) {
if (testCases[i].id == testId) {
- testCases[i].enabled = state;
+ testCases[i]._enabled = state;
break;
}
}
@@ -858,6 +679,12 @@
*/
bool filterStacks = true;
+void _requireNotRunning() {
+ if(_currentTestCaseIndex != -1) {
+ throw new StateError('Not allowed when tests are running.');
+ }
+}
+
/**
* Returns a Trace object from a StackTrace object or a String, or the
* unchanged input if formatStacks is false;
diff --git a/pkg/unittest/pubspec.yaml b/pkg/unittest/pubspec.yaml
index 66d6839..b0caec5 100644
--- a/pkg/unittest/pubspec.yaml
+++ b/pkg/unittest/pubspec.yaml
@@ -1,5 +1,5 @@
name: unittest
-version: 0.9.3-dev+1
+version: 0.10.0-dev
author: Dart Team <misc@dartlang.org>
description: A library for writing dart unit tests.
homepage: http://www.dartlang.org
diff --git a/pkg/unittest/test/unitttest_group_name_test.dart b/pkg/unittest/test/unittest_group_name_test.dart
similarity index 100%
rename from pkg/unittest/test/unitttest_group_name_test.dart
rename to pkg/unittest/test/unittest_group_name_test.dart
diff --git a/pkg/unittest/test/unittest_invalid_ops_test.dart b/pkg/unittest/test/unittest_invalid_ops_test.dart
new file mode 100644
index 0000000..4f1091c
--- /dev/null
+++ b/pkg/unittest/test/unittest_invalid_ops_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'invalid ops throw while test is running';
+
+var testFunction = (_) {
+ test(testName, () {
+ expect(() => test('test', () {}), throwsStateError);
+ expect(() => solo_test('test', () {}), throwsStateError);
+ expect(() => group('test', () {}), throwsStateError);
+ expect(() => solo_group('test', () {}), throwsStateError);
+ expect(() => setUp(() {}), throwsStateError);
+ expect(() => tearDown(() {}), throwsStateError);
+ expect(() => runTests(), throwsStateError);
+ });
+};
+
+var expected = buildStatusString(1, 0, 0, testName);
diff --git a/pkg/unittest/test/unittest_protect_async_test.dart b/pkg/unittest/test/unittest_protect_async_test.dart
new file mode 100644
index 0000000..12ded3c
--- /dev/null
+++ b/pkg/unittest/test/unittest_protect_async_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testFunction = (_) {
+ test('protectAsync0', () {
+ var protected = protectAsync0(() {
+ throw new StateError('error during protectAsync0');
+ });
+ new Future(protected);
+ });
+
+ test('protectAsync1', () {
+ var protected = protectAsync1((arg) {
+ throw new StateError('error during protectAsync1: $arg');
+ });
+ new Future(() => protected('one arg'));
+ });
+
+ test('protectAsync2', () {
+ var protected = protectAsync2((arg1, arg2) {
+ throw new StateError('error during protectAsync2: $arg1, $arg2');
+ });
+ new Future(() => protected('arg1', 'arg2'));
+ });
+
+ test('throw away 1', () {
+ return new Future(() {});
+ });
+};
+
+var expected = '1:0:3:4:0:::null:'
+ 'protectAsync0:Caught Bad state: error during protectAsync0:'
+ 'protectAsync1:Caught Bad state: error during protectAsync1: one arg:'
+ 'protectAsync2:Caught Bad state: error during protectAsync2: arg1, arg2:'
+ 'throw away 1:';
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 27b0eea..eefdd58 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -16,11 +16,13 @@
#undef DeleteFile
+#define MAX_LONG_PATH 32767
+
namespace dart {
namespace bin {
PathBuffer::PathBuffer() : length_(0) {
- data_ = calloc(MAX_PATH + 1, sizeof(wchar_t)); // NOLINT
+ data_ = calloc(MAX_LONG_PATH + 1, sizeof(wchar_t)); // NOLINT
}
char* PathBuffer::AsString() const {
@@ -41,13 +43,13 @@
bool PathBuffer::AddW(const wchar_t* name) {
wchar_t* data = AsStringW();
int written = _snwprintf(data + length_,
- MAX_PATH - length_,
+ MAX_LONG_PATH - length_,
L"%s",
name);
- data[MAX_PATH] = L'\0';
- if (written <= MAX_PATH - length_ &&
+ data[MAX_LONG_PATH] = L'\0';
+ if (written <= MAX_LONG_PATH - length_ &&
written >= 0 &&
- static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) {
+ static_cast<size_t>(written) == wcsnlen(name, MAX_LONG_PATH + 1)) {
length_ += written;
return true;
} else {
@@ -390,7 +392,8 @@
char* Directory::SystemTemp() {
PathBuffer path;
- path.Reset(GetTempPathW(MAX_PATH, path.AsStringW()) - 1); // Remove \ at end.
+ // Remove \ at end.
+ path.Reset(GetTempPathW(MAX_LONG_PATH, path.AsStringW()) - 1);
return path.AsString();
}
@@ -407,7 +410,7 @@
free(const_cast<wchar_t*>(system_prefix));
// Length of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 36.
- if (path.length() > MAX_PATH - 36) {
+ if (path.length() > MAX_LONG_PATH - 36) {
return NULL;
}
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index 0c5b765..90eddd09 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -106,12 +106,7 @@
UNREACHABLE();
}
int64_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
- if ((id == kTimerId) && (data == 0)) {
- // This is a 0-timer. Simply queue a 'null' on the port.
- DartUtils::PostNull(dart_port);
- } else {
- event_handler->SendData(id, dart_port, data);
- }
+ event_handler->SendData(id, dart_port, data);
}
} // namespace bin
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index b6ac1ce..993670c 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -988,7 +988,9 @@
Handle::ScopedLock lock(handle);
- if (!handle->IsError()) {
+ if (handle->IsError()) {
+ DartUtils::PostInt32(msg->dart_port, 1 << kErrorEvent);
+ } else {
if ((msg->data & ((1 << kInEvent) | (1 << kOutEvent))) != 0) {
// Only set mask if we turned on kInEvent or kOutEvent.
handle->SetPortAndMask(msg->dart_port, msg->data);
diff --git a/runtime/bin/file_system_entity_patch.dart b/runtime/bin/file_system_entity_patch.dart
index e6b3fdc..24782aa 100644
--- a/runtime/bin/file_system_entity_patch.dart
+++ b/runtime/bin/file_system_entity_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
patch class FileStat {
- /* patch */ static List<int> _statSync(String path) native "File_Stat";
+ /* patch */ static _statSync(String path) native "File_Stat";
}
diff --git a/runtime/bin/file_system_watcher_macos.cc b/runtime/bin/file_system_watcher_macos.cc
index 678f45f..2fa80a2 100644
--- a/runtime/bin/file_system_watcher_macos.cc
+++ b/runtime/bin/file_system_watcher_macos.cc
@@ -55,37 +55,88 @@
public:
class Node {
public:
- Node(intptr_t base_path_length, int read_fd, int write_fd, bool recursive)
- : base_path_length_(base_path_length),
- read_fd_(read_fd),
- write_fd_(write_fd),
- recursive_(recursive),
- ref_(NULL) {}
+ Node(FSEventsWatcher* watcher, intptr_t base_path_length, int read_fd,
+ int write_fd, bool recursive)
+ : watcher_(watcher),
+ ready_(false),
+ base_path_length_(base_path_length),
+ read_fd_(read_fd),
+ write_fd_(write_fd),
+ recursive_(recursive),
+ ref_(NULL) {}
~Node() {
close(write_fd_);
- FSEventStreamInvalidate(ref_);
- FSEventStreamRelease(ref_);
}
void set_ref(FSEventStreamRef ref) {
ref_ = ref;
}
+ static void StartCallback(CFRunLoopTimerRef timer, void* info) {
+ Node* node = reinterpret_cast<Node*>(info);
+ FSEventStreamScheduleWithRunLoop(
+ node->ref_,
+ node->watcher_->run_loop_,
+ kCFRunLoopDefaultMode);
+ FSEventStreamStart(node->ref_);
+ FSEventStreamFlushSync(node->ref_);
+ node->watcher_->monitor_.Enter();
+ node->ready_ = true;
+ node->watcher_->monitor_.Notify();
+ node->watcher_->monitor_.Exit();
+ }
+
void Start() {
- FSEventStreamStart(ref_);
+ ASSERT(!ready_);
+ CFRunLoopTimerContext context;
+ memset(&context, 0, sizeof(context));
+ context.info = this;
+ CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
+ NULL, 0, 0, 0, 0, StartCallback, &context);
+ CFRunLoopAddTimer(watcher_->run_loop_, timer, kCFRunLoopCommonModes);
+ watcher_->monitor_.Enter();
+ while (!ready_) {
+ watcher_->monitor_.Wait(Monitor::kNoTimeout);
+ }
+ watcher_->monitor_.Exit();
+ }
+
+ static void StopCallback(CFRunLoopTimerRef timer, void* info) {
+ Node* node = reinterpret_cast<Node*>(info);
+ FSEventStreamStop(node->ref_);
+ FSEventStreamInvalidate(node->ref_);
+ FSEventStreamRelease(node->ref_);
+ node->watcher_->monitor_.Enter();
+ node->ready_ = false;
+ node->watcher_->monitor_.Notify();
+ node->watcher_->monitor_.Exit();
}
void Stop() {
- FSEventStreamStop(ref_);
+ ASSERT(ready_);
+ CFRunLoopTimerContext context;
+ memset(&context, 0, sizeof(context));
+ context.info = this;
+ CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
+ NULL, 0, 0, 0, 0, StopCallback, &context);
+ CFRunLoopAddTimer(watcher_->run_loop_, timer, kCFRunLoopCommonModes);
+ watcher_->monitor_.Enter();
+ while (ready_) {
+ watcher_->monitor_.Wait(Monitor::kNoTimeout);
+ }
+ watcher_->monitor_.Exit();
}
+ bool ready() const { return ready_; }
intptr_t base_path_length() const { return base_path_length_; }
int read_fd() const { return read_fd_; }
int write_fd() const { return write_fd_; }
bool recursive() const { return recursive_; }
private:
+ FSEventsWatcher* watcher_;
+ bool ready_;
intptr_t base_path_length_;
int read_fd_;
int write_fd_;
@@ -143,7 +194,7 @@
CFStringRef path_ref = CFStringCreateWithCString(
NULL, base_path, kCFStringEncodingUTF8);
- Node* node = new Node(strlen(base_path), fds[0], fds[1], recursive);
+ Node* node = new Node(this, strlen(base_path), fds[0], fds[1], recursive);
FSEventStreamContext context;
context.version = 0;
@@ -162,11 +213,6 @@
node->set_ref(ref);
- FSEventStreamScheduleWithRunLoop(
- ref,
- run_loop_,
- kCFRunLoopDefaultMode);
-
return node;
}
@@ -178,6 +224,9 @@
const FSEventStreamEventFlags event_flags[],
const FSEventStreamEventId event_ids[]) {
Node* node = reinterpret_cast<Node*>(client);
+ // `ready` is set on same thread as this callback is invoked, so we don't
+ // need to lock here.
+ if (!node->ready()) return;
for (size_t i = 0; i < num_events; i++) {
char *path = reinterpret_cast<char**>(event_paths)[i];
FSEvent event;
@@ -207,7 +256,7 @@
FSEventsWatcher* watcher = new FSEventsWatcher();
watcher->monitor().Enter();
while (!watcher->has_run_loop()) {
- watcher->monitor().Wait(1);
+ watcher->monitor().Wait(Monitor::kNoTimeout);
}
watcher->monitor().Exit();
return reinterpret_cast<intptr_t>(watcher);
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 5d17d04..eda6e9b 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -635,13 +635,14 @@
static Mutex* signal_mutex = new Mutex();
static SignalInfo* signal_handlers = NULL;
-static const int kSignalsCount = 5;
+static const int kSignalsCount = 6;
static const int kSignals[kSignalsCount] = {
+ SIGHUP,
SIGINT,
- SIGWINCH,
SIGTERM,
SIGUSR1,
- SIGUSR2
+ SIGUSR2,
+ SIGWINCH
};
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index 175e36d..037dd16 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -634,13 +634,14 @@
static Mutex* signal_mutex = new Mutex();
static SignalInfo* signal_handlers = NULL;
-static const int kSignalsCount = 5;
+static const int kSignalsCount = 6;
static const int kSignals[kSignalsCount] = {
+ SIGHUP,
SIGINT,
- SIGWINCH,
SIGTERM,
SIGUSR1,
- SIGUSR2
+ SIGUSR2,
+ SIGWINCH
};
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index e369b21..c2d8b20 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -676,13 +676,14 @@
static Mutex* signal_mutex = new Mutex();
static SignalInfo* signal_handlers = NULL;
-static const int kSignalsCount = 5;
+static const int kSignalsCount = 6;
static const int kSignals[kSignalsCount] = {
+ SIGHUP,
SIGINT,
- SIGWINCH,
SIGTERM,
SIGUSR1,
- SIGUSR2
+ SIGUSR2,
+ SIGWINCH
};
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index cab5b49..78cae4f 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -130,6 +130,7 @@
/* patch */ static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
if (signal != ProcessSignal.SIGHUP &&
signal != ProcessSignal.SIGINT &&
+ signal != ProcessSignal.SIGTERM &&
(Platform.isWindows ||
(signal != ProcessSignal.SIGUSR1 &&
signal != ProcessSignal.SIGUSR2 &&
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 75c7d47..2cc3de7 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -876,12 +876,20 @@
DART_EXPORT Dart_Isolate Dart_CurrentIsolate();
/**
- * Returns the callback data which was passed to the isolate when it
- * was created.
+ * Returns the callback data associated with the current Isolate. This data was
+ * passed to the isolate when it was created.
*/
DART_EXPORT void* Dart_CurrentIsolateData();
/**
+ * Returns the callback data associated with the specified Isolate. This data
+ * was passed to the isolate when it was created.
+ * The embedder is responsible for ensuring the consistency of this data
+ * with respect to the lifecycle of an Isolate.
+ */
+DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate);
+
+/**
* Returns the debugging name for the current isolate.
*
* This name is unique to each isolate and should only be used to make
diff --git a/runtime/lib/convert_patch.dart b/runtime/lib/convert_patch.dart
index 3ba4f7e..93da461 100644
--- a/runtime/lib/convert_patch.dart
+++ b/runtime/lib/convert_patch.dart
@@ -2,6 +2,8 @@
// 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:typed_data";
+
// JSON conversion.
patch _parseJson(String json, reviver(var key, var value)) {
@@ -554,3 +556,9 @@
throw new FormatException("Unexpected character at $position: $slice");
}
}
+
+// UTF-8 conversion.
+
+patch class _Utf8Encoder {
+ /* patch */ static List<int> _createBuffer(int size) => new Uint8List(size);
+}
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 80e830b..a5955a9 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -273,3 +273,9 @@
static SendPort _spawnUri(String uri) native "Isolate_spawnUri";
}
+
+patch class Capability {
+ /* patch */ factory Capability() {
+ throw new UnimplementedError();
+ }
+}
diff --git a/runtime/lib/math.cc b/runtime/lib/math.cc
index 801c8c6..8f773f9 100644
--- a/runtime/lib/math.cc
+++ b/runtime/lib/math.cc
@@ -111,38 +111,67 @@
}
+uint64_t mix64(uint64_t n) {
+ // Thomas Wang 64-bit mix.
+ // http://www.concentric.net/~Ttwang/tech/inthash.htm
+ // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+ n = (~n) + (n << 21); // n = (n << 21) - n - 1;
+ n = n ^ (n >> 24);
+ n = n * 265; // n = (n + (n << 3)) + (n << 8);
+ n = n ^ (n >> 14);
+ n = n * 21; // n = (n + (n << 2)) + (n << 4);
+ n = n ^ (n >> 28);
+ n = n + (n << 31);
+ return n;
+}
+
+
// Implements:
+// uint64_t hash = 0;
// do {
-// seed = (seed + 0x5A17) & _Random._MASK_64;
-// } while (seed == 0);
-// _state[kSTATE_LO] = seed & _MASK_32;
-// _state[kSTATE_HI] = seed >> 32;
+// hash = hash * 1037 ^ mix64((uint64_t)seed);
+// seed >>= 64;
+// } while (seed != 0 && seed != -1); // Limits if seed positive or negative.
+// if (hash == 0) {
+// hash = 0x5A17;
+// }
+// _state[kSTATE_LO] = hash & _MASK_32;
+// _state[kSTATE_HI] = hash >> 32;
DEFINE_NATIVE_ENTRY(Random_setupSeed, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, receiver, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, seed_int, arguments->NativeArgAt(1));
const TypedData& array = TypedData::Handle(GetRandomStateArray(receiver));
ASSERT(!seed_int.IsNull());
ASSERT(!array.IsNull());
- int64_t seed = 0;
+ uint64_t seed = 0;
if (seed_int.IsBigint()) {
const Bigint& mask64 = Bigint::Handle(
BigintOperations::NewFromUint64(0xffffffffffffffffLL));
Bigint& big_seed = Bigint::Handle();
big_seed ^= seed_int.raw();
+ uint64_t negate_mask = 0;
+ if (big_seed.IsNegative()) {
+ // Negate bits to make seed positive.
+ // Negate bits again (by xor with negate_mask) when extracted below,
+ // to get original bits.
+ negate_mask = 0xffffffffffffffffLL;
+ big_seed ^= BigintOperations::BitNot(big_seed);
+ }
Bigint& low64 = Bigint::Handle();
- while (!big_seed.IsZero()) {
+ do {
low64 = BigintOperations::BitAnd(big_seed, mask64);
ASSERT(BigintOperations::FitsIntoUint64(low64));
- seed ^= BigintOperations::ToUint64(low64);
+ uint64_t chunk = BigintOperations::ToUint64(low64) ^ negate_mask;
+ seed = (seed * 1037) ^ mix64(chunk);
big_seed = BigintOperations::ShiftRight(big_seed, 64);
- }
+ } while (!big_seed.IsZero());
} else {
- seed = seed_int.AsInt64Value();
+ seed = mix64(static_cast<uint64_t>(seed_int.AsInt64Value()));
}
- do {
- seed = seed + 0x5A17;
- } while (seed == 0);
+ if (seed == 0) {
+ seed = 0x5a17;
+ }
array.SetUint32(0, static_cast<uint32_t>(seed));
array.SetUint32(array.ElementSizeInBytes(),
static_cast<uint32_t>(seed >> 32));
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 3b7391c..9f5c763 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -1301,6 +1301,33 @@
}
+DEFINE_NATIVE_ENTRY(Mirrors_evalInLibraryWithPrivateKey, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(String, expression, arguments->NativeArgAt(0));
+ GET_NATIVE_ARGUMENT(String, private_key, arguments->NativeArgAt(1));
+
+ const GrowableObjectArray& libraries =
+ GrowableObjectArray::Handle(isolate->object_store()->libraries());
+ const int num_libraries = libraries.Length();
+ Library& each_library = Library::Handle();
+ Library& ctxt_library = Library::Handle();
+ String& library_key = String::Handle();
+
+ if (library_key.IsNull()) {
+ ctxt_library = Library::CoreLibrary();
+ } else {
+ for (int i = 0; i < num_libraries; i++) {
+ each_library ^= libraries.At(i);
+ library_key = each_library.private_key();
+ if (library_key.Equals(private_key)) {
+ ctxt_library = each_library.raw();
+ break;
+ }
+ }
+ }
+ ASSERT(!ctxt_library.IsNull());
+ return ctxt_library.Evaluate(expression);
+}
+
DEFINE_NATIVE_ENTRY(TypedefMirror_declaration, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
const Class& cls = Class::Handle(type.type_class());
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index cd8182f..8f5a1a2 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -52,8 +52,9 @@
}
Map _makeMemberMap(List mirrors) {
- return new _UnmodifiableMapView(
- new Map<Symbol, dynamic>.fromIterable(mirrors, key: (e) => e.simpleName));
+ return new _UnmodifiableMapView<Symbol, DeclarationMirror>(
+ new Map<Symbol, DeclarationMirror>.fromIterable(
+ mirrors, key: (e) => e.simpleName));
}
String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
@@ -331,6 +332,95 @@
return new _InvocationTrampoline(this, selector);
}
+ // TODO(16539): Make these weak or soft.
+ static var _getFieldClosures = new HashMap();
+ static var _setFieldClosures = new HashMap();
+ static var _getFieldCallCounts = new HashMap();
+ static var _setFieldCallCounts = new HashMap();
+ static const _closureThreshold = 20;
+
+ _getFieldSlow(unwrapped) {
+ // Slow path factored out to give the fast path a better chance at being
+ // inlined.
+ var callCount = _getFieldCallCounts[unwrapped];
+ if (callCount == null) {
+ callCount = 0;
+ }
+ if (callCount == _closureThreshold) {
+ // We've seen a success getter invocation a few times: time to invest in a
+ // closure.
+ var f;
+ var atPosition = unwrapped.indexOf('@');
+ if (atPosition == -1) {
+ // Public symbol.
+ f = _eval('(x) => x.$unwrapped', null);
+ } else {
+ // Private symbol.
+ var withoutKey = unwrapped.substring(0, atPosition);
+ var privateKey = unwrapped.substring(atPosition);
+ f = _eval('(x) => x.$withoutKey', privateKey);
+ }
+ _getFieldClosures[unwrapped] = f;
+ _getFieldCallCounts.remove(unwrapped); // We won't look for this again.
+ return reflect(f(_reflectee));
+ }
+ var result = reflect(_invokeGetter(_reflectee, unwrapped));
+ // Only update call count if we don't throw to avoid creating closures for
+ // non-existent getters.
+ _getFieldCallCounts[unwrapped] = callCount + 1;
+ return result;
+ }
+
+ InstanceMirror getField(Symbol memberName) {
+ var unwrapped = _n(memberName);
+ var f = _getFieldClosures[unwrapped];
+ return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee));
+ }
+
+ _setFieldSlow(unwrapped, arg) {
+ // Slow path factored out to give the fast path a better chance at being
+ // inlined.
+ var callCount = _setFieldCallCounts[unwrapped];
+ if (callCount == null) {
+ callCount = 0;
+ }
+ if (callCount == _closureThreshold) {
+ // We've seen a success getter invocation a few times: time to invest in a
+ // closure.
+ var f;
+ var atPosition = unwrapped.indexOf('@');
+ if (atPosition == -1) {
+ // Public symbol.
+ f = _eval('(x, v) => x.$unwrapped = v', null);
+ } else {
+ // Private symbol.
+ var withoutKey = unwrapped.substring(0, atPosition);
+ var privateKey = unwrapped.substring(atPosition);
+ f = _eval('(x, v) => x.$withoutKey = v', privateKey);
+ }
+ _setFieldClosures[unwrapped] = f;
+ _setFieldCallCounts.remove(unwrapped);
+ return reflect(f(_reflectee, arg));
+ }
+ _invokeSetter(_reflectee, unwrapped, arg);
+ var result = reflect(arg);
+ // Only update call count if we don't throw to avoid creating closures for
+ // non-existent setters.
+ _setFieldCallCounts[unwrapped] = callCount + 1;
+ return result;
+ }
+
+ InstanceMirror setField(Symbol memberName, arg) {
+ var unwrapped = _n(memberName);
+ var f = _setFieldClosures[unwrapped];
+ return (f == null)
+ ? _setFieldSlow(unwrapped, arg)
+ : reflect(f(_reflectee, arg));
+ }
+
+ static _eval(expression, privateKey)
+ native "Mirrors_evalInLibraryWithPrivateKey";
+
// Override to include the receiver in the arguments.
InstanceMirror invoke(Symbol memberName,
List positionalArguments,
@@ -653,7 +743,8 @@
var constructorsList = _computeConstructors(_reflectee);
var stringName = _n(simpleName);
constructorsList.forEach((c) => c._patchConstructorName(stringName));
- _cachedConstructors = _makeMemberMap(constructorsList);
+ _cachedConstructors =
+ new Map.fromIterable(constructorsList, key: (e) => e.simpleName);
}
return _cachedConstructors;
}
diff --git a/runtime/lib/simd128.cc b/runtime/lib/simd128.cc
index d52530b..5485953 100644
--- a/runtime/lib/simd128.cc
+++ b/runtime/lib/simd128.cc
@@ -30,10 +30,10 @@
GET_NON_NULL_NATIVE_ARGUMENT(Double, y, arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Double, z, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(Double, w, arguments->NativeArgAt(4));
- float _x = x.value();
- float _y = y.value();
- float _z = z.value();
- float _w = w.value();
+ float _x = static_cast<float>(x.value());
+ float _y = static_cast<float>(y.value());
+ float _z = static_cast<float>(z.value());
+ float _w = static_cast<float>(w.value());
return Float32x4::New(_x, _y, _z, _w);
}
@@ -60,6 +60,14 @@
}
+DEFINE_NATIVE_ENTRY(Float32x4_fromFloat64x2, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, v, arguments->NativeArgAt(1));
+ float _x = static_cast<float>(v.x());
+ float _y = static_cast<float>(v.y());
+ return Float32x4::New(_x, _y, 0.0f, 0.0f);
+}
+
+
DEFINE_NATIVE_ENTRY(Float32x4_add, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, self, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, other, arguments->NativeArgAt(1));
@@ -708,4 +716,180 @@
}
+DEFINE_NATIVE_ENTRY(Float64x2_fromDoubles, 3) {
+ ASSERT(AbstractTypeArguments::CheckedHandle(
+ arguments->NativeArgAt(0)).IsNull());
+ GET_NON_NULL_NATIVE_ARGUMENT(Double, x, arguments->NativeArgAt(1));
+ GET_NON_NULL_NATIVE_ARGUMENT(Double, y, arguments->NativeArgAt(2));
+ return Float64x2::New(x.value(), y.value());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_splat, 2) {
+ ASSERT(AbstractTypeArguments::CheckedHandle(
+ arguments->NativeArgAt(0)).IsNull());
+ GET_NON_NULL_NATIVE_ARGUMENT(Double, v, arguments->NativeArgAt(1));
+ return Float64x2::New(v.value(), v.value());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_zero, 1) {
+ ASSERT(AbstractTypeArguments::CheckedHandle(
+ arguments->NativeArgAt(0)).IsNull());
+ return Float64x2::New(0.0, 0.0);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_fromFloat32x4, 2) {
+ ASSERT(AbstractTypeArguments::CheckedHandle(
+ arguments->NativeArgAt(0)).IsNull());
+ GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, v, arguments->NativeArgAt(1));
+ double _x = v.x();
+ double _y = v.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_add, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+ double _x = self.x() + other.x();
+ double _y = self.y() + other.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_negate, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ double _x = -self.x();
+ double _y = -self.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_sub, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+ double _x = self.x() - other.x();
+ double _y = self.y() - other.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_mul, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+ double _x = self.x() * other.x();
+ double _y = self.y() * other.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_div, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+ double _x = self.x() / other.x();
+ double _y = self.y() / other.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_scale, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Double, scale, arguments->NativeArgAt(1));
+ double _s = scale.value();
+ double _x = self.x() * _s;
+ double _y = self.y() * _s;
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_abs, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ double _x = fabs(self.x());
+ double _y = fabs(self.y());
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_clamp, 3) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, lo, arguments->NativeArgAt(1));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, hi, arguments->NativeArgAt(2));
+ // The order of the clamping must match the order of the optimized code:
+ // MAX(MIN(self, hi), lo).
+ double _x = self.x() < hi.x() ? self.x() : hi.x();
+ double _y = self.y() < hi.y() ? self.y() : hi.y();
+ _x = _x < lo.x() ? lo.x() : _x;
+ _y = _y < lo.y() ? lo.y() : _y;
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_getX, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ return Double::New(self.x());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_getY, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ return Double::New(self.y());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_getSignMask, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ uint32_t mx = (bit_cast<uint64_t>(self.x()) & 0x8000000000000000LL) >> 63;
+ uint32_t my = (bit_cast<uint64_t>(self.y()) & 0x8000000000000000LL) >> 63;
+ uint32_t value = mx | (my << 1);
+ return Integer::New(value);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_setX, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Double, x, arguments->NativeArgAt(1));
+ double _x = x.value();
+ double _y = self.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_setY, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Double, y, arguments->NativeArgAt(1));
+ double _x = self.x();
+ double _y = y.value();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_min, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other,
+ arguments->NativeArgAt(1));
+ double _x = self.x() < other.x() ? self.x() : other.x();
+ double _y = self.y() < other.y() ? self.y() : other.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_max, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other,
+ arguments->NativeArgAt(1));
+ double _x = self.x() > other.x() ? self.x() : other.x();
+ double _y = self.y() > other.y() ? self.y() : other.y();
+ return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_sqrt, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+ double _x = sqrt(self.x());
+ double _y = sqrt(self.y());
+ return Float64x2::New(_x, _y);
+}
+
} // namespace dart
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index 406786e..0a10465 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -300,6 +300,8 @@
TYPED_DATA_NATIVES(
GetFloat32x4, SetFloat32x4, Float32x4, value, 16, simd128_value_t)
TYPED_DATA_NATIVES(GetInt32x4, SetInt32x4, Int32x4, value, 16, simd128_value_t)
+TYPED_DATA_NATIVES(
+ GetFloat64x2, SetFloat64x2, Float64x2, value, 16, simd128_value_t)
DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt16, 2) {
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index aac1cda..7430819 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -230,6 +230,23 @@
}
+patch class Float64x2List {
+ /* patch */ factory Float64x2List(int length) {
+ return new _Float64x2Array(length);
+ }
+
+ /* patch */ factory Float64x2List.fromList(List<Float64x2> elements) {
+ return new _Float64x2Array(elements.length)
+ ..setRange(0, elements.length, elements);
+ }
+
+ /* patch */ factory Float64x2List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return new _Float64x2ArrayView(buffer, offsetInBytes, length);
+ }
+}
+
+
patch class Float32x4 {
/* patch */ factory Float32x4(double x, double y, double z, double w) {
return new _Float32x4(x, y, z, w);
@@ -243,6 +260,9 @@
/* patch */ factory Float32x4.fromInt32x4Bits(Int32x4 x) {
return new _Float32x4.fromInt32x4Bits(x);
}
+ /* patch */ factory Float32x4.fromFloat64x2(Float64x2 v) {
+ return new _Float32x4.fromFloat64x2(v);
+ }
}
@@ -259,6 +279,25 @@
}
+patch class Float64x2 {
+ /* patch */ factory Float64x2(double x, double y) {
+ return new _Float64x2(x, y);
+ }
+
+ /* patch */ factory Float64x2.splat(double v) {
+ return new _Float64x2.splat(v);
+ }
+
+ /* patch */ factory Float64x2.zero() {
+ return new _Float64x2.zero();
+ }
+
+ /* patch */ factory Float64x2.fromFloat32x4(Float32x4 v) {
+ return new _Float64x2.fromFloat32x4(v);
+ }
+}
+
+
patch class ByteData {
/* patch */ factory ByteData(int length) {
var list = new _Uint8Array(length);
@@ -630,6 +669,10 @@
Int32x4 _getInt32x4(int offsetInBytes) native "TypedData_GetInt32x4";
void _setInt32x4(int offsetInBytes, Int32x4 value)
native "TypedData_SetInt32x4";
+
+ Float64x2 _getFloat64x2(int offsetInBytes) native "TypedData_GetFloat64x2";
+ void _setFloat64x2(int offsetInBytes, Float64x2 value)
+ native "TypedData_SetFloat64x2";
}
@@ -1420,6 +1463,67 @@
}
+class _Float64x2Array extends _TypedList implements Float64x2List {
+ // Factory constructors.
+
+ factory _Float64x2Array(int length) {
+ return _new(length);
+ }
+
+ factory _Float64x2Array.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ if (length == null) {
+ length = (buffer.lengthInBytes - offsetInBytes) ~/
+ Float64x2List.BYTES_PER_ELEMENT;
+ }
+ return new _Float64x2ArrayView(buffer, offsetInBytes, length);
+ }
+
+
+ Float64x2 operator[](int index) {
+ if (index < 0 || index >= length) {
+ _throwRangeError(index, length);
+ }
+ return _getIndexedFloat64x2(index);
+ }
+
+ void operator[]=(int index, Float64x2 value) {
+ if (index < 0 || index >= length) {
+ _throwRangeError(index, length);
+ }
+ _setIndexedFloat64x2(index, value);
+ }
+
+ Iterator<Float64x2> get iterator {
+ return new _TypedListIterator<Float64x2>(this);
+ }
+
+
+ // Method(s) implementing the TypedData interface.
+
+ int get elementSizeInBytes {
+ return Float64x2List.BYTES_PER_ELEMENT;
+ }
+
+
+ // Internal utility methods.
+
+ _Float64x2Array _createList(int length) {
+ return _new(length);
+ }
+
+ Float64x2 _getIndexedFloat64x2(int index) {
+ return _getFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT);
+ }
+
+ void _setIndexedFloat64x2(int index, Float64x2 value) {
+ _setFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT, value);
+ }
+
+ static _Float64x2Array _new(int length) native "TypedData_Float64x2Array_new";
+}
+
+
class _ExternalInt8Array extends _TypedList implements Int8List {
// Factory constructors.
@@ -2111,6 +2215,61 @@
}
+class _ExternalFloat64x2Array extends _TypedList implements Float64x2List {
+ // Factory constructors.
+
+ factory _ExternalFloat64x2Array(int length) {
+ return _new(length);
+ }
+
+
+ // Method(s) implementing the List interface.
+
+ Float64x2 operator[](int index) {
+ if (index < 0 || index >= length) {
+ _throwRangeError(index, length);
+ }
+ return _getIndexedFloat64x2(index);
+ }
+
+ void operator[]=(int index, Float64x2 value) {
+ if (index < 0 || index >= length) {
+ _throwRangeError(index, length);
+ }
+ _setIndexedFloat64x2(index, value);
+ }
+
+ Iterator<Float64x2> get iterator {
+ return new _TypedListIterator<Float64x2>(this);
+ }
+
+
+ // Method(s) implementing the TypedData interface.
+
+ int get elementSizeInBytes {
+ return Float64x2List.BYTES_PER_ELEMENT;
+ }
+
+
+ // Internal utility methods.
+
+ Float64x2List _createList(int length) {
+ return new Float64x2List(length);
+ }
+
+ Float64x2 _getIndexedFloat64x2(int index) {
+ return _getFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT);
+ }
+
+ void _setIndexedFloat64x2(int index, Float64x2 value) {
+ _setFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT, value);
+ }
+
+ static _ExternalFloat64x2Array _new(int length) native
+ "ExternalTypedData_Float64x2Array_new";
+}
+
+
class _Float32x4 implements Float32x4 {
factory _Float32x4(double x, double y, double z, double w)
native "Float32x4_fromDoubles";
@@ -2118,6 +2277,8 @@
factory _Float32x4.zero() native "Float32x4_zero";
factory _Float32x4.fromInt32x4Bits(Int32x4 x)
native "Float32x4_fromInt32x4Bits";
+ factory _Float32x4.fromFloat64x2(Float64x2 v)
+ native "Float32x4_fromFloat64x2";
Float32x4 operator +(Float32x4 other) {
return _add(other);
}
@@ -2270,6 +2431,69 @@
native "Int32x4_select";
}
+
+class _Float64x2 implements Float64x2 {
+ factory _Float64x2(double x, double y) native "Float64x2_fromDoubles";
+ factory _Float64x2.splat(double v) native "Float64x2_splat";
+ factory _Float64x2.zero() native "Float64x2_zero";
+ factory _Float64x2.fromFloat32x4(Float32x4 v) native "Float64x2_fromFloat32x4";
+
+ Float64x2 operator +(Float64x2 other) {
+ return _add(other);
+ }
+ Float64x2 _add(Float64x2 other) native "Float64x2_add";
+ Float64x2 operator -() {
+ return _negate();
+ }
+ Float64x2 _negate() native "Float64x2_negate";
+ Float64x2 operator -(Float64x2 other) {
+ return _sub(other);
+ }
+ Float64x2 _sub(Float64x2 other) native "Float64x2_sub";
+ Float64x2 operator *(Float64x2 other) {
+ return _mul(other);
+ }
+ Float64x2 _mul(Float64x2 other) native "Float64x2_mul";
+ Float64x2 operator /(Float64x2 other) {
+ return _div(other);
+ }
+ Float64x2 _div(Float64x2 other) native "Float64x2_div";
+
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ Float64x2 scale(double s) native "Float64x2_scale";
+ /// Returns the absolute value of this [Float64x2].
+ Float64x2 abs() native "Float64x2_abs";
+
+ /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+ Float64x2 clamp(Float64x2 lowerLimit,
+ Float64x2 upperLimit) native "Float64x2_clamp";
+
+ /// Extracted x value.
+ double get x native "Float64x2_getX";
+ /// Extracted y value.
+ double get y native "Float64x2_getY";
+
+ /// Extract the sign bits from each lane return them in the first 2 bits.
+ int get signMask native "Float64x2_getSignMask";
+
+ /// Returns a new [Float64x2] copied from [this] with a new x value.
+ Float64x2 withX(double x) native "Float64x2_setX";
+ /// Returns a new [Float64x2] copied from [this] with a new y value.
+ Float64x2 withY(double y) native "Float64x2_setY";
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float64x2 min(Float64x2 other) native "Float64x2_min";
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float64x2 max(Float64x2 other) native "Float64x2_max";
+
+ /// Returns the lane-wise square root of [this].
+ Float64x2 sqrt() native "Float64x2_sqrt";
+}
+
+
+
class _TypedListIterator<E> implements Iterator<E> {
final List<E> _array;
final int _length;
@@ -2996,6 +3220,58 @@
}
+class _Float64x2ArrayView extends _TypedListView implements Float64x2List {
+ // Constructor.
+ _Float64x2ArrayView(ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
+ : super(buffer, _offsetInBytes,
+ _defaultIfNull(_length,
+ ((buffer.lengthInBytes - _offsetInBytes) ~/
+ Float64x2List.BYTES_PER_ELEMENT))) {
+ _rangeCheck(buffer.lengthInBytes,
+ offsetInBytes,
+ length * Float64x2List.BYTES_PER_ELEMENT);
+ _offsetAlignmentCheck(_offsetInBytes, Float64x2List.BYTES_PER_ELEMENT);
+ }
+
+
+ // Method(s) implementing List interface.
+
+ Float64x2 operator[](int index) {
+ if (index < 0 || index >= length) {
+ _throwRangeError(index, length);
+ }
+ return _typedData._getFloat64x2(offsetInBytes +
+ (index * Float64x2List.BYTES_PER_ELEMENT));
+ }
+
+ void operator[]=(int index, Float64x2 value) {
+ if (index < 0 || index >= length) {
+ _throwRangeError(index, length);
+ }
+ _typedData._setFloat64x2(offsetInBytes +
+ (index * Float64x2List.BYTES_PER_ELEMENT), value);
+ }
+
+ Iterator<Float64x2> get iterator {
+ return new _TypedListIterator<Float64x2>(this);
+ }
+
+
+ // Method(s) implementing TypedData interface.
+
+ int get elementSizeInBytes {
+ return Float64x2List.BYTES_PER_ELEMENT;
+ }
+
+
+ // Internal utility methods.
+
+ Float64x2List _createList(int length) {
+ return new Float64x2List(length);
+ }
+}
+
+
class _ByteDataView implements ByteData {
_ByteDataView(ByteBuffer _buffer, int _offsetInBytes, int _lengthInBytes)
: _typedData = _buffer, // _buffer is guaranteed to be a TypedData here.
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 52adc16..b35c4f5 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -76,6 +76,7 @@
union {
float float_storage[4];
int32_t int_storage[4];
+ double double_storage[2];
};
simd128_value_t& readFrom(const float* v) {
float_storage[0] = v[0];
@@ -91,6 +92,11 @@
int_storage[3] = v[3];
return *this;
}
+ simd128_value_t& readFrom(const double* v) {
+ double_storage[0] = v[0];
+ double_storage[1] = v[1];
+ return *this;
+ }
simd128_value_t& readFrom(const simd128_value_t* v) {
*this = *v;
return *this;
@@ -107,6 +113,10 @@
v[2] = int_storage[2];
v[3] = int_storage[3];
}
+ void writeTo(double* v) {
+ v[0] = double_storage[0];
+ v[1] = double_storage[1];
+ }
void writeTo(simd128_value_t* v) {
*v = *this;
}
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index fd4ce60..cee8b72 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -256,9 +256,7 @@
// library tag handler so that we can load all the bootstrap libraries.
isolate->set_library_tag_handler(BootstrapLibraryTagHandler);
- // Enter the Dart Scope as we will be calling back into the library
- // tag handler when compiling the bootstrap libraries.
- Dart_EnterScope();
+ HANDLESCOPE(isolate);
// Create library objects for all the bootstrap libraries.
for (intptr_t i = 0;
@@ -309,9 +307,6 @@
SetupNativeResolver();
}
- // Exit the Dart scope.
- Dart_ExitScope();
-
// Restore the library tag handler for the isolate.
isolate->set_library_tag_handler(saved_tag_handler);
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index efc972a..0c8faca 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -147,6 +147,7 @@
V(TypedData_Float64Array_new, 1) \
V(TypedData_Float32x4Array_new, 1) \
V(TypedData_Int32x4Array_new, 1) \
+ V(TypedData_Float64x2Array_new, 1) \
V(ExternalTypedData_Int8Array_new, 1) \
V(ExternalTypedData_Uint8Array_new, 1) \
V(ExternalTypedData_Uint8ClampedArray_new, 1) \
@@ -160,6 +161,7 @@
V(ExternalTypedData_Float64Array_new, 1) \
V(ExternalTypedData_Float32x4Array_new, 1) \
V(ExternalTypedData_Int32x4Array_new, 1) \
+ V(ExternalTypedData_Float64x2Array_new, 1) \
V(TypedData_length, 1) \
V(TypedData_setRange, 5) \
V(TypedData_GetInt8, 2) \
@@ -186,6 +188,8 @@
V(TypedData_SetFloat32x4, 3) \
V(TypedData_GetInt32x4, 2) \
V(TypedData_SetInt32x4, 3) \
+ V(TypedData_GetFloat64x2, 2) \
+ V(TypedData_SetFloat64x2, 3) \
V(ByteData_ToEndianInt16, 2) \
V(ByteData_ToEndianUint16, 2) \
V(ByteData_ToEndianInt32, 2) \
@@ -197,6 +201,7 @@
V(Float32x4_fromDoubles, 5) \
V(Float32x4_splat, 2) \
V(Float32x4_fromInt32x4Bits, 2) \
+ V(Float32x4_fromFloat64x2, 2) \
V(Float32x4_zero, 1) \
V(Float32x4_add, 2) \
V(Float32x4_negate, 1) \
@@ -228,6 +233,26 @@
V(Float32x4_sqrt, 1) \
V(Float32x4_reciprocal, 1) \
V(Float32x4_reciprocalSqrt, 1) \
+ V(Float64x2_fromDoubles, 3) \
+ V(Float64x2_splat, 2) \
+ V(Float64x2_zero, 1) \
+ V(Float64x2_fromFloat32x4, 2) \
+ V(Float64x2_add, 2) \
+ V(Float64x2_negate, 1) \
+ V(Float64x2_sub, 2) \
+ V(Float64x2_mul, 2) \
+ V(Float64x2_div, 2) \
+ V(Float64x2_scale, 2) \
+ V(Float64x2_abs, 1) \
+ V(Float64x2_clamp, 3) \
+ V(Float64x2_getX, 1) \
+ V(Float64x2_getY, 1) \
+ V(Float64x2_getSignMask, 1) \
+ V(Float64x2_setX, 2) \
+ V(Float64x2_setY, 2) \
+ V(Float64x2_min, 2) \
+ V(Float64x2_max, 2) \
+ V(Float64x2_sqrt, 1) \
V(Int32x4_fromInts, 5) \
V(Int32x4_fromBools, 5) \
V(Int32x4_fromFloat32x4Bits, 2) \
@@ -259,6 +284,7 @@
V(Isolate_mainPort, 0) \
V(Isolate_spawnFunction, 1) \
V(Isolate_spawnUri, 1) \
+ V(Mirrors_evalInLibraryWithPrivateKey, 2) \
V(Mirrors_makeLocalClassMirror, 1) \
V(Mirrors_makeLocalTypeMirror, 1) \
V(Mirrors_makeLocalMirrorSystem, 0) \
diff --git a/runtime/vm/cha.cc b/runtime/vm/cha.cc
index 5a4f54f..5c5ccb0 100644
--- a/runtime/vm/cha.cc
+++ b/runtime/vm/cha.cc
@@ -13,16 +13,27 @@
namespace dart {
bool CHA::HasSubclasses(intptr_t cid) {
+ Isolate* isolate = Isolate::Current();
+ const bool has_subclasses = HasSubclassesSafe(cid);
+ if (!has_subclasses) {
+ isolate->set_cha_used(true);
+ }
+ return has_subclasses;
+}
+
+
+bool CHA::HasSubclassesSafe(intptr_t cid) {
ASSERT(cid >= kInstanceCid);
- const ClassTable& class_table = *Isolate::Current()->class_table();
- const Class& cls = Class::Handle(class_table.At(cid));
+ Isolate* isolate = Isolate::Current();
+ const ClassTable& class_table = *isolate->class_table();
+ const Class& cls = Class::Handle(isolate, class_table.At(cid));
ASSERT(!cls.IsNull());
if (cls.IsObjectClass()) {
// Class Object has subclasses, although we do not keep track of them.
return true;
}
const GrowableObjectArray& cls_direct_subclasses =
- GrowableObjectArray::Handle(cls.direct_subclasses());
+ GrowableObjectArray::Handle(isolate, cls.direct_subclasses());
return
!cls_direct_subclasses.IsNull() && (cls_direct_subclasses.Length() > 0);
}
@@ -61,26 +72,32 @@
ZoneGrowableArray<intptr_t>* CHA::GetSubclassIdsOf(intptr_t cid) {
ASSERT(cid > kInstanceCid);
- const ClassTable& class_table = *Isolate::Current()->class_table();
- const Class& cls = Class::Handle(class_table.At(cid));
+ Isolate* isolate = Isolate::Current();
+ const ClassTable& class_table = *isolate->class_table();
+ const Class& cls = Class::Handle(isolate, class_table.At(cid));
ASSERT(!cls.IsNull());
ZoneGrowableArray<intptr_t>* ids = new ZoneGrowableArray<intptr_t>();
CollectSubclassIds(ids, cls);
+ isolate->set_cha_used(true);
return ids;
}
bool CHA::HasOverride(const Class& cls, const String& function_name) {
+ Isolate* isolate = Isolate::Current();
const GrowableObjectArray& cls_direct_subclasses =
- GrowableObjectArray::Handle(cls.direct_subclasses());
+ GrowableObjectArray::Handle(isolate, cls.direct_subclasses());
// Subclasses of Object are not tracked by CHA. Safely assume that overrides
// exist.
- if (cls.IsObjectClass()) return true;
+ if (cls.IsObjectClass()) {
+ return true;
+ }
if (cls_direct_subclasses.IsNull()) {
+ isolate->set_cha_used(true);
return false;
}
- Class& direct_subclass = Class::Handle();
+ Class& direct_subclass = Class::Handle(isolate);
for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) {
direct_subclass ^= cls_direct_subclasses.At(i);
// Unfinalized classes are treated as non-existent for CHA purposes,
@@ -94,6 +111,7 @@
return true;
}
}
+ isolate->set_cha_used(true);
return false;
}
@@ -101,20 +119,22 @@
ZoneGrowableArray<Function*>* CHA::GetNamedInstanceFunctionsOf(
const ZoneGrowableArray<intptr_t>& cids,
const String& function_name) {
+ Isolate* isolate = Isolate::Current();
ASSERT(!function_name.IsNull());
- const ClassTable& class_table = *Isolate::Current()->class_table();
+ const ClassTable& class_table = *isolate->class_table();
ZoneGrowableArray<Function*>* functions = new ZoneGrowableArray<Function*>();
- Class& cls = Class::Handle();
- Function& cls_function = Function::Handle();
+ Class& cls = Class::Handle(isolate);
+ Function& cls_function = Function::Handle(isolate);
for (intptr_t i = 0; i < cids.length(); i++) {
const intptr_t cid = cids[i];
ASSERT(cid > kInstanceCid);
cls = class_table.At(cid);
cls_function = cls.LookupDynamicFunction(function_name);
if (!cls_function.IsNull()) {
- functions->Add(&Function::ZoneHandle(cls_function.raw()));
+ functions->Add(&Function::ZoneHandle(isolate, cls_function.raw()));
}
}
+ isolate->set_cha_used(true);
return functions;
}
@@ -122,10 +142,12 @@
ZoneGrowableArray<Function*>* CHA::GetOverridesOf(const Function& function) {
ASSERT(!function.IsNull());
ASSERT(function.IsDynamicFunction());
- const Class& function_owner = Class::Handle(function.Owner());
- const String& function_name = String::Handle(function.name());
+ Isolate* isolate = Isolate::Current();
+ const Class& function_owner = Class::Handle(isolate, function.Owner());
+ const String& function_name = String::Handle(isolate, function.name());
ZoneGrowableArray<intptr_t>* cids = new ZoneGrowableArray<intptr_t>();
CollectSubclassIds(cids, function_owner);
+ isolate->set_cha_used(true);
return GetNamedInstanceFunctionsOf(*cids, function_name);
}
diff --git a/runtime/vm/cha.h b/runtime/vm/cha.h
index d20445f..18a0bcb 100644
--- a/runtime/vm/cha.h
+++ b/runtime/vm/cha.h
@@ -19,6 +19,10 @@
// Returns true if the class given by its cid has subclasses.
static bool HasSubclasses(intptr_t cid);
+ // Use only on known private classes that can never be subclassed by lazy
+ // class finalization. Does not affect Isolate::use_cha flag.
+ static bool HasSubclassesSafe(intptr_t cid);
+
// Returns an array containing the cids of the direct and indirect subclasses
// of the class given by its cid.
// Must not be called for kInstanceCid.
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 8c8abfc..7221924 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -36,30 +36,18 @@
// optimizations may have become invalid.
// Only methods which owner classes where subclasses can be invalid.
// TODO(srdjan): Be even more precise by recording the exact CHA optimization.
-static void RemoveOptimizedCode(
+static void RemoveCHAOptimizedCode(
const GrowableArray<intptr_t>& added_subclass_to_cids) {
ASSERT(FLAG_use_cha);
if (added_subclass_to_cids.is_empty()) return;
- // Deoptimize all live frames.
- DeoptimizeIfOwner(added_subclass_to_cids);
// Switch all functions' code to unoptimized.
const ClassTable& class_table = *Isolate::Current()->class_table();
Class& cls = Class::Handle();
- Array& array = Array::Handle();
- Function& function = Function::Handle();
for (intptr_t i = 0; i < added_subclass_to_cids.length(); i++) {
intptr_t cid = added_subclass_to_cids[i];
cls = class_table.At(cid);
ASSERT(!cls.IsNull());
- array = cls.functions();
- const intptr_t num_functions = array.IsNull() ? 0 : array.Length();
- for (intptr_t f = 0; f < num_functions; f++) {
- function ^= array.At(f);
- ASSERT(!function.IsNull());
- if (function.HasOptimizedCode()) {
- function.SwitchToUnoptimizedCode();
- }
- }
+ cls.DisableCHAOptimizedCode();
}
}
@@ -2195,7 +2183,7 @@
CheckForLegalConstClass(cls);
}
if (FLAG_use_cha) {
- RemoveOptimizedCode(added_subclass_to_cids);
+ RemoveCHAOptimizedCode(added_subclass_to_cids);
}
}
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 0b0c6f9..511daa5 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1437,8 +1437,16 @@
const Code& target_code = Code::Handle(
caller_code.GetStaticCallTargetCodeAt(frame->pc()));
ASSERT(!target_code.IsNull());
- // Since there was a reference to the target_code in the caller_code, it is
- // not possible for the target_function's code to be disconnected.
+ if (!target_function.HasCode()) {
+ // If target code was unoptimized than the code must have been kept
+ // connected to the function.
+ ASSERT(target_code.is_optimized());
+ const Error& error =
+ Error::Handle(Compiler::CompileFunction(target_function));
+ if (!error.IsNull()) {
+ Exceptions::PropagateError(error);
+ }
+ }
ASSERT(target_function.HasCode());
ASSERT(target_function.raw() == target_code.function());
@@ -1486,6 +1494,11 @@
uword lazy_deopt_jump = optimized_code.GetLazyDeoptPc();
ASSERT(lazy_deopt_jump != 0);
CodePatcher::InsertCallAt(pc, lazy_deopt_jump);
+ if (FLAG_trace_patching) {
+ const String& name = String::Handle(function.name());
+ OS::PrintErr("InsertCallAt: %" Px " to %" Px " for %s\n", pc,
+ lazy_deopt_jump, name.ToCString());
+ }
// Mark code as dead (do not GC its embedded objects).
optimized_code.set_is_alive(false);
}
@@ -1507,36 +1520,6 @@
}
-// Returns true if the given array of cids contains the given cid.
-static bool ContainsCid(const GrowableArray<intptr_t>& cids, intptr_t cid) {
- for (intptr_t i = 0; i < cids.length(); i++) {
- if (cids[i] == cid) {
- return true;
- }
- }
- return false;
-}
-
-
-// Deoptimize optimized code on stack if its class is in the 'classes' array.
-void DeoptimizeIfOwner(const GrowableArray<intptr_t>& classes) {
- DartFrameIterator iterator;
- StackFrame* frame = iterator.NextFrame();
- Code& optimized_code = Code::Handle();
- while (frame != NULL) {
- optimized_code = frame->LookupDartCode();
- if (optimized_code.is_optimized()) {
- const intptr_t owner_cid = Class::Handle(Function::Handle(
- optimized_code.function()).Owner()).id();
- if (ContainsCid(classes, owner_cid)) {
- DeoptimizeAt(optimized_code, frame->pc());
- }
- }
- frame = iterator.NextFrame();
- }
-}
-
-
static void CopySavedRegisters(uword saved_registers_address,
fpu_register_t** fpu_registers,
intptr_t** cpu_registers) {
diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h
index 57ffb50..3931588 100644
--- a/runtime/vm/code_generator.h
+++ b/runtime/vm/code_generator.h
@@ -96,7 +96,6 @@
void DeoptimizeAt(const Code& optimized_code, uword pc);
void DeoptimizeAll();
-void DeoptimizeIfOwner(const GrowableArray<intptr_t>& classes);
double DartModulo(double a, double b);
void SinCos(double arg, double* sin_res, double* cos_res);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 9a8cadd..e8a5b4f 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -263,6 +263,7 @@
bool is_compiled = false;
Isolate* isolate = Isolate::Current();
HANDLESCOPE(isolate);
+ isolate->set_cha_used(false);
// We may reattempt compilation if the function needs to be assembled using
// far branches on ARM and MIPS. In the else branch of the setjmp call,
@@ -540,6 +541,12 @@
const Code& code = Code::Handle(
Code::FinalizeCode(function, &assembler, optimized));
code.set_is_optimized(optimized);
+ // CHA should not be used for unoptimized code.
+ ASSERT(optimized || !isolate->cha_used());
+ if (isolate->cha_used()) {
+ Class::Handle(function.Owner()).RegisterCHACode(code);
+ isolate->set_cha_used(false);
+ }
graph_compiler.FinalizePcDescriptors(code);
graph_compiler.FinalizeDeoptInfo(code);
graph_compiler.FinalizeStackmaps(code);
diff --git a/runtime/vm/compiler_stats.cc b/runtime/vm/compiler_stats.cc
index 2a0671f..786fff9 100644
--- a/runtime/vm/compiler_stats.cc
+++ b/runtime/vm/compiler_stats.cc
@@ -61,6 +61,11 @@
intptr_t CompilerStats::num_tokens_rewind = 0;
intptr_t CompilerStats::num_tokens_lookahead = 0;
+intptr_t CompilerStats::num_lib_cache_hit = 0;
+intptr_t CompilerStats::num_names_cached = 0;
+intptr_t CompilerStats::make_accessor_name = 0;
+intptr_t CompilerStats::make_field_name = 0;
+
void CompilerStats::Print() {
if (!FLAG_compiler_stats) {
return;
@@ -79,6 +84,12 @@
OS::Print("Token lookahead: %" Pd " (%" Pd "%% of tokens checked)\n",
num_tokens_lookahead,
(100 * num_tokens_lookahead) / num_token_checks);
+
+ OS::Print("Lib names cached: %" Pd "\n", num_names_cached);
+ OS::Print("Lib name cache hit: %" Pd "\n", num_lib_cache_hit);
+ OS::Print("Accessor mangling: %" Pd " field->acc %" Pd " acc->field\n",
+ make_accessor_name, make_field_name);
+
OS::Print("Source length: %" Pd " characters\n", src_length);
int64_t scan_usecs = scanner_timer.TotalElapsedTime();
OS::Print("Scanner time: %" Pd64 " msecs\n",
diff --git a/runtime/vm/compiler_stats.h b/runtime/vm/compiler_stats.h
index 363a537..57d4d65 100644
--- a/runtime/vm/compiler_stats.h
+++ b/runtime/vm/compiler_stats.h
@@ -15,7 +15,6 @@
DECLARE_FLAG(bool, compiler_stats);
-
class CompilerStats : AllStatic {
public:
static intptr_t num_tokens_total;
@@ -26,6 +25,11 @@
static intptr_t num_tokens_rewind;
static intptr_t num_tokens_lookahead;
+ static intptr_t num_lib_cache_hit;
+ static intptr_t num_names_cached;
+ static intptr_t make_accessor_name;
+ static intptr_t make_field_name;
+
static intptr_t src_length; // Total number of characters in source.
static intptr_t code_allocated; // Bytes allocated for generated code.
static Timer parser_timer; // Cumulative runtime of parser.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 91d6eb7..754f0d6 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -920,6 +920,17 @@
}
+DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate) {
+ TRACE_API_CALL(CURRENT_FUNC);
+ if (isolate == NULL) {
+ FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
+ }
+ // TODO(16615): Validate isolate parameter.
+ Isolate* iso = reinterpret_cast<Isolate*>(isolate);
+ return iso->init_callback_data();
+}
+
+
DART_EXPORT Dart_Handle Dart_DebugName() {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
@@ -928,10 +939,11 @@
-DART_EXPORT void Dart_EnterIsolate(Dart_Isolate dart_isolate) {
+DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate) {
CHECK_NO_ISOLATE(Isolate::Current());
- Isolate* isolate = reinterpret_cast<Isolate*>(dart_isolate);
- Isolate::SetCurrent(isolate);
+ // TODO(16615): Validate isolate parameter.
+ Isolate* iso = reinterpret_cast<Isolate*>(isolate);
+ Isolate::SetCurrent(iso);
}
@@ -1007,6 +1019,7 @@
if (isolate == NULL) {
FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
}
+ // TODO(16615): Validate isolate parameter.
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
iso->ScheduleInterrupts(Isolate::kApiInterrupt);
}
@@ -1017,6 +1030,7 @@
if (isolate == NULL) {
FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
}
+ // TODO(16615): Validate isolate parameter.
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
return iso->MakeRunnable();
}
@@ -3059,21 +3073,25 @@
}
const Class& cls = Class::Handle(isolate, type_obj.type_class());
- // Mark all fields as nullable.
- Class& iterate_cls = Class::Handle(isolate, cls.raw());
- Field& field = Field::Handle(isolate);
- Array& fields = Array::Handle(isolate);
- while (!iterate_cls.IsNull()) {
- fields = iterate_cls.fields();
- iterate_cls = iterate_cls.SuperClass();
- for (int field_num = 0; field_num < fields.Length(); field_num++) {
- field ^= fields.At(field_num);
- if (field.is_static()) {
- continue;
+ if (!cls.is_fields_marked_nullable()) {
+ // Mark all fields as nullable.
+ Class& iterate_cls = Class::Handle(isolate, cls.raw());
+ Field& field = Field::Handle(isolate);
+ Array& fields = Array::Handle(isolate);
+ while (!iterate_cls.IsNull()) {
+ iterate_cls.set_is_fields_marked_nullable();
+ fields = iterate_cls.fields();
+ iterate_cls = iterate_cls.SuperClass();
+ for (int field_num = 0; field_num < fields.Length(); field_num++) {
+ field ^= fields.At(field_num);
+ if (field.is_static()) {
+ continue;
+ }
+ field.UpdateGuardedCidAndLength(Object::null_object());
}
- field.UpdateGuardedCidAndLength(Object::null_object());
}
}
+
// Allocate an object for the given class.
return Api::NewHandle(isolate, Instance::New(cls));
}
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 30b3ad5..4a7642e 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3059,6 +3059,7 @@
&err);
EXPECT(isolate != NULL);
EXPECT_EQ(mydata, reinterpret_cast<intptr_t>(Dart_CurrentIsolateData()));
+ EXPECT_EQ(mydata, reinterpret_cast<intptr_t>(Dart_IsolateData(isolate)));
Dart_ShutdownIsolate();
}
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index bc7efff..a858a5f 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -899,7 +899,7 @@
const Library& library,
const String& fname) {
ASSERT(!library.IsNull());
- const Object& object = Object::Handle(library.LookupObject(fname));
+ const Object& object = Object::Handle(library.ResolveName(fname));
if (!object.IsNull() && object.IsFunction()) {
return Function::Cast(object).raw();
}
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 150e451..3981beb 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -251,6 +251,7 @@
case 0x57: return "xorps";
case 0x58: return "addps";
case 0x59: return "mulps";
+ case 0x5A: return "cvtps2pd";
case 0x5C: return "subps";
case 0x5D: return "minps";
case 0x5E: return "divps";
@@ -262,6 +263,23 @@
}
}
+static const char* PackedDoubleMnemonic(uint8_t data) {
+ const char* mnemonic = NULL;
+ if (data == 0xFE) mnemonic = "paddd ";
+ if (data == 0xFA) mnemonic = "psubd ";
+ if (data == 0x2F) mnemonic = "comisd ";
+ if (data == 0x58) mnemonic = "addpd ";
+ if (data == 0x5C) mnemonic = "subpd ";
+ if (data == 0x59) mnemonic = "mulpd ";
+ if (data == 0x5E) mnemonic = "divpd ";
+ if (data == 0x5D) mnemonic = "minpd ";
+ if (data == 0x5F) mnemonic = "maxpd ";
+ if (data == 0x51) mnemonic = "sqrtpd ";
+ if (data == 0x5A) mnemonic = "cvtpd2ps ";
+ ASSERT(mnemonic != NULL);
+ return mnemonic;
+}
+
static bool IsTwoXmmRegInstruction(uint8_t f0byte) {
return f0byte == 0x28 || f0byte == 0x11 || f0byte == 0x12 ||
@@ -269,7 +287,7 @@
f0byte == 0x51 || f0byte == 0x52 || f0byte == 0x53 ||
f0byte == 0x54 || f0byte == 0x56 || f0byte == 0x58 ||
f0byte == 0x59 || f0byte == 0x5C || f0byte == 0x5D ||
- f0byte == 0x5E || f0byte == 0x5F;
+ f0byte == 0x5E || f0byte == 0x5F || f0byte == 0x5A;
}
@@ -1602,11 +1620,11 @@
Print(",");
PrintXmmRegister(rm);
data += 2;
- } else if ((*data == 0xFE) || (*data == 0xFA) || (*data == 0x2F)) {
- const char* mnemonic = NULL;
- if (*data == 0xFE) mnemonic = "paddd ";
- if (*data == 0xFA) mnemonic = "psubd ";
- if (*data == 0x2F) mnemonic = "comisd ";
+ } else if ((*data == 0xFE) || (*data == 0xFA) || (*data == 0x2F) ||
+ (*data == 0x58) || (*data == 0x5C) || (*data == 0x59) ||
+ (*data == 0x5E) || (*data == 0x5D) || (*data == 0x5F) ||
+ (*data == 0x51) || (*data == 0x5A)) {
+ const char* mnemonic = PackedDoubleMnemonic(*data);
int mod, regop, rm;
GetModRm(*(data+1), &mod, ®op, &rm);
Print(mnemonic);
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 86f8d25..4d58672 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -1287,6 +1287,22 @@
mnemonic = "paddd";
} else if (opcode == 0xFA) {
mnemonic = "psubd";
+ } else if (opcode == 0x58) {
+ mnemonic = "addpd";
+ } else if (opcode == 0x5C) {
+ mnemonic = "subpd";
+ } else if (opcode == 0x59) {
+ mnemonic = "mulpd";
+ } else if (opcode == 0x5E) {
+ mnemonic = "divpd";
+ } else if (opcode == 0x5D) {
+ mnemonic = "minpd";
+ } else if (opcode == 0x5F) {
+ mnemonic = "maxpd";
+ } else if (opcode == 0x51) {
+ mnemonic = "sqrtpd";
+ } else if (opcode == 0x5A) {
+ mnemonic = "cvtpd2ps";
} else {
UnimplementedInstruction();
}
@@ -1379,6 +1395,11 @@
get_modrm(*current, &mod, ®op, &rm);
AppendToBuffer("movq %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
+ } else if (opcode == 0x58) {
+ int mod, regop, rm;
+ get_modrm(*current, &mod, ®op, &rm);
+ AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
+ current += PrintRightXMMOperand(current);
} else {
UnimplementedInstruction();
}
@@ -1552,6 +1573,10 @@
return "movsxb";
case 0xBF:
return "movsxw";
+ case 0x12:
+ return "movhlps";
+ case 0x16:
+ return "movlhps";
default:
return NULL;
}
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index f5678b7..d716b25 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2173,14 +2173,15 @@
AbstractTypeArguments::ZoneHandle(node->type().arguments());
Value* element_type = BuildInstantiatedTypeArguments(node->token_pos(),
type_args);
+ Value* num_elements =
+ Bind(new ConstantInstr(Smi::ZoneHandle(Smi::New(node->length()))));
CreateArrayInstr* create = new CreateArrayInstr(node->token_pos(),
- node->length(),
- node->type(),
- element_type);
+ element_type,
+ num_elements);
Value* array_val = Bind(create);
{ LocalVariable* tmp_var = EnterTempLocalScope(array_val);
- const intptr_t class_id = create->Type()->ToCid();
+ const intptr_t class_id = kArrayCid;
const intptr_t deopt_id = Isolate::kNoDeoptId;
for (int i = 0; i < node->length(); ++i) {
Value* array = Bind(new LoadLocalInstr(*tmp_var));
@@ -2553,32 +2554,6 @@
}
-// Class that recognizes factories and returns corresponding result cid.
-class FactoryRecognizer : public AllStatic {
- public:
- // Return kDynamicCid if factory is not recognized.
- static intptr_t ResultCid(const Function& factory) {
- ASSERT(factory.IsFactory());
- const Class& function_class = Class::Handle(factory.Owner());
- const Library& lib = Library::Handle(function_class.library());
- ASSERT((lib.raw() == Library::CoreLibrary()) ||
- (lib.raw() == Library::TypedDataLibrary()));
- const String& factory_name = String::Handle(factory.name());
-#define RECOGNIZE_FACTORY(test_factory_symbol, cid, fp) \
- if (String::EqualsIgnoringPrivateKey( \
- factory_name, Symbols::test_factory_symbol())) { \
- ASSERT(factory.CheckSourceFingerprint(fp)); \
- return cid; \
- } \
-
-RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY);
-#undef RECOGNIZE_FACTORY
-
- return kDynamicCid;
- }
-};
-
-
static intptr_t GetResultCidOfListFactory(ConstructorCallNode* node) {
const Function& function = node->constructor();
const Class& function_class = Class::Handle(function.Owner());
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index ead8e24..b527bff 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -49,6 +49,32 @@
V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 879975401) \
+// Class that recognizes factories and returns corresponding result cid.
+class FactoryRecognizer : public AllStatic {
+ public:
+ // Return kDynamicCid if factory is not recognized.
+ static intptr_t ResultCid(const Function& factory) {
+ ASSERT(factory.IsFactory());
+ const Class& function_class = Class::Handle(factory.Owner());
+ const Library& lib = Library::Handle(function_class.library());
+ ASSERT((lib.raw() == Library::CoreLibrary()) ||
+ (lib.raw() == Library::TypedDataLibrary()));
+ const String& factory_name = String::Handle(factory.name());
+#define RECOGNIZE_FACTORY(test_factory_symbol, cid, fp) \
+ if (String::EqualsIgnoringPrivateKey( \
+ factory_name, Symbols::test_factory_symbol())) { \
+ ASSERT(factory.CheckSourceFingerprint(fp)); \
+ return cid; \
+ } \
+
+RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY);
+#undef RECOGNIZE_FACTORY
+
+ return kDynamicCid;
+ }
+};
+
+
// A class to collect the exits from an inlined function during graph
// construction so they can be plugged into the caller's flow graph.
class InlineExitCollector: public ZoneAllocated {
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 41c43b6..91ff5fe 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -26,6 +26,8 @@
DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
// Flags for inlining heuristics.
+DEFINE_FLAG(int, inline_getters_setters_smaller_than, 10,
+ "Always inline getters and setters that have fewer instructions");
DEFINE_FLAG(int, inlining_depth_threshold, 3,
"Inline function calls up to threshold nesting depth");
DEFINE_FLAG(int, inlining_size_threshold, 25,
@@ -271,9 +273,7 @@
}
StaticCallInstr* static_call = current->AsStaticCall();
if (static_call != NULL) {
- if (static_call->function().IsInlineable()) {
- static_calls_.Add(StaticCallInfo(static_call));
- }
+ static_calls_.Add(StaticCallInfo(static_call));
continue;
}
PolymorphicInstanceCallInstr* instance_call =
@@ -365,7 +365,8 @@
// Prevent methods becoming humongous and thus slow to compile.
return false;
}
- if (instr_count <= FLAG_inlining_size_threshold) {
+ // 'instr_count' can be 0 if it was not computed yet.
+ if ((instr_count != 0) && (instr_count <= FLAG_inlining_size_threshold)) {
return true;
}
if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) {
@@ -375,7 +376,7 @@
(instr_count <= FLAG_inlining_constant_arguments_size_threshold)) {
return true;
}
- if (MethodRecognizer::AlwaysInline(callee)) {
+ if (FlowGraphInliner::AlwaysInline(callee)) {
return true;
}
return false;
@@ -777,7 +778,7 @@
}
}
const Function& target = call->function();
- if (!MethodRecognizer::AlwaysInline(target) &&
+ if (!FlowGraphInliner::AlwaysInline(target) &&
(call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
TRACE_INLINING(OS::Print(
" => %s (deopt count %d)\n Bailout: cold %f\n",
@@ -849,7 +850,7 @@
const ICData& ic_data = call->ic_data();
const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
- if (!MethodRecognizer::AlwaysInline(target) &&
+ if (!FlowGraphInliner::AlwaysInline(target) &&
(call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
TRACE_INLINING(OS::Print(
" => %s (deopt count %d)\n Bailout: cold %f\n",
@@ -1448,6 +1449,18 @@
}
+bool FlowGraphInliner::AlwaysInline(const Function& function) {
+ if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
+ function.IsImplicitSetterFunction() || function.IsSetterFunction()) {
+ const intptr_t count = function.optimized_instruction_count();
+ if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) {
+ return true;
+ }
+ }
+ return MethodRecognizer::AlwaysInline(function);
+}
+
+
void FlowGraphInliner::Inline() {
// Collect graph info and store it on the function.
// We might later use it for an early bailout from the inlining.
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index dfee0d5..e408d92 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -11,6 +11,7 @@
class Field;
class FlowGraph;
+class Function;
template <typename T> class GrowableArray;
class FlowGraphInliner : ValueObject {
@@ -22,6 +23,8 @@
static void CollectGraphInfo(FlowGraph* flow_graph);
+ static bool AlwaysInline(const Function& function);
+
private:
FlowGraph* flow_graph_;
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 83d9045..2c7c516 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -354,10 +354,12 @@
(other_binop->right()->definition() == right_def)) {
(*merge_candidates)[k] = NULL; // Clear it.
// Append a LoadIndexed behind TRUNC_DIV and MOD.
+ ASSERT(curr_instr->HasUses());
AppendLoadIndexedForMerged(
curr_instr,
MergedMathInstr::ResultIndexOf(curr_instr->op_kind()),
kArrayCid);
+ ASSERT(other_binop->HasUses());
AppendLoadIndexedForMerged(
other_binop,
MergedMathInstr::ResultIndexOf(other_binop->op_kind()),
@@ -414,10 +416,12 @@
(other_op->value()->definition() == def)) {
(*merge_candidates)[k] = NULL; // Clear it.
// Append a LoadIndexed behind SIN and COS.
+ ASSERT(curr_instr->HasUses());
AppendLoadIndexedForMerged(
curr_instr,
MergedMathInstr::ResultIndexOf(curr_instr->kind()),
kTypedDataFloat64ArrayCid);
+ ASSERT(other_op->HasUses());
AppendLoadIndexedForMerged(
other_op,
MergedMathInstr::ResultIndexOf(other_op->kind()),
@@ -467,7 +471,9 @@
binop->right()->definition());
} else if ((binop->op_kind() == Token::kTRUNCDIV) ||
(binop->op_kind() == Token::kMOD)) {
- div_mod_merge.Add(binop);
+ if (binop->HasUses()) {
+ div_mod_merge.Add(binop);
+ }
}
} else if (it.Current()->IsBinaryMintOp()) {
BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
@@ -480,7 +486,9 @@
MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
if ((math_unary->kind() == MethodRecognizer::kMathSin) ||
(math_unary->kind() == MethodRecognizer::kMathCos)) {
- sin_cos_merge.Add(math_unary);
+ if (math_unary->HasUses()) {
+ sin_cos_merge.Add(math_unary);
+ }
}
}
}
@@ -3680,6 +3688,31 @@
ConstantInstr* cid_instr = new ConstantInstr(Smi::Handle(Smi::New(cid)));
ReplaceCall(call, cid_instr);
}
+
+ if (call->function().IsFactory()) {
+ const Class& function_class = Class::Handle(call->function().Owner());
+ if ((function_class.library() == Library::CoreLibrary()) ||
+ (function_class.library() == Library::TypedDataLibrary())) {
+ intptr_t cid = FactoryRecognizer::ResultCid(call->function());
+ switch (cid) {
+ case kArrayCid: {
+ Value* type = new Value(call->ArgumentAt(0));
+ Value* num_elements = new Value(call->ArgumentAt(1));
+ if (num_elements->BindsToConstant() &&
+ num_elements->BoundConstant().IsSmi()) {
+ intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
+ if (length >= 0 && length <= Array::kMaxElements) {
+ CreateArrayInstr* create_array =
+ new CreateArrayInstr(call->token_pos(), type, num_elements);
+ ReplaceCall(call, create_array);
+ }
+ }
+ }
+ default:
+ break;
+ }
+ }
+ }
}
@@ -7119,11 +7152,15 @@
void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
(instr->instance()->definition()->IsCreateArray())) {
- const intptr_t length =
+ Value* num_elements =
instr->instance()->definition()->AsCreateArray()->num_elements();
- const Object& result = Smi::ZoneHandle(Smi::New(length));
- SetValue(instr, result);
- return;
+ if (num_elements->BindsToConstant() &&
+ num_elements->BoundConstant().IsSmi()) {
+ intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
+ const Object& result = Smi::ZoneHandle(Smi::New(length));
+ SetValue(instr, result);
+ return;
+ }
}
if (instr->IsImmutableLengthLoad()) {
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 8ad89cc..99a92bb 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -96,7 +96,9 @@
BranchInstr* branch = instr->AsBranch();
if (branch != NULL) {
ConstrainedCompileType* constrained_type = branch->constrained_type();
- if (constrained_type != NULL) constrained_type->Update();
+ if (constrained_type != NULL) {
+ constrained_type->Update();
+ }
}
}
}
@@ -225,7 +227,7 @@
ConstrainedCompileType* FlowGraphTypePropagator::MarkNonNullable(
Definition* def) {
CompileType* current = TypeOf(def);
- if (current->is_nullable()) {
+ if (current->is_nullable() && (current->ToCid() != kNullCid)) {
ConstrainedCompileType* constrained_type =
new NotNullConstrainedCompileType(current);
SetTypeOf(def, constrained_type->ToCompileType());
@@ -512,7 +514,7 @@
if (FLAG_use_cha || IsKnownPrivateClass(type_class)) {
// A known private class cannot be subclassed or implemented.
if (!type_class.is_implemented() &&
- !CHA::HasSubclasses(type_class.id())) {
+ !CHA::HasSubclassesSafe(type_class.id())) {
cid_ = type_class.id();
} else {
cid_ = kDynamicCid;
@@ -922,7 +924,8 @@
CompileType CreateArrayInstr::ComputeType() const {
- return CompileType::FromAbstractType(type(), CompileType::kNonNullable);
+ // TODO(fschneider): Add abstract type and type arguments to the compile type.
+ return CompileType::FromCid(kArrayCid);
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index ba68b52..4ec778a 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -151,6 +151,21 @@
}
+Representation LoadFieldInstr::representation() const {
+ if (IsUnboxedLoad()) {
+ const intptr_t cid = field()->UnboxedFieldCid();
+ switch (cid) {
+ case kDoubleCid:
+ return kUnboxedDouble;
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ default:
+ UNREACHABLE();
+ }
+ }
+ return kTagged;
+}
+
+
bool StoreInstanceFieldInstr::IsUnboxedStore() const {
return FLAG_unbox_double_fields && field().IsUnboxedField();
}
@@ -161,6 +176,22 @@
}
+Representation StoreInstanceFieldInstr::RequiredInputRepresentation(
+ intptr_t index) const {
+ ASSERT((index == 0) || (index == 1));
+ if ((index == 1) && IsUnboxedStore()) {
+ const intptr_t cid = field().UnboxedFieldCid();
+ switch (cid) {
+ case kDoubleCid:
+ return kUnboxedDouble;
+ default:
+ UNREACHABLE();
+ }
+ }
+ return kTagged;
+}
+
+
bool GuardFieldInstr::AttributesEqual(Instruction* other) const {
return field().raw() == other->AsGuardField()->field().raw();
}
@@ -408,11 +439,6 @@
bool MethodRecognizer::AlwaysInline(const Function& function) {
- if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
- function.IsImplicitSetterFunction() || function.IsSetterFunction()) {
- return true;
- }
-
const Class& function_class = Class::Handle(function.Owner());
const Library& lib = Library::Handle(function_class.library());
if (!IsRecognizedLibrary(lib)) {
@@ -1388,6 +1414,14 @@
}
+// A math unary instruction has a side effect (exception
+// thrown) if the argument is not a number.
+// TODO(srdjan): eliminate if has no uses and input is guaranteed to be number.
+Definition* MathUnaryInstr::Canonicalize(FlowGraph* flow_graph) {
+ return this;
+}
+
+
Definition* LoadFieldInstr::Canonicalize(FlowGraph* flow_graph) {
if (!HasUses()) return NULL;
if (!IsImmutableLengthLoad()) return this;
@@ -2917,8 +2951,14 @@
CreateArrayInstr* create_array = value()->definition()->AsCreateArray();
ASSERT(create_array != NULL);
// Check if the string interpolation has only constant inputs.
- GrowableArray<ConstantInstr*> constants(create_array->num_elements());
- for (intptr_t i = 0; i < create_array->num_elements(); i++) {
+ Value* num_elements = create_array->num_elements();
+ if (!num_elements->BindsToConstant() ||
+ !num_elements->BoundConstant().IsSmi()) {
+ return this;
+ }
+ intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
+ GrowableArray<ConstantInstr*> constants(length);
+ for (intptr_t i = 0; i < length; i++) {
constants.Add(NULL);
}
for (Value::Iterator it(create_array->input_use_list());
@@ -2944,7 +2984,7 @@
}
// Interpolate string at compile time.
const Array& array_argument =
- Array::Handle(Array::New(create_array->num_elements()));
+ Array::Handle(Array::New(length));
for (intptr_t i = 0; i < constants.length(); i++) {
array_argument.SetAt(i, constants[i]->value());
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index d3959f3..1b63f7a 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -3509,11 +3509,7 @@
bool IsPotentialUnboxedStore() const;
- virtual Representation RequiredInputRepresentation(intptr_t index) const {
- ASSERT((index == 0) || (index == 1));
- if ((index == 1) && IsUnboxedStore()) return kUnboxedDouble;
- return kTagged;
- }
+ virtual Representation RequiredInputRepresentation(intptr_t index) const;
private:
friend class FlowGraphOptimizer; // For ASSERT(initialization_).
@@ -4095,29 +4091,28 @@
};
-class CreateArrayInstr : public TemplateDefinition<1> {
+class CreateArrayInstr : public TemplateDefinition<2> {
public:
CreateArrayInstr(intptr_t token_pos,
- intptr_t num_elements,
- const AbstractType& type,
- Value* element_type)
- : token_pos_(token_pos),
- num_elements_(num_elements),
- type_(type) {
- ASSERT(type_.IsZoneHandle());
- ASSERT(!type_.IsNull());
- ASSERT(type_.IsFinalized());
- SetInputAt(0, element_type);
+ Value* element_type,
+ Value* num_elements)
+ : token_pos_(token_pos) {
+ SetInputAt(kElementTypePos, element_type);
+ SetInputAt(kLengthPos, num_elements);
}
+ enum {
+ kElementTypePos = 0,
+ kLengthPos = 1
+ };
+
DECLARE_INSTRUCTION(CreateArray)
virtual CompileType ComputeType() const;
- intptr_t num_elements() const { return num_elements_; }
intptr_t token_pos() const { return token_pos_; }
- const AbstractType& type() const { return type_; }
- Value* element_type() const { return inputs_[0]; }
+ Value* element_type() const { return inputs_[kElementTypePos]; }
+ Value* num_elements() const { return inputs_[kLengthPos]; }
virtual void PrintOperandsTo(BufferFormatter* f) const;
@@ -4129,8 +4124,6 @@
private:
const intptr_t token_pos_;
- const intptr_t num_elements_;
- const AbstractType& type_;
DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
};
@@ -4263,9 +4256,7 @@
const Field* field() const { return field_; }
void set_field(const Field* field) { field_ = field; }
- virtual Representation representation() const {
- return IsUnboxedLoad() ? kUnboxedDouble : kTagged;
- }
+ virtual Representation representation() const;
bool IsUnboxedLoad() const;
@@ -4918,6 +4909,8 @@
virtual bool MayThrow() const { return false; }
+ Definition* Canonicalize(FlowGraph* flow_graph);
+
private:
const MethodRecognizer::Kind kind_;
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index bb286e3..977763a 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1583,16 +1583,16 @@
class StoreInstanceFieldSlowPath : public SlowPathCode {
public:
- explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
- : instruction_(instruction) { }
+ StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+ const Class& cls)
+ : instruction_(instruction), cls_(cls) { }
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
__ Comment("StoreInstanceFieldSlowPath");
__ Bind(entry_label());
- const Class& double_class = compiler->double_class();
const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+ Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+ const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
LocationSummary* locs = instruction_->locs();
locs->live_registers()->Remove(locs->out());
@@ -1610,6 +1610,7 @@
private:
StoreInstanceFieldInstr* instruction_;
+ const Class& cls_;
};
@@ -1653,12 +1654,22 @@
DRegister value = EvenDRegisterOf(locs()->in(1).fpu_reg());
Register temp = locs()->temp(0).reg();
Register temp2 = locs()->temp(1).reg();
+ const intptr_t cid = field().UnboxedFieldCid();
if (is_initialization_) {
+ const Class* cls = NULL;
+ switch (cid) {
+ case kDoubleCid:
+ cls = &compiler->double_class();
+ break;
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ default:
+ UNREACHABLE();
+ }
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, *cls);
compiler->AddSlowPathCode(slow_path);
- __ TryAllocate(compiler->double_class(),
+ __ TryAllocate(*cls,
slow_path->entry_label(),
temp,
temp2);
@@ -1670,7 +1681,15 @@
} else {
__ ldr(temp, FieldAddress(instance_reg, field().Offset()));
}
- __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ switch (cid) {
+ case kDoubleCid:
+ __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ break;
+ default:
+ UNREACHABLE();
+ }
+
return;
}
@@ -1680,25 +1699,36 @@
Register temp2 = locs()->temp(1).reg();
DRegister fpu_temp = EvenDRegisterOf(locs()->temp(2).fpu_reg());
- Label store_pointer, copy_payload;
+ Label store_pointer;
+ Label copy_double;
+ Label store_double;
+
__ LoadObject(temp, Field::ZoneHandle(field().raw()));
- __ ldr(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
- __ CompareImmediate(temp2, kDoubleCid);
- __ b(&store_pointer, NE);
+
__ ldr(temp2, FieldAddress(temp, Field::is_nullable_offset()));
__ CompareImmediate(temp2, kNullCid);
__ b(&store_pointer, EQ);
+
__ ldrb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
__ tst(temp2, ShifterOperand(1 << Field::kUnboxingCandidateBit));
__ b(&store_pointer, EQ);
+ __ ldr(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
+ __ CompareImmediate(temp2, kDoubleCid);
+ __ b(&store_double, EQ);
+
+ // Fall through.
+ __ b(&store_pointer);
+
+ __ Bind(&store_double);
+
__ ldr(temp, FieldAddress(instance_reg, field().Offset()));
__ CompareImmediate(temp,
reinterpret_cast<intptr_t>(Object::null()));
- __ b(©_payload, NE);
+ __ b(©_double, NE);
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, compiler->double_class());
compiler->AddSlowPathCode(slow_path);
if (!compiler->is_optimizing()) {
@@ -1715,7 +1745,7 @@
__ StoreIntoObject(instance_reg,
FieldAddress(instance_reg, field().Offset()),
temp2);
- __ Bind(©_payload);
+ __ Bind(©_double);
__ LoadDFromOffset(fpu_temp,
value_reg,
Double::value_offset() - kHeapObjectTag);
@@ -1822,11 +1852,12 @@
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
- const intptr_t kNumInputs = 1;
+ const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- locs->set_in(0, Location::RegisterLocation(R1));
+ locs->set_in(kElementTypePos, Location::RegisterLocation(R1));
+ locs->set_in(kLengthPos, Location::RegisterLocation(R2));
locs->set_out(Location::RegisterLocation(R0));
return locs;
}
@@ -1834,8 +1865,8 @@
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Allocate the array. R2 = length, R1 = element type.
- ASSERT(locs()->in(0).reg() == R1);
- __ LoadImmediate(R2, Smi::RawValue(num_elements()));
+ ASSERT(locs()->in(kElementTypePos).reg() == R1);
+ ASSERT(locs()->in(kLengthPos).reg() == R2);
compiler->GenerateCall(token_pos(),
&StubCode::AllocateArrayLabel(),
PcDescriptors::kOther,
@@ -1925,7 +1956,16 @@
DRegister result = EvenDRegisterOf(locs()->out().fpu_reg());
Register temp = locs()->temp(0).reg();
__ ldr(temp, FieldAddress(instance_reg, offset_in_bytes()));
- __ LoadDFromOffset(result, temp, Double::value_offset() - kHeapObjectTag);
+ intptr_t cid = field()->UnboxedFieldCid();
+ switch (cid) {
+ case kDoubleCid:
+ __ LoadDFromOffset(result, temp,
+ Double::value_offset() - kHeapObjectTag);
+ break;
+ // TODO(johnmccutchan): Add Float32x4 path here.
+ default:
+ UNREACHABLE();
+ }
return;
}
@@ -1936,20 +1976,27 @@
DRegister value = EvenDRegisterOf(locs()->temp(0).fpu_reg());
Label load_pointer;
+ Label load_double;
+
__ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(result_reg,
Field::is_nullable_offset());
- __ ldr(temp, field_cid_operand);
- __ CompareImmediate(temp, kDoubleCid);
- __ b(&load_pointer, NE);
-
__ ldr(temp, field_nullability_operand);
__ CompareImmediate(temp, kNullCid);
__ b(&load_pointer, EQ);
+ __ ldr(temp, field_cid_operand);
+ __ CompareImmediate(temp, kDoubleCid);
+ __ b(&load_double, EQ);
+
+ // Fall through.
+ __ b(&load_pointer);
+
+ __ Bind(&load_double);
+
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -1968,6 +2015,9 @@
result_reg,
Double::value_offset() - kHeapObjectTag);
__ b(&done);
+
+ // TODO(johnmccutchan): Add Float32x4 path here.
+
__ Bind(&load_pointer);
}
__ LoadFromOffset(kWord, result_reg,
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 50075ba..c1b3e04 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1592,16 +1592,16 @@
class StoreInstanceFieldSlowPath : public SlowPathCode {
public:
- explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
- : instruction_(instruction) { }
+ StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+ const Class& cls)
+ : instruction_(instruction), cls_(cls) { }
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
__ Comment("StoreInstanceFieldSlowPath");
__ Bind(entry_label());
- const Class& double_class = compiler->double_class();
const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+ Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+ const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
LocationSummary* locs = instruction_->locs();
locs->live_registers()->Remove(locs->out());
@@ -1619,6 +1619,7 @@
private:
StoreInstanceFieldInstr* instruction_;
+ const Class& cls_;
};
@@ -1662,13 +1663,23 @@
XmmRegister value = locs()->in(1).fpu_reg();
Register temp = locs()->temp(0).reg();
Register temp2 = locs()->temp(1).reg();
+ const intptr_t cid = field().UnboxedFieldCid();
if (is_initialization_) {
+ const Class* cls = NULL;
+ switch (cid) {
+ case kDoubleCid:
+ cls = &compiler->double_class();
+ break;
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ default:
+ UNREACHABLE();
+ }
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, *cls);
compiler->AddSlowPathCode(slow_path);
- __ TryAllocate(compiler->double_class(),
+ __ TryAllocate(*cls,
slow_path->entry_label(),
Assembler::kFarJump,
temp,
@@ -1681,7 +1692,14 @@
} else {
__ movl(temp, FieldAddress(instance_reg, field().Offset()));
}
- __ movsd(FieldAddress(temp, Double::value_offset()), value);
+ switch (cid) {
+ case kDoubleCid:
+ __ movsd(FieldAddress(temp, Double::value_offset()), value);
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ break;
+ default:
+ UNREACHABLE();
+ }
return;
}
@@ -1691,26 +1709,37 @@
Register temp2 = locs()->temp(1).reg();
FpuRegister fpu_temp = locs()->temp(2).fpu_reg();
- Label store_pointer, copy_payload;
+ Label store_pointer;
+ Label copy_double;
+ Label store_double;
+
__ LoadObject(temp, Field::ZoneHandle(field().raw()));
- __ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
- Immediate(kDoubleCid));
- __ j(NOT_EQUAL, &store_pointer);
+
__ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
Immediate(kNullCid));
__ j(EQUAL, &store_pointer);
+
__ movzxb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
__ testl(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
__ j(ZERO, &store_pointer);
+ __ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
+ Immediate(kDoubleCid));
+ __ j(EQUAL, &store_double);
+
+ // Fall through.
+ __ jmp(&store_pointer);
+
+ __ Bind(&store_double);
+
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movl(temp, FieldAddress(instance_reg, field().Offset()));
__ cmpl(temp, raw_null);
- __ j(NOT_EQUAL, ©_payload);
+ __ j(NOT_EQUAL, ©_double);
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, compiler->double_class());
compiler->AddSlowPathCode(slow_path);
if (!compiler->is_optimizing()) {
@@ -1729,7 +1758,7 @@
FieldAddress(instance_reg, field().Offset()),
temp2);
- __ Bind(©_payload);
+ __ Bind(©_double);
__ movsd(fpu_temp, FieldAddress(value_reg, Double::value_offset()));
__ movsd(FieldAddress(temp, Double::value_offset()), fpu_temp);
__ jmp(&skip_store);
@@ -1835,11 +1864,12 @@
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
- const intptr_t kNumInputs = 1;
+ const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(ECX));
+ locs->set_in(1, Location::RegisterLocation(EDX));
locs->set_out(Location::RegisterLocation(EAX));
return locs;
}
@@ -1848,7 +1878,7 @@
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Allocate the array. EDX = length, ECX = element type.
ASSERT(locs()->in(0).reg() == ECX);
- __ movl(EDX, Immediate(Smi::RawValue(num_elements())));
+ ASSERT(locs()->in(1).reg() == EDX);
compiler->GenerateCall(token_pos(),
&StubCode::AllocateArrayLabel(),
PcDescriptors::kOther,
@@ -1938,7 +1968,15 @@
XmmRegister result = locs()->out().fpu_reg();
Register temp = locs()->temp(0).reg();
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
- __ movsd(result, FieldAddress(temp, Double::value_offset()));
+ const intptr_t cid = field()->UnboxedFieldCid();
+ switch (cid) {
+ case kDoubleCid:
+ __ movsd(result, FieldAddress(temp, Double::value_offset()));
+ break;
+ // TODO(johnmccutchan): Add Float32x4 path here.
+ default:
+ UNREACHABLE();
+ }
return;
}
@@ -1949,17 +1987,22 @@
XmmRegister value = locs()->temp(0).fpu_reg();
Label load_pointer;
+ Label load_double;
__ LoadObject(result, Field::ZoneHandle(field()->raw()));
FieldAddress field_cid_operand(result, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(result, Field::is_nullable_offset());
- __ cmpl(field_cid_operand, Immediate(kDoubleCid));
- __ j(NOT_EQUAL, &load_pointer);
-
__ cmpl(field_nullability_operand, Immediate(kNullCid));
__ j(EQUAL, &load_pointer);
+ __ cmpl(field_cid_operand, Immediate(kDoubleCid));
+ __ j(EQUAL, &load_double);
+
+ // Fall through.
+ __ jmp(&load_pointer);
+
+ __ Bind(&load_double);
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -1977,6 +2020,9 @@
__ movsd(value, FieldAddress(temp, Double::value_offset()));
__ movsd(FieldAddress(result, Double::value_offset()), value);
__ jmp(&done);
+
+ // TODO(johnmccutchan): Add Float32x4 path here.
+
__ Bind(&load_pointer);
}
__ movl(result, FieldAddress(instance_reg, offset_in_bytes()));
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 94d1ee5..450c24b 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1658,16 +1658,16 @@
class StoreInstanceFieldSlowPath : public SlowPathCode {
public:
- explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
- : instruction_(instruction) { }
+ StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+ const Class& cls)
+ : instruction_(instruction), cls_(cls) { }
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
__ Comment("StoreInstanceFieldSlowPath");
__ Bind(entry_label());
- const Class& double_class = compiler->double_class();
const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+ Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+ const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
LocationSummary* locs = instruction_->locs();
locs->live_registers()->Remove(locs->out());
@@ -1685,6 +1685,7 @@
private:
StoreInstanceFieldInstr* instruction_;
+ const Class& cls_;
};
@@ -1728,12 +1729,21 @@
DRegister value = locs()->in(1).fpu_reg();
Register temp = locs()->temp(0).reg();
Register temp2 = locs()->temp(1).reg();
+ const intptr_t cid = field().UnboxedFieldCid();
if (is_initialization_) {
+ const Class* cls = NULL;
+ switch (cid) {
+ case kDoubleCid:
+ cls = &compiler->double_class();
+ break;
+ default:
+ UNREACHABLE();
+ }
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, *cls);
compiler->AddSlowPathCode(slow_path);
- __ TryAllocate(compiler->double_class(),
+ __ TryAllocate(*cls,
slow_path->entry_label(),
temp,
temp2);
@@ -1745,7 +1755,13 @@
} else {
__ lw(temp, FieldAddress(instance_reg, field().Offset()));
}
- __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ switch (cid) {
+ case kDoubleCid:
+ __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ break;
+ default:
+ UNREACHABLE();
+ }
return;
}
@@ -1755,22 +1771,33 @@
Register temp2 = locs()->temp(1).reg();
DRegister fpu_temp = locs()->temp(2).fpu_reg();
- Label store_pointer, copy_payload;
+ Label store_pointer;
+ Label copy_double;
+ Label store_double;
+
__ LoadObject(temp, Field::ZoneHandle(field().raw()));
- __ lw(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
- __ BranchNotEqual(temp2, kDoubleCid, &store_pointer);
+
__ lw(temp2, FieldAddress(temp, Field::is_nullable_offset()));
__ BranchEqual(temp2, kNullCid, &store_pointer);
+
__ lbu(temp2, FieldAddress(temp, Field::kind_bits_offset()));
__ andi(CMPRES1, temp2, Immediate(1 << Field::kUnboxingCandidateBit));
__ beq(CMPRES1, ZR, &store_pointer);
+ __ lw(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
+ __ BranchEqual(temp2, kDoubleCid, &store_double);
+
+ // Fall through.
+ __ b(&store_pointer);
+
+ __ Bind(&store_double);
+
__ lw(temp, FieldAddress(instance_reg, field().Offset()));
__ BranchNotEqual(temp, reinterpret_cast<int32_t>(Object::null()),
- ©_payload);
+ ©_double);
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, compiler->double_class());
compiler->AddSlowPathCode(slow_path);
if (!compiler->is_optimizing()) {
@@ -1788,7 +1815,7 @@
FieldAddress(instance_reg, field().Offset()),
temp2);
- __ Bind(©_payload);
+ __ Bind(©_double);
__ LoadDFromOffset(fpu_temp,
value_reg,
Double::value_offset() - kHeapObjectTag);
@@ -1897,11 +1924,12 @@
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
- const intptr_t kNumInputs = 1;
+ const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(A0));
+ locs->set_in(1, Location::RegisterLocation(A1));
locs->set_out(Location::RegisterLocation(V0));
return locs;
}
@@ -1911,7 +1939,7 @@
__ TraceSimMsg("CreateArrayInstr");
// Allocate the array. A1 = length, A0 = element type.
ASSERT(locs()->in(0).reg() == A0);
- __ LoadImmediate(A1, Smi::RawValue(num_elements()));
+ ASSERT(locs()->in(1).reg() == A1);
compiler->GenerateCall(token_pos(),
&StubCode::AllocateArrayLabel(),
PcDescriptors::kOther,
@@ -2003,7 +2031,15 @@
DRegister result = locs()->out().fpu_reg();
Register temp = locs()->temp(0).reg();
__ lw(temp, FieldAddress(instance_reg, offset_in_bytes()));
- __ LoadDFromOffset(result, temp, Double::value_offset() - kHeapObjectTag);
+ intptr_t cid = field()->UnboxedFieldCid();
+ switch (cid) {
+ case kDoubleCid:
+ __ LoadDFromOffset(result, temp,
+ Double::value_offset() - kHeapObjectTag);
+ break;
+ default:
+ UNREACHABLE();
+ }
return;
}
@@ -2014,18 +2050,25 @@
DRegister value = locs()->temp(0).fpu_reg();
Label load_pointer;
+ Label load_double;
+
__ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(result_reg,
Field::is_nullable_offset());
- __ lw(temp, field_cid_operand);
- __ BranchNotEqual(temp, kDoubleCid, &load_pointer);
-
__ lw(temp, field_nullability_operand);
__ BranchEqual(temp, kNullCid, &load_pointer);
+ __ lw(temp, field_cid_operand);
+ __ BranchEqual(temp, kDoubleCid, &load_double);
+
+ // Fall through.
+ __ b(&load_pointer);
+
+ __ Bind(&load_double);
+
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index bc1a553..f47abad 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1492,16 +1492,16 @@
class StoreInstanceFieldSlowPath : public SlowPathCode {
public:
- explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
- : instruction_(instruction) { }
+ StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+ const Class& cls)
+ : instruction_(instruction), cls_(cls) { }
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
__ Comment("StoreInstanceFieldSlowPath");
__ Bind(entry_label());
- const Class& double_class = compiler->double_class();
const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+ Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+ const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
LocationSummary* locs = instruction_->locs();
locs->live_registers()->Remove(locs->out());
@@ -1519,6 +1519,7 @@
private:
StoreInstanceFieldInstr* instruction_;
+ const Class& cls_;
};
@@ -1562,13 +1563,23 @@
XmmRegister value = locs()->in(1).fpu_reg();
Register temp = locs()->temp(0).reg();
Register temp2 = locs()->temp(1).reg();
+ const intptr_t cid = field().UnboxedFieldCid();
if (is_initialization_) {
+ const Class* cls = NULL;
+ switch (cid) {
+ case kDoubleCid:
+ cls = &compiler->double_class();
+ break;
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ default:
+ UNREACHABLE();
+ }
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, *cls);
compiler->AddSlowPathCode(slow_path);
- __ TryAllocate(compiler->double_class(),
+ __ TryAllocate(*cls,
slow_path->entry_label(),
Assembler::kFarJump,
temp,
@@ -1581,7 +1592,14 @@
} else {
__ movq(temp, FieldAddress(instance_reg, field().Offset()));
}
- __ movsd(FieldAddress(temp, Double::value_offset()), value);
+ switch (cid) {
+ case kDoubleCid:
+ __ movsd(FieldAddress(temp, Double::value_offset()), value);
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ break;
+ default:
+ UNREACHABLE();
+ }
return;
}
@@ -1591,24 +1609,35 @@
Register temp2 = locs()->temp(1).reg();
FpuRegister fpu_temp = locs()->temp(2).fpu_reg();
- Label store_pointer, copy_payload;
+ Label store_pointer;
+ Label copy_double;
+ Label store_double;
+
__ LoadObject(temp, Field::ZoneHandle(field().raw()), PP);
- __ cmpq(FieldAddress(temp, Field::guarded_cid_offset()),
- Immediate(kDoubleCid));
- __ j(NOT_EQUAL, &store_pointer);
+
__ cmpq(FieldAddress(temp, Field::is_nullable_offset()),
Immediate(kNullCid));
__ j(EQUAL, &store_pointer);
+
__ movzxb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
__ testq(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
__ j(ZERO, &store_pointer);
+ __ cmpq(FieldAddress(temp, Field::guarded_cid_offset()),
+ Immediate(kDoubleCid));
+ __ j(EQUAL, &store_double);
+
+ // Fall through.
+ __ jmp(&store_pointer);
+
+ __ Bind(&store_double);
+
__ movq(temp, FieldAddress(instance_reg, field().Offset()));
__ CompareObject(temp, Object::null_object(), PP);
- __ j(NOT_EQUAL, ©_payload);
+ __ j(NOT_EQUAL, ©_double);
StoreInstanceFieldSlowPath* slow_path =
- new StoreInstanceFieldSlowPath(this);
+ new StoreInstanceFieldSlowPath(this, compiler->double_class());
compiler->AddSlowPathCode(slow_path);
if (!compiler->is_optimizing()) {
@@ -1626,7 +1655,7 @@
FieldAddress(instance_reg, field().Offset()),
temp2);
- __ Bind(©_payload);
+ __ Bind(©_double);
__ movsd(fpu_temp, FieldAddress(value_reg, Double::value_offset()));
__ movsd(FieldAddress(temp, Double::value_offset()), fpu_temp);
__ jmp(&skip_store);
@@ -1728,11 +1757,12 @@
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
- const intptr_t kNumInputs = 1;
+ const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(RBX));
+ locs->set_in(1, Location::RegisterLocation(R10));
locs->set_out(Location::RegisterLocation(RAX));
return locs;
}
@@ -1741,7 +1771,7 @@
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Allocate the array. R10 = length, RBX = element type.
ASSERT(locs()->in(0).reg() == RBX);
- __ LoadImmediate(R10, Immediate(Smi::RawValue(num_elements())), PP);
+ ASSERT(locs()->in(1).reg() == R10);
compiler->GenerateCall(token_pos(),
&StubCode::AllocateArrayLabel(),
PcDescriptors::kOther,
@@ -1831,7 +1861,15 @@
XmmRegister result = locs()->out().fpu_reg();
Register temp = locs()->temp(0).reg();
__ movq(temp, FieldAddress(instance_reg, offset_in_bytes()));
- __ movsd(result, FieldAddress(temp, Double::value_offset()));
+ intptr_t cid = field()->UnboxedFieldCid();
+ switch (cid) {
+ case kDoubleCid:
+ __ movsd(result, FieldAddress(temp, Double::value_offset()));
+ break;
+ // TODO(johnmccutchan): Add Float32x4 path here.
+ default:
+ UNREACHABLE();
+ }
return;
}
@@ -1842,16 +1880,23 @@
XmmRegister value = locs()->temp(0).fpu_reg();
Label load_pointer;
+ Label load_double;
+
__ LoadObject(result, Field::ZoneHandle(field()->raw()), PP);
-
- __ cmpq(FieldAddress(result, Field::guarded_cid_offset()),
- Immediate(kDoubleCid));
- __ j(NOT_EQUAL, &load_pointer);
__ cmpq(FieldAddress(result, Field::is_nullable_offset()),
Immediate(kNullCid));
__ j(EQUAL, &load_pointer);
+ __ cmpq(FieldAddress(result, Field::guarded_cid_offset()),
+ Immediate(kDoubleCid));
+ __ j(EQUAL, &load_double);
+
+ // Fall through.
+ __ jmp(&load_pointer);
+
+ __ Bind(&load_double);
+
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -1869,6 +1914,9 @@
__ movsd(value, FieldAddress(temp, Double::value_offset()));
__ movsd(FieldAddress(result, Double::value_offset()), value);
__ jmp(&done);
+
+ // TODO(johnmccutchan): Add Float32x4 path here.
+
__ Bind(&load_pointer);
}
__ movq(result, FieldAddress(instance_reg, offset_in_bytes()));
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index d1605d9..82f4d11 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -117,6 +117,7 @@
V(_Float64Array, _new, TypedData_Float64Array_new, 311965335) \
V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 775330800) \
V(_Int32x4Array, _new, TypedData_Int32x4Array_new, 2074077580) \
+ V(_Float64x2Array, _new, TypedData_Float64x2Array_new, 1540328543) \
V(_Int8Array, ., TypedData_Int8Array_factory, 545976988) \
V(_Uint8Array, ., TypedData_Uint8Array_factory, 981297074) \
V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1617830104) \
@@ -130,6 +131,7 @@
V(_Float64Array, ., TypedData_Float64Array_factory, 1599078532) \
V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 879975401) \
V(_Int32x4Array, ., TypedData_Int32x4Array_factory, 924582681) \
+ V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 1654170890) \
// TODO(srdjan): Implement _FixedSizeArrayIterator, get:current and
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 10a1578..abe9dda 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -312,6 +312,7 @@
stacktrace_(NULL),
stack_frame_index_(-1),
object_histogram_(NULL),
+ cha_used_(false),
object_id_ring_(NULL),
profiler_data_(NULL),
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index ff1682c..8356d97 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -113,6 +113,9 @@
ObjectHistogram* object_histogram() { return object_histogram_; }
+ bool cha_used() const { return cha_used_; }
+ void set_cha_used(bool value) { cha_used_ = value; }
+
MegamorphicCacheTable* megamorphic_cache_table() {
return &megamorphic_cache_table_;
}
@@ -457,6 +460,8 @@
intptr_t stack_frame_index_;
ObjectHistogram* object_histogram_;
+ bool cha_used_;
+
// Ring buffer of objects assigned an id.
ObjectIdRing* object_id_ring_;
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index ce15960..a608ea9 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -42,7 +42,12 @@
if (obj.IsType() || obj.IsClass()) {
const Class& cls = (obj.IsType()) ?
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
- return Dart_NewStringFromCString(cls.ToCString());
+ const char* str = cls.ToCString();
+ if (str == NULL) {
+ RETURN_NULL_ERROR(str);
+ }
+ CHECK_CALLBACK_STATE(isolate);
+ return Api::NewHandle(isolate, String::New(str));
} else {
RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c5c9a41..1de1ac0 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -59,6 +59,8 @@
DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false,
"Throw an exception when the result of an integer calculation will not "
"fit into a javascript integer.");
+DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
+
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, error_on_bad_override);
@@ -1189,6 +1191,9 @@
cls = Class::New<Int32x4>();
object_store->set_int32x4_class(cls);
RegisterPrivateClass(cls, Symbols::_Int32x4(), lib);
+ cls = Class::New<Float64x2>();
+ object_store->set_float64x2_class(cls);
+ RegisterPrivateClass(cls, Symbols::_Float64x2(), lib);
cls = Class::New<Instance>(kIllegalCid);
RegisterClass(cls, Symbols::Float32x4(), lib);
@@ -1208,6 +1213,15 @@
type = Type::NewNonParameterizedType(cls);
object_store->set_int32x4_type(type);
+ cls = Class::New<Instance>(kIllegalCid);
+ RegisterClass(cls, Symbols::Float64x2(), lib);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ pending_classes.Add(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_float64x2_type(type);
+
object_store->set_typed_data_classes(typed_data_classes);
// Set the super type of class Stacktrace to Object type so that the
@@ -1348,6 +1362,9 @@
cls = Class::New<Int32x4>();
object_store->set_int32x4_class(cls);
+ cls = Class::New<Float64x2>();
+ object_store->set_float64x2_class(cls);
+
#define REGISTER_TYPED_DATA_CLASS(clazz) \
cls = Class::NewTypedDataClass(kTypedData##clazz##Cid);
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
@@ -2319,6 +2336,157 @@
}
+// Helper class to handle an array of code weak properties. Implements
+// registration and disabling of stored code objects.
+class WeakCodeReferences : public ValueObject {
+ public:
+ explicit WeakCodeReferences(const Array& value) : array_(value) {}
+ virtual ~WeakCodeReferences() {}
+
+ void Register(const Code& value) {
+ if (!array_.IsNull()) {
+ // Try to find and reuse cleared WeakProperty to avoid allocating new one.
+ WeakProperty& weak_property = WeakProperty::Handle();
+ for (intptr_t i = 0; i < array_.Length(); i++) {
+ weak_property ^= array_.At(i);
+ if (weak_property.key() == Code::null()) {
+ // Empty property found. Reuse it.
+ weak_property.set_key(value);
+ return;
+ }
+ }
+ }
+
+ const WeakProperty& weak_property = WeakProperty::Handle(
+ WeakProperty::New(Heap::kOld));
+ weak_property.set_key(value);
+
+ intptr_t length = array_.IsNull() ? 0 : array_.Length();
+ const Array& new_array = Array::Handle(
+ Array::Grow(array_, length + 1, Heap::kOld));
+ new_array.SetAt(length, weak_property);
+ UpdateArrayTo(new_array);
+ }
+
+ virtual void UpdateArrayTo(const Array& array) = 0;
+ virtual void ReportDeoptimization(const Code& code) = 0;
+ virtual void ReportSwitchingCode(const Code& code) = 0;
+
+ static bool IsOptimizedCode(const Array& dependent_code, const Code& code) {
+ if (!code.is_optimized()) {
+ return false;
+ }
+ WeakProperty& weak_property = WeakProperty::Handle();
+ for (intptr_t i = 0; i < dependent_code.Length(); i++) {
+ weak_property ^= dependent_code.At(i);
+ if (code.raw() == weak_property.key()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void DisableCode() {
+ const Array& code_objects = Array::Handle(array_.raw());
+ if (code_objects.IsNull()) {
+ return;
+ }
+ UpdateArrayTo(Object::null_array());
+ // Disable all code on stack.
+ Code& code = Code::Handle();
+ {
+ DartFrameIterator iterator;
+ StackFrame* frame = iterator.NextFrame();
+ while (frame != NULL) {
+ code = frame->LookupDartCode();
+ if (IsOptimizedCode(code_objects, code)) {
+ ReportDeoptimization(code);
+ DeoptimizeAt(code, frame->pc());
+ }
+ frame = iterator.NextFrame();
+ }
+ }
+
+ // Switch functions that use dependent code to unoptimized code.
+ WeakProperty& weak_property = WeakProperty::Handle();
+ Function& function = Function::Handle();
+ for (intptr_t i = 0; i < code_objects.Length(); i++) {
+ weak_property ^= code_objects.At(i);
+ code ^= weak_property.key();
+ if (code.IsNull()) {
+ // Code was garbage collected already.
+ continue;
+ }
+
+ function ^= code.function();
+ // If function uses dependent code switch it to unoptimized.
+ if (function.CurrentCode() == code.raw()) {
+ ASSERT(function.HasOptimizedCode());
+ ReportSwitchingCode(code);
+ function.SwitchToUnoptimizedCode();
+ }
+ }
+ }
+
+ private:
+ const Array& array_;
+ DISALLOW_COPY_AND_ASSIGN(WeakCodeReferences);
+};
+
+
+class CHACodeArray : public WeakCodeReferences {
+ public:
+ explicit CHACodeArray(const Class& cls)
+ : WeakCodeReferences(Array::Handle(cls.cha_codes())), cls_(cls) {
+ }
+
+ virtual void UpdateArrayTo(const Array& value) {
+ cls_.set_cha_codes(value);
+ }
+
+ virtual void ReportDeoptimization(const Code& code) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+ Function& function = Function::Handle(code.function());
+ OS::PrintErr("Deoptimizing %s because CHA optimized (%s).\n",
+ function.ToFullyQualifiedCString(),
+ cls_.ToCString());
+ }
+ }
+
+ virtual void ReportSwitchingCode(const Code& code) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+ Function& function = Function::Handle(code.function());
+ OS::PrintErr("Switching %s to unoptimized code because CHA invalid"
+ " (%s)\n",
+ function.ToFullyQualifiedCString(),
+ cls_.ToCString());
+ }
+ }
+
+ private:
+ const Class& cls_;
+ DISALLOW_COPY_AND_ASSIGN(CHACodeArray);
+};
+
+
+void Class::RegisterCHACode(const Code& code) {
+ ASSERT(code.is_optimized());
+ CHACodeArray a(*this);
+ a.Register(code);
+}
+
+
+void Class::DisableCHAOptimizedCode() {
+ CHACodeArray a(*this);
+ a.DisableCode();
+}
+
+
+void Class::set_cha_codes(const Array& cache) const {
+ StorePointer(&raw_ptr()->cha_codes_, cache.raw());
+}
+
+
// Apply the members from the patch class to the original class.
bool Class::ApplyPatch(const Class& patch, Error* error) const {
ASSERT(error != NULL);
@@ -2948,6 +3116,11 @@
}
+void Class::set_is_fields_marked_nullable() const {
+ set_state_bits(FieldsMarkedNullableBit::update(true, raw_ptr()->state_bits_));
+}
+
+
void Class::set_is_finalized() const {
ASSERT(!is_finalized());
set_state_bits(ClassFinalizedBits::update(RawClass::kFinalized,
@@ -6118,6 +6291,7 @@
RawString* Field::GetterName(const String& field_name) {
+ CompilerStats::make_accessor_name++;
return String::Concat(Symbols::GetterPrefix(), field_name);
}
@@ -6129,6 +6303,7 @@
RawString* Field::SetterName(const String& field_name) {
+ CompilerStats::make_accessor_name++;
return String::Concat(Symbols::SetterPrefix(), field_name);
}
@@ -6140,11 +6315,13 @@
RawString* Field::NameFromGetter(const String& getter_name) {
+ CompilerStats::make_field_name++;
return String::SubString(getter_name, strlen(kGetterPrefix));
}
RawString* Field::NameFromSetter(const String& setter_name) {
+ CompilerStats::make_field_name++;
return String::SubString(setter_name, strlen(kSetterPrefix));
}
@@ -6278,6 +6455,19 @@
}
+bool Field::IsUnboxedField() const {
+ // TODO(johnmccutchan): Add kFloat32x4Cid here.
+ return is_unboxing_candidate() && !is_final() && !is_nullable() &&
+ ((guarded_cid() == kDoubleCid));
+}
+
+
+bool Field::IsPotentialUnboxedField() const {
+ return is_unboxing_candidate() &&
+ (IsUnboxedField() || (!is_final() && (guarded_cid() == kIllegalCid)));
+}
+
+
const char* Field::ToCString() const {
if (IsNull()) {
return "Field::null";
@@ -6360,107 +6550,55 @@
void Field::set_dependent_code(const Array& array) const {
- raw_ptr()->dependent_code_ = array.raw();
+ StorePointer(&raw_ptr()->dependent_code_, array.raw());
}
+class FieldDependentArray : public WeakCodeReferences {
+ public:
+ explicit FieldDependentArray(const Field& field)
+ : WeakCodeReferences(Array::Handle(field.dependent_code())),
+ field_(field) {}
+
+ virtual void UpdateArrayTo(const Array& value) {
+ field_.set_dependent_code(value);
+ }
+
+ virtual void ReportDeoptimization(const Code& code) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+ Function& function = Function::Handle(code.function());
+ OS::PrintErr("Deoptimizing %s because guard on field %s failed.\n",
+ function.ToFullyQualifiedCString(),
+ field_.ToCString());
+ }
+ }
+
+ virtual void ReportSwitchingCode(const Code& code) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+ Function& function = Function::Handle(code.function());
+ OS::PrintErr("Switching %s to unoptimized code because guard"
+ " on field %s was violated.\n",
+ function.ToFullyQualifiedCString(),
+ field_.ToCString());
+ }
+ }
+
+ private:
+ const Field& field_;
+ DISALLOW_COPY_AND_ASSIGN(FieldDependentArray);
+};
+
+
void Field::RegisterDependentCode(const Code& code) const {
- const Array& dependent = Array::Handle(dependent_code());
-
- if (!dependent.IsNull()) {
- // Try to find and reuse cleared WeakProperty to avoid allocating new one.
- WeakProperty& weak_property = WeakProperty::Handle();
- for (intptr_t i = 0; i < dependent.Length(); i++) {
- weak_property ^= dependent.At(i);
- if (weak_property.key() == Code::null()) {
- // Empty property found. Reuse it.
- weak_property.set_key(code);
- return;
- }
- }
- }
-
- const WeakProperty& weak_property = WeakProperty::Handle(
- WeakProperty::New(Heap::kOld));
- weak_property.set_key(code);
-
- intptr_t length = dependent.IsNull() ? 0 : dependent.Length();
- const Array& new_dependent = Array::Handle(
- Array::Grow(dependent, length + 1, Heap::kOld));
- new_dependent.SetAt(length, weak_property);
- set_dependent_code(new_dependent);
-}
-
-
-static bool IsDependentCode(const Array& dependent_code, const Code& code) {
- if (!code.is_optimized()) {
- return false;
- }
-
- WeakProperty& weak_property = WeakProperty::Handle();
- for (intptr_t i = 0; i < dependent_code.Length(); i++) {
- weak_property ^= dependent_code.At(i);
- if (code.raw() == weak_property.key()) {
- return true;
- }
- }
-
- return false;
+ ASSERT(code.is_optimized());
+ FieldDependentArray a(*this);
+ a.Register(code);
}
void Field::DeoptimizeDependentCode() const {
- const Array& code_objects = Array::Handle(dependent_code());
-
- if (code_objects.IsNull()) {
- return;
- }
- set_dependent_code(Object::null_array());
-
- // Deoptimize all dependent code on the stack.
- Code& code = Code::Handle();
- {
- DartFrameIterator iterator;
- StackFrame* frame = iterator.NextFrame();
- while (frame != NULL) {
- code = frame->LookupDartCode();
- if (IsDependentCode(code_objects, code)) {
- if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
- Function& function = Function::Handle(code.function());
- OS::PrintErr("Deoptimizing %s because guard on field %s failed.\n",
- function.ToFullyQualifiedCString(),
- ToCString());
- }
- DeoptimizeAt(code, frame->pc());
- }
- frame = iterator.NextFrame();
- }
- }
-
- // Switch functions that use dependent code to unoptimized code.
- WeakProperty& weak_property = WeakProperty::Handle();
- Function& function = Function::Handle();
- for (intptr_t i = 0; i < code_objects.Length(); i++) {
- weak_property ^= code_objects.At(i);
- code ^= weak_property.key();
- if (code.IsNull()) {
- // Code was garbage collected already.
- continue;
- }
-
- function ^= code.function();
- // If function uses dependent code switch it to unoptimized.
- if (function.CurrentCode() == code.raw()) {
- ASSERT(function.HasOptimizedCode());
- if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("Switching %s to unoptimized code because guard"
- " on field %s was violated.\n",
- function.ToFullyQualifiedCString(),
- ToCString());
- }
- function.SwitchToUnoptimizedCode();
- }
- }
+ FieldDependentArray a(*this);
+ a.DisableCode();
}
@@ -7405,39 +7543,37 @@
intptr_t length = src.Length();
intptr_t line = 1 + line_offset();
intptr_t column = 1;
- intptr_t lookahead = 0;
+ intptr_t scan_position = 0;
intptr_t snippet_start = -1;
intptr_t snippet_end = -1;
if (from_line - line_offset() == 1) {
column += col_offset();
}
- char c = src.CharAt(lookahead);
- while (lookahead != length) {
- if (snippet_start == -1) {
- if ((line == from_line) && (column == from_column)) {
- snippet_start = lookahead;
- }
- } else if ((line == to_line) && (column == to_column)) {
- snippet_end = lookahead;
- break;
- }
+
+ while (scan_position != length) {
+ char c = src.CharAt(scan_position);
if (c == '\n') {
line++;
column = 0;
- }
- column++;
- lookahead++;
- if (lookahead != length) {
- // Replace '\r' with '\n' and a sequence of '\r' '\n' with a single '\n'.
- if (src.CharAt(lookahead) == '\r') {
- c = '\n';
- if (lookahead + 1 != length && src.CharAt(lookahead) == '\n') {
- lookahead++;
- }
- } else {
- c = src.CharAt(lookahead);
+ } else if (c == '\r') {
+ line++;
+ column = 0;
+ if ((scan_position + 1 != length) &&
+ (src.CharAt(scan_position + 1) == '\n')) {
+ scan_position++;
}
}
+ scan_position++;
+ column++;
+
+ if (snippet_start == -1) {
+ if ((line == from_line) && (column == from_column)) {
+ snippet_start = scan_position;
+ }
+ } else if ((line == to_line) && (column == to_column)) {
+ snippet_end = scan_position;
+ break;
+ }
}
String& snippet = String::Handle();
if ((snippet_start != -1) && (snippet_end != -1)) {
@@ -7756,6 +7892,136 @@
}
+RawObject* Library::ResolveName(const String& name) const {
+ Object& obj = Object::Handle();
+ if (FLAG_use_lib_cache && LookupResolvedNamesCache(name, &obj)) {
+ return obj.raw();
+ }
+ obj = LookupLocalObject(name);
+ if (!obj.IsNull()) {
+ // Names that are in this library's dictionary and are unmangled
+ // are not cached. This reduces the size of the the cache.
+ return obj.raw();
+ }
+ String& accessor_name = String::Handle(Field::GetterName(name));
+ obj = LookupLocalObject(accessor_name);
+ if (obj.IsNull()) {
+ accessor_name = Field::SetterName(name);
+ obj = LookupLocalObject(accessor_name);
+ if (obj.IsNull()) {
+ obj = LookupImportedObject(name);
+ }
+ }
+ AddToResolvedNamesCache(name, obj);
+ return obj.raw();
+}
+
+
+static intptr_t ResolvedNameCacheSize(const Array& cache) {
+ return (cache.Length() - 1) / 2;
+}
+
+
+// Returns true if the name is found in the cache, false no cache hit.
+// obj is set to the cached entry. It may be null, indicating that the
+// name does not resolve to anything in this library.
+bool Library::LookupResolvedNamesCache(const String& name,
+ Object* obj) const {
+ const Array& cache = Array::Handle(resolved_names());
+ const intptr_t cache_size = ResolvedNameCacheSize(cache);
+ intptr_t index = name.Hash() % cache_size;
+ String& entry_name = String::Handle();
+ entry_name ^= cache.At(index);
+ while (!entry_name.IsNull()) {
+ if (entry_name.Equals(name)) {
+ CompilerStats::num_lib_cache_hit++;
+ *obj = cache.At(index + cache_size);
+ return true;
+ }
+ index = (index + 1) % cache_size;
+ entry_name ^= cache.At(index);
+ }
+ *obj = Object::null();
+ return false;
+}
+
+
+void Library::GrowResolvedNamesCache() const {
+ const Array& old_cache = Array::Handle(resolved_names());
+ const intptr_t old_cache_size = ResolvedNameCacheSize(old_cache);
+
+ // Create empty new cache and add entries from the old cache.
+ const intptr_t new_cache_size = old_cache_size * 3 / 2;
+ InitResolvedNamesCache(new_cache_size);
+ String& name = String::Handle();
+ Object& entry = Object::Handle();
+ for (intptr_t i = 0; i < old_cache_size; i++) {
+ name ^= old_cache.At(i);
+ if (!name.IsNull()) {
+ entry = old_cache.At(i + old_cache_size);
+ AddToResolvedNamesCache(name, entry);
+ }
+ }
+}
+
+
+// Add a name to the resolved name cache. This name resolves to the
+// given object in this library scope. obj may be null, which means
+// the name does not resolve to anything in this library scope.
+void Library::AddToResolvedNamesCache(const String& name,
+ const Object& obj) const {
+ if (!FLAG_use_lib_cache) {
+ return;
+ }
+ const Array& cache = Array::Handle(resolved_names());
+ // let N = cache.Length();
+ // The entry cache[N-1] is used as a counter
+ // The array entries [0..N-2] are used as cache entries.
+ // cache[i] contains the name of the entry
+ // cache[i+(N-1)/2] contains the resolved entity, or NULL if that name
+ // is not present in the library.
+ const intptr_t counter_index = cache.Length() - 1;
+ intptr_t cache_size = ResolvedNameCacheSize(cache);
+ intptr_t index = name.Hash() % cache_size;
+ String& entry_name = String::Handle();
+ entry_name ^= cache.At(index);
+ // An empty spot will be found because we keep the hash set at most 75% full.
+ while (!entry_name.IsNull()) {
+ index = (index + 1) % cache_size;
+ entry_name ^= cache.At(index);
+ }
+ // Insert the object at the empty slot.
+ cache.SetAt(index, name);
+ ASSERT(cache.At(index + cache_size) == Object::null());
+ cache.SetAt(index + cache_size, obj);
+
+ // One more element added.
+ intptr_t num_used = Smi::Value(Smi::RawCast(cache.At(counter_index))) + 1;
+ cache.SetAt(counter_index, Smi::Handle(Smi::New(num_used)));
+ CompilerStats::num_names_cached++;
+
+ // Rehash if symbol_table is 75% full.
+ if (num_used > ((cache_size / 4) * 3)) {
+ CompilerStats::num_names_cached -= num_used;
+ GrowResolvedNamesCache();
+ }
+}
+
+
+void Library::InvalidateResolvedName(const String& name) const {
+ Object& entry = Object::Handle();
+ if (LookupResolvedNamesCache(name, &entry)) {
+ InvalidateResolvedNamesCache();
+ }
+}
+
+
+void Library::InvalidateResolvedNamesCache() const {
+ const intptr_t kInvalidatedCacheSize = 16;
+ InitResolvedNamesCache(kInvalidatedCacheSize);
+}
+
+
void Library::GrowDictionary(const Array& dict, intptr_t dict_size) const {
// TODO(iposva): Avoid exponential growth.
intptr_t new_dict_size = dict_size * 2;
@@ -7888,9 +8154,11 @@
void Library::AddClass(const Class& cls) const {
- AddObject(cls, String::Handle(cls.Name()));
+ const String& class_name = String::Handle(cls.Name());
+ AddObject(cls, class_name);
// Link class to this library.
cls.set_library(*this);
+ InvalidateResolvedName(class_name);
}
static void AddScriptIfUnique(const GrowableObjectArray& scripts,
@@ -8072,17 +8340,6 @@
}
-RawObject* Library::LookupObject(const String& name) const {
- // First check if name is found in the local scope of the library.
- Object& obj = Object::Handle(LookupLocalObject(name));
- if (!obj.IsNull()) {
- return obj.raw();
- }
- // Now check if name is found in any imported libs.
- return LookupImportedObject(name);
-}
-
-
RawObject* Library::LookupImportedObject(const String& name) const {
Object& obj = Object::Handle();
Namespace& import = Namespace::Handle();
@@ -8121,7 +8378,7 @@
RawClass* Library::LookupClass(const String& name) const {
- Object& obj = Object::Handle(LookupObject(name));
+ Object& obj = Object::Handle(ResolveName(name));
if (obj.IsClass()) {
return Class::Cast(obj).raw();
}
@@ -8260,15 +8517,24 @@
}
-void Library::InitClassDictionary() const {
+static RawArray* NewDictionary(intptr_t initial_size) {
+ const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld));
// The last element of the dictionary specifies the number of in use slots.
+ dict.SetAt(initial_size, Smi::Handle(Smi::New(0)));
+ return dict.raw();
+}
+
+
+void Library::InitResolvedNamesCache(intptr_t size) const {
+ // Need space for 'size' names and 'size' resolved object entries.
+ StorePointer(&raw_ptr()->resolved_names_, NewDictionary(2 * size));
+}
+
+
+void Library::InitClassDictionary() const {
// TODO(iposva): Find reasonable initial size.
const int kInitialElementCount = 16;
-
- const Array& dictionary =
- Array::Handle(Array::New(kInitialElementCount + 1, Heap::kOld));
- dictionary.SetAt(kInitialElementCount, Smi::Handle(Smi::New(0)));
- StorePointer(&raw_ptr()->dictionary_, dictionary.raw());
+ StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount));
}
@@ -8295,6 +8561,7 @@
result.StorePointer(&result.raw_ptr()->name_, Symbols::Empty().raw());
result.StorePointer(&result.raw_ptr()->url_, url.raw());
result.raw_ptr()->private_key_ = Scanner::AllocatePrivateKey(result);
+ result.raw_ptr()->resolved_names_ = Object::empty_array().raw();
result.raw_ptr()->dictionary_ = Object::empty_array().raw();
result.StorePointer(&result.raw_ptr()->metadata_,
GrowableObjectArray::New(4, Heap::kOld));
@@ -8308,6 +8575,8 @@
result.set_debuggable(false);
result.raw_ptr()->load_state_ = RawLibrary::kAllocated;
result.raw_ptr()->index_ = -1;
+ const intptr_t kInitialNameCacheSize = 64;
+ result.InitResolvedNamesCache(kInitialNameCacheSize);
result.InitClassDictionary();
result.InitImportList();
if (import_core_lib) {
@@ -8382,6 +8651,7 @@
}
+// Returns library with given url in current isolate, or NULL.
RawLibrary* Library::LookupLibrary(const String &url) {
Isolate* isolate = Isolate::Current();
Library& lib = Library::Handle(isolate, Library::null());
@@ -10172,8 +10442,11 @@
jsobj.AddProperty("is_alive", is_alive());
jsobj.AddProperty("function", Object::Handle(function()));
JSONArray jsarr(&jsobj, "disassembly");
- DisassembleToJSONStream formatter(jsarr);
- Disassemble(&formatter);
+ if (is_alive()) {
+ // Only disassemble alive code objects.
+ DisassembleToJSONStream formatter(jsarr);
+ Disassemble(&formatter);
+ }
}
@@ -16366,7 +16639,7 @@
RawFloat32x4* Float32x4::New(simd128_value_t value, Heap::Space space) {
-ASSERT(Isolate::Current()->object_store()->float32x4_class() !=
+ ASSERT(Isolate::Current()->object_store()->float32x4_class() !=
Class::null());
Float32x4& result = Float32x4::Handle();
{
@@ -16555,6 +16828,86 @@
}
+RawFloat64x2* Float64x2::New(double value0, double value1, Heap::Space space) {
+ ASSERT(Isolate::Current()->object_store()->float64x2_class() !=
+ Class::null());
+ Float64x2& result = Float64x2::Handle();
+ {
+ RawObject* raw = Object::Allocate(Float64x2::kClassId,
+ Float64x2::InstanceSize(),
+ space);
+ NoGCScope no_gc;
+ result ^= raw;
+ }
+ result.set_x(value0);
+ result.set_y(value1);
+ return result.raw();
+}
+
+
+RawFloat64x2* Float64x2::New(simd128_value_t value, Heap::Space space) {
+ ASSERT(Isolate::Current()->object_store()->float64x2_class() !=
+ Class::null());
+ Float64x2& result = Float64x2::Handle();
+ {
+ RawObject* raw = Object::Allocate(Float64x2::kClassId,
+ Float64x2::InstanceSize(),
+ space);
+ NoGCScope no_gc;
+ result ^= raw;
+ }
+ result.set_value(value);
+ return result.raw();
+}
+
+
+double Float64x2::x() const {
+ return raw_ptr()->value_[0];
+}
+
+
+double Float64x2::y() const {
+ return raw_ptr()->value_[1];
+}
+
+
+void Float64x2::set_x(double x) const {
+ raw_ptr()->value_[0] = x;
+}
+
+
+void Float64x2::set_y(double y) const {
+ raw_ptr()->value_[1] = y;
+}
+
+
+simd128_value_t Float64x2::value() const {
+ return simd128_value_t().readFrom(&raw_ptr()->value_[0]);
+}
+
+
+void Float64x2::set_value(simd128_value_t value) const {
+ value.writeTo(&raw_ptr()->value_[0]);
+}
+
+
+const char* Float64x2::ToCString() const {
+ const char* kFormat = "[%f, %f]";
+ double _x = x();
+ double _y = y();
+ // Calculate the size of the string.
+ intptr_t len = OS::SNPrint(NULL, 0, kFormat, _x, _y) + 1;
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ OS::SNPrint(chars, len, kFormat, _x, _y);
+ return chars;
+}
+
+
+void Float64x2::PrintToJSONStream(JSONStream* stream, bool ref) const {
+ Instance::PrintToJSONStream(stream, ref);
+}
+
+
const intptr_t TypedData::element_size[] = {
1, // kTypedDataInt8ArrayCid.
1, // kTypedDataUint8ArrayCid.
@@ -16569,6 +16922,7 @@
8, // kTypedDataFloat64ArrayCid.
16, // kTypedDataFloat32x4ArrayCid.
16, // kTypedDataInt32x4ArrayCid.
+ 16, // kTypedDataFloat64x2ArrayCid,
};
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 2144156..37dfc34 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -992,6 +992,11 @@
}
void set_is_mixin_type_applied() const;
+ bool is_fields_marked_nullable() const {
+ return FieldsMarkedNullableBit::decode(raw_ptr()->state_bits_);
+ }
+ void set_is_fields_marked_nullable() const;
+
uint16_t num_native_fields() const {
return raw_ptr()->num_native_fields_;
}
@@ -1069,6 +1074,16 @@
// otherwise a new object is allocated and returned.
static RawClass* GetClass(intptr_t class_id, bool is_signature_class);
+ // Register code that has used CHA for optimization.
+ // TODO(srdjan): Also register kind of CHA optimization (e.g.: leaf class,
+ // leaf method, ...).
+ void RegisterCHACode(const Code& code);
+
+ void DisableCHAOptimizedCode();
+
+ RawArray* cha_codes() const { return raw_ptr()->cha_codes_; }
+ void set_cha_codes(const Array& value) const;
+
private:
enum {
kAny = 0,
@@ -1089,6 +1104,7 @@
kMarkedForParsingBit = 8,
kMixinAppAliasBit = 9,
kMixinTypeAppliedBit = 10,
+ kFieldsMarkedNullableBit = 11,
};
class ConstBit : public BitField<bool, kConstBit, 1> {};
class ImplementedBit : public BitField<bool, kImplementedBit, 1> {};
@@ -1101,6 +1117,8 @@
class MarkedForParsingBit : public BitField<bool, kMarkedForParsingBit, 1> {};
class MixinAppAliasBit : public BitField<bool, kMixinAppAliasBit, 1> {};
class MixinTypeAppliedBit : public BitField<bool, kMixinTypeAppliedBit, 1> {};
+ class FieldsMarkedNullableBit : public BitField<bool,
+ kFieldsMarkedNullableBit, 1> {}; // NOLINT
void set_name(const String& value) const;
void set_user_name(const String& value) const;
@@ -2187,17 +2205,14 @@
return r;
}
- bool IsUnboxedField() const {
- return is_unboxing_candidate()
- && !is_final()
- && (guarded_cid() == kDoubleCid && !is_nullable());
+ intptr_t UnboxedFieldCid() const {
+ ASSERT(IsUnboxedField());
+ return guarded_cid();
}
- bool IsPotentialUnboxedField() const {
- return is_unboxing_candidate()
- && (IsUnboxedField() ||
- (!is_final() && (guarded_cid() == kIllegalCid)));
- }
+ bool IsUnboxedField() const;
+
+ bool IsPotentialUnboxedField() const;
bool is_unboxing_candidate() const {
return UnboxingCandidateBit::decode(raw_ptr()->kind_bits_);
@@ -2584,7 +2599,6 @@
void AddObject(const Object& obj, const String& name) const;
void ReplaceObject(const Object& obj, const String& name) const;
RawObject* LookupReExport(const String& name) const;
- RawObject* LookupObject(const String& name) const;
RawObject* LookupObjectAllowPrivate(const String& name) const;
RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
RawObject* LookupLocalObject(const String& name) const;
@@ -2600,6 +2614,15 @@
RawScript* LookupScript(const String& url) const;
RawArray* LoadedScripts() const;
+ // Resolve name in the scope of this library. First check the cache
+ // of already resolved names for this library. Then look in the
+ // local dictionary for the unmangled name N, the getter name get:N
+ // and setter name set:N.
+ // If the local dictionary contains no entry for these names,
+ // look in the scopes of all libraries that are imported
+ // without a library prefix.
+ RawObject* ResolveName(const String& name) const;
+
void AddAnonymousClass(const Class& cls) const;
void AddExport(const Namespace& ns) const;
@@ -2708,6 +2731,15 @@
RawGrowableObjectArray* metadata() const { return raw_ptr()->metadata_; }
RawArray* dictionary() const { return raw_ptr()->dictionary_; }
void InitClassDictionary() const;
+
+ RawArray* resolved_names() const { return raw_ptr()->resolved_names_; }
+ void InitResolvedNamesCache(intptr_t size) const;
+ void GrowResolvedNamesCache() const;
+ bool LookupResolvedNamesCache(const String& name, Object* obj) const;
+ void AddToResolvedNamesCache(const String& name, const Object& obj) const;
+ void InvalidateResolvedName(const String& name) const;
+ void InvalidateResolvedNamesCache() const;
+
void InitImportList() const;
void GrowDictionary(const Array& dict, intptr_t dict_size) const;
static RawLibrary* NewLibraryHelper(const String& url,
@@ -5939,6 +5971,36 @@
};
+class Float64x2 : public Instance {
+ public:
+ static RawFloat64x2* New(double value0, double value1,
+ Heap::Space space = Heap::kNew);
+ static RawFloat64x2* New(simd128_value_t value,
+ Heap::Space space = Heap::kNew);
+
+ double x() const;
+ double y() const;
+
+ void set_x(double x) const;
+ void set_y(double y) const;
+
+ simd128_value_t value() const;
+ void set_value(simd128_value_t value) const;
+
+ static intptr_t InstanceSize() {
+ return RoundedAllocationSize(sizeof(RawFloat64x2));
+ }
+
+ static intptr_t value_offset() {
+ return OFFSET_OF(RawFloat64x2, value_);
+ }
+
+ private:
+ FINAL_HEAP_OBJECT_IMPLEMENTATION(Float64x2, Instance);
+ friend class Class;
+};
+
+
class TypedData : public Instance {
public:
intptr_t Length() const {
@@ -5987,6 +6049,7 @@
TYPED_GETTER_SETTER(Float64, double)
TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
+ TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
#undef TYPED_GETTER_SETTER
@@ -6116,7 +6179,8 @@
TYPED_GETTER_SETTER(Float32, float)
TYPED_GETTER_SETTER(Float64, double)
TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
- TYPED_GETTER_SETTER(Int32x4, simd128_value_t);
+ TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
+ TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
#undef TYPED_GETTER_SETTER
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index fe389c2..c8a046c 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -29,6 +29,9 @@
mint_class_(Class::null()),
bigint_class_(Class::null()),
double_class_(Class::null()),
+ float32x4_type_(Type::null()),
+ int32x4_type_(Type::null()),
+ float64x2_type_(Type::null()),
string_type_(Type::null()),
one_byte_string_class_(Class::null()),
two_byte_string_class_(Class::null()),
@@ -42,6 +45,7 @@
growable_object_array_class_(Class::null()),
float32x4_class_(Class::null()),
int32x4_class_(Class::null()),
+ float64x2_class_(Class::null()),
typed_data_classes_(Array::null()),
error_class_(Class::null()),
stacktrace_class_(Class::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 710572f..b5f022a 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -208,6 +208,16 @@
RawType* int32x4_type() const { return int32x4_type_; }
void set_int32x4_type(const Type& value) { int32x4_type_ = value.raw(); }
+ RawClass* float64x2_class() const {
+ return float64x2_class_;
+ }
+ void set_float64x2_class(const Class& value) {
+ float64x2_class_ = value.raw();
+ }
+
+ RawType* float64x2_type() const { return float64x2_type_; }
+ void set_float64x2_type(const Type& value) { float64x2_type_ = value.raw(); }
+
RawArray* typed_data_classes() const {
return typed_data_classes_;
}
@@ -438,6 +448,7 @@
RawType* double_type_;
RawType* float32x4_type_;
RawType* int32x4_type_;
+ RawType* float64x2_type_;
RawType* string_type_;
RawClass* one_byte_string_class_;
RawClass* two_byte_string_class_;
@@ -451,6 +462,7 @@
RawClass* growable_object_array_class_;
RawClass* float32x4_class_;
RawClass* int32x4_class_;
+ RawClass* float64x2_class_;
RawArray* typed_data_classes_;
RawClass* error_class_;
RawClass* stacktrace_class_;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 2958e47..c376a74 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -4855,6 +4855,19 @@
}
+class DartApiScope : public StackResource {
+ public:
+ explicit DartApiScope(Isolate* isolate) : StackResource(isolate) {
+ Dart_EnterScope();
+ }
+ ~DartApiScope() {
+ Dart_ExitScope();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DartApiScope);
+};
+
RawObject* Parser::CallLibraryTagHandler(Dart_LibraryTag tag,
intptr_t token_pos,
@@ -4872,6 +4885,7 @@
// Block class finalization attempts when calling into the library
// tag handler.
isolate()->BlockClassFinalization();
+ DartApiScope api_scope(isolate());
Dart_Handle result = handler(tag,
Api::NewHandle(isolate(), library_.raw()),
Api::NewHandle(isolate(), url.raw()));
@@ -9102,43 +9116,9 @@
}
-static RawObject* LookupNameInLibrary(Isolate* isolate,
- const Library& lib,
- const String& name) {
- Object& obj = Object::Handle(isolate);
- obj = lib.LookupLocalObject(name);
- if (!obj.IsNull()) {
- return obj.raw();
- }
- String& accessor_name = String::Handle(isolate, Field::GetterName(name));
- obj = lib.LookupLocalObject(accessor_name);
- if (!obj.IsNull()) {
- return obj.raw();
- }
- accessor_name = Field::SetterName(name);
- obj = lib.LookupLocalObject(accessor_name);
- return obj.raw();
-}
-
-
-// Resolve a name by checking the global scope of the current
-// library. If not found in the current library, then look in the scopes
-// of all libraries that are imported without a library prefix.
-RawObject* Parser::ResolveNameInCurrentLibraryScope(const String& name) {
- TRACE_PARSER("ResolveNameInCurrentLibraryScope");
- HANDLESCOPE(isolate());
- Object& obj = Object::Handle(isolate(),
- LookupNameInLibrary(isolate(), library_, name));
- if (!obj.IsNull()) {
- return obj.raw();
- }
- return library_.LookupImportedObject(name);
-}
-
-
RawClass* Parser::ResolveClassInCurrentLibraryScope(const String& name) {
- const Object& obj =
- Object::Handle(ResolveNameInCurrentLibraryScope(name));
+ HANDLESCOPE(isolate());
+ const Object& obj = Object::Handle(library_.ResolveName(name));
if (obj.IsClass()) {
return Class::Cast(obj).raw();
}
@@ -9152,8 +9132,8 @@
AstNode* Parser::ResolveIdentInCurrentLibraryScope(intptr_t ident_pos,
const String& ident) {
TRACE_PARSER("ResolveIdentInCurrentLibraryScope");
- const Object& obj =
- Object::Handle(ResolveNameInCurrentLibraryScope(ident));
+ HANDLESCOPE(isolate());
+ const Object& obj = Object::Handle(library_.ResolveName(ident));
if (obj.IsClass()) {
const Class& cls = Class::Cast(obj);
return new PrimaryNode(ident_pos, Class::ZoneHandle(cls.raw()));
@@ -9182,17 +9162,10 @@
}
-RawObject* Parser::ResolveNameInPrefixScope(const LibraryPrefix& prefix,
- const String& name) {
- HANDLESCOPE(isolate());
- return prefix.LookupObject(name);
-}
-
-
RawClass* Parser::ResolveClassInPrefixScope(const LibraryPrefix& prefix,
const String& name) {
- const Object& obj =
- Object::Handle(ResolveNameInPrefixScope(prefix, name));
+ HANDLESCOPE(isolate());
+ const Object& obj = Object::Handle(prefix.LookupObject(name));
if (obj.IsClass()) {
return Class::Cast(obj).raw();
}
@@ -9207,7 +9180,8 @@
const LibraryPrefix& prefix,
const String& ident) {
TRACE_PARSER("ResolveIdentInPrefixScope");
- Object& obj = Object::Handle(ResolveNameInPrefixScope(prefix, ident));
+ HANDLESCOPE(isolate());
+ Object& obj = Object::Handle(prefix.LookupObject(ident));
if (obj.IsNull()) {
// Unresolved prefixed primary identifier.
String& qualified_name = String::ZoneHandle(prefix.name());
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 321a56f..1bb7ec4 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -597,12 +597,6 @@
RawClass* ResolveClassInPrefixScope(const LibraryPrefix& prefix,
const String& name);
- // Find name in the library or prefix scope and return the corresponding
- // object (field, class, function etc).
- RawObject* ResolveNameInCurrentLibraryScope(const String& ident);
- RawObject* ResolveNameInPrefixScope(const LibraryPrefix& prefix,
- const String& name);
-
AstNode* ResolveIdent(intptr_t ident_pos,
const String& ident,
bool allow_closure_names);
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 529e733..8b39ec9 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -21,7 +21,7 @@
#if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
- defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID)
+ defined(TARGET_OS_ANDROID)
DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
#else
DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 3fcb212..f9df8e5 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -792,6 +792,13 @@
}
+intptr_t RawFloat64x2::VisitFloat64x2Pointers(
+ RawFloat64x2* raw_obj,
+ ObjectPointerVisitor* visitor) {
+ ASSERT(raw_obj->IsHeapObject());
+ return Float64x2::InstanceSize();
+}
+
intptr_t RawTypedData::VisitTypedDataPointers(
RawTypedData* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 810d637..ef3368c 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -70,6 +70,7 @@
V(MirrorReference) \
V(Float32x4) \
V(Int32x4) \
+ V(Float64x2) \
#define CLASS_LIST_ARRAYS(V) \
V(Array) \
@@ -96,6 +97,7 @@
V(Float64Array) \
V(Float32x4Array) \
V(Int32x4Array) \
+ V(Float64x2Array) \
#define CLASS_LIST_FOR_HANDLES(V) \
CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V) \
@@ -494,7 +496,8 @@
RawArray* constants_; // Canonicalized values of this class.
RawObject* canonical_types_; // An array of canonicalized types of this class
// or the canonical type.
- RawArray* invocation_dispatcher_cache_; // Cache for dispatcher functions.
+ RawArray* invocation_dispatcher_cache_; // Cache for dispatcher functions.
+ RawArray* cha_codes_; // CHA optimized codes.
RawCode* allocation_stub_; // Stub code for allocation of instances.
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->allocation_stub_);
@@ -778,6 +781,7 @@
RawScript* script_;
RawString* private_key_;
RawArray* dictionary_; // Top-level names in this library.
+ RawArray* resolved_names_; // Cache of resolved names in library scope.
RawGrowableObjectArray* metadata_; // Metadata on classes, methods etc.
RawArray* anonymous_classes_; // Classes containing top-level elements.
RawArray* imports_; // List of Namespaces imported without prefix.
@@ -1452,6 +1456,18 @@
};
+class RawFloat64x2 : public RawInstance {
+ RAW_HEAP_OBJECT_IMPLEMENTATION(Float64x2);
+
+ double value_[2];
+
+ friend class SnapshotReader;
+ public:
+ double x() const { return value_[0]; }
+ double y() const { return value_[1]; }
+};
+
+
// Define an aliases for intptr_t.
#if defined(ARCH_IS_32_BIT)
#define kIntPtrCid kTypedDataInt32ArrayCid
@@ -1677,9 +1693,10 @@
kTypedDataFloat64ArrayCid == kTypedDataInt8ArrayCid + 10 &&
kTypedDataFloat32x4ArrayCid == kTypedDataInt8ArrayCid + 11 &&
kTypedDataInt32x4ArrayCid == kTypedDataInt8ArrayCid + 12 &&
- kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 13);
+ kTypedDataFloat64x2ArrayCid == kTypedDataInt8ArrayCid + 13 &&
+ kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 14);
return (index >= kTypedDataInt8ArrayCid &&
- index <= kTypedDataInt32x4ArrayCid);
+ index <= kTypedDataFloat64x2ArrayCid);
}
@@ -1697,8 +1714,9 @@
kTypedDataFloat64ArrayViewCid == kTypedDataInt8ArrayViewCid + 10 &&
kTypedDataFloat32x4ArrayViewCid == kTypedDataInt8ArrayViewCid + 11 &&
kTypedDataInt32x4ArrayViewCid == kTypedDataInt8ArrayViewCid + 12 &&
- kByteDataViewCid == kTypedDataInt8ArrayViewCid + 13 &&
- kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 14);
+ kTypedDataFloat64x2ArrayViewCid == kTypedDataInt8ArrayViewCid + 13 &&
+ kByteDataViewCid == kTypedDataInt8ArrayViewCid + 14 &&
+ kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 15);
return (index >= kTypedDataInt8ArrayViewCid &&
index <= kByteDataViewCid);
}
@@ -1730,9 +1748,11 @@
kExternalTypedDataInt8ArrayCid + 11) &&
(kExternalTypedDataInt32x4ArrayCid ==
kExternalTypedDataInt8ArrayCid + 12) &&
- (kNullCid == kExternalTypedDataInt8ArrayCid + 13));
+ (kExternalTypedDataFloat64x2ArrayCid ==
+ kExternalTypedDataInt8ArrayCid + 13) &&
+ (kNullCid == kExternalTypedDataInt8ArrayCid + 14));
return (index >= kExternalTypedDataInt8ArrayCid &&
- index <= kExternalTypedDataInt32x4ArrayCid);
+ index <= kExternalTypedDataFloat64x2ArrayCid);
}
@@ -1767,9 +1787,9 @@
inline intptr_t RawObject::NumberOfTypedDataClasses() {
// Make sure this is updated when new TypedData types are added.
- ASSERT(kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 13);
- ASSERT(kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 14);
- ASSERT(kNullCid == kExternalTypedDataInt8ArrayCid + 13);
+ ASSERT(kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 14);
+ ASSERT(kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 15);
+ ASSERT(kNullCid == kExternalTypedDataInt8ArrayCid + 14);
return (kNullCid - kTypedDataInt8ArrayCid);
}
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index a34039c..e46625b 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -2209,9 +2209,9 @@
RawFloat32x4* Float32x4::ReadFrom(SnapshotReader* reader,
- intptr_t object_id,
- intptr_t tags,
- Snapshot::Kind kind) {
+ intptr_t object_id,
+ intptr_t tags,
+ Snapshot::Kind kind) {
ASSERT(reader != NULL);
// Read the values.
float value0 = reader->Read<float>();
@@ -2235,8 +2235,8 @@
void RawFloat32x4::WriteTo(SnapshotWriter* writer,
- intptr_t object_id,
- Snapshot::Kind kind) {
+ intptr_t object_id,
+ Snapshot::Kind kind) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
@@ -2255,9 +2255,9 @@
RawInt32x4* Int32x4::ReadFrom(SnapshotReader* reader,
- intptr_t object_id,
- intptr_t tags,
- Snapshot::Kind kind) {
+ intptr_t object_id,
+ intptr_t tags,
+ Snapshot::Kind kind) {
ASSERT(reader != NULL);
// Read the values.
uint32_t value0 = reader->Read<uint32_t>();
@@ -2281,8 +2281,8 @@
void RawInt32x4::WriteTo(SnapshotWriter* writer,
- intptr_t object_id,
- Snapshot::Kind kind) {
+ intptr_t object_id,
+ Snapshot::Kind kind) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
@@ -2300,6 +2300,48 @@
}
+RawFloat64x2* Float64x2::ReadFrom(SnapshotReader* reader,
+ intptr_t object_id,
+ intptr_t tags,
+ Snapshot::Kind kind) {
+ ASSERT(reader != NULL);
+ // Read the values.
+ double value0 = reader->Read<double>();
+ double value1 = reader->Read<double>();
+
+ // Create a Float64x2 object.
+ Float64x2& simd = Float64x2::ZoneHandle(reader->isolate(),
+ Float64x2::null());
+ if (kind == Snapshot::kFull) {
+ simd = reader->NewFloat64x2(value0, value1);
+ } else {
+ simd = Float64x2::New(value0, value1, HEAP_SPACE(kind));
+ }
+ reader->AddBackRef(object_id, &simd, kIsDeserialized);
+ // Set the object tags.
+ simd.set_tags(tags);
+ return simd.raw();
+}
+
+
+void RawFloat64x2::WriteTo(SnapshotWriter* writer,
+ intptr_t object_id,
+ Snapshot::Kind kind) {
+ ASSERT(writer != NULL);
+
+ // Write out the serialization header value for this object.
+ writer->WriteInlinedObjectHeader(object_id);
+
+ // Write out the class and tags information.
+ writer->WriteIndexedObject(kFloat64x2Cid);
+ writer->WriteIntptrValue(writer->GetObjectTags(this));
+
+ // Write out the float values.
+ writer->Write<double>(ptr()->value_[0]);
+ writer->Write<double>(ptr()->value_[1]);
+}
+
+
#define TYPED_DATA_READ(setter, type) \
for (intptr_t i = 0; i < lengthInBytes; i += element_size) { \
result.Set##setter(i, reader->Read<type>()); \
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index fcbed02..11cd7e5 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -150,7 +150,7 @@
Function& function = Function::Handle();
if (class_name.IsNull() || (class_name.Length() == 0)) {
// Check if we are referring to a top level function.
- const Object& object = Object::Handle(library.LookupObject(function_name));
+ const Object& object = Object::Handle(library.ResolveName(function_name));
if (!object.IsNull() && object.IsFunction()) {
function ^= object.raw();
if (!function.AreValidArguments(num_arguments, argument_names, NULL)) {
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 7c2fee2..e89cc65 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -72,6 +72,25 @@
}
+// Search for the formatted string in buff.
+static void ExpectSubstringF(const char* buff, const char* fmt, ...) {
+ Isolate* isolate = Isolate::Current();
+
+ va_list args;
+ va_start(args, fmt);
+ intptr_t len = OS::VSNPrint(NULL, 0, fmt, args);
+ va_end(args);
+
+ char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ va_list args2;
+ va_start(args2, fmt);
+ OS::VSNPrint(buffer, (len + 1), fmt, args2);
+ va_end(args2);
+
+ EXPECT_SUBSTRING(buffer, buff);
+}
+
+
static RawFunction* GetFunction(const Class& cls, const char* name) {
const Function& result = Function::Handle(cls.LookupDynamicFunction(
String::Handle(String::New(name))));
@@ -331,87 +350,59 @@
service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "'], [], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
- "{\"type\":\"Class\",\"id\":\"classes\\/1009\",\"name\":\"A\","
- "\"user_name\":\"A\",\"implemented\":false,\"abstract\":false,"
- "\"patch\":false,\"finalized\":true,\"const\":false,\"super\":"
- "{\"type\":\"@Class\",\"id\":\"classes\\/35\",\"name\":\"Object\","
- "\"user_name\":\"Object\"},\"library\":{\"type\":\"@Library\",\"id\":"
- "\"libraries\\/12\",\"name\":\"\",\"user_name\":\"dart:test-lib\"},"
- "\"fields\":[{\"type\":\"@Field\",\"id\":\"classes\\/1009\\/fields\\/0\","
- "\"name\":\"a\",\"user_name\":\"a\",\"owner\":{\"type\":\"@Class\","
- "\"id\":\"classes\\/1009\",\"name\":\"A\",\"user_name\":\"A\"},"
- "\"declared_type\":{\"type\":\"@Class\",\"id\":\"classes\\/106\","
- "\"name\":\"dynamic\",\"user_name\":\"dynamic\"},\"static\":false,"
- "\"final\":false,\"const\":false}],\"functions\":["
- "{\"type\":\"@Function\",\"id\":\"classes\\/1009\\/functions\\/0\","
- "\"name\":\"get:a\",\"user_name\":\"A.a\"},{\"type\":\"@Function\","
- "\"id\":\"classes\\/1009\\/functions\\/1\",\"name\":\"set:a\","
- "\"user_name\":\"A.a=\"},{\"type\":\"@Function\",\"id\":"
- "\"classes\\/1009\\/functions\\/2\",\"name\":\"b\",\"user_name\":\"A.b\"}"
- ",{\"type\":\"@Function\",\"id\":\"classes\\/1009\\/functions\\/3\","
- "\"name\":\"c\",\"user_name\":\"A.c\"},{\"type\":\"@Function\",\"id\":"
- "\"classes\\/1009\\/functions\\/4\",\"name\":\"A.\",\"user_name\":"
- "\"A.A\"}]}",
- handler.msg());
- // Request function 0 from class A.
+ EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
+ ExpectSubstringF(handler.msg(),
+ "\"id\":\"classes\\/%" Pd "\",\"name\":\"A\",", cid);
+
service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '0'],"
"[], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
- "{\"type\":\"Function\",\"id\":\"classes\\/1009\\/functions\\/0\",\"name\":"
- "\"get:a\",\"user_name\":\"A.a\",\"is_static\":false,\"is_const\":false,"
- "\"is_optimizable\":true,\"is_inlinable\":false,\"kind\":"
- "\"kImplicitGetter\",\"unoptimized_code\":{\"type\":\"null\"},"
- "\"usage_counter\":0,\"optimized_call_site_count\":0,\"code\":"
- "{\"type\":\"null\"},\"deoptimizations\":0}", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"Function\"", handler.msg());
+ ExpectSubstringF(handler.msg(),
+ "\"id\":\"classes\\/%" Pd "\\/functions\\/0\","
+ "\"name\":\"get:a\",", cid);
// Request field 0 from class A.
service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '0'],"
"[], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
- "{\"type\":\"Field\",\"id\":\"classes\\/1009\\/fields\\/0\",\"name\":\"a\","
- "\"user_name\":\"a\",\"owner\":{\"type\":\"@Class\",\"id\":"
- "\"classes\\/1009\",\"name\":\"A\",\"user_name\":\"A\"},\"declared_type\":"
- "{\"type\":\"@Class\",\"id\":\"classes\\/106\",\"name\":\"dynamic\","
- "\"user_name\":\"dynamic\"},\"static\":false,\"final\":false,\"const\":"
- "false,\"guard_nullable\":true,\"guard_class\":{\"type\":\"@Class\","
- "\"id\":\"classes\\/105\",\"name\":\"Null\",\"user_name\":\"Null\"},"
- "\"guard_length\":\"variable\"}", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"Field\"", handler.msg());
+ ExpectSubstringF(handler.msg(),
+ "\"id\":\"classes\\/%" Pd "\\/fields\\/0\","
+ "\"name\":\"a\",", cid);
// Invalid sub command.
service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'huh', '0'],"
"[], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
+ ExpectSubstringF(handler.msg(),
"{\"type\":\"Error\",\"text\":\"Invalid sub collection huh\",\"message\":"
- "{\"arguments\":[\"classes\",\"1009\",\"huh\",\"0\"],\"option_keys\":[],"
- "\"option_values\":[]}}", handler.msg());
+ "{\"arguments\":[\"classes\",\"%" Pd "\",\"huh\",\"0\"],\"option_keys\":[],"
+ "\"option_values\":[]}}", cid);
// Invalid field request.
service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '9'],"
"[], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
+ ExpectSubstringF(handler.msg(),
"{\"type\":\"Error\",\"text\":\"Field 9 not found\","
- "\"message\":{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\"],"
- "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+ "\"message\":{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\"],"
+ "\"option_keys\":[],\"option_values\":[]}}", cid);
// Invalid function request.
service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9'],"
"[], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
+ ExpectSubstringF(handler.msg(),
"{\"type\":\"Error\",\"text\":\"Function 9 not found\","
- "\"message\":{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\"],"
- "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+ "\"message\":{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"9\"],"
+ "\"option_keys\":[],\"option_values\":[]}}", cid);
// Invalid field subcommand.
@@ -419,22 +410,20 @@
",[], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
+ ExpectSubstringF(handler.msg(),
"{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":"
- "{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\",\"x\"],"
- "\"option_keys\":[],\"option_values\":[]}}",
- handler.msg());
+ "{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\",\"x\"],"
+ "\"option_keys\":[],\"option_values\":[]}}", cid);
// Invalid function request.
service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9',"
"'x'], [], []]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
+ ExpectSubstringF(handler.msg(),
"{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":"
- "{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\",\"x\"],"
- "\"option_keys\":[],\"option_values\":[]}}",
- handler.msg());
+ "{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"9\",\"x\"],"
+ "\"option_keys\":[],\"option_values\":[]}}", cid);
}
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index d029476..c3cf071 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -648,6 +648,18 @@
}
+RawFloat64x2* SnapshotReader::NewFloat64x2(double v0, double v1) {
+ ASSERT(kind_ == Snapshot::kFull);
+ ASSERT(isolate()->no_gc_scope_depth() != 0);
+ cls_ = object_store()->float64x2_class();
+ RawFloat64x2* obj = reinterpret_cast<RawFloat64x2*>(
+ AllocateUninitialized(cls_, Float64x2::InstanceSize()));
+ obj->ptr()->value_[0] = v0;
+ obj->ptr()->value_[1] = v1;
+ return obj;
+}
+
+
RawApiError* SnapshotReader::NewApiError() {
ALLOC_NEW_OBJECT(ApiError, Object::api_error_class());
}
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index cc001386..9aa5bc3 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -45,6 +45,7 @@
class RawFunction;
class RawGrowableObjectArray;
class RawFloat32x4;
+class RawFloat64x2;
class RawInt32x4;
class RawImmutableArray;
class RawLanguageError;
@@ -275,6 +276,7 @@
RawGrowableObjectArray* NewGrowableObjectArray();
RawFloat32x4* NewFloat32x4(float v0, float v1, float v2, float v3);
RawInt32x4* NewInt32x4(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3);
+ RawFloat64x2* NewFloat64x2(double v0, double v1);
RawApiError* NewApiError();
RawLanguageError* NewLanguageError();
RawObject* NewInteger(int64_t value);
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 3907235..8052a1a 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -136,8 +136,10 @@
V(Int, "int") \
V(Double, "double") \
V(_Float32x4, "_Float32x4") \
+ V(_Float64x2, "_Float64x2") \
V(_Int32x4, "_Int32x4") \
V(Float32x4, "Float32x4") \
+ V(Float64x2, "Float64x2") \
V(Int32x4, "Int32x4") \
V(Int8List, "Int8List") \
V(Int8ListFactory, "Int8List.") \
@@ -161,6 +163,8 @@
V(Float32x4ListFactory, "Float32x4List.") \
V(Int32x4List, "Int32x4List") \
V(Int32x4ListFactory, "Int32x4List.") \
+ V(Float64x2List, "Float64x2List") \
+ V(Float64x2ListFactory, "Float64x2List.") \
V(Float32List, "Float32List") \
V(Float32ListFactory, "Float32List.") \
V(Float64List, "Float64List") \
@@ -187,6 +191,8 @@
V(_Float32x4ArrayFactory, "_Float32x4Array.") \
V(_Int32x4Array, "_Int32x4Array") \
V(_Int32x4ArrayFactory, "_Int32x4Array.") \
+ V(_Float64x2Array, "_Float64x2Array") \
+ V(_Float64x2ArrayFactory, "_Float64x2Array.") \
V(_Float32Array, "_Float32Array") \
V(_Float32ArrayFactory, "_Float32Array.") \
V(_Float64Array, "_Float64Array") \
@@ -204,6 +210,7 @@
V(_Float64ArrayView, "_Float64ArrayView") \
V(_Float32x4ArrayView, "_Float32x4ArrayView") \
V(_Int32x4ArrayView, "_Int32x4ArrayView") \
+ V(_Float64x2ArrayView, "_Float64x2ArrayView") \
V(_ExternalInt8Array, "_ExternalInt8Array") \
V(_ExternalUint8Array, "_ExternalUint8Array") \
V(_ExternalUint8ClampedArray, "_ExternalUint8ClampedArray") \
@@ -217,6 +224,7 @@
V(_ExternalInt32x4Array, "_ExternalInt32x4Array") \
V(_ExternalFloat32Array, "_ExternalFloat32Array") \
V(_ExternalFloat64Array, "_ExternalFloat64Array") \
+ V(_ExternalFloat64x2Array, "_ExternalFloat64x2Array") \
V(ByteData, "ByteData") \
V(ByteDataDot, "ByteData.") \
V(ByteDataDotview, "ByteData.view") \
diff --git a/sdk/bin/dart2js.bat b/sdk/bin/dart2js.bat
index 8951a02..ed460c8 100644
--- a/sdk/bin/dart2js.bat
+++ b/sdk/bin/dart2js.bat
@@ -36,7 +36,7 @@
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --heap_growth_rate=512
rem We allow extra vm options to be passed in through an environment variable.
-if not _%DART_VM_OPTIONS%_ == __ (
+if not "_%DART_VM_OPTIONS%_" == "__" (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
)
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index efb75b8..d0bb37b 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -17,6 +17,8 @@
* Contains the initial value of fields. Must contain all static and global
* initializations of const fields. May contain eagerly compiled values for
* statics and instance fields.
+ *
+ * Invariant: The keys in this map are declarations.
*/
final Map<VariableElement, Constant> initialVariableValues;
@@ -44,7 +46,7 @@
}
Constant getConstantForVariable(VariableElement element) {
- return initialVariableValues[element];
+ return initialVariableValues[element.declaration];
}
/**
@@ -61,8 +63,8 @@
*/
Constant compileVariable(VariableElement element, {bool isConst: false}) {
return measure(() {
- if (initialVariableValues.containsKey(element)) {
- Constant result = initialVariableValues[element];
+ if (initialVariableValues.containsKey(element.declaration)) {
+ Constant result = initialVariableValues[element.declaration];
return result;
}
Element currentElement = element;
@@ -145,7 +147,7 @@
}
}
if (value != null) {
- initialVariableValues[element] = value;
+ initialVariableValues[element.declaration] = value;
} else {
assert(!isConst);
lazyStatics.add(element);
@@ -223,7 +225,7 @@
}
Constant getInitialValueFor(VariableElement element) {
- Constant initialValue = initialVariableValues[element];
+ Constant initialValue = initialVariableValues[element.declaration];
if (initialValue == null) {
compiler.internalError("No initial value for given element",
element: element);
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index d13da55..2551bf8 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -499,10 +499,7 @@
return f();
} on SpannableAssertionFailure catch (ex) {
if (!hasCrashed) {
- String message = (ex.message != null) ? tryToString(ex.message)
- : tryToString(ex);
- SourceSpan span = spanFromSpannable(ex.node);
- reportError(ex.node, MessageKind.GENERIC, {'text': message});
+ reportAssertionFailure(ex);
pleaseReportCrash();
}
hasCrashed = true;
@@ -1397,6 +1394,13 @@
void reportDiagnostic(SourceSpan span, String message, api.Diagnostic kind);
+ void reportAssertionFailure(SpannableAssertionFailure ex) {
+ String message = (ex.message != null) ? tryToString(ex.message)
+ : tryToString(ex);
+ SourceSpan span = spanFromSpannable(ex.node);
+ reportError(ex.node, MessageKind.GENERIC, {'text': message});
+ }
+
SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
if (begin == null || end == null) {
// TODO(ahe): We can almost always do better. Often it is only
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
index 6b885d6..14a2cc9 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
@@ -117,6 +117,9 @@
visitLiteralString(LiteralString node) => new LiteralString(
node.token, node.dartString);
+ visitMetadata(Metadata node) => new Metadata(
+ node.token, visit(node.expression));
+
visitMixinApplication(MixinApplication node) => new MixinApplication(
visit(node.superclass), visit(node.mixins));
@@ -213,8 +216,10 @@
visitTypeVariable(TypeVariable node) => new TypeVariable(
visit(node.name), visit(node.bound));
- visitVariableDefinitions(VariableDefinitions node) => new VariableDefinitions(
- visit(node.type), visit(node.modifiers), visit(node.definitions));
+ visitVariableDefinitions(VariableDefinitions node) =>
+ new VariableDefinitions.forParameter(
+ visit(node.metadata), visit(node.type),
+ visit(node.modifiers), visit(node.definitions));
visitWhile(While node) => new While(
visit(node.condition), visit(node.body), node.whileKeyword);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index a61dac8..ee6f15c 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -363,7 +363,7 @@
TypeDeclarationElement get element;
/// Creates a new instance of this type using the provided type arguments.
- GenericType _createType(Link<DartType> newTypeArguments);
+ GenericType createInstantiation(Link<DartType> newTypeArguments);
DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
if (typeArguments.isEmpty) {
@@ -379,7 +379,7 @@
Types.substTypes(typeArguments, arguments, parameters);
if (!identical(typeArguments, newTypeArguments)) {
// Create a new type only if necessary.
- return _createType(newTypeArguments);
+ return createInstantiation(newTypeArguments);
}
return this;
}
@@ -465,7 +465,7 @@
String get name => element.name;
- InterfaceType _createType(Link<DartType> newTypeArguments) {
+ InterfaceType createInstantiation(Link<DartType> newTypeArguments) {
return new InterfaceType(element, newTypeArguments);
}
@@ -798,7 +798,7 @@
[Link<DartType> typeArguments = const Link<DartType>()])
: super(typeArguments);
- TypedefType _createType(Link<DartType> newTypeArguments) {
+ TypedefType createInstantiation(Link<DartType> newTypeArguments) {
return new TypedefType(element, newTypeArguments);
}
@@ -1216,11 +1216,17 @@
bool visitInterfaceType(InterfaceType t, DartType s) {
if (super.visitInterfaceType(t, s)) return true;
- lookupCall(type) => type.lookupMember(Compiler.CALL_OPERATOR_NAME);
+ InterfaceTypeMember lookupCall(type) =>
+ type.lookupMember(Compiler.CALL_OPERATOR_NAME);
+
+ bool hasCallMethod(type) {
+ InterfaceTypeMember member = lookupCall(type);
+ return member != null && member.element.isFunction();
+ }
if (s is InterfaceType &&
s.element == compiler.functionClass &&
- lookupCall(t) != null) {
+ hasCallMethod(t)) {
return true;
} else if (s is FunctionType) {
InterfaceTypeMember call = lookupCall(t);
@@ -1717,7 +1723,7 @@
element.typeVariables.forEach((TypeVariableType typeVariable) {
typeArguments.addLast(constraintMap[typeVariable]);
});
- return element.thisType._createType(typeArguments.toLink());
+ return element.thisType.createInstantiation(typeArguments.toLink());
}
return null;
}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 53d6650..3243e90 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -907,6 +907,11 @@
bool isObject(Compiler compiler);
bool isSubclassOf(ClassElement cls);
+ /// Returns true if `this` explicitly/nominally implements [intrface].
+ ///
+ /// Note that, if [intrface] is the `Function` class, this method returns
+ /// falso for a class that has a `call` method but does not explicitly
+ /// implement `Function`.
bool implementsInterface(ClassElement intrface);
bool hasFieldShadowedBy(Element fieldMember);
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index b52189b..8701835 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -1140,6 +1140,12 @@
variables = null,
super(name, kind, enclosing);
+ void addMetadata(MetadataAnnotation metadata) {
+ variables.addMetadata(metadata);
+ }
+
+ Link<MetadataAnnotation> get metadata => variables.metadata;
+
Node parseNode(DiagnosticListener listener) {
if (cachedNode != null) return cachedNode;
VariableDefinitions definitions = variables.parseNode(listener);
@@ -1169,6 +1175,20 @@
Token position() => findMyName(variables.position());
accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
+
+ // TODO(johnniwinther): Move the patch/origin implementation to a parameter
+ // specific element when added.
+
+ /**
+ * A function declaration that should be parsed instead of the current one.
+ * The patch should be parsed as if it was in the current scope. Its
+ * signature must match this function's signature.
+ */
+ VariableElementX patch = null;
+ VariableElementX origin = null;
+
+ bool get isPatch => origin != null;
+ bool get isPatched => patch != null;
}
class FieldElementX extends VariableElementX implements FieldElement {
@@ -2461,7 +2481,7 @@
* The compile-time constant which this annotation resolves to.
* In the mirror system, this would be an object mirror.
*/
- Constant get value;
+ Constant value;
Element annotatedElement;
int resolutionState;
@@ -2479,5 +2499,20 @@
return this;
}
+ Node parseNode(DiagnosticListener listener);
+
String toString() => 'MetadataAnnotation($value, $resolutionState)';
}
+
+/// Metadata annotation on a parameter.
+class ParameterMetadataAnnotation extends MetadataAnnotationX {
+ final Metadata metadata;
+
+ ParameterMetadataAnnotation(Metadata this.metadata);
+
+ Node parseNode(DiagnosticListener listener) => metadata.expression;
+
+ Token get beginToken => metadata.getBeginToken();
+
+ Token get endToken => metadata.getEndToken();
+}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
index 6890de7..29d898b 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
@@ -47,7 +47,7 @@
Element enclosing,
[T elementType, int length]);
- T allocateMap(T keyType, T valueType, T type);
+ T allocateMap(T type, Node node, Element element, [T keyType, T valueType]);
T allocateClosure(Node node, Element element);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
index 1d2d063..df9630a 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
@@ -9,7 +9,7 @@
* change the element type of the list, or let the list escape to code
* that might change the element type.
*/
-Set<String> okSelectorsSet = new Set<String>.from(
+Set<String> okListSelectorsSet = new Set<String>.from(
const <String>[
// From Object.
'==',
@@ -127,31 +127,33 @@
class ListTracerVisitor extends TracerVisitor {
- // The list of found assignments to the container.
- final List<TypeInformation> assignments = <TypeInformation>[];
+ // The [List] of found assignments to the list.
+ List<TypeInformation> assignments = <TypeInformation>[];
bool callsGrowableMethod = false;
-
+
ListTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
- List<TypeInformation> run() {
+ /**
+ * Returns [true] if the analysis completed successfully, [false] if it
+ * bailed out. In the former case, [assignments] holds a list of
+ * [TypeInformation] nodes that flow into the element type of this list.
+ */
+ bool run() {
analyze();
- ListTypeInformation container = tracedType;
+ ListTypeInformation list = tracedType;
if (continueAnalyzing) {
- if (!callsGrowableMethod && container.inferredLength == null) {
- container.inferredLength = container.originalLength;
+ if (!callsGrowableMethod && list.inferredLength == null) {
+ list.inferredLength = list.originalLength;
}
- container.flowsInto.addAll(flowsInto);
- return assignments;
+ list.flowsInto.addAll(flowsInto);
+ return true;
} else {
callsGrowableMethod = true;
- return null;
+ assignments = null;
+ return false;
}
}
- visitMapTypeInformation(MapTypeInformation info) {
- bailout('Stored in a map');
- }
-
visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
bailout('Passed to a closure');
}
@@ -169,7 +171,7 @@
Selector selector = info.selector;
String selectorName = selector.name;
if (currentUser == info.receiver) {
- if (!okSelectorsSet.contains(selectorName)) {
+ if (!okListSelectorsSet.contains(selectorName)) {
if (selector.isCall()) {
int positionalLength = info.arguments.positional.length;
if (selectorName == 'add') {
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/map_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/map_tracer.dart
new file mode 100644
index 0000000..595505a
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/map_tracer.dart
@@ -0,0 +1,111 @@
+// 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.
+
+part of type_graph_inferrer;
+
+Set<String> okMapSelectorsSet = new Set.from(
+ const <String>[
+ "[]",
+ "isEmpty",
+ "isNotEmpty",
+ "keys",
+ "length",
+ "values",
+ "clear",
+ "containsKey",
+ "containsValue",
+ "forEach",
+ "remove"]);
+
+class MapTracerVisitor extends TracerVisitor {
+ List<TypeInformation> keyAssignments = <TypeInformation>[];
+ List<TypeInformation> valueAssignments = <TypeInformation>[];
+
+ MapTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
+
+ /**
+ * Returns [true] if the analysis completed successfully, [false]
+ * if it bailed out. In the former case, [keyAssignments] and
+ * [valueAssignments] hold a list of [TypeInformation] nodes that
+ * flow into the key and value types of this map.
+ */
+ bool run() {
+ analyze();
+ MapTypeInformation map = tracedType;
+ if (continueAnalyzing) {
+ map.flowsInto.addAll(flowsInto);
+ return true;
+ }
+ keyAssignments = valueAssignments = null;
+ return false;
+ }
+
+ visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
+ bailout('Passed to a closure');
+ }
+
+ visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
+ super.visitStaticCallSiteTypeInformation(info);
+ Element called = info.calledElement;
+ if (called.isForeign(compiler) && called.name == 'JS') {
+ bailout('Used in JS ${info.call}');
+ }
+ }
+
+ visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
+ super.visitDynamicCallSiteTypeInformation(info);
+ Selector selector = info.selector;
+ String selectorName = selector.name;
+ if (currentUser == info.receiver) {
+ if (!okMapSelectorsSet.contains(selectorName)) {
+ if (selector.isCall()) {
+ int positionalLength = info.arguments.positional.length;
+ if (selectorName == 'addAll') {
+ // All keys and values from the argument flow into
+ // the map.
+ TypeInformation map = info.arguments.positional[0];
+ if (map is MapTypeInformation) {
+ keyAssignments.add(map.keyType);
+ valueAssignments.add(map.valueType);
+ } else {
+ // If we could select a component from a [TypeInformation],
+ // like the keytype or valuetype in this case, we could
+ // propagate more here.
+ // TODO(herhut): implement selection on [TypeInformation].
+ bailout('Adding map with unknown typeinfo to current map');
+ }
+ } else if (selectorName == 'putIfAbsent') {
+ // The first argument is a new key, the result type of
+ // the second argument becomes a new value.
+ // Unfortunately, the type information does not
+ // explicitly track the return type, yet, so we have
+ // to go to dynamic.
+ // TODO(herhut,16507): Use return type of closure in
+ // Map.putIfAbsent.
+ keyAssignments.add(info.arguments.positional[0]);
+ valueAssignments.add(inferrer.types.dynamicType);
+ } else {
+ // It would be nice to handle [Map.keys] and [Map.values], too.
+ // However, currently those calls do not trigger the creation
+ // of a [ListTypeInformation], so I have nowhere to propagate
+ // that information.
+ // TODO(herhut): add support for Map.keys and Map.values.
+ bailout('Map used in a not-ok selector');
+ return;
+ }
+ } else if (selector.isIndexSet()) {
+ keyAssignments.add(info.arguments.positional[0]);
+ valueAssignments.add(info.arguments.positional[1]);
+ } else if (!selector.isIndex()) {
+ bailout('Map used in a not-ok selector');
+ return;
+ }
+ }
+ } else if (selector.isCall()
+ && !info.targets.every((element) => element.isFunction())) {
+ bailout('Passed to a closure');
+ return;
+ }
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
index 380a472..98a6589 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
@@ -6,7 +6,7 @@
// A set of selectors we know do not escape the elements inside the
// list.
-Set<String> doesNotEscapeElementSet = new Set<String>.from(
+Set<String> doesNotEscapeListSet = new Set<String>.from(
const <String>[
// From Object.
'==',
@@ -46,6 +46,23 @@
'checkGrowable',
]);
+Set<String> doesNotEscapeMapSet = new Set<String>.from(
+ const <String>[
+ // From Object.
+ '==',
+ 'hashCode',
+ 'toString',
+ 'noSuchMethod',
+ 'runtimeType',
+ // from Map.
+ 'isEmpty',
+ 'isNotEmpty',
+ 'length',
+ 'clear',
+ 'containsKey',
+ 'containsValue'
+ ]);
+
abstract class TracerVisitor implements TypeInformationVisitor {
final TypeInformation tracedType;
final TypeGraphInferrerEngine inferrer;
@@ -61,12 +78,16 @@
// contain the container.
final List<TypeInformation> workList = <TypeInformation>[];
- // Work list of containers to analyze after analyzing the users of a
- // [TypeInformation] that may be [container]. We know [container]
- // has been stored in these containers and we must check how
- // [container] escapes from these containers.
- final List<ListTypeInformation> containersToAnalyze =
+ // Work list of lists to analyze after analyzing the users of a
+ // [TypeInformation]. We know the [tracedType] has been stored in these
+ // lists and we must check how it escapes from these lists.
+ final List<ListTypeInformation> listsToAnalyze =
<ListTypeInformation>[];
+ // Work list of maps to analyze after analyzing the users of a
+ // [TypeInformation]. We know the [tracedType] has been stored in these
+ // maps and we must check how it escapes from these maps.
+ final List<MapTypeInformation> mapsToAnalyze =
+ <MapTypeInformation>[];
final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
@@ -81,7 +102,7 @@
}
void analyze() {
- // Collect the [TypeInformation] where the container can flow in,
+ // Collect the [TypeInformation] where the list can flow in,
// as well as the operations done on all these [TypeInformation]s.
addNewEscapeInformation(tracedType);
while (!workList.isEmpty) {
@@ -90,8 +111,11 @@
analyzedElements.add(info.owner);
info.accept(this);
});
- while (!containersToAnalyze.isEmpty) {
- analyzeStoredIntoContainer(containersToAnalyze.removeLast());
+ while (!listsToAnalyze.isEmpty) {
+ analyzeStoredIntoList(listsToAnalyze.removeLast());
+ }
+ while (!mapsToAnalyze.isEmpty) {
+ analyzeStoredIntoMap(mapsToAnalyze.removeLast());
}
if (!continueAnalyzing) break;
if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
@@ -121,10 +145,21 @@
addNewEscapeInformation(info);
}
- visitListTypeInformation(ListTypeInformation info) {
- containersToAnalyze.add(info);
+ void visitKeyInMapTypeInformation(KeyInMapTypeInformation info) {
+ addNewEscapeInformation(info);
}
+ void visitValueInMapTypeInformation(ValueInMapTypeInformation info) {
+ addNewEscapeInformation(info);
+ }
+
+ void visitListTypeInformation(ListTypeInformation info) {
+ listsToAnalyze.add(info);
+ }
+
+ void visitMapTypeInformation(MapTypeInformation info) {
+ mapsToAnalyze.add(info);
+ }
void visitConcreteTypeInformation(ConcreteTypeInformation info) {}
void visitClosureTypeInformation(ClosureTypeInformation info) {}
@@ -139,19 +174,38 @@
}
}
- void analyzeStoredIntoContainer(ListTypeInformation container) {
- inferrer.analyzeContainer(container);
- if (container.bailedOut) {
- bailout('Stored in a container that bailed out');
+ void analyzeStoredIntoList(ListTypeInformation list) {
+ inferrer.analyzeListAndEnqueue(list);
+ if (list.bailedOut) {
+ bailout('Stored in a list that bailed out');
} else {
- container.flowsInto.forEach((flow) {
+ list.flowsInto.forEach((flow) {
flow.users.forEach((user) {
if (user is !DynamicCallSiteTypeInformation) return;
if (user.receiver != flow) return;
- if (returnsElementTypeSet.contains(user.selector)) {
+ if (returnsListElementTypeSet.contains(user.selector)) {
addNewEscapeInformation(user);
- } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
- bailout('Escape from a container');
+ } else if (!doesNotEscapeListSet.contains(user.selector.name)) {
+ bailout('Escape from a list');
+ }
+ });
+ });
+ }
+ }
+
+ void analyzeStoredIntoMap(MapTypeInformation map) {
+ inferrer.analyzeMapAndEnqueue(map);
+ if (map.bailedOut) {
+ bailout('Stored in a map that bailed out');
+ } else {
+ map.flowsInto.forEach((flow) {
+ flow.users.forEach((user) {
+ if (user is !DynamicCallSiteTypeInformation) return;
+ if (user.receiver != flow) return;
+ if (user.selector.isIndex()) {
+ addNewEscapeInformation(user);
+ } else if (!doesNotEscapeMapSet.contains(user.selector.name)) {
+ bailout('Escape from a map');
}
});
});
@@ -169,20 +223,40 @@
|| (selectorName == 'add' && currentUser == arguments[0]);
}
+ bool isValueAddedToMap(DynamicCallSiteTypeInformation info) {
+ if (info.arguments == null) return false;
+ var receiverType = info.receiver.type;
+ if (!receiverType.isMap) return false;
+ String selectorName = info.selector.name;
+ List<TypeInformation> arguments = info.arguments.positional;
+ return selectorName == '[]=' && currentUser == arguments[1];
+ }
+
void visitDynamicCallSiteTypeInformation(
DynamicCallSiteTypeInformation info) {
if (isAddedToContainer(info)) {
ContainerTypeMask mask = info.receiver.type;
if (mask.allocationNode != null) {
- ListTypeInformation container =
+ ListTypeInformation list =
inferrer.types.allocatedLists[mask.allocationNode];
- containersToAnalyze.add(container);
+ listsToAnalyze.add(list);
} else {
// The [ContainerTypeMask] is a union of two containers, and
// we lose track of where these containers have been allocated
// at this point.
bailout('Stored in too many containers');
}
+ } else if (isValueAddedToMap(info)) {
+ MapTypeMask mask = info.receiver.type;
+ if (mask.allocationNode != null) {
+ MapTypeInformation map =
+ inferrer.types.allocatedMaps[mask.allocationNode];
+ mapsToAnalyze.add(map);
+ } else {
+ // The [MapTypeMask] is a union. See comment for
+ // [ContainerTypeMask] above.
+ bailout('Stored in too many maps');
+ }
}
Iterable<Element> inferredTargetTypes = info.targets.map((element) {
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
index 34c9c02..8137f75 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
@@ -107,7 +107,8 @@
return new ContainerTypeMask(type, node, enclosing, elementType, length);
}
- TypeMask allocateMap(TypeMask keys, TypeMask values, TypeMask type) {
+ TypeMask allocateMap(TypeMask type, Node node, Element element,
+ [TypeMask keys, TypeMask values]) {
return type;
}
@@ -629,27 +630,35 @@
}
T visitLiteralMap(LiteralMap node) {
- NodeList entries = node.entries;
- T keyType;
- T valueType;
- if (entries.isEmpty) {
- keyType = types.nonNullEmpty();
- valueType = types.nonNullEmpty();
- } else {
- for (LiteralMapEntry entry in entries) {
- T key = visit(entry.key);
- keyType = keyType == null
- ? types.allocatePhi(null, null, key)
- : types.addPhiInput(null, keyType, key);
+ return inferrer.concreteTypes.putIfAbsent(node, () {
+ NodeList entries = node.entries;
+ T keyType;
+ T valueType;
+ if (entries.isEmpty) {
+ keyType = types.nonNullEmpty();
+ valueType = types.nonNullEmpty();
+ } else {
+ for (LiteralMapEntry entry in entries) {
+ T key = visit(entry.key);
+ keyType = keyType == null
+ ? types.allocatePhi(null, null, key)
+ : types.addPhiInput(null, keyType, key);
- T value = visit(entry.value);
- valueType = valueType == null
- ? types.allocatePhi(null, null, value)
- : types.addPhiInput(null, valueType, value);
+ T value = visit(entry.value);
+ valueType = valueType == null
+ ? types.allocatePhi(null, null, value)
+ : types.addPhiInput(null, valueType, value);
+ }
+ keyType = types.simplifyPhi(null, null, keyType);
+ valueType = types.simplifyPhi(null, null, valueType);
}
- }
- T type = node.isConst() ? types.constMapType : types.mapType;
- return types.allocateMap(keyType, valueType, type);
+ T type = node.isConst() ? types.constMapType : types.mapType;
+ return types.allocateMap(type,
+ node,
+ outermostElement,
+ keyType,
+ valueType);
+ });
}
bool isThisOrSuper(Node node) => node.isThis() || node.isSuper();
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
index b568d03..80d5bb6 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
@@ -9,7 +9,8 @@
import '../elements/elements.dart';
import '../tree/tree.dart' show LiteralList, Node;
import '../ir/ir_nodes.dart' show IrNode;
-import '../types/types.dart' show TypeMask, ContainerTypeMask, TypesInferrer;
+import '../types/types.dart'
+ show TypeMask, ContainerTypeMask, MapTypeMask, TypesInferrer;
import '../universe/universe.dart' show Selector, TypedSelector, SideEffects;
import '../dart2jslib.dart' show Compiler, TreeElementMapping;
import 'inferrer_visitor.dart' show TypeSystem, ArgumentsTypes;
@@ -17,12 +18,13 @@
import '../util/util.dart' show Spannable, Setlet;
import 'simple_types_inferrer.dart';
import 'ir_type_inferrer.dart';
-import '../dart2jslib.dart' show invariant, Constant;
+import '../dart2jslib.dart' show invariant, Constant, FunctionConstant;
part 'type_graph_nodes.dart';
part 'closure_tracer.dart';
part 'list_tracer.dart';
part 'node_tracer.dart';
+part 'map_tracer.dart';
bool _VERBOSE = false;
@@ -30,7 +32,7 @@
* A set of selector names that [List] implements, that we know return
* their element type.
*/
-Set<Selector> returnsElementTypeSet = new Set<Selector>.from(
+Set<Selector> returnsListElementTypeSet = new Set<Selector>.from(
<Selector>[
new Selector.getter('first', null),
new Selector.getter('last', null),
@@ -42,10 +44,16 @@
new Selector.call('removeLast', null, 0)
]);
-bool returnsElementType(Selector selector) {
+bool returnsListElementType(Selector selector) {
return (selector.mask != null)
&& selector.mask.isContainer
- && returnsElementTypeSet.contains(selector.asUntyped);
+ && returnsListElementTypeSet.contains(selector.asUntyped);
+}
+
+bool returnsMapValueType(Selector selector) {
+ return (selector.mask != null)
+ && selector.mask.isMap
+ && selector.isIndex();
}
class TypeInformationSystem extends TypeSystem<TypeInformation> {
@@ -59,6 +67,10 @@
final Map<Node, TypeInformation> allocatedLists =
new Map<Node, TypeInformation>();
+ /// [MapTypeInformation] for allocated Maps.
+ final Map<Node, TypeInformation> allocatedMaps =
+ new Map<Node, TypeInformation>();
+
/// Closures found during the analysis.
final Set<TypeInformation> allocatedClosures = new Set<TypeInformation>();
@@ -311,12 +323,35 @@
return result;
}
- TypeInformation allocateMap(TypeInformation keyType,
- TypeInformation valueType,
- ConcreteTypeInformation type) {
+ TypeInformation allocateMap(ConcreteTypeInformation type,
+ Node node,
+ Element element,
+ [TypeInformation keyType,
+ TypeInformation valueType]) {
+ bool isFixed = (type.type == compiler.typesTask.constMapType);
+
+ // transform the key and value into inferrable type informations
+ KeyInMapTypeInformation inferredKeyType =
+ new KeyInMapTypeInformation(keyType);
+ ValueInMapTypeInformation inferredValueType =
+ new ValueInMapTypeInformation(valueType);
+ if (isFixed) {
+ inferredValueType.inferred = inferredKeyType.inferred = true;
+ }
+ MapTypeMask mask = new MapTypeMask(type.type,
+ node,
+ element,
+ isFixed ? keyType.type
+ : dynamicType.type,
+ isFixed ? valueType.type
+ : dynamicType.type);
+
MapTypeInformation map =
- new MapTypeInformation(keyType, valueType, type.type);
- allocatedTypes.add(map);
+ new MapTypeInformation(inferredKeyType, inferredValueType, mask);
+
+ allocatedTypes.add(inferredKeyType);
+ allocatedTypes.add(inferredValueType);
+ allocatedMaps[node] = map;
return map;
}
@@ -441,12 +476,11 @@
TypeGraphInferrerEngine(Compiler compiler, this.mainElement)
: super(compiler, new TypeInformationSystem(compiler));
- void analyzeContainer(ListTypeInformation info) {
+ void analyzeListAndEnqueue(ListTypeInformation info) {
if (info.analyzed) return;
info.analyzed = true;
ListTracerVisitor tracer = new ListTracerVisitor(info, this);
- List<TypeInformation> newAssignments = tracer.run();
- if (newAssignments == null) {
+ if (!tracer.run()) {
return;
}
info.bailedOut = false;
@@ -455,7 +489,26 @@
if (info.originalContainerType.forwardTo == fixedListType) {
info.checksGrowable = tracer.callsGrowableMethod;
}
- newAssignments.forEach(info.elementType.addAssignment);
+ tracer.assignments.forEach(info.elementType.addAssignment);
+ // Enqueue the list for later refinement
+ workQueue.add(info);
+ workQueue.add(info.elementType);
+ }
+
+ void analyzeMapAndEnqueue(MapTypeInformation info) {
+ if (info.analyzed) return;
+ info.analyzed = true;
+ MapTracerVisitor tracer = new MapTracerVisitor(info, this);
+ if (!tracer.run()) return;
+ info.bailedOut = false;
+ info.keyType.inferred = true;
+ tracer.keyAssignments.forEach(info.keyType.addAssignment);
+ workQueue.add(info.keyType);
+ info.valueType.inferred = true;
+ tracer.valueAssignments.forEach(info.valueType.addAssignment);
+ // Enqueue the map for later refinement
+ workQueue.add(info.valueType);
+ workQueue.add(info);
}
void runOverAllElements() {
@@ -480,10 +533,13 @@
// Try to infer element types of lists.
types.allocatedLists.values.forEach((ListTypeInformation info) {
if (info.elementType.inferred) return;
- analyzeContainer(info);
- if (info.bailedOut) return;
- workQueue.add(info);
- workQueue.add(info.elementType);
+ analyzeListAndEnqueue(info);
+ });
+
+ // Try to infer the key and value types for maps.
+ types.allocatedMaps.values.forEach((MapTypeInformation info) {
+ if (info.keyType.inferred && info.valueType.inferred) return;
+ analyzeMapAndEnqueue(info);
});
types.allocatedClosures.forEach((info) {
@@ -498,8 +554,8 @@
});
});
- // Reset all nodes that use lists that have been inferred, as well
- // as nodes that use elements fetched from these lists. The
+ // Reset all nodes that use lists/maps that have been inferred, as well
+ // as nodes that use elements fetched from these lists/maps. The
// workset for a new run of the analysis will be these nodes.
Set<TypeInformation> seenTypes = new Set<TypeInformation>();
while (!workQueue.isEmpty) {
@@ -519,6 +575,11 @@
'for ${info.originalContainerType.allocationNode} '
'at ${info.originalContainerType.allocationElement}');
});
+ types.allocatedMaps.values.forEach((MapTypeInformation info) {
+ print('${info.type} '
+ 'for ${(info.type as MapTypeMask).allocationNode} '
+ 'at ${(info.type as MapTypeMask).allocationElement}');
+ });
}
compiler.log('Inferred $overallRefineCount types.');
@@ -555,7 +616,12 @@
Constant value =
compiler.constantHandler.getConstantForVariable(element);
if (value != null) {
- type = types.getConcreteTypeFor(value.computeMask(compiler));
+ if (value.isFunction()) {
+ FunctionConstant functionConstant = value;
+ type = types.allocateClosure(node, functionConstant.element);
+ } else {
+ type = types.getConcreteTypeFor(value.computeMask(compiler));
+ }
}
}
recordType(element, type);
@@ -975,11 +1041,17 @@
if (selector.isSetter() || selector.isIndexSet()) {
return compiler.typesTask.dynamicType;
}
- if (returnsElementType(selector)) {
+ if (returnsListElementType(selector)) {
ContainerTypeMask mask = selector.mask;
TypeMask elementType = mask.elementType;
return elementType == null ? compiler.typesTask.dynamicType : elementType;
}
+ if (returnsMapValueType(selector)) {
+ MapTypeMask mask = selector.mask;
+ TypeMask valueType = mask.valueType;
+ return valueType == null ? compiler.typesTask.dynamicType
+ : valueType.nullable();
+ }
TypeMask result = const TypeMask.nonNullEmpty();
Iterable<Element> elements = compiler.world.allFunctions.filter(selector);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index bd34d0c..fddc6fc 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -665,9 +665,12 @@
return const TypeMask.nonNullEmpty();
}
- if (returnsElementType(typedSelector)) {
+ if (returnsListElementType(typedSelector)) {
ContainerTypeMask mask = receiver.type;
return mask.elementType;
+ } else if (returnsMapValueType(typedSelector)) {
+ MapTypeMask mask = receiver.type;
+ return mask.valueType.nullable();
} else {
TypeInformation info =
handleIntrisifiedSelector(typedSelector, inferrer);
@@ -866,6 +869,32 @@
}
/**
+ * An [InferredTypeInformation] is a [TypeInformation] that
+ * defaults to the dynamic type until it is marked as beeing
+ * inferred, at which point it computes its type based on
+ * its assignments.
+ */
+abstract class InferredTypeInformation extends TypeInformation {
+ /** Whether the element type in that container has been inferred. */
+ bool inferred = false;
+
+ InferredTypeInformation(parentType) {
+ if (parentType != null) addAssignment(parentType);
+ }
+
+ TypeMask refine(TypeGraphInferrerEngine inferrer) {
+ if (!inferred) {
+ return inferrer.types.dynamicType.type;
+ }
+ return inferrer.types.computeTypeMask(assignments);
+ }
+
+ bool hasStableType(TypeGraphInferrerEngine inferrer) {
+ return inferred && super.hasStableType(inferrer);
+ }
+}
+
+/**
* A [ListTypeInformation] is a [TypeInformation] created
* for each `List` instantiations.
*/
@@ -931,30 +960,14 @@
* An [ElementInContainerTypeInformation] holds the common type of the
* elements in a [ListTypeInformation].
*/
-class ElementInContainerTypeInformation extends TypeInformation {
- /** Whether the element type in that container has been inferred. */
- bool inferred = false;
-
- ElementInContainerTypeInformation(elementType) {
- if (elementType != null) addAssignment(elementType);
- }
-
- TypeMask refine(TypeGraphInferrerEngine inferrer) {
- if (!inferred) {
- return inferrer.types.dynamicType.type;
- }
- return inferrer.types.computeTypeMask(assignments);
- }
+class ElementInContainerTypeInformation extends InferredTypeInformation {
+ ElementInContainerTypeInformation(elementType) : super(elementType);
String toString() => 'Element in container $type';
accept(TypeInformationVisitor visitor) {
return visitor.visitElementInContainerTypeInformation(this);
}
-
- bool hasStableType(TypeGraphInferrerEngine inferrer) {
- return inferred && super.hasStableType(inferrer);
- }
}
/**
@@ -962,9 +975,17 @@
* for maps.
*/
class MapTypeInformation extends TypeInformation {
- final TypeInformation keyType;
- final TypeInformation valueType;
- final TypeMask initialType;
+ final KeyInMapTypeInformation keyType;
+ final ValueInMapTypeInformation valueType;
+ final MapTypeMask initialType;
+
+ // The set of [TypeInformation] where values from the traced map could
+ // flow in.
+ final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
+
+ // Set to false once analysis has succeeded.
+ bool bailedOut = true;
+ bool analyzed = false;
MapTypeInformation(this.keyType, this.valueType, this.initialType) {
keyType.addUser(this);
@@ -977,10 +998,63 @@
}
TypeMask refine(TypeGraphInferrerEngine inferrer) {
- return initialType;
+ var mask = type;
+ if (!mask.isMap
+ || mask.keyType != keyType.type
+ || mask.valueType != valueType.type) {
+ return new MapTypeMask(initialType.forwardTo,
+ initialType.allocationNode,
+ initialType.allocationElement,
+ keyType.type,
+ valueType.type);
+ }
+
+ return mask;
}
- String toString() => 'Map $type';
+ bool hasStableType(TypeGraphInferrerEngine inferrer) {
+ return keyType.isStable
+ && valueType.isStable
+ && super.hasStableType(inferrer);
+ }
+
+ String toString() => 'Map $type (K:$keyType, V:$valueType)';
+}
+
+/**
+ * A [KeyInMapTypeInformation] holds the common type
+ * for the keys in a [MapTypeInformation]
+ */
+class KeyInMapTypeInformation extends InferredTypeInformation {
+ KeyInMapTypeInformation(TypeInformation keyType) : super(keyType);
+
+ accept(TypeInformationVisitor visitor) {
+ return visitor.visitKeyInMapTypeInformation(this);
+ }
+
+ TypeMask refine(TypeGraphInferrerEngine inferrer) {
+ return super.refine(inferrer);
+ }
+
+ String toString() => 'Key in Map $type';
+}
+
+/**
+ * A [ValueInMapTypeInformation] holds the common type
+ * for the values in a [MapTypeInformation]
+ */
+class ValueInMapTypeInformation extends InferredTypeInformation {
+ ValueInMapTypeInformation(TypeInformation valueType) : super(valueType);
+
+ accept(TypeInformationVisitor visitor) {
+ return visitor.visitValueInMapTypeInformation(this);
+ }
+
+ TypeMask refine(TypeGraphInferrerEngine inferrer) {
+ return super.refine(inferrer);
+ }
+
+ String toString() => 'Value in Map $type';
}
/**
@@ -1031,6 +1105,8 @@
T visitPhiElementTypeInformation(PhiElementTypeInformation info);
T visitElementInContainerTypeInformation(
ElementInContainerTypeInformation info);
+ T visitKeyInMapTypeInformation(KeyInMapTypeInformation info);
+ T visitValueInMapTypeInformation(ValueInMapTypeInformation info);
T visitListTypeInformation(ListTypeInformation info);
T visitMapTypeInformation(MapTypeInformation info);
T visitConcreteTypeInformation(ConcreteTypeInformation info);
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 35abf1c..36ddfa5 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -1738,10 +1738,12 @@
}
bool couldBeTypedArray(TypeMask mask) {
- TypeMask indexing = new TypeMask.subtype(jsIndexingBehaviorInterface);
- // Checking if [mask] contains [indexing] means that we want to
- // know if [mask] is not a more specific type than [indexing].
- return isTypedArray(mask) || mask.containsMask(indexing, compiler);
+ bool intersects(TypeMask type1, TypeMask type2) =>
+ !type1.intersection(type2, compiler).isEmpty;
+
+ return compiler.typedDataClass != null
+ && intersects(mask, new TypeMask.subtype(compiler.typedDataClass))
+ && intersects(mask, new TypeMask.subtype(jsIndexingBehaviorInterface));
}
/// Returns all static fields that are referenced through [targetsUsed].
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 93241b7..2f81f2d 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -1381,16 +1381,15 @@
emitFinishClassesInvocationIfNecessary(mainBuffer);
classesCollector = oldClassesCollector;
}
-
- typeTestEmitter.emitRuntimeTypeSupport(mainBuffer);
+ OutputUnit mainOutputUnit = compiler.deferredLoadTask.mainOutputUnit;
+ typeTestEmitter.emitRuntimeTypeSupport(mainBuffer, mainOutputUnit);
interceptorEmitter.emitGetInterceptorMethods(mainBuffer);
interceptorEmitter.emitOneShotInterceptors(mainBuffer);
// Constants in checked mode call into RTI code to set type information
// which may need getInterceptor (and one-shot interceptor) methods, so
// we have to make sure that [emitGetInterceptorMethods] and
// [emitOneShotInterceptors] have been called.
- emitCompileTimeConstants(
- mainBuffer, compiler.deferredLoadTask.mainOutputUnit);
+ emitCompileTimeConstants(mainBuffer, mainOutputUnit);
// We write a javascript mapping from DeferredLibrary elements
// (really their String argument) to the js hunk to load.
@@ -1569,6 +1568,8 @@
classesCollector = oldClassesCollector;
+ typeTestEmitter.emitRuntimeTypeSupport(buffer, outputUnit);
+
emitCompileTimeConstants(buffer, outputUnit);
String code = buffer.getText();
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
index 9070243..2881d91 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
@@ -4,8 +4,6 @@
library dart2js.js_emitter;
-import 'dart:collection' show Queue;
-
import '../common.dart';
import '../js/js.dart' as jsAst;
@@ -59,8 +57,6 @@
import '../util/uri_extras.dart' show
relativize;
-import '../dump_info.dart' as dumpInfo;
-
import '../deferred_load.dart' show
OutputUnit;
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
index 8733590..87a5036 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -276,13 +276,18 @@
}
}
- void emitRuntimeTypeSupport(CodeBuffer buffer) {
+ void emitRuntimeTypeSupport(CodeBuffer buffer, OutputUnit outputUnit) {
task.addComment('Runtime type support', buffer);
RuntimeTypes rti = backend.rti;
TypeChecks typeChecks = rti.requiredChecks;
// Add checks to the constructors of instantiated classes.
+ // TODO(sigurdm): We should avoid running through this list for each
+ // output unit.
for (ClassElement cls in typeChecks) {
+ OutputUnit destination =
+ compiler.deferredLoadTask.outputUnitForElement(cls);
+ if (destination != outputUnit) continue;
// TODO(9556). The properties added to 'holder' should be generated
// directly as properties of the class object, not added later.
String holder = namer.isolateAccess(backend.getImplementationClass(cls));
@@ -306,12 +311,20 @@
buffer.write(jsAst.prettyPrint(encoding, compiler));
buffer.add('$N');
}
+ if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) {
+ // TODO(sigurdm): These should also be possibly deferred.
+ // They should be handled similarly to constants.
+ // They have 3 dependencies:
+ // 1. The libraries containing the check.
+ // 2. The typedef defining it.
+ // 3. The types involved in the typedef.
+ // TODO(sigurdm): Actually these seems to never be used. Remove them.
+ checkedNonGenericFunctionTypes.forEach(addSignature);
+ checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
+ functionTypes.forEach(addSignature);
+ });
+ }
- checkedNonGenericFunctionTypes.forEach(addSignature);
-
- checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
- functionTypes.forEach(addSignature);
- });
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart b/sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart
new file mode 100644
index 0000000..c1231a8
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2012, 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 dart2js.source_mirrors.analyze;
+
+import 'dart:async';
+
+import 'source_mirrors.dart';
+import 'dart2js_mirrors.dart' show Dart2JsMirrorSystem;
+import '../../compiler.dart' as api;
+import '../apiimpl.dart' as apiimpl;
+import '../dart2jslib.dart' show Compiler;
+
+//------------------------------------------------------------------------------
+// Analysis entry point.
+//------------------------------------------------------------------------------
+
+/**
+ * Analyzes set of libraries and provides a mirror system which can be used for
+ * static inspection of the source code.
+ */
+// TODO(johnniwinther): Move this to [compiler/compiler.dart].
+Future<MirrorSystem> analyze(List<Uri> libraries,
+ Uri libraryRoot,
+ Uri packageRoot,
+ api.CompilerInputProvider inputProvider,
+ api.DiagnosticHandler diagnosticHandler,
+ [List<String> options = const <String>[]]) {
+ if (!libraryRoot.path.endsWith("/")) {
+ throw new ArgumentError("libraryRoot must end with a /");
+ }
+ if (packageRoot != null && !packageRoot.path.endsWith("/")) {
+ throw new ArgumentError("packageRoot must end with a /");
+ }
+ options = new List<String>.from(options);
+ options.add('--analyze-only');
+ options.add('--analyze-signatures-only');
+ options.add('--analyze-all');
+ options.add('--categories=Client,Server');
+
+ bool compilationFailed = false;
+ void internalDiagnosticHandler(Uri uri, int begin, int end,
+ String message, api.Diagnostic kind) {
+ if (kind == api.Diagnostic.ERROR ||
+ kind == api.Diagnostic.CRASH) {
+ compilationFailed = true;
+ }
+ diagnosticHandler(uri, begin, end, message, kind);
+ }
+
+ Compiler compiler = new apiimpl.Compiler(inputProvider,
+ null,
+ internalDiagnosticHandler,
+ libraryRoot, packageRoot,
+ options,
+ const {});
+ compiler.librariesToAnalyzeWhenRun = libraries;
+ return compiler.run(null).then((bool success) {
+ if (success && !compilationFailed) {
+ return new Dart2JsMirrorSystem(compiler);
+ } else {
+ throw new StateError('Failed to create mirror system.');
+ }
+ });
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_instance_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_instance_mirrors.dart
new file mode 100644
index 0000000..40a5d3f
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_instance_mirrors.dart
@@ -0,0 +1,285 @@
+// Copyright (c) 2013, 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.
+
+part of dart2js.mirrors;
+
+abstract class ObjectMirrorMixin implements ObjectMirror {
+ InstanceMirror getField(Symbol fieldName) {
+ throw new UnsupportedError('ObjectMirror.getField unsupported.');
+ }
+
+ InstanceMirror setField(Symbol fieldName, Object value) {
+ throw new UnsupportedError('ObjectMirror.setField unsupported.');
+ }
+
+ InstanceMirror invoke(Symbol memberName,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ throw new UnsupportedError('ObjectMirror.invoke unsupported.');
+ }
+}
+
+abstract class InstanceMirrorMixin implements InstanceMirror {
+
+ bool get hasReflectee => false;
+
+ get reflectee {
+ throw new UnsupportedError('InstanceMirror.reflectee unsupported.');
+ }
+
+ Function operator [](Symbol name) {
+ throw new UnsupportedError('InstanceMirror.operator [] unsupported.');
+ }
+
+ delegate(Invocation invocation) {
+ throw new UnsupportedError('InstanceMirror.delegate unsupported');
+ }
+}
+
+InstanceMirror _convertConstantToInstanceMirror(
+ Dart2JsMirrorSystem mirrorSystem, Constant constant) {
+ if (constant is BoolConstant) {
+ return new Dart2JsBoolConstantMirror(mirrorSystem, constant);
+ } else if (constant is NumConstant) {
+ return new Dart2JsNumConstantMirror(mirrorSystem, constant);
+ } else if (constant is StringConstant) {
+ return new Dart2JsStringConstantMirror(mirrorSystem, constant);
+ } else if (constant is ListConstant) {
+ return new Dart2JsListConstantMirror(mirrorSystem, constant);
+ } else if (constant is MapConstant) {
+ return new Dart2JsMapConstantMirror(mirrorSystem, constant);
+ } else if (constant is TypeConstant) {
+ return new Dart2JsTypeConstantMirror(mirrorSystem, constant);
+ } else if (constant is FunctionConstant) {
+ return new Dart2JsConstantMirror(mirrorSystem, constant);
+ } else if (constant is NullConstant) {
+ return new Dart2JsNullConstantMirror(mirrorSystem, constant);
+ } else if (constant is ConstructedConstant) {
+ return new Dart2JsConstructedConstantMirror(mirrorSystem, constant);
+ }
+ mirrorSystem.compiler.internalError("Unexpected constant $constant");
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Mirrors on constant values used for metadata.
+////////////////////////////////////////////////////////////////////////////////
+
+class Dart2JsConstantMirror extends Object
+ with ObjectMirrorMixin, InstanceMirrorMixin
+ implements InstanceMirror {
+ final Dart2JsMirrorSystem mirrorSystem;
+ final Constant _constant;
+
+ Dart2JsConstantMirror(this.mirrorSystem, this._constant);
+
+ // TODO(johnniwinther): Improve the quality of this method.
+ String toString() => '$_constant';
+
+ ClassMirror get type {
+ return mirrorSystem._getTypeDeclarationMirror(
+ _constant.computeType(mirrorSystem.compiler).element);
+ }
+
+ int get hashCode => 13 * _constant.hashCode;
+
+ bool operator ==(var other) {
+ if (other is! Dart2JsConstantMirror) return false;
+ return _constant == other._constant;
+ }
+}
+
+class Dart2JsNullConstantMirror extends Dart2JsConstantMirror {
+ Dart2JsNullConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ NullConstant constant)
+ : super(mirrorSystem, constant);
+
+ NullConstant get _constant => super._constant;
+
+ bool get hasReflectee => true;
+
+ get reflectee => null;
+}
+
+class Dart2JsBoolConstantMirror extends Dart2JsConstantMirror {
+ Dart2JsBoolConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ BoolConstant constant)
+ : super(mirrorSystem, constant);
+
+ Dart2JsBoolConstantMirror.fromBool(Dart2JsMirrorSystem mirrorSystem,
+ bool value)
+ : super(mirrorSystem, value ? new TrueConstant() : new FalseConstant());
+
+ BoolConstant get _constant => super._constant;
+
+ bool get hasReflectee => true;
+
+ get reflectee => _constant is TrueConstant;
+}
+
+class Dart2JsStringConstantMirror extends Dart2JsConstantMirror {
+ Dart2JsStringConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ StringConstant constant)
+ : super(mirrorSystem, constant);
+
+ Dart2JsStringConstantMirror.fromString(Dart2JsMirrorSystem mirrorSystem,
+ String text)
+ : super(mirrorSystem, new StringConstant(new DartString.literal(text)));
+
+ StringConstant get _constant => super._constant;
+
+ bool get hasReflectee => true;
+
+ get reflectee => _constant.value.slowToString();
+}
+
+class Dart2JsNumConstantMirror extends Dart2JsConstantMirror {
+ Dart2JsNumConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ NumConstant constant)
+ : super(mirrorSystem, constant);
+
+ NumConstant get _constant => super._constant;
+
+ bool get hasReflectee => true;
+
+ get reflectee => _constant.value;
+}
+
+class Dart2JsListConstantMirror extends Dart2JsConstantMirror
+ implements ListInstanceMirror {
+ Dart2JsListConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ ListConstant constant)
+ : super(mirrorSystem, constant);
+
+ ListConstant get _constant => super._constant;
+
+ int get length => _constant.length;
+
+ InstanceMirror getElement(int index) {
+ if (index < 0) throw new RangeError('Negative index');
+ if (index >= _constant.length) throw new RangeError('Index out of bounds');
+ return _convertConstantToInstanceMirror(mirrorSystem,
+ _constant.entries[index]);
+ }
+}
+
+class Dart2JsMapConstantMirror extends Dart2JsConstantMirror
+ implements MapInstanceMirror {
+ List<String> _listCache;
+
+ Dart2JsMapConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ MapConstant constant)
+ : super(mirrorSystem, constant);
+
+ MapConstant get _constant => super._constant;
+
+ List<String> get _list {
+ if (_listCache == null) {
+ _listCache = new List<String>(_constant.keys.entries.length);
+ int index = 0;
+ for (StringConstant keyConstant in _constant.keys.entries) {
+ _listCache[index] = keyConstant.value.slowToString();
+ index++;
+ }
+ _listCache = new UnmodifiableListView<String>(_listCache);
+ }
+ return _listCache;
+ }
+
+ int get length => _constant.length;
+
+ Iterable<String> get keys {
+ return _list;
+ }
+
+ InstanceMirror getValue(String key) {
+ int index = _list.indexOf(key);
+ if (index == -1) return null;
+ return _convertConstantToInstanceMirror(mirrorSystem,
+ _constant.values[index]);
+ }
+}
+
+class Dart2JsTypeConstantMirror extends Dart2JsConstantMirror
+ implements TypeInstanceMirror {
+
+ Dart2JsTypeConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ TypeConstant constant)
+ : super(mirrorSystem, constant);
+
+ TypeConstant get _constant => super._constant;
+
+ TypeMirror get representedType =>
+ mirrorSystem._convertTypeToTypeMirror(_constant.representedType);
+}
+
+class Dart2JsConstructedConstantMirror extends Dart2JsConstantMirror {
+ Map<String,Constant> _fieldMapCache;
+
+ Dart2JsConstructedConstantMirror(Dart2JsMirrorSystem mirrorSystem,
+ ConstructedConstant constant)
+ : super(mirrorSystem, constant);
+
+ ConstructedConstant get _constant => super._constant;
+
+ Map<String,Constant> get _fieldMap {
+ if (_fieldMapCache == null) {
+ _fieldMapCache = new Map<String,Constant>();
+ if (identical(_constant.type.element.kind, ElementKind.CLASS)) {
+ var index = 0;
+ ClassElement element = _constant.type.element;
+ element.forEachInstanceField((_, Element field) {
+ String fieldName = field.name;
+ _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]);
+ index++;
+ }, includeSuperAndInjectedMembers: true);
+ }
+ }
+ return _fieldMapCache;
+ }
+
+ InstanceMirror getField(Symbol fieldName) {
+ Constant fieldConstant = _fieldMap[MirrorSystem.getName(fieldName)];
+ if (fieldConstant != null) {
+ return _convertConstantToInstanceMirror(mirrorSystem, fieldConstant);
+ }
+ return super.getField(fieldName);
+ }
+}
+
+class Dart2JsCommentInstanceMirror extends Object
+ with ObjectMirrorMixin, InstanceMirrorMixin
+ implements CommentInstanceMirror {
+ final Dart2JsMirrorSystem mirrorSystem;
+ final String text;
+ String _trimmedText;
+
+ Dart2JsCommentInstanceMirror(this.mirrorSystem, this.text);
+
+ ClassMirror get type {
+ return mirrorSystem._getTypeDeclarationMirror(
+ mirrorSystem.compiler.documentClass);
+ }
+
+ bool get isDocComment => text.startsWith('/**') || text.startsWith('///');
+
+ String get trimmedText {
+ if (_trimmedText == null) {
+ _trimmedText = stripComment(text);
+ }
+ return _trimmedText;
+ }
+
+ InstanceMirror getField(Symbol fieldName) {
+ if (fieldName == #isDocComment) {
+ return new Dart2JsBoolConstantMirror.fromBool(mirrorSystem, isDocComment);
+ } else if (fieldName == #text) {
+ return new Dart2JsStringConstantMirror.fromString(mirrorSystem, text);
+ } else if (fieldName == #trimmedText) {
+ return new Dart2JsStringConstantMirror.fromString(mirrorSystem,
+ trimmedText);
+ }
+ super.getField(fieldName);
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_library_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_library_mirror.dart
new file mode 100644
index 0000000..9a5e58d
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_library_mirror.dart
@@ -0,0 +1,234 @@
+// Copyright (c) 2013, 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.
+
+part of dart2js.mirrors;
+
+
+class Dart2JsLibraryMirror
+ extends Dart2JsElementMirror
+ with ObjectMirrorMixin, ContainerMixin
+ implements LibrarySourceMirror {
+ List<LibraryDependencyMirror> _libraryDependencies;
+
+ Dart2JsLibraryMirror(Dart2JsMirrorSystem system, LibraryElement library)
+ : super(system, library);
+
+ Function operator [](Symbol name) {
+ throw new UnsupportedError('LibraryMirror.operator [] unsupported.');
+ }
+
+ LibraryElement get _element => super._element;
+
+ Uri get uri => _element.canonicalUri;
+
+ DeclarationMirror get owner => null;
+
+ bool get isPrivate => false;
+
+ LibraryMirror library() => this;
+
+ /**
+ * Returns the library name (for libraries with a library tag) or the script
+ * file name (for scripts without a library tag). The latter case is used to
+ * provide a 'library name' for scripts, to use for instance in dartdoc.
+ */
+ String get _simpleNameString {
+ if (_element.libraryTag != null) {
+ return _element.libraryTag.name.toString();
+ } else {
+ // Use the file name as script name.
+ String path = _element.canonicalUri.path;
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+ }
+
+ Symbol get qualifiedName => simpleName;
+
+ void _forEachElement(f(Element element)) => _element.forEachLocalMember(f);
+
+ Iterable<Dart2JsDeclarationMirror> _getDeclarationMirrors(Element element) {
+ if (element.isClass() || element.isTypedef()) {
+ return [mirrorSystem._getTypeDeclarationMirror(element)];
+ } else {
+ return super._getDeclarationMirrors(element);
+ }
+ }
+
+ Map<Symbol, MethodMirror> get topLevelMembers => null;
+
+ /**
+ * Computes the first token of this library using the first library tag as
+ * indicator.
+ */
+ Token getBeginToken() {
+ if (_element.libraryTag != null) {
+ return _element.libraryTag.getBeginToken();
+ } else if (!_element.tags.isEmpty) {
+ return _element.tags.reverse().head.getBeginToken();
+ }
+ return null;
+ }
+
+ /**
+ * Computes the first token of this library using the last library tag as
+ * indicator.
+ */
+ Token getEndToken() {
+ if (!_element.tags.isEmpty) {
+ return _element.tags.head.getEndToken();
+ }
+ return null;
+ }
+
+ void _ensureLibraryDependenciesAnalyzed() {
+ if (_libraryDependencies == null) {
+ _libraryDependencies = <LibraryDependencyMirror>[];
+ for (LibraryTag node in _element.tags.reverse()) {
+ LibraryDependency libraryDependency = node.asLibraryDependency();
+ if (libraryDependency != null) {
+ LibraryElement targetLibraryElement =
+ _element.getLibraryFromTag(libraryDependency);
+ assert(targetLibraryElement != null);
+ LibraryMirror targetLibrary =
+ mirrorSystem._getLibrary(targetLibraryElement);
+ _libraryDependencies.add(new Dart2JsLibraryDependencyMirror(
+ libraryDependency, this, targetLibrary));
+ }
+ }
+ }
+ }
+
+ List<LibraryDependencyMirror> get libraryDependencies {
+ _ensureLibraryDependenciesAnalyzed();
+ return _libraryDependencies;
+ }
+}
+
+class Dart2JsLibraryDependencyMirror implements LibraryDependencyMirror {
+ final LibraryDependency _node;
+ final Dart2JsLibraryMirror _sourceLibrary;
+ final Dart2JsLibraryMirror _targetLibrary;
+ List<CombinatorMirror> _combinators;
+
+ Dart2JsLibraryDependencyMirror(this._node,
+ this._sourceLibrary,
+ this._targetLibrary);
+
+ SourceLocation get location {
+ return new Dart2JsSourceLocation(
+ _sourceLibrary._element.entryCompilationUnit.script,
+ _sourceLibrary.mirrorSystem.compiler.spanFromNode(_node));
+ }
+
+ List<CombinatorMirror> get combinators {
+ if (_combinators == null) {
+ _combinators = <CombinatorMirror>[];
+ if (_node.combinators != null) {
+ for (Combinator combinator in _node.combinators.nodes) {
+ List<String> identifiers = <String>[];
+ for (Identifier identifier in combinator.identifiers.nodes) {
+ identifiers.add(identifier.source);
+ }
+ _combinators.add(new Dart2JsCombinatorMirror(
+ identifiers, isShow: combinator.isShow));
+ }
+ }
+ }
+ return _combinators;
+ }
+
+ LibraryMirror get sourceLibrary => _sourceLibrary;
+
+ LibraryMirror get targetLibrary => _targetLibrary;
+
+ String get prefix {
+ Import import = _node.asImport();
+ if (import != null && import.prefix != null) {
+ return import.prefix.source;
+ }
+ return null;
+ }
+
+ bool get isImport => _node.asImport() != null;
+
+ bool get isExport => _node.asExport() != null;
+}
+
+class Dart2JsCombinatorMirror implements CombinatorMirror {
+ final List<String> identifiers;
+ final bool isShow;
+
+ Dart2JsCombinatorMirror(this.identifiers, {bool isShow: true})
+ : this.isShow = isShow;
+
+ bool get isHide => !isShow;
+}
+
+class Dart2JsSourceLocation implements SourceLocation {
+ final Script _script;
+ final SourceSpan _span;
+ int _line;
+ int _column;
+
+ Dart2JsSourceLocation(this._script, this._span);
+
+ int _computeLine() {
+ var sourceFile = _script.file;
+ if (sourceFile != null) {
+ return sourceFile.getLine(offset) + 1;
+ }
+ var index = 0;
+ var lineNumber = 0;
+ while (index <= offset && index < sourceText.length) {
+ index = sourceText.indexOf('\n', index) + 1;
+ if (index <= 0) break;
+ lineNumber++;
+ }
+ return lineNumber;
+ }
+
+ int get line {
+ if (_line == null) {
+ _line = _computeLine();
+ }
+ return _line;
+ }
+
+ int _computeColumn() {
+ if (length == 0) return 0;
+
+ var sourceFile = _script.file;
+ if (sourceFile != null) {
+ return sourceFile.getColumn(sourceFile.getLine(offset), offset) + 1;
+ }
+ int index = offset - 1;
+ var columnNumber = 0;
+ while (0 <= index && index < sourceText.length) {
+ columnNumber++;
+ var codeUnit = sourceText.codeUnitAt(index);
+ if (codeUnit == $CR || codeUnit == $LF) {
+ break;
+ }
+ index--;
+ }
+ return columnNumber;
+ }
+
+ int get column {
+ if (_column == null) {
+ _column = _computeColumn();
+ }
+ return _column;
+ }
+
+ int get offset => _span.begin;
+
+ int get length => _span.end - _span.begin;
+
+ String get text => _script.text.substring(_span.begin, _span.end);
+
+ Uri get sourceUri => _script.uri;
+
+ String get sourceText => _script.text;
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
new file mode 100644
index 0000000..0a22d4d
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
@@ -0,0 +1,288 @@
+// Copyright (c) 2013, 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.
+
+part of dart2js.mirrors;
+
+//------------------------------------------------------------------------------
+// Member mirrors implementation.
+//------------------------------------------------------------------------------
+
+abstract class Dart2JsMemberMirror extends Dart2JsElementMirror {
+
+ Dart2JsMemberMirror(Dart2JsMirrorSystem system, Element element)
+ : super(system, element);
+
+ bool get isStatic => false;
+}
+
+
+class Dart2JsMethodKind {
+ static const Dart2JsMethodKind REGULAR = const Dart2JsMethodKind("regular");
+ static const Dart2JsMethodKind GENERATIVE =
+ const Dart2JsMethodKind("generative");
+ static const Dart2JsMethodKind REDIRECTING =
+ const Dart2JsMethodKind("redirecting");
+ static const Dart2JsMethodKind CONST = const Dart2JsMethodKind("const");
+ static const Dart2JsMethodKind FACTORY = const Dart2JsMethodKind("factory");
+ static const Dart2JsMethodKind GETTER = const Dart2JsMethodKind("getter");
+ static const Dart2JsMethodKind SETTER = const Dart2JsMethodKind("setter");
+ static const Dart2JsMethodKind OPERATOR = const Dart2JsMethodKind("operator");
+
+ final String text;
+
+ const Dart2JsMethodKind(this.text);
+
+ String toString() => text;
+}
+
+
+String _getOperatorFromOperatorName(String name) {
+ Map<String, String> mapping = const {
+ 'eq': '==',
+ 'not': '~',
+ 'index': '[]',
+ 'indexSet': '[]=',
+ 'mul': '*',
+ 'div': '/',
+ 'mod': '%',
+ 'tdiv': '~/',
+ 'add': '+',
+ 'sub': '-',
+ 'shl': '<<',
+ 'shr': '>>',
+ 'ge': '>=',
+ 'gt': '>',
+ 'le': '<=',
+ 'lt': '<',
+ 'and': '&',
+ 'xor': '^',
+ 'or': '|',
+ };
+ String newName = mapping[name];
+ if (newName == null) {
+ throw new Exception('Unhandled operator name: $name');
+ }
+ return newName;
+}
+
+class Dart2JsMethodMirror extends Dart2JsMemberMirror
+ implements MethodMirror {
+ final Dart2JsDeclarationMirror owner;
+ final String _simpleNameString;
+ final Dart2JsMethodKind _kind;
+
+ Dart2JsMethodMirror._internal(Dart2JsDeclarationMirror owner,
+ FunctionElement function,
+ String this._simpleNameString,
+ Dart2JsMethodKind this._kind)
+ : this.owner = owner,
+ super(owner.mirrorSystem, function);
+
+ factory Dart2JsMethodMirror(Dart2JsDeclarationMirror owner,
+ FunctionElement function) {
+ String realName = function.name;
+ // TODO(ahe): This method should not be calling
+ // Elements.operatorNameToIdentifier.
+ String simpleName =
+ Elements.operatorNameToIdentifier(function.name);
+ Dart2JsMethodKind kind;
+ if (function.kind == ElementKind.GETTER) {
+ kind = Dart2JsMethodKind.GETTER;
+ } else if (function.kind == ElementKind.SETTER) {
+ kind = Dart2JsMethodKind.SETTER;
+ simpleName = '$simpleName=';
+ } else if (function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
+ // TODO(johnniwinther): Support detection of redirecting constructors.
+ if (function.modifiers.isConst()) {
+ kind = Dart2JsMethodKind.CONST;
+ } else {
+ kind = Dart2JsMethodKind.GENERATIVE;
+ }
+ } else if (function.modifiers.isFactory()) {
+ // TODO(johnniwinther): Support detection of redirecting constructors.
+ kind = Dart2JsMethodKind.FACTORY;
+ } else if (realName == 'unary-') {
+ // TODO(johnniwinther): Use a constant for 'unary-'.
+ kind = Dart2JsMethodKind.OPERATOR;
+ // Simple name is 'unary-'.
+ simpleName = 'unary-';
+ } else if (simpleName.startsWith('operator\$')) {
+ String str = simpleName.substring(9);
+ simpleName = 'operator';
+ kind = Dart2JsMethodKind.OPERATOR;
+ simpleName = _getOperatorFromOperatorName(str);
+ } else {
+ kind = Dart2JsMethodKind.REGULAR;
+ }
+ return new Dart2JsMethodMirror._internal(owner, function,
+ simpleName, kind);
+ }
+
+ FunctionElement get _function => _element;
+
+ bool get isTopLevel => owner is LibraryMirror;
+
+ // TODO(johnniwinther): This seems stale and broken.
+ Symbol get constructorName => isConstructor ? simpleName : const Symbol('');
+
+ bool get isConstructor
+ => isGenerativeConstructor || isConstConstructor ||
+ isFactoryConstructor || isRedirectingConstructor;
+
+ bool get isSynthetic => false;
+
+ bool get isStatic => _function.modifiers.isStatic();
+
+ List<ParameterMirror> get parameters {
+ return _parametersFromFunctionSignature(this,
+ _function.computeSignature(mirrorSystem.compiler));
+ }
+
+ TypeMirror get returnType => owner._getTypeMirror(
+ _function.computeSignature(mirrorSystem.compiler).returnType);
+
+ bool get isAbstract => _function.isAbstract;
+
+ bool get isRegularMethod => !(isGetter || isSetter || isConstructor);
+
+ bool get isConstConstructor => _kind == Dart2JsMethodKind.CONST;
+
+ bool get isGenerativeConstructor => _kind == Dart2JsMethodKind.GENERATIVE;
+
+ bool get isRedirectingConstructor => _kind == Dart2JsMethodKind.REDIRECTING;
+
+ bool get isFactoryConstructor => _kind == Dart2JsMethodKind.FACTORY;
+
+ bool get isGetter => _kind == Dart2JsMethodKind.GETTER;
+
+ bool get isSetter => _kind == Dart2JsMethodKind.SETTER;
+
+ bool get isOperator => _kind == Dart2JsMethodKind.OPERATOR;
+
+ DeclarationMirror lookupInScope(String name) {
+ for (Dart2JsParameterMirror parameter in parameters) {
+ if (parameter._element.name == name) {
+ return parameter;
+ }
+ }
+ return super.lookupInScope(name);
+ }
+
+ // TODO(johnniwinther): Should this really be in the interface of
+ // [MethodMirror]?
+ String get source => location.sourceText;
+
+ String toString() => 'Mirror on method ${_element.name}';
+}
+
+class Dart2JsFieldMirror extends Dart2JsMemberMirror implements VariableMirror {
+ final Dart2JsDeclarationMirror owner;
+ VariableElement _variable;
+
+ Dart2JsFieldMirror(Dart2JsDeclarationMirror owner,
+ VariableElement variable)
+ : this.owner = owner,
+ this._variable = variable,
+ super(owner.mirrorSystem, variable);
+
+ Element get _beginElement => _variable.variables;
+
+ bool get isTopLevel => owner is LibraryMirror;
+
+ bool get isStatic => _variable.modifiers.isStatic();
+
+ bool get isFinal => _variable.modifiers.isFinal();
+
+ bool get isConst => _variable.modifiers.isConst();
+
+ TypeMirror get type =>
+ owner._getTypeMirror(_variable.computeType(mirrorSystem.compiler));
+}
+
+class Dart2JsParameterMirror extends Dart2JsMemberMirror
+ implements ParameterMirror {
+ final Dart2JsDeclarationMirror owner;
+ final bool isOptional;
+ final bool isNamed;
+
+ factory Dart2JsParameterMirror(Dart2JsDeclarationMirror owner,
+ VariableElement element,
+ {bool isOptional: false,
+ bool isNamed: false}) {
+ if (element is FieldParameterElement) {
+ return new Dart2JsFieldParameterMirror(
+ owner, element, isOptional, isNamed);
+ }
+ return new Dart2JsParameterMirror._normal(
+ owner, element, isOptional, isNamed);
+ }
+
+ Dart2JsParameterMirror._normal(Dart2JsDeclarationMirror owner,
+ VariableElement element,
+ this.isOptional,
+ this.isNamed)
+ : this.owner = owner,
+ super(owner.mirrorSystem, element);
+
+ Element get _beginElement => _variableElement.variables;
+
+ VariableElement get _variableElement => _element;
+
+ TypeMirror get type => owner._getTypeMirror(
+ _variableElement.computeType(mirrorSystem.compiler),
+ _variableElement.variables.functionSignature);
+
+
+ bool get isFinal => false;
+
+ bool get isConst => false;
+
+ InstanceMirror get defaultValue {
+ if (hasDefaultValue) {
+ Constant constant = mirrorSystem.compiler.constantHandler
+ .getConstantForVariable(_variableElement);
+ assert(invariant(_variableElement, constant != null,
+ message: "Missing constant for parameter "
+ "$_variableElement with default value."));
+ return _convertConstantToInstanceMirror(mirrorSystem, constant);
+ }
+ return null;
+ }
+
+ bool get hasDefaultValue {
+ return _variableElement.cachedNode.asSendSet() != null;
+ }
+
+ bool get isInitializingFormal => false;
+
+ VariableMirror get initializedField => null;
+}
+
+class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror {
+
+ Dart2JsFieldParameterMirror(Dart2JsDeclarationMirror method,
+ FieldParameterElement element,
+ bool isOptional,
+ bool isNamed)
+ : super._normal(method, element, isOptional, isNamed);
+
+ FieldParameterElement get _fieldParameterElement => _element;
+
+ TypeMirror get type {
+ VariableListElement variables = _fieldParameterElement.variables;
+ VariableDefinitions node = variables.parseNode(mirrorSystem.compiler);
+ if (node.type != null) {
+ return super.type;
+ }
+ // Use the field type for initializing formals with no type annotation.
+ return owner._getTypeMirror(
+ _fieldParameterElement.fieldElement.computeType(mirrorSystem.compiler),
+ _fieldParameterElement.fieldElement.variables.functionSignature);
+ }
+
+ bool get isInitializingFormal => true;
+
+ VariableMirror get initializedField => new Dart2JsFieldMirror(
+ owner.owner, _fieldParameterElement.fieldElement);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
deleted file mode 100644
index 453882a..0000000
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ /dev/null
@@ -1,1873 +0,0 @@
-// Copyright (c) 2012, 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 mirrors_dart2js;
-
-import 'dart:async';
-
-import '../../compiler.dart' as api;
-import '../elements/elements.dart';
-import '../apiimpl.dart' as apiimpl;
-import '../scanner/scannerlib.dart';
-import '../resolution/resolution.dart' show Scope;
-import '../dart2jslib.dart';
-import '../dart_types.dart';
-import '../tree/tree.dart';
-import '../util/util.dart' show Spannable, Link;
-import '../util/characters.dart' show $CR, $LF;
-
-import 'mirrors.dart';
-import 'mirrors_util.dart';
-import 'util.dart';
-
-//------------------------------------------------------------------------------
-// Utility types and functions for the dart2js mirror system
-//------------------------------------------------------------------------------
-
-bool _isPrivate(String name) {
- return name.startsWith('_');
-}
-
-List<ParameterMirror> _parametersFromFunctionSignature(
- Dart2JsMirrorSystem system,
- Dart2JsMethodMirror method,
- FunctionSignature signature) {
- var parameters = <ParameterMirror>[];
- Link<Element> link = signature.requiredParameters;
- while (!link.isEmpty) {
- parameters.add(new Dart2JsParameterMirror(
- system, method, link.head, isOptional: false, isNamed: false));
- link = link.tail;
- }
- link = signature.optionalParameters;
- bool isNamed = signature.optionalParametersAreNamed;
- while (!link.isEmpty) {
- parameters.add(new Dart2JsParameterMirror(
- system, method, link.head, isOptional: true, isNamed: isNamed));
- link = link.tail;
- }
- return parameters;
-}
-
-Dart2JsTypeMirror _convertTypeToTypeMirror(
- Dart2JsMirrorSystem system,
- DartType type,
- InterfaceType defaultType,
- [FunctionSignature functionSignature]) {
- if (type == null) {
- return new Dart2JsInterfaceTypeMirror(system, defaultType);
- } else if (type is InterfaceType) {
- if (type == system.compiler.types.dynamicType) {
- return new Dart2JsDynamicMirror(system, type);
- } else {
- return new Dart2JsInterfaceTypeMirror(system, type);
- }
- } else if (type is TypeVariableType) {
- return new Dart2JsTypeVariableMirror(system, type);
- } else if (type is FunctionType) {
- return new Dart2JsFunctionTypeMirror(system, type, functionSignature);
- } else if (type is VoidType) {
- return new Dart2JsVoidMirror(system, type);
- } else if (type is TypedefType) {
- return new Dart2JsTypedefMirror(system, type);
- } else if (type is MalformedType) {
- // TODO(johnniwinther): We need a mirror on malformed types.
- return system.dynamicType;
- }
- system.compiler.internalError("Unexpected type $type of kind ${type.kind}");
-}
-
-Iterable<Dart2JsMemberMirror> _convertElementMemberToMemberMirrors(
- Dart2JsContainerMirror library, Element element) {
- if (element.isSynthesized) {
- return const <Dart2JsMemberMirror>[];
- } else if (element is VariableElement) {
- return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(library, element)];
- } else if (element is FunctionElement) {
- return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(library, element)];
- } else if (element is AbstractFieldElement) {
- var members = <Dart2JsMemberMirror>[];
- AbstractFieldElement field = element;
- if (field.getter != null) {
- members.add(new Dart2JsMethodMirror(library, field.getter));
- }
- if (field.setter != null) {
- members.add(new Dart2JsMethodMirror(library, field.setter));
- }
- return members;
- }
- library.mirrors.compiler.internalError(
- "Unexpected member type $element ${element.kind}");
-}
-
-MethodMirror _convertElementMethodToMethodMirror(Dart2JsContainerMirror library,
- Element element) {
- if (element is FunctionElement) {
- return new Dart2JsMethodMirror(library, element);
- } else {
- return null;
- }
-}
-
-InstanceMirror _convertConstantToInstanceMirror(Dart2JsMirrorSystem mirrors,
- Constant constant) {
- if (constant is BoolConstant) {
- return new Dart2JsBoolConstantMirror(mirrors, constant);
- } else if (constant is NumConstant) {
- return new Dart2JsNumConstantMirror(mirrors, constant);
- } else if (constant is StringConstant) {
- return new Dart2JsStringConstantMirror(mirrors, constant);
- } else if (constant is ListConstant) {
- return new Dart2JsListConstantMirror(mirrors, constant);
- } else if (constant is MapConstant) {
- return new Dart2JsMapConstantMirror(mirrors, constant);
- } else if (constant is TypeConstant) {
- return new Dart2JsTypeConstantMirror(mirrors, constant);
- } else if (constant is FunctionConstant) {
- return new Dart2JsConstantMirror(mirrors, constant);
- } else if (constant is NullConstant) {
- return new Dart2JsNullConstantMirror(mirrors, constant);
- } else if (constant is ConstructedConstant) {
- return new Dart2JsConstructedConstantMirror(mirrors, constant);
- }
- mirrors.compiler.internalError("Unexpected constant $constant");
-}
-
-class Dart2JsMethodKind {
- static const Dart2JsMethodKind REGULAR = const Dart2JsMethodKind("regular");
- static const Dart2JsMethodKind GENERATIVE =
- const Dart2JsMethodKind("generative");
- static const Dart2JsMethodKind REDIRECTING =
- const Dart2JsMethodKind("redirecting");
- static const Dart2JsMethodKind CONST = const Dart2JsMethodKind("const");
- static const Dart2JsMethodKind FACTORY = const Dart2JsMethodKind("factory");
- static const Dart2JsMethodKind GETTER = const Dart2JsMethodKind("getter");
- static const Dart2JsMethodKind SETTER = const Dart2JsMethodKind("setter");
- static const Dart2JsMethodKind OPERATOR = const Dart2JsMethodKind("operator");
-
- final String text;
-
- const Dart2JsMethodKind(this.text);
-
- String toString() => text;
-}
-
-
-String _getOperatorFromOperatorName(String name) {
- Map<String, String> mapping = const {
- 'eq': '==',
- 'not': '~',
- 'index': '[]',
- 'indexSet': '[]=',
- 'mul': '*',
- 'div': '/',
- 'mod': '%',
- 'tdiv': '~/',
- 'add': '+',
- 'sub': '-',
- 'shl': '<<',
- 'shr': '>>',
- 'ge': '>=',
- 'gt': '>',
- 'le': '<=',
- 'lt': '<',
- 'and': '&',
- 'xor': '^',
- 'or': '|',
- };
- String newName = mapping[name];
- if (newName == null) {
- throw new Exception('Unhandled operator name: $name');
- }
- return newName;
-}
-
-//------------------------------------------------------------------------------
-// Analysis entry point.
-//------------------------------------------------------------------------------
-
-/**
- * Analyzes set of libraries and provides a mirror system which can be used for
- * static inspection of the source code.
- */
-// TODO(johnniwinther): Move this to [compiler/compiler.dart].
-Future<MirrorSystem> analyze(List<Uri> libraries,
- Uri libraryRoot,
- Uri packageRoot,
- api.CompilerInputProvider inputProvider,
- api.DiagnosticHandler diagnosticHandler,
- [List<String> options = const <String>[]]) {
- if (!libraryRoot.path.endsWith("/")) {
- throw new ArgumentError("libraryRoot must end with a /");
- }
- if (packageRoot != null && !packageRoot.path.endsWith("/")) {
- throw new ArgumentError("packageRoot must end with a /");
- }
- options = new List<String>.from(options);
- options.add('--analyze-only');
- options.add('--analyze-signatures-only');
- options.add('--analyze-all');
- options.add('--categories=Client,Server');
-
- bool compilationFailed = false;
- void internalDiagnosticHandler(Uri uri, int begin, int end,
- String message, api.Diagnostic kind) {
- if (kind == api.Diagnostic.ERROR ||
- kind == api.Diagnostic.CRASH) {
- compilationFailed = true;
- }
- diagnosticHandler(uri, begin, end, message, kind);
- }
-
- Compiler compiler = new apiimpl.Compiler(inputProvider,
- null,
- internalDiagnosticHandler,
- libraryRoot, packageRoot,
- options,
- const {});
- compiler.librariesToAnalyzeWhenRun = libraries;
- return compiler.run(null).then((bool success) {
- if (success && !compilationFailed) {
- return new Dart2JsMirrorSystem(compiler);
- } else {
- throw new StateError('Failed to create mirror system.');
- }
- });
-}
-
-//------------------------------------------------------------------------------
-// Dart2Js specific extensions of mirror interfaces
-//------------------------------------------------------------------------------
-
-abstract class Dart2JsMirror implements Mirror {
- Dart2JsMirrorSystem get mirrors;
-}
-
-abstract class Dart2JsDeclarationMirror extends Dart2JsMirror
- implements DeclarationMirror {
-
- bool get isTopLevel => owner != null && owner is LibraryMirror;
-
- bool get isPrivate => _isPrivate(simpleName);
-
- /**
- * Returns the first token for the source of this declaration, not including
- * metadata annotations.
- */
- Token getBeginToken();
-
- /**
- * Returns the last token for the source of this declaration.
- */
- Token getEndToken();
-
- /**
- * Returns the script for the source of this declaration.
- */
- Script getScript();
-}
-
-abstract class Dart2JsTypeMirror extends Dart2JsDeclarationMirror
- implements TypeMirror {
-}
-
-abstract class Dart2JsElementMirror extends Dart2JsDeclarationMirror {
- final Dart2JsMirrorSystem mirrors;
- final Element _element;
- List<InstanceMirror> _metadata;
-
- Dart2JsElementMirror(this.mirrors, this._element) {
- assert (mirrors != null);
- assert (_element != null);
- }
-
- /**
- * Returns the element to be used to determine the begin token of this
- * declaration and the metadata associated with this declaration.
- *
- * This indirection is needed to use the [VariableListElement] as the location
- * for type and metadata information on a [VariableElement].
- */
- Element get _beginElement => _element;
-
- String get simpleName => _element.name;
-
- bool get isNameSynthetic => false;
-
- /**
- * Computes the first token for this declaration using the begin token of the
- * element node or element position as indicator.
- */
- Token getBeginToken() {
- // TODO(johnniwinther): Avoid calling [parseNode].
- Node node = _beginElement.parseNode(mirrors.compiler);
- if (node == null) {
- return _beginElement.position();
- }
- return node.getBeginToken();
- }
-
- /**
- * Computes the last token for this declaration using the end token of the
- * element node or element position as indicator.
- */
- Token getEndToken() {
- // TODO(johnniwinther): Avoid calling [parseNode].
- Node node = _element.parseNode(mirrors.compiler);
- if (node == null) {
- return _element.position();
- }
- return node.getEndToken();
- }
-
- /**
- * Returns the first token for the source of this declaration, including
- * metadata annotations.
- */
- Token getFirstToken() {
- if (!_beginElement.metadata.isEmpty) {
- for (MetadataAnnotation metadata in _beginElement.metadata) {
- if (metadata.beginToken != null) {
- return metadata.beginToken;
- }
- }
- }
- return getBeginToken();
- }
-
- Script getScript() => _element.getCompilationUnit().script;
-
- SourceLocation get location {
- Token beginToken = getFirstToken();
- Script script = getScript();
- SourceSpan span;
- if (beginToken == null) {
- span = new SourceSpan(script.uri, 0, 0);
- } else {
- Token endToken = getEndToken();
- span = mirrors.compiler.spanFromTokens(beginToken, endToken, script.uri);
- }
- return new Dart2JsSourceLocation(script, span);
- }
-
- String toString() => _element.toString();
-
- void _appendCommentTokens(Token commentToken) {
- while (commentToken != null && commentToken.kind == COMMENT_TOKEN) {
- _metadata.add(new Dart2JsCommentInstanceMirror(
- mirrors, commentToken.value));
- commentToken = commentToken.next;
- }
- }
-
- List<InstanceMirror> get metadata {
- if (_metadata == null) {
- _metadata = <InstanceMirror>[];
- for (MetadataAnnotation metadata in _element.metadata) {
- _appendCommentTokens(mirrors.compiler.commentMap[metadata.beginToken]);
- metadata.ensureResolved(mirrors.compiler);
- _metadata.add(
- _convertConstantToInstanceMirror(mirrors, metadata.value));
- }
- _appendCommentTokens(mirrors.compiler.commentMap[getBeginToken()]);
- }
- // TODO(johnniwinther): Return an unmodifiable list instead.
- return new List<InstanceMirror>.from(_metadata);
- }
-
- DeclarationMirror lookupInScope(String name) {
- // TODO(11653): Support lookup of constructors.
- Scope scope = _element.buildScope();
- Element result;
- int index = name.indexOf('.');
- if (index != -1) {
- // Lookup [: prefix.id :].
- String prefix = name.substring(0, index);
- String id = name.substring(index+1);
- result = scope.lookup(prefix);
- if (result != null && result.isPrefix()) {
- PrefixElement prefix = result;
- result = prefix.lookupLocalMember(id);
- } else {
- result = null;
- }
- } else {
- // Lookup [: id :].
- result = scope.lookup(name);
- }
- if (result == null || result.isPrefix()) return null;
- return _convertElementToDeclarationMirror(mirrors, result);
- }
-
- bool operator ==(var other) {
- if (identical(this, other)) return true;
- if (other == null) return false;
- if (other is! Dart2JsElementMirror) return false;
- return _element == other._element &&
- owner == other.owner;
- }
-
- int get hashCode {
- return 13 * _element.hashCode + 17 * owner.hashCode;
- }
-}
-
-abstract class Dart2JsMemberMirror extends Dart2JsElementMirror
- implements MemberMirror {
-
- Dart2JsMemberMirror(Dart2JsMirrorSystem system, Element element)
- : super(system, element);
-
- bool get isConstructor => false;
-
- bool get isVariable => false;
-
- bool get isMethod => false;
-
- bool get isStatic => false;
-
- bool get isParameter => false;
-}
-
-//------------------------------------------------------------------------------
-// Mirror system implementation.
-//------------------------------------------------------------------------------
-
-class Dart2JsMirrorSystem extends MirrorSystem {
- final Compiler compiler;
- Map<Uri, Dart2JsLibraryMirror> _libraries;
- Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap;
-
- Dart2JsMirrorSystem(this.compiler)
- : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>();
-
- void _ensureLibraries() {
- if (_libraries == null) {
- _libraries = new Map<Uri, Dart2JsLibraryMirror>();
- compiler.libraries.forEach((_, LibraryElement v) {
- var mirror = new Dart2JsLibraryMirror(mirrors, v);
- _libraries[mirror.uri] = mirror;
- _libraryMap[v] = mirror;
- });
- }
- }
-
- Map<Uri, LibraryMirror> get libraries {
- _ensureLibraries();
- return new FilteredImmutableMap<Uri, LibraryMirror>(_libraries,
- (library) => new bool.fromEnvironment("list_all_libraries") ||
- !library._element.isInternalLibrary);
- }
-
- Dart2JsLibraryMirror _getLibrary(LibraryElement element) =>
- _libraryMap[element];
-
- Dart2JsMirrorSystem get mirrors => this;
-
- TypeMirror get dynamicType =>
- _convertTypeToTypeMirror(this, compiler.types.dynamicType, null);
-
- TypeMirror get voidType =>
- _convertTypeToTypeMirror(this, compiler.types.voidType, null);
-}
-
-abstract class Dart2JsContainerMirror extends Dart2JsElementMirror
- implements ContainerMirror {
- Map<String, MemberMirror> _members;
-
- Dart2JsContainerMirror(Dart2JsMirrorSystem system, Element element)
- : super(system, element);
-
- void _ensureMembers();
-
- Map<String, MemberMirror> get members {
- _ensureMembers();
- return new ImmutableMapWrapper<String, MemberMirror>(_members);
- }
-
- Map<String, MethodMirror> get functions {
- _ensureMembers();
- return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
- _members,
- (MemberMirror member) => member is MethodMirror ? member : null);
- }
-
- Map<String, MethodMirror> get getters {
- _ensureMembers();
- return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
- _members,
- (MemberMirror member) =>
- member is MethodMirror && member.isGetter ? member : null);
- }
-
- Map<String, MethodMirror> get setters {
- _ensureMembers();
- return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
- _members,
- (MemberMirror member) =>
- member is MethodMirror && member.isSetter ? member : null);
- }
-
- Map<String, VariableMirror> get variables {
- _ensureMembers();
- return new AsFilteredImmutableMap<String, MemberMirror, VariableMirror>(
- _members,
- (MemberMirror member) => member is VariableMirror ? member : null);
- }
-}
-
-class Dart2JsLibraryMirror extends Dart2JsContainerMirror
- implements LibraryMirror {
- Map<String, ClassMirror> _classes;
- List<LibraryDependencyMirror> _libraryDependencies;
-
-
- Dart2JsLibraryMirror(Dart2JsMirrorSystem system, LibraryElement library)
- : super(system, library);
-
- LibraryElement get _library => _element;
-
- Uri get uri => _library.canonicalUri;
-
- DeclarationMirror get owner => null;
-
- bool get isPrivate => false;
-
- LibraryMirror library() => this;
-
- /**
- * Returns the library name (for libraries with a library tag) or the script
- * file name (for scripts without a library tag). The latter case is used to
- * provide a 'library name' for scripts, to use for instance in dartdoc.
- */
- String get simpleName {
- if (_library.libraryTag != null) {
- return _library.libraryTag.name.toString();
- } else {
- // Use the file name as script name.
- String path = _library.canonicalUri.path;
- return path.substring(path.lastIndexOf('/') + 1);
- }
- }
-
- String get qualifiedName => simpleName;
-
- void _ensureClasses() {
- if (_classes == null) {
- _classes = <String, ClassMirror>{};
- _library.forEachLocalMember((Element e) {
- if (e.isClass()) {
- ClassElement classElement = e;
- classElement.ensureResolved(mirrors.compiler);
- var type = new Dart2JsClassMirror.fromLibrary(this, classElement);
- assert(invariant(_library, !_classes.containsKey(type.simpleName),
- message: "Type name '${type.simpleName}' "
- "is not unique in $_library."));
- _classes[type.simpleName] = type;
- } else if (e.isTypedef()) {
- var type = new Dart2JsTypedefMirror.fromLibrary(this,
- e.computeType(mirrors.compiler));
- assert(invariant(_library, !_classes.containsKey(type.simpleName),
- message: "Type name '${type.simpleName}' "
- "is not unique in $_library."));
- _classes[type.simpleName] = type;
- }
- });
- }
- }
-
- void _ensureMembers() {
- if (_members == null) {
- _members = <String, MemberMirror>{};
- _library.forEachLocalMember((Element e) {
- if (!e.isClass() && !e.isTypedef()) {
- // TODO(ahe): I think it is incorrect to filter out classes
- // and typedefs. See http://dartbug.com/10371.
- for (var member in _convertElementMemberToMemberMirrors(this, e)) {
- assert(!_members.containsKey(member.simpleName));
- _members[member.simpleName] = member;
- }
- }
- });
- }
- }
-
- Map<String, ClassMirror> get classes {
- _ensureClasses();
- return new ImmutableMapWrapper<String, ClassMirror>(_classes);
- }
-
- /**
- * Computes the first token of this library using the first library tag as
- * indicator.
- */
- Token getBeginToken() {
- if (_library.libraryTag != null) {
- return _library.libraryTag.getBeginToken();
- } else if (!_library.tags.isEmpty) {
- return _library.tags.reverse().head.getBeginToken();
- }
- return null;
- }
-
- /**
- * Computes the first token of this library using the last library tag as
- * indicator.
- */
- Token getEndToken() {
- if (!_library.tags.isEmpty) {
- return _library.tags.head.getEndToken();
- }
- return null;
- }
-
- void _ensureLibraryDependenciesAnalyzed() {
- if (_libraryDependencies == null) {
- _libraryDependencies = <LibraryDependencyMirror>[];
- for (LibraryTag node in _library.tags.reverse()) {
- LibraryDependency libraryDependency = node.asLibraryDependency();
- if (libraryDependency != null) {
- LibraryElement targetLibraryElement =
- _library.getLibraryFromTag(libraryDependency);
- assert(targetLibraryElement != null);
- LibraryMirror targetLibrary =
- mirrors._getLibrary(targetLibraryElement);
- _libraryDependencies.add(new Dart2JsLibraryDependencyMirror(
- libraryDependency, this, targetLibrary));
- }
- }
- }
- }
-
- List<LibraryDependencyMirror> get libraryDependencies {
- _ensureLibraryDependenciesAnalyzed();
- return _libraryDependencies;
- }
-}
-
-class Dart2JsLibraryDependencyMirror implements LibraryDependencyMirror {
- final LibraryDependency _node;
- final Dart2JsLibraryMirror _sourceLibrary;
- final Dart2JsLibraryMirror _targetLibrary;
- List<CombinatorMirror> _combinators;
-
- Dart2JsLibraryDependencyMirror(this._node,
- this._sourceLibrary,
- this._targetLibrary);
-
- SourceLocation get location {
- return new Dart2JsSourceLocation(
- _sourceLibrary._library.entryCompilationUnit.script,
- _sourceLibrary.mirrors.compiler.spanFromNode(_node));
- }
-
- List<CombinatorMirror> get combinators {
- if (_combinators == null) {
- _combinators = <CombinatorMirror>[];
- if (_node.combinators != null) {
- for (Combinator combinator in _node.combinators.nodes) {
- List<String> identifiers = <String>[];
- for (Identifier identifier in combinator.identifiers.nodes) {
- identifiers.add(identifier.source);
- }
- _combinators.add(new Dart2JsCombinatorMirror(
- identifiers, isShow: combinator.isShow));
- }
- }
- }
- return _combinators;
- }
-
- LibraryMirror get sourceLibrary => _sourceLibrary;
-
- LibraryMirror get targetLibrary => _targetLibrary;
-
- String get prefix {
- Import import = _node.asImport();
- if (import != null && import.prefix != null) {
- return import.prefix.source;
- }
- return null;
- }
-
- bool get isImport => _node.asImport() != null;
-
- bool get isExport => _node.asExport() != null;
-}
-
-class Dart2JsCombinatorMirror implements CombinatorMirror {
- final List<String> identifiers;
- final bool isShow;
-
- Dart2JsCombinatorMirror(this.identifiers, {bool isShow: true})
- : this.isShow = isShow;
-
- bool get isHide => !isShow;
-}
-
-class Dart2JsSourceLocation implements SourceLocation {
- final Script _script;
- final SourceSpan _span;
- int _line;
- int _column;
-
- Dart2JsSourceLocation(this._script, this._span);
-
- int _computeLine() {
- var sourceFile = _script.file;
- if (sourceFile != null) {
- return sourceFile.getLine(offset) + 1;
- }
- var index = 0;
- var lineNumber = 0;
- while (index <= offset && index < sourceText.length) {
- index = sourceText.indexOf('\n', index) + 1;
- if (index <= 0) break;
- lineNumber++;
- }
- return lineNumber;
- }
-
- int get line {
- if (_line == null) {
- _line = _computeLine();
- }
- return _line;
- }
-
- int _computeColumn() {
- if (length == 0) return 0;
-
- var sourceFile = _script.file;
- if (sourceFile != null) {
- return sourceFile.getColumn(sourceFile.getLine(offset), offset) + 1;
- }
- int index = offset - 1;
- var columnNumber = 0;
- while (0 <= index && index < sourceText.length) {
- columnNumber++;
- var codeUnit = sourceText.codeUnitAt(index);
- if (codeUnit == $CR || codeUnit == $LF) {
- break;
- }
- index--;
- }
- return columnNumber;
- }
-
- int get column {
- if (_column == null) {
- _column = _computeColumn();
- }
- return _column;
- }
-
- int get offset => _span.begin;
-
- int get length => _span.end - _span.begin;
-
- String get text => _script.text.substring(_span.begin, _span.end);
-
- Uri get sourceUri => _script.uri;
-
- String get sourceText => _script.text;
-}
-
-class Dart2JsParameterMirror extends Dart2JsMemberMirror
- implements ParameterMirror {
- final MethodMirror _method;
- final bool isOptional;
- final bool isNamed;
-
- factory Dart2JsParameterMirror(Dart2JsMirrorSystem system,
- MethodMirror method,
- VariableElement element,
- {bool isOptional: false,
- bool isNamed: false}) {
- if (element is FieldParameterElement) {
- return new Dart2JsFieldParameterMirror(system,
- method, element, isOptional, isNamed);
- }
- return new Dart2JsParameterMirror._normal(system,
- method, element, isOptional, isNamed);
- }
-
- Dart2JsParameterMirror._normal(Dart2JsMirrorSystem system,
- this._method,
- VariableElement element,
- this.isOptional,
- this.isNamed)
- : super(system, element);
-
- Element get _beginElement => _variableElement.variables;
-
- DeclarationMirror get owner => _method;
-
- VariableElement get _variableElement => _element;
-
- String get qualifiedName => '${_method.qualifiedName}#${simpleName}';
-
- TypeMirror get type => _convertTypeToTypeMirror(mirrors,
- _variableElement.computeType(mirrors.compiler),
- mirrors.compiler.types.dynamicType,
- _variableElement.variables.functionSignature);
-
-
- bool get isFinal => false;
-
- bool get isConst => false;
-
- String get defaultValue {
- if (hasDefaultValue) {
- SendSet expression = _variableElement.cachedNode.asSendSet();
- return unparse(expression.arguments.head);
- }
- return null;
- }
-
- bool get hasDefaultValue {
- return _variableElement.cachedNode != null &&
- _variableElement.cachedNode is SendSet;
- }
-
- bool get isInitializingFormal => false;
-
- VariableMirror get initializedField => null;
-}
-
-class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror {
-
- Dart2JsFieldParameterMirror(Dart2JsMirrorSystem system,
- MethodMirror method,
- FieldParameterElement element,
- bool isOptional,
- bool isNamed)
- : super._normal(system, method, element, isOptional, isNamed);
-
- FieldParameterElement get _fieldParameterElement => _element;
-
- TypeMirror get type {
- VariableListElement variables = _fieldParameterElement.variables;
- VariableDefinitions node = variables.parseNode(mirrors.compiler);
- if (node.type != null) {
- return super.type;
- }
- // Use the field type for initializing formals with no type annotation.
- return _convertTypeToTypeMirror(mirrors,
- _fieldParameterElement.fieldElement.computeType(mirrors.compiler),
- mirrors.compiler.types.dynamicType,
- _variableElement.variables.functionSignature);
- }
-
- bool get isInitializingFormal => true;
-
- VariableMirror get initializedField => new Dart2JsFieldMirror(
- _method.owner, _fieldParameterElement.fieldElement);
-}
-
-//------------------------------------------------------------------------------
-// Declarations
-//------------------------------------------------------------------------------
-class Dart2JsClassMirror extends Dart2JsContainerMirror
- implements Dart2JsTypeMirror, ClassMirror {
- final Dart2JsLibraryMirror library;
- List<TypeVariableMirror> _typeVariables;
-
- Dart2JsClassMirror(Dart2JsMirrorSystem system, ClassElement _class)
- : this.library = system._getLibrary(_class.getLibrary()),
- super(system, _class);
-
- ClassElement get _class => _element;
-
- Dart2JsClassMirror.fromLibrary(Dart2JsLibraryMirror library,
- ClassElement _class)
- : this.library = library,
- super(library.mirrors, _class);
-
- DeclarationMirror get owner => library;
-
- String get qualifiedName => '${library.qualifiedName}.${simpleName}';
-
- void _ensureMembers() {
- if (_members == null) {
- _members = <String, Dart2JsMemberMirror>{};
- _class.forEachMember((_, e) {
- for (var member in _convertElementMemberToMemberMirrors(this, e)) {
- assert(!_members.containsKey(member.simpleName));
- _members[member.simpleName] = member;
- }
- });
- }
- }
-
- Map<String, MethodMirror> get methods => functions;
-
- Map<String, MethodMirror> get constructors {
- _ensureMembers();
- return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
- _members, (m) => m.isConstructor ? m : null);
- }
-
- bool get isObject => _class == mirrors.compiler.objectClass;
-
- bool get isDynamic => false;
-
- bool get isVoid => false;
-
- bool get isTypeVariable => false;
-
- bool get isTypedef => false;
-
- bool get isFunction => false;
-
- ClassMirror get originalDeclaration => this;
-
- ClassMirror get superclass {
- if (_class.supertype != null) {
- return new Dart2JsInterfaceTypeMirror(mirrors, _class.supertype);
- }
- return null;
- }
-
- ClassMirror get mixin {
- if (_class.isMixinApplication) {
- MixinApplicationElement mixinApplication = _class;
- return new Dart2JsInterfaceTypeMirror(mirrors,
- mixinApplication.mixinType);
- }
- return this;
- }
-
- bool get isNameSynthetic {
- if (_class.isMixinApplication) {
- MixinApplicationElement mixinApplication = _class;
- return mixinApplication.isUnnamedMixinApplication;
- }
- return false;
- }
-
- List<ClassMirror> get superinterfaces {
- var list = <ClassMirror>[];
- Link<DartType> link = _class.interfaces;
- while (!link.isEmpty) {
- var type = _convertTypeToTypeMirror(mirrors, link.head,
- mirrors.compiler.types.dynamicType);
- list.add(type);
- link = link.tail;
- }
- return list;
- }
-
- bool get isClass => true;
-
- bool get isAbstract => _class.modifiers.isAbstract();
-
- bool get isOriginalDeclaration => true;
-
- List<TypeMirror> get typeArguments {
- throw new UnsupportedError(
- 'Declarations do not have type arguments');
- }
-
- List<TypeVariableMirror> get typeVariables {
- if (_typeVariables == null) {
- _typeVariables = <TypeVariableMirror>[];
- _class.ensureResolved(mirrors.compiler);
- for (TypeVariableType typeVariable in _class.typeVariables) {
- _typeVariables.add(
- new Dart2JsTypeVariableMirror(mirrors, typeVariable));
- }
- }
- return _typeVariables;
- }
-
- bool operator ==(other) {
- if (identical(this, other)) {
- return true;
- }
- if (other is! ClassMirror) {
- return false;
- }
- if (library != other.library) {
- return false;
- }
- if (!identical(isOriginalDeclaration, other.isOriginalDeclaration)) {
- return false;
- }
- return qualifiedName == other.qualifiedName;
- }
-}
-
-class Dart2JsTypedefMirror extends Dart2JsTypeElementMirror
- implements Dart2JsTypeMirror, TypedefMirror {
- final Dart2JsLibraryMirror _library;
- List<TypeVariableMirror> _typeVariables;
- TypeMirror _definition;
-
- Dart2JsTypedefMirror(Dart2JsMirrorSystem system, TypedefType _typedef)
- : this._library = system._getLibrary(_typedef.element.getLibrary()),
- super(system, _typedef);
-
- Dart2JsTypedefMirror.fromLibrary(Dart2JsLibraryMirror library,
- TypedefType _typedef)
- : this._library = library,
- super(library.mirrors, _typedef);
-
- TypedefType get _typedef => _type;
-
- String get qualifiedName => '${library.qualifiedName}.${simpleName}';
-
- LibraryMirror get library => _library;
-
- bool get isTypedef => true;
-
- List<TypeMirror> get typeArguments {
- throw new UnsupportedError(
- 'Declarations do not have type arguments');
- }
-
- List<TypeVariableMirror> get typeVariables {
- if (_typeVariables == null) {
- _typeVariables = <TypeVariableMirror>[];
- for (TypeVariableType typeVariable in _typedef.typeArguments) {
- _typeVariables.add(
- new Dart2JsTypeVariableMirror(mirrors, typeVariable));
- }
- }
- return _typeVariables;
- }
-
- TypeMirror get value {
- if (_definition == null) {
- // TODO(johnniwinther): Should be [ensureResolved].
- mirrors.compiler.resolveTypedef(_typedef.element);
- _definition = _convertTypeToTypeMirror(
- mirrors,
- _typedef.element.alias,
- mirrors.compiler.types.dynamicType,
- _typedef.element.functionSignature);
- }
- return _definition;
- }
-
- ClassMirror get originalDeclaration => this;
-
- // TODO(johnniwinther): How should a typedef respond to these?
- ClassMirror get superclass => null;
-
- List<ClassMirror> get superinterfaces => const <ClassMirror>[];
-
- // TODO(johnniwinther): Refactor [TypedefMirror] to not extend [ClassMirror]
- // and remove this.
- ClassMirror get mixin => this;
-
- bool get isClass => false;
-
- bool get isOriginalDeclaration => true;
-
- bool get isAbstract => false;
-}
-
-class Dart2JsTypeVariableMirror extends Dart2JsTypeElementMirror
- implements TypeVariableMirror {
- final TypeVariableType _typeVariableType;
- ClassMirror _declarer;
-
- Dart2JsTypeVariableMirror(Dart2JsMirrorSystem system,
- TypeVariableType typeVariableType)
- : this._typeVariableType = typeVariableType,
- super(system, typeVariableType) {
- assert(_typeVariableType != null);
- }
-
-
- String get qualifiedName => '${declarer.qualifiedName}.${simpleName}';
-
- ClassMirror get declarer {
- if (_declarer == null) {
- if (_typeVariableType.element.enclosingElement.isClass()) {
- _declarer = new Dart2JsClassMirror(mirrors,
- _typeVariableType.element.enclosingElement);
- } else if (_typeVariableType.element.enclosingElement.isTypedef()) {
- _declarer = new Dart2JsTypedefMirror(mirrors,
- _typeVariableType.element.enclosingElement.computeType(
- mirrors.compiler));
- }
- }
- return _declarer;
- }
-
- LibraryMirror get library => declarer.library;
-
- DeclarationMirror get owner => declarer;
-
- bool get isTypeVariable => true;
-
- TypeMirror get upperBound => _convertTypeToTypeMirror(
- mirrors,
- _typeVariableType.element.bound,
- mirrors.compiler.objectClass.computeType(mirrors.compiler));
-
- bool operator ==(var other) {
- if (identical(this, other)) {
- return true;
- }
- if (other is! TypeVariableMirror) {
- return false;
- }
- if (declarer != other.declarer) {
- return false;
- }
- return qualifiedName == other.qualifiedName;
- }
-}
-
-
-//------------------------------------------------------------------------------
-// Types
-//------------------------------------------------------------------------------
-
-abstract class Dart2JsTypeElementMirror extends Dart2JsElementMirror
- implements Dart2JsTypeMirror {
- final DartType _type;
-
- Dart2JsTypeElementMirror(Dart2JsMirrorSystem system, DartType type)
- : super(system, type.element),
- this._type = type;
-
- String get simpleName => _type.name;
-
- DeclarationMirror get owner => library;
-
- LibraryMirror get library {
- return mirrors._getLibrary(_type.element.getLibrary());
- }
-
- bool get isObject => false;
-
- bool get isVoid => false;
-
- bool get isDynamic => false;
-
- bool get isTypeVariable => false;
-
- bool get isTypedef => false;
-
- bool get isFunction => false;
-
- String toString() => _type.toString();
-
- Map<String, MemberMirror> get members => const <String, MemberMirror>{};
-
- Map<String, MethodMirror> get constructors => const <String, MethodMirror>{};
-
- Map<String, MethodMirror> get methods => const <String, MethodMirror>{};
-
- Map<String, MethodMirror> get getters => const <String, MethodMirror>{};
-
- Map<String, MethodMirror> get setters => const <String, MethodMirror>{};
-
- Map<String, VariableMirror> get variables => const <String, VariableMirror>{};
-}
-
-class Dart2JsInterfaceTypeMirror extends Dart2JsTypeElementMirror
- implements ClassMirror {
- List<TypeMirror> _typeArguments;
-
- Dart2JsInterfaceTypeMirror(Dart2JsMirrorSystem system,
- InterfaceType interfaceType)
- : super(system, interfaceType);
-
- InterfaceType get _interfaceType => _type;
-
- bool get isNameSynthetic => originalDeclaration.isNameSynthetic;
-
- String get qualifiedName => originalDeclaration.qualifiedName;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- Map<String, MemberMirror> get members => originalDeclaration.members;
-
- bool get isObject => mirrors.compiler.objectClass == _type.element;
-
- // TODO(johnniwinther): How to show malformed types?
- bool get isDynamic => _type.isDynamic;
-
- ClassMirror get originalDeclaration
- => new Dart2JsClassMirror(mirrors, _type.element);
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- ClassMirror get superclass => originalDeclaration.superclass;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- ClassMirror get mixin {
- if (originalDeclaration.mixin == originalDeclaration) {
- return this;
- }
- return originalDeclaration.mixin;
- }
-
- bool get isClass => originalDeclaration.isClass;
-
- bool get isAbstract => originalDeclaration.isAbstract;
-
- bool get isPrivate => originalDeclaration.isPrivate;
-
- bool get isOriginalDeclaration => false;
-
- List<TypeMirror> get typeArguments {
- if (_typeArguments == null) {
- _typeArguments = <TypeMirror>[];
- if (!_interfaceType.isRaw) {
- Link<DartType> type = _interfaceType.typeArguments;
- while (type != null && type.head != null) {
- _typeArguments.add(_convertTypeToTypeMirror(mirrors, type.head,
- mirrors.compiler.types.dynamicType));
- type = type.tail;
- }
- }
- }
- return _typeArguments;
- }
-
- List<TypeVariableMirror> get typeVariables =>
- originalDeclaration.typeVariables;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- Map<String, MethodMirror> get constructors =>
- originalDeclaration.constructors;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- Map<String, MethodMirror> get methods => originalDeclaration.methods;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- Map<String, MethodMirror> get setters => originalDeclaration.setters;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- Map<String, MethodMirror> get getters => originalDeclaration.getters;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- Map<String, VariableMirror> get variables => originalDeclaration.variables;
-
- bool operator ==(other) {
- if (identical(this, other)) {
- return true;
- }
- if (other is! ClassMirror) {
- return false;
- }
- if (other.isOriginalDeclaration) {
- return false;
- }
- if (originalDeclaration != other.originalDeclaration) {
- return false;
- }
- var thisTypeArguments = typeArguments.iterator;
- var otherTypeArguments = other.typeArguments.iterator;
- while (thisTypeArguments.moveNext()) {
- if (!otherTypeArguments.moveNext()) return false;
- if (thisTypeArguments.current != otherTypeArguments.current) {
- return false;
- }
- }
- return !otherTypeArguments.moveNext();
- }
-}
-
-
-class Dart2JsFunctionTypeMirror extends Dart2JsTypeElementMirror
- implements FunctionTypeMirror {
- final FunctionSignature _functionSignature;
- List<ParameterMirror> _parameters;
-
- Dart2JsFunctionTypeMirror(Dart2JsMirrorSystem system,
- FunctionType functionType, this._functionSignature)
- : super(system, functionType) {
- assert (_functionSignature != null);
- }
-
- FunctionType get _functionType => _type;
-
- // TODO(johnniwinther): Is this the qualified name of a function type?
- String get qualifiedName => originalDeclaration.qualifiedName;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- Map<String, MemberMirror> get members {
- var method = callMethod;
- if (method != null) {
- var map = new Map<String, MemberMirror>.from(
- originalDeclaration.members);
- var name = method.qualifiedName;
- assert(!map.containsKey(name));
- map[name] = method;
- return new ImmutableMapWrapper<String, MemberMirror>(map);
- }
- return originalDeclaration.members;
- }
-
- bool get isFunction => true;
-
- MethodMirror get callMethod => _convertElementMethodToMethodMirror(
- mirrors._getLibrary(_functionType.element.getLibrary()),
- _functionType.element);
-
- ClassMirror get originalDeclaration
- => new Dart2JsClassMirror(mirrors, mirrors.compiler.functionClass);
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- ClassMirror get superclass => originalDeclaration.superclass;
-
- // TODO(johnniwinther): Substitute type arguments for type variables.
- List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces;
-
- ClassMirror get mixin => this;
-
- bool get isClass => originalDeclaration.isClass;
-
- bool get isPrivate => originalDeclaration.isPrivate;
-
- bool get isOriginalDeclaration => false;
-
- bool get isAbstract => false;
-
- List<TypeMirror> get typeArguments => const <TypeMirror>[];
-
- List<TypeVariableMirror> get typeVariables =>
- originalDeclaration.typeVariables;
-
- TypeMirror get returnType {
- return _convertTypeToTypeMirror(mirrors, _functionType.returnType,
- mirrors.compiler.types.dynamicType);
- }
-
- List<ParameterMirror> get parameters {
- if (_parameters == null) {
- _parameters = _parametersFromFunctionSignature(mirrors, callMethod,
- _functionSignature);
- }
- return _parameters;
- }
-}
-
-class Dart2JsVoidMirror extends Dart2JsTypeElementMirror {
-
- Dart2JsVoidMirror(Dart2JsMirrorSystem system, VoidType voidType)
- : super(system, voidType);
-
- VoidType get _voidType => _type;
-
- String get qualifiedName => simpleName;
-
- /**
- * The void type has no location.
- */
- SourceLocation get location => null;
-
- /**
- * The void type has no library.
- */
- LibraryMirror get library => null;
-
- bool get isVoid => true;
-
- bool operator ==(other) {
- if (identical(this, other)) {
- return true;
- }
- if (other is! TypeMirror) {
- return false;
- }
- return other.isVoid;
- }
-}
-
-
-class Dart2JsDynamicMirror extends Dart2JsTypeElementMirror {
- Dart2JsDynamicMirror(Dart2JsMirrorSystem system, InterfaceType voidType)
- : super(system, voidType);
-
- InterfaceType get _dynamicType => _type;
-
- String get qualifiedName => simpleName;
-
- /**
- * The dynamic type has no location.
- */
- SourceLocation get location => null;
-
- /**
- * The dynamic type has no library.
- */
- LibraryMirror get library => null;
-
- bool get isDynamic => true;
-
- bool operator ==(other) {
- if (identical(this, other)) {
- return true;
- }
- if (other is! TypeMirror) {
- return false;
- }
- return other.isDynamic;
- }
-}
-
-//------------------------------------------------------------------------------
-// Member mirrors implementation.
-//------------------------------------------------------------------------------
-
-class Dart2JsMethodMirror extends Dart2JsMemberMirror
- implements MethodMirror {
- final Dart2JsContainerMirror _objectMirror;
- final String simpleName;
- final Dart2JsMethodKind _kind;
-
- Dart2JsMethodMirror._internal(Dart2JsContainerMirror objectMirror,
- FunctionElement function,
- String this.simpleName,
- Dart2JsMethodKind this._kind)
- : this._objectMirror = objectMirror,
- super(objectMirror.mirrors, function);
-
- factory Dart2JsMethodMirror(Dart2JsContainerMirror objectMirror,
- FunctionElement function) {
- String realName = function.name;
- // TODO(ahe): This method should not be calling
- // Elements.operatorNameToIdentifier.
- String simpleName =
- Elements.operatorNameToIdentifier(function.name);
- Dart2JsMethodKind kind;
- if (function.kind == ElementKind.GETTER) {
- kind = Dart2JsMethodKind.GETTER;
- } else if (function.kind == ElementKind.SETTER) {
- kind = Dart2JsMethodKind.SETTER;
- simpleName = '$simpleName=';
- } else if (function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
- // TODO(johnniwinther): Support detection of redirecting constructors.
- if (function.modifiers.isConst()) {
- kind = Dart2JsMethodKind.CONST;
- } else {
- kind = Dart2JsMethodKind.GENERATIVE;
- }
- } else if (function.modifiers.isFactory()) {
- kind = Dart2JsMethodKind.FACTORY;
- } else if (realName == 'unary-') {
- kind = Dart2JsMethodKind.OPERATOR;
- // Simple name is 'unary-'.
- simpleName = Mirror.UNARY_MINUS;
- } else if (simpleName.startsWith('operator\$')) {
- String str = simpleName.substring(9);
- simpleName = 'operator';
- kind = Dart2JsMethodKind.OPERATOR;
- simpleName = _getOperatorFromOperatorName(str);
- } else {
- kind = Dart2JsMethodKind.REGULAR;
- }
- return new Dart2JsMethodMirror._internal(objectMirror, function,
- simpleName, kind);
- }
-
- FunctionElement get _function => _element;
-
- String get qualifiedName
- => '${owner.qualifiedName}.$simpleName';
-
- DeclarationMirror get owner => _objectMirror;
-
- bool get isTopLevel => _objectMirror is LibraryMirror;
-
- bool get isConstructor
- => isGenerativeConstructor || isConstConstructor ||
- isFactoryConstructor || isRedirectingConstructor;
-
- bool get isMethod => !isConstructor;
-
- bool get isStatic => _function.modifiers.isStatic();
-
- List<ParameterMirror> get parameters {
- return _parametersFromFunctionSignature(mirrors, this,
- _function.computeSignature(mirrors.compiler));
- }
-
- TypeMirror get returnType => _convertTypeToTypeMirror(
- mirrors, _function.computeSignature(mirrors.compiler).returnType,
- mirrors.compiler.types.dynamicType);
-
- bool get isAbstract => _function.isAbstract;
-
- bool get isRegularMethod => !(isGetter || isSetter || isConstructor);
-
- bool get isConstConstructor => _kind == Dart2JsMethodKind.CONST;
-
- bool get isGenerativeConstructor => _kind == Dart2JsMethodKind.GENERATIVE;
-
- bool get isRedirectingConstructor => _kind == Dart2JsMethodKind.REDIRECTING;
-
- bool get isFactoryConstructor => _kind == Dart2JsMethodKind.FACTORY;
-
- bool get isGetter => _kind == Dart2JsMethodKind.GETTER;
-
- bool get isSetter => _kind == Dart2JsMethodKind.SETTER;
-
- bool get isOperator => _kind == Dart2JsMethodKind.OPERATOR;
-
- DeclarationMirror lookupInScope(String name) {
- for (ParameterMirror parameter in parameters) {
- if (parameter.simpleName == name) {
- return parameter;
- }
- }
- return super.lookupInScope(name);
- }
-}
-
-class Dart2JsFieldMirror extends Dart2JsMemberMirror implements VariableMirror {
- Dart2JsContainerMirror _objectMirror;
- VariableElement _variable;
-
- Dart2JsFieldMirror(Dart2JsContainerMirror objectMirror,
- VariableElement variable)
- : this._objectMirror = objectMirror,
- this._variable = variable,
- super(objectMirror.mirrors, variable);
-
- Element get _beginElement => _variable.variables;
-
- String get qualifiedName
- => '${owner.qualifiedName}.$simpleName';
-
- DeclarationMirror get owner => _objectMirror;
-
- bool get isTopLevel => _objectMirror is LibraryMirror;
-
- bool get isVariable => true;
-
- bool get isStatic => _variable.modifiers.isStatic();
-
- bool get isFinal => _variable.modifiers.isFinal();
-
- bool get isConst => _variable.modifiers.isConst();
-
- TypeMirror get type => _convertTypeToTypeMirror(mirrors,
- _variable.computeType(mirrors.compiler),
- mirrors.compiler.types.dynamicType);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Mirrors on constant values used for metadata.
-////////////////////////////////////////////////////////////////////////////////
-
-class Dart2JsConstantMirror extends InstanceMirror {
- final Dart2JsMirrorSystem mirrors;
- final Constant _constant;
-
- Dart2JsConstantMirror(this.mirrors, this._constant);
-
- ClassMirror get type {
- return new Dart2JsClassMirror(mirrors,
- _constant.computeType(mirrors.compiler).element);
- }
-
- bool get hasReflectee => false;
-
- get reflectee {
- // TODO(johnniwinther): Which exception/error should be thrown here?
- throw new UnsupportedError('InstanceMirror does not have a reflectee');
- }
-
- InstanceMirror getField(String fieldName) {
- // TODO(johnniwinther): Which exception/error should be thrown here?
- throw new UnsupportedError('InstanceMirror does not have a reflectee');
- }
-}
-
-class Dart2JsNullConstantMirror extends Dart2JsConstantMirror {
- Dart2JsNullConstantMirror(Dart2JsMirrorSystem mirrors, NullConstant constant)
- : super(mirrors, constant);
-
- NullConstant get _constant => super._constant;
-
- bool get hasReflectee => true;
-
- get reflectee => null;
-}
-
-class Dart2JsBoolConstantMirror extends Dart2JsConstantMirror {
- Dart2JsBoolConstantMirror(Dart2JsMirrorSystem mirrors, BoolConstant constant)
- : super(mirrors, constant);
-
- Dart2JsBoolConstantMirror.fromBool(Dart2JsMirrorSystem mirrors, bool value)
- : super(mirrors, value ? new TrueConstant() : new FalseConstant());
-
- BoolConstant get _constant => super._constant;
-
- bool get hasReflectee => true;
-
- get reflectee => _constant is TrueConstant;
-}
-
-class Dart2JsStringConstantMirror extends Dart2JsConstantMirror {
- Dart2JsStringConstantMirror(Dart2JsMirrorSystem mirrors,
- StringConstant constant)
- : super(mirrors, constant);
-
- Dart2JsStringConstantMirror.fromString(Dart2JsMirrorSystem mirrors,
- String text)
- : super(mirrors, new StringConstant(new DartString.literal(text)));
-
- StringConstant get _constant => super._constant;
-
- bool get hasReflectee => true;
-
- get reflectee => _constant.value.slowToString();
-}
-
-class Dart2JsNumConstantMirror extends Dart2JsConstantMirror {
- Dart2JsNumConstantMirror(Dart2JsMirrorSystem mirrors,
- NumConstant constant)
- : super(mirrors, constant);
-
- NumConstant get _constant => super._constant;
-
- bool get hasReflectee => true;
-
- get reflectee => _constant.value;
-}
-
-class Dart2JsListConstantMirror extends Dart2JsConstantMirror
- implements ListInstanceMirror {
- Dart2JsListConstantMirror(Dart2JsMirrorSystem mirrors,
- ListConstant constant)
- : super(mirrors, constant);
-
- ListConstant get _constant => super._constant;
-
- int get length => _constant.length;
-
- InstanceMirror operator[](int index) {
- if (index < 0) throw new RangeError('Negative index');
- if (index >= _constant.length) throw new RangeError('Index out of bounds');
- return _convertConstantToInstanceMirror(mirrors, _constant.entries[index]);
- }
-}
-
-class Dart2JsMapConstantMirror extends Dart2JsConstantMirror
- implements MapInstanceMirror {
- List<String> _listCache;
-
- Dart2JsMapConstantMirror(Dart2JsMirrorSystem mirrors,
- MapConstant constant)
- : super(mirrors, constant);
-
- MapConstant get _constant => super._constant;
-
- List<String> get _list {
- if (_listCache == null) {
- _listCache = new List<String>(_constant.keys.entries.length);
- int index = 0;
- for (StringConstant keyConstant in _constant.keys.entries) {
- _listCache[index] = keyConstant.value.slowToString();
- index++;
- }
- }
- return _listCache;
- }
-
- int get length => _constant.length;
-
- Iterable<String> get keys {
- // TODO(johnniwinther): Return an unmodifiable list instead.
- return new List<String>.from(_list);
- }
-
- InstanceMirror operator[](String key) {
- int index = _list.indexOf(key);
- if (index == -1) return null;
- return _convertConstantToInstanceMirror(mirrors, _constant.values[index]);
- }
-}
-
-class Dart2JsTypeConstantMirror extends Dart2JsConstantMirror
- implements TypeInstanceMirror {
-
- Dart2JsTypeConstantMirror(Dart2JsMirrorSystem mirrors,
- TypeConstant constant)
- : super(mirrors, constant);
-
- TypeConstant get _constant => super._constant;
-
- TypeMirror get representedType => _convertTypeToTypeMirror(
- mirrors, _constant.representedType, mirrors.compiler.types.dynamicType);
-}
-
-class Dart2JsConstructedConstantMirror extends Dart2JsConstantMirror {
- Map<String,Constant> _fieldMapCache;
-
- Dart2JsConstructedConstantMirror(Dart2JsMirrorSystem mirrors,
- ConstructedConstant constant)
- : super(mirrors, constant);
-
- ConstructedConstant get _constant => super._constant;
-
- Map<String,Constant> get _fieldMap {
- if (_fieldMapCache == null) {
- _fieldMapCache = new Map<String,Constant>();
- if (identical(_constant.type.element.kind, ElementKind.CLASS)) {
- var index = 0;
- ClassElement element = _constant.type.element;
- element.forEachInstanceField((_, Element field) {
- String fieldName = field.name;
- _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]);
- index++;
- }, includeSuperAndInjectedMembers: true);
- }
- }
- return _fieldMapCache;
- }
-
- InstanceMirror getField(String fieldName) {
- Constant fieldConstant = _fieldMap[fieldName];
- if (fieldConstant != null) {
- return _convertConstantToInstanceMirror(mirrors, fieldConstant);
- }
- return super.getField(fieldName);
- }
-}
-
-class Dart2JsCommentInstanceMirror implements CommentInstanceMirror {
- final Dart2JsMirrorSystem mirrors;
- final String text;
- String _trimmedText;
-
- Dart2JsCommentInstanceMirror(this.mirrors, this.text);
-
- ClassMirror get type {
- return new Dart2JsClassMirror(mirrors, mirrors.compiler.documentClass);
- }
-
- bool get isDocComment => text.startsWith('/**') || text.startsWith('///');
-
- String get trimmedText {
- if (_trimmedText == null) {
- _trimmedText = stripComment(text);
- }
- return _trimmedText;
- }
-
- bool get hasReflectee => false;
-
- get reflectee {
- // TODO(johnniwinther): Which exception/error should be thrown here?
- throw new UnsupportedError('InstanceMirror does not have a reflectee');
- }
-
- InstanceMirror getField(String fieldName) {
- if (fieldName == 'isDocComment') {
- return new Dart2JsBoolConstantMirror.fromBool(mirrors, isDocComment);
- } else if (fieldName == 'text') {
- return new Dart2JsStringConstantMirror.fromString(mirrors, text);
- } else if (fieldName == 'trimmedText') {
- return new Dart2JsStringConstantMirror.fromString(mirrors, trimmedText);
- }
- // TODO(johnniwinther): Which exception/error should be thrown here?
- throw new UnsupportedError('InstanceMirror does not have a reflectee');
- }
-}
-
-_convertElementToMembers(Dart2JsLibraryMirror library, Element e) {
- // TODO(ahe): This method creates new mirror objects which is not correct.
- if (e.isClass()) {
- ClassElement classElement = e;
- classElement.ensureResolved(library.mirrors.compiler);
- return [new Dart2JsClassMirror.fromLibrary(library, classElement)];
- } else if (e.isTypedef()) {
- return [new Dart2JsTypedefMirror.fromLibrary(
- library, e.computeType(library.mirrors.compiler))];
- } else {
- return _convertElementMemberToMemberMirrors(library, e);
- }
-}
-
-/**
- * Converts [element] into its corresponding [DeclarationMirror], if any.
- *
- * If [element] is an [AbstractFieldElement] the mirror for its getter is
- * returned or, if not present, the mirror for its setter.
- */
-DeclarationMirror _convertElementToDeclarationMirror(Dart2JsMirrorSystem system,
- Element element) {
- if (element.isTypeVariable()) {
- return new Dart2JsTypeVariableMirror(
- system, element.computeType(system.compiler));
- }
-
- Dart2JsLibraryMirror library = system._libraryMap[element.getLibrary()];
- if (element.isLibrary()) return library;
- if (element.isTypedef()) {
- return new Dart2JsTypedefMirror.fromLibrary(
- library, element.computeType(system.compiler));
- }
-
- Dart2JsContainerMirror container = library;
- if (element.getEnclosingClass() != null) {
- container = new Dart2JsClassMirror.fromLibrary(
- library, element.getEnclosingClass());
- }
- if (element.isClass()) return container;
- if (element.isParameter()) {
- MethodMirror method = _convertElementMethodToMethodMirror(
- container, element.getOutermostEnclosingMemberOrTopLevel());
- // TODO(johnniwinther): Find the right info for [isOptional] and [isNamed].
- return new Dart2JsParameterMirror(
- system, method, element, isOptional: false, isNamed: false);
- }
- Iterable<MemberMirror> members =
- _convertElementMemberToMemberMirrors(container, element);
- if (members.isEmpty) return null;
- return members.first;
-}
-
-/**
- * Experimental API for accessing compilation units defined in a
- * library.
- */
-// TODO(ahe): Superclasses? Is this really a mirror?
-class Dart2JsCompilationUnitMirror extends Dart2JsMirror {
- final Dart2JsLibraryMirror _library;
- final CompilationUnitElement _element;
-
- Dart2JsCompilationUnitMirror(this._element, this._library);
-
- Dart2JsMirrorSystem get mirrors => _library.mirrors;
-
- List<DeclarationMirror> get members {
- // TODO(ahe): Should return an immutable List.
- // TODO(johnniwinther): make sure that these are returned in declaration
- // order.
- List<DeclarationMirror> members= <DeclarationMirror>[];
- _element.forEachLocalMember((m) {
- members.addAll(_convertElementToMembers(_library, m));
- });
- return members;
- }
-
- Uri get uri => _element.script.uri;
-}
-
-/**
- * Transitional class that allows access to features that have not yet
- * made it to the mirror API.
- *
- * All API in this class is experimental.
- */
-class BackDoor {
- /// Return the compilation units comprising [library].
- static List<Mirror> compilationUnitsOf(Dart2JsLibraryMirror library) {
- return library._library.compilationUnits.toList().map(
- (cu) => new Dart2JsCompilationUnitMirror(cu, library)).toList();
- }
-}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
new file mode 100644
index 0000000..a399a8c
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
@@ -0,0 +1,468 @@
+// Copyright (c) 2012, 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 dart2js.mirrors;
+
+import 'dart:collection' show UnmodifiableListView;
+
+import '../elements/elements.dart';
+import '../scanner/scannerlib.dart';
+import '../resolution/resolution.dart' show Scope;
+import '../dart2jslib.dart';
+import '../dart_types.dart';
+import '../tree/tree.dart';
+import '../util/util.dart' show Spannable, Link, LinkBuilder;
+import '../util/characters.dart' show $CR, $LF;
+
+import 'source_mirrors.dart';
+import 'mirrors_util.dart';
+import 'util.dart';
+
+part 'dart2js_library_mirror.dart';
+part 'dart2js_type_mirrors.dart';
+part 'dart2js_member_mirrors.dart';
+part 'dart2js_instance_mirrors.dart';
+
+//------------------------------------------------------------------------------
+// Utility types and functions for the dart2js mirror system
+//------------------------------------------------------------------------------
+
+bool _isPrivate(String name) {
+ return name.startsWith('_');
+}
+
+List<ParameterMirror> _parametersFromFunctionSignature(
+ Dart2JsDeclarationMirror owner,
+ FunctionSignature signature) {
+ var parameters = <ParameterMirror>[];
+ Link<Element> link = signature.requiredParameters;
+ while (!link.isEmpty) {
+ parameters.add(new Dart2JsParameterMirror(
+ owner, link.head, isOptional: false, isNamed: false));
+ link = link.tail;
+ }
+ link = signature.optionalParameters;
+ bool isNamed = signature.optionalParametersAreNamed;
+ while (!link.isEmpty) {
+ parameters.add(new Dart2JsParameterMirror(
+ owner, link.head, isOptional: true, isNamed: isNamed));
+ link = link.tail;
+ }
+ return parameters;
+}
+
+MethodMirror _convertElementMethodToMethodMirror(
+ Dart2JsDeclarationMirror library, Element element) {
+ if (element is FunctionElement) {
+ return new Dart2JsMethodMirror(library, element);
+ } else {
+ return null;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Dart2Js specific extensions of mirror interfaces
+//------------------------------------------------------------------------------
+
+abstract class Dart2JsMirror implements Mirror {
+ Dart2JsMirrorSystem get mirrorSystem;
+}
+
+abstract class Dart2JsDeclarationMirror extends Dart2JsMirror
+ implements DeclarationSourceMirror {
+
+ bool get isTopLevel => owner != null && owner is LibraryMirror;
+
+ bool get isPrivate => _isPrivate(_simpleNameString);
+
+ String get _simpleNameString;
+
+ String get _qualifiedNameString {
+ var parent = owner;
+ if (parent is Dart2JsDeclarationMirror) {
+ return '${parent._qualifiedNameString}.${_simpleNameString}';
+ }
+ assert(parent == null);
+ return _simpleNameString;
+ }
+
+ Symbol get simpleName => symbolOf(_simpleNameString, getLibrary(this));
+
+ Symbol get qualifiedName => symbolOf(_qualifiedNameString, getLibrary(this));
+
+ /**
+ * Returns the first token for the source of this declaration, not including
+ * metadata annotations.
+ */
+ Token getBeginToken();
+
+ /**
+ * Returns the last token for the source of this declaration.
+ */
+ Token getEndToken();
+
+ /**
+ * Returns the script for the source of this declaration.
+ */
+ Script getScript();
+
+ /// Returns the type mirror for [type] in the context of this declaration.
+ TypeMirror _getTypeMirror(DartType type, [FunctionSignature signature]) {
+ return mirrorSystem._convertTypeToTypeMirror(type, signature);
+ }
+
+ /// Returns a list of the declaration mirrorSystem for [element].
+ Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element) {
+ if (element.isSynthesized) {
+ return const <Dart2JsMemberMirror>[];
+ } else if (element is VariableElement) {
+ return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(this, element)];
+ } else if (element is FunctionElement) {
+ return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(this, element)];
+ } else if (element is AbstractFieldElement) {
+ var members = <Dart2JsMemberMirror>[];
+ AbstractFieldElement field = element;
+ if (field.getter != null) {
+ members.add(new Dart2JsMethodMirror(this, field.getter));
+ }
+ if (field.setter != null) {
+ members.add(new Dart2JsMethodMirror(this, field.setter));
+ }
+ return members;
+ }
+ mirrorSystem.compiler.internalError(
+ "Unexpected member type $element ${element.kind}");
+ }
+
+}
+
+abstract class Dart2JsElementMirror extends Dart2JsDeclarationMirror {
+ final Dart2JsMirrorSystem mirrorSystem;
+ final Element _element;
+ List<InstanceMirror> _metadata;
+
+ Dart2JsElementMirror(this.mirrorSystem, this._element) {
+ assert (mirrorSystem != null);
+ assert (_element != null);
+ }
+
+ /**
+ * Returns the element to be used to determine the begin token of this
+ * declaration and the metadata associated with this declaration.
+ *
+ * This indirection is needed to use the [VariableListElement] as the location
+ * for type and metadata information on a [VariableElement].
+ */
+ Element get _beginElement => _element;
+
+ String get _simpleNameString => _element.name;
+
+ bool get isNameSynthetic => false;
+
+ /**
+ * Computes the first token for this declaration using the begin token of the
+ * element node or element position as indicator.
+ */
+ Token getBeginToken() {
+ // TODO(johnniwinther): Avoid calling [parseNode].
+ Node node = _beginElement.parseNode(mirrorSystem.compiler);
+ if (node == null) {
+ return _beginElement.position();
+ }
+ return node.getBeginToken();
+ }
+
+ /**
+ * Computes the last token for this declaration using the end token of the
+ * element node or element position as indicator.
+ */
+ Token getEndToken() {
+ // TODO(johnniwinther): Avoid calling [parseNode].
+ Node node = _element.parseNode(mirrorSystem.compiler);
+ if (node == null) {
+ return _element.position();
+ }
+ return node.getEndToken();
+ }
+
+ /**
+ * Returns the first token for the source of this declaration, including
+ * metadata annotations.
+ */
+ Token getFirstToken() {
+ if (!_beginElement.metadata.isEmpty) {
+ for (MetadataAnnotation metadata in _beginElement.metadata) {
+ if (metadata.beginToken != null) {
+ return metadata.beginToken;
+ }
+ }
+ }
+ return getBeginToken();
+ }
+
+ Script getScript() => _element.getCompilationUnit().script;
+
+ SourceLocation get location {
+ Token beginToken = getFirstToken();
+ Script script = getScript();
+ SourceSpan span;
+ if (beginToken == null) {
+ span = new SourceSpan(script.uri, 0, 0);
+ } else {
+ Token endToken = getEndToken();
+ span = mirrorSystem.compiler.spanFromTokens(
+ beginToken, endToken, script.uri);
+ }
+ return new Dart2JsSourceLocation(script, span);
+ }
+
+ String toString() => _element.toString();
+
+ void _appendCommentTokens(Token commentToken) {
+ while (commentToken != null && commentToken.kind == COMMENT_TOKEN) {
+ _metadata.add(new Dart2JsCommentInstanceMirror(
+ mirrorSystem, commentToken.value));
+ commentToken = commentToken.next;
+ }
+ }
+
+ List<InstanceMirror> get metadata {
+ if (_metadata == null) {
+ _metadata = <InstanceMirror>[];
+ for (MetadataAnnotation metadata in _element.metadata) {
+ _appendCommentTokens(
+ mirrorSystem.compiler.commentMap[metadata.beginToken]);
+ metadata.ensureResolved(mirrorSystem.compiler);
+ _metadata.add(
+ _convertConstantToInstanceMirror(mirrorSystem, metadata.value));
+ }
+ _appendCommentTokens(mirrorSystem.compiler.commentMap[getBeginToken()]);
+ }
+ // TODO(johnniwinther): Return an unmodifiable list instead.
+ return new List<InstanceMirror>.from(_metadata);
+ }
+
+ DeclarationMirror lookupInScope(String name) {
+ // TODO(11653): Support lookup of constructors.
+ Scope scope = _element.buildScope();
+ Element result;
+ int index = name.indexOf('.');
+ if (index != -1) {
+ // Lookup [: prefix.id :].
+ String prefix = name.substring(0, index);
+ String id = name.substring(index+1);
+ result = scope.lookup(prefix);
+ if (result != null && result.isPrefix()) {
+ PrefixElement prefix = result;
+ result = prefix.lookupLocalMember(id);
+ } else {
+ result = null;
+ }
+ } else {
+ // Lookup [: id :].
+ result = scope.lookup(name);
+ }
+ if (result == null || result.isPrefix()) return null;
+ return _convertElementToDeclarationMirror(mirrorSystem, result);
+ }
+
+ bool operator ==(var other) {
+ if (identical(this, other)) return true;
+ if (other == null) return false;
+ if (other is! Dart2JsElementMirror) return false;
+ return _element == other._element &&
+ owner == other.owner;
+ }
+
+ int get hashCode {
+ return 13 * _element.hashCode + 17 * owner.hashCode;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Mirror system implementation.
+//------------------------------------------------------------------------------
+
+class Dart2JsMirrorSystem extends MirrorSystem {
+ final Compiler compiler;
+ Map<Uri, Dart2JsLibraryMirror> _libraries;
+ Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap;
+
+ Dart2JsMirrorSystem(this.compiler)
+ : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>();
+
+ IsolateMirror get isolate => null;
+
+ void _ensureLibraries() {
+ if (_libraries == null) {
+ _libraries = new Map<Uri, Dart2JsLibraryMirror>();
+ compiler.libraries.forEach((_, LibraryElement v) {
+ var mirror = new Dart2JsLibraryMirror(mirrorSystem, v);
+ _libraries[mirror.uri] = mirror;
+ _libraryMap[v] = mirror;
+ });
+ }
+ }
+
+ Map<Uri, LibraryMirror> get libraries {
+ _ensureLibraries();
+ return new FilteredImmutableMap<Uri, LibraryMirror>(_libraries,
+ (library) => const bool.fromEnvironment("list_all_libraries") ||
+ !library._element.isInternalLibrary);
+ }
+
+ Dart2JsLibraryMirror _getLibrary(LibraryElement element) =>
+ _libraryMap[element];
+
+ Dart2JsMirrorSystem get mirrorSystem => this;
+
+ TypeMirror get dynamicType =>
+ _convertTypeToTypeMirror(compiler.types.dynamicType);
+
+ TypeMirror get voidType =>
+ _convertTypeToTypeMirror(compiler.types.voidType);
+
+ TypeMirror _convertTypeToTypeMirror(DartType type,
+ [FunctionSignature signature]) {
+ assert(type != null);
+ if (type.treatAsDynamic) {
+ return new Dart2JsDynamicMirror(this, type);
+ } else if (type is InterfaceType) {
+ if (type.typeArguments.isEmpty) {
+ return _getTypeDeclarationMirror(type.element);
+ } else {
+ return new Dart2JsInterfaceTypeMirror(this, type);
+ }
+ } else if (type is TypeVariableType) {
+ return new Dart2JsTypeVariableMirror(this, type);
+ } else if (type is FunctionType) {
+ return new Dart2JsFunctionTypeMirror(this, type, signature);
+ } else if (type is VoidType) {
+ return new Dart2JsVoidMirror(this, type);
+ } else if (type is TypedefType) {
+ if (type.typeArguments.isEmpty) {
+ return _getTypeDeclarationMirror(type.element);
+ } else {
+ return new Dart2JsTypedefMirror(this, type);
+ }
+ }
+ compiler.internalError("Unexpected type $type of kind ${type.kind}");
+ }
+
+ DeclarationMirror _getTypeDeclarationMirror(Element element) {
+ if (element.isClass()) {
+ return new Dart2JsClassDeclarationMirror(
+ this, element.computeType(compiler));
+ } else if (element.isTypedef()) {
+ return new Dart2JsTypedefDeclarationMirror(this,
+ element.computeType(compiler));
+ }
+ }
+}
+
+abstract class ContainerMixin {
+ Map<Symbol, DeclarationMirror> _declarations;
+
+ void _ensureDeclarations() {
+ if (_declarations == null) {
+ _declarations = <Symbol, DeclarationMirror>{};
+ _forEachElement((Element element) {
+ for (DeclarationMirror mirror in _getDeclarationMirrors(element)) {
+ assert(invariant(_element,
+ !_declarations.containsKey(mirror.simpleName),
+ message: "Declaration name '${nameOf(mirror)}' "
+ "is not unique in $_element."));
+ _declarations[mirror.simpleName] = mirror;
+ }
+ });
+ }
+ }
+
+ Element get _element;
+
+ void _forEachElement(f(Element element));
+
+ Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element);
+
+ Map<Symbol, DeclarationMirror> get declarations {
+ _ensureDeclarations();
+ return new ImmutableMapWrapper<Symbol, DeclarationMirror>(_declarations);
+ }
+}
+
+/**
+ * Converts [element] into its corresponding [DeclarationMirror], if any.
+ *
+ * If [element] is an [AbstractFieldElement] the mirror for its getter is
+ * returned or, if not present, the mirror for its setter.
+ */
+DeclarationMirror _convertElementToDeclarationMirror(Dart2JsMirrorSystem system,
+ Element element) {
+ if (element.isTypeVariable()) {
+ return new Dart2JsTypeVariableMirror(
+ system, element.computeType(system.compiler));
+ }
+
+ Dart2JsLibraryMirror library = system._libraryMap[element.getLibrary()];
+ if (element.isLibrary()) return library;
+ if (element.isTypedef()) {
+ return new Dart2JsTypedefMirror.fromLibrary(
+ library, element.computeType(system.compiler));
+ }
+
+ Dart2JsDeclarationMirror container = library;
+ if (element.getEnclosingClass() != null) {
+ container = system._getTypeDeclarationMirror(element.getEnclosingClass());
+ }
+ if (element.isClass()) return container;
+ if (element.isParameter()) {
+ Dart2JsMethodMirror method = _convertElementMethodToMethodMirror(
+ container, element.getOutermostEnclosingMemberOrTopLevel());
+ // TODO(johnniwinther): Find the right info for [isOptional] and [isNamed].
+ return new Dart2JsParameterMirror(
+ method, element, isOptional: false, isNamed: false);
+ }
+ Iterable<DeclarationMirror> members =
+ container._getDeclarationMirrors(element);
+ if (members.isEmpty) return null;
+ return members.first;
+}
+
+/**
+ * Experimental API for accessing compilation units defined in a
+ * library.
+ */
+// TODO(ahe): Superclasses? Is this really a mirror?
+class Dart2JsCompilationUnitMirror extends Dart2JsMirror
+ with ContainerMixin {
+ final Dart2JsLibraryMirror _library;
+ final CompilationUnitElement _element;
+
+ Dart2JsCompilationUnitMirror(this._element, this._library);
+
+ Dart2JsMirrorSystem get mirrorSystem => _library.mirrorSystem;
+
+ // TODO(johnniwinther): make sure that these are returned in declaration
+ // order.
+ void _forEachElement(f(Element element)) => _element.forEachLocalMember(f);
+
+ Iterable<DeclarationMirror> _getDeclarationMirrors(Element element) =>
+ _library._getDeclarationMirrors(element);
+
+ Uri get uri => _element.script.uri;
+}
+
+/**
+ * Transitional class that allows access to features that have not yet
+ * made it to the mirror API.
+ *
+ * All API in this class is experimental.
+ */
+class BackDoor {
+ /// Return the compilation units comprising [library].
+ static List<Mirror> compilationUnitsOf(Dart2JsLibraryMirror library) {
+ return library._element.compilationUnits.toList().map(
+ (cu) => new Dart2JsCompilationUnitMirror(cu, library)).toList();
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_type_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_type_mirrors.dart
new file mode 100644
index 0000000..64c54c4
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_type_mirrors.dart
@@ -0,0 +1,460 @@
+// Copyright (c) 2013, 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.
+
+part of dart2js.mirrors;
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+abstract class ClassMirrorMixin implements ClassSourceMirror {
+ bool get hasReflectedType => false;
+ Type get reflectedType {
+ throw new UnsupportedError("ClassMirror.reflectedType is not supported.");
+ }
+ InstanceMirror newInstance(Symbol constructorName,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ throw new UnsupportedError("ClassMirror.newInstance is not supported.");
+ }
+}
+
+abstract class Dart2JsTypeMirror
+ extends Dart2JsElementMirror
+ implements TypeSourceMirror {
+ final DartType _type;
+
+ Dart2JsTypeMirror(Dart2JsMirrorSystem system, DartType type)
+ : super(system, type.element),
+ this._type = type;
+
+ String get _simpleNameString => _type.name;
+
+ Dart2JsDeclarationMirror get owner => library;
+
+ Dart2JsLibraryMirror get library {
+ return mirrorSystem._getLibrary(_type.element.getLibrary());
+ }
+
+ bool get isOriginalDeclaration => true;
+
+ TypeMirror get originalDeclaration => this;
+
+ List<TypeMirror> get typeArguments => const <TypeMirror>[];
+
+ List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
+
+ TypeMirror createInstantiation(List<TypeMirror> typeArguments) {
+ if (typeArguments.isEmpty) return this;
+ throw new ArgumentError('Cannot create generic instantiation of $_type.');
+ }
+
+ bool get isVoid => false;
+
+ bool get isDynamic => false;
+
+ String toString() => _type.toString();
+}
+
+abstract class DeclarationMixin implements TypeMirror {
+
+ bool get isOriginalDeclaration => true;
+
+ TypeMirror get originalDeclaration => this;
+
+ List<TypeMirror> get typeArguments => const <TypeMirror>[];
+}
+
+abstract class Dart2JsGenericTypeMirror extends Dart2JsTypeMirror {
+ List<TypeMirror> _typeArguments;
+ List<TypeVariableMirror> _typeVariables;
+
+ Dart2JsGenericTypeMirror(Dart2JsMirrorSystem system, GenericType type)
+ : super(system, type);
+
+ TypeDeclarationElement get _element => super._element;
+
+ GenericType get _type => super._type;
+
+ bool get isOriginalDeclaration => false;
+
+ TypeMirror get originalDeclaration =>
+ mirrorSystem._getTypeDeclarationMirror(_element);
+
+ List<TypeMirror> get typeArguments {
+ if (_typeArguments == null) {
+ _typeArguments = <TypeMirror>[];
+ if (!_type.isRaw) {
+ Link<DartType> type = _type.typeArguments;
+ while (type != null && type.head != null) {
+ _typeArguments.add(_getTypeMirror(type.head));
+ type = type.tail;
+ }
+ }
+ }
+ return _typeArguments;
+ }
+
+ List<TypeVariableMirror> get typeVariables {
+ if (_typeVariables == null) {
+ _typeVariables = <TypeVariableMirror>[];
+ for (TypeVariableType typeVariable in _element.typeVariables) {
+ _typeVariables.add(
+ new Dart2JsTypeVariableMirror(mirrorSystem, typeVariable));
+ }
+ }
+ return _typeVariables;
+ }
+
+ Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element) {
+ if (element.isTypeVariable()) {
+ assert(invariant(_element, _element == element.enclosingElement,
+ message: 'Foreigned type variable element $element.'));
+ for (Dart2JsTypeVariableMirror mirror in typeVariables) {
+ if (mirror._element == element) return [mirror];
+ }
+ }
+ return super._getDeclarationMirrors(element);
+ }
+
+ TypeMirror _getTypeMirror(DartType type, [FunctionSignature signature]) {
+ return super._getTypeMirror(
+ type.subst(_type.typeArguments, _type.element.typeVariables),
+ signature);
+ }
+
+ TypeSourceMirror createInstantiation(
+ List<TypeSourceMirror> newTypeArguments) {
+ if (newTypeArguments.isEmpty) return owner._getTypeMirror(_type.asRaw());
+ if (newTypeArguments.length != typeVariables.length) {
+ throw new ArgumentError('Cannot create generic instantiation of $_type '
+ 'with ${newTypeArguments.length} arguments, '
+ 'expect ${typeVariables.length} arguments.');
+ }
+ LinkBuilder<DartType> builder = new LinkBuilder<DartType>();
+ for (TypeSourceMirror newTypeArgument in newTypeArguments) {
+ if (newTypeArgument.isVoid) {
+ throw new ArgumentError('Cannot use void as type argument.');
+ }
+ if (newTypeArgument is Dart2JsTypeMirror) {
+ builder.addLast(newTypeArgument._type);
+ } else {
+ throw new UnsupportedError(
+ 'Cannot create instantiation using a type '
+ 'mirror from a different mirrorSystem implementation.');
+ }
+ }
+ return owner._getTypeMirror(_type.createInstantiation(builder.toLink()));
+ }
+}
+
+class Dart2JsInterfaceTypeMirror
+ extends Dart2JsGenericTypeMirror
+ with ObjectMirrorMixin, InstanceMirrorMixin, ClassMirrorMixin,
+ ContainerMixin
+ implements ClassMirror {
+ Dart2JsInterfaceTypeMirror(Dart2JsMirrorSystem system,
+ InterfaceType interfaceType)
+ : super(system, interfaceType);
+
+ ClassElement get _element => super._element;
+
+ InterfaceType get _type => super._type;
+
+ bool get isNameSynthetic {
+ if (_element.isMixinApplication) {
+ MixinApplicationElement mixinApplication = _element;
+ return mixinApplication.isUnnamedMixinApplication;
+ }
+ return false;
+ }
+
+ void _forEachElement(f(Element element)) {
+ _element.forEachMember((_, element) => f(element));
+ }
+
+ ClassMirror get superclass {
+ if (_element.supertype != null) {
+ return _getTypeMirror(_element.supertype);
+ }
+ return null;
+ }
+
+ ClassMirror get mixin {
+ if (_element.isMixinApplication) {
+ MixinApplicationElement mixinApplication = _element;
+ return _getTypeMirror(mixinApplication.mixinType);
+ }
+ return this;
+ }
+
+ List<ClassMirror> get superinterfaces {
+ var list = <ClassMirror>[];
+ Link<DartType> link = _element.interfaces;
+ while (!link.isEmpty) {
+ var type = _getTypeMirror(link.head);
+ list.add(type);
+ link = link.tail;
+ }
+ return list;
+ }
+
+ Map<Symbol, MethodMirror> get instanceMembers => null;
+ Map<Symbol, MethodMirror> get staticMembers => null;
+
+ bool get isAbstract => _element.modifiers.isAbstract();
+
+ bool operator ==(other) {
+ if (identical(this, other)) {
+ return true;
+ }
+ if (other is! ClassMirror) {
+ return false;
+ }
+ return _type == other._type;
+ }
+
+ String toString() => 'Mirror on interface type $_type';
+}
+
+class Dart2JsClassDeclarationMirror
+ extends Dart2JsInterfaceTypeMirror
+ with DeclarationMixin {
+
+ Dart2JsClassDeclarationMirror(Dart2JsMirrorSystem system,
+ InterfaceType type)
+ : super(system, type);
+
+ String toString() => 'Mirror on class ${_type.name}';
+}
+
+class Dart2JsTypedefMirror
+ extends Dart2JsGenericTypeMirror
+ implements TypedefMirror {
+ final Dart2JsLibraryMirror _library;
+ List<TypeVariableMirror> _typeVariables;
+ var _definition;
+
+ Dart2JsTypedefMirror(Dart2JsMirrorSystem system, TypedefType _typedef)
+ : this._library = system._getLibrary(_typedef.element.getLibrary()),
+ super(system, _typedef);
+
+ Dart2JsTypedefMirror.fromLibrary(Dart2JsLibraryMirror library,
+ TypedefType _typedef)
+ : this._library = library,
+ super(library.mirrorSystem, _typedef);
+
+ TypedefType get _typedef => _type;
+
+ LibraryMirror get library => _library;
+
+ bool get isTypedef => true;
+
+ FunctionTypeMirror get referent {
+ if (_definition == null) {
+ _definition = _getTypeMirror(
+ _typedef.element.alias,
+ _typedef.element.functionSignature);
+ }
+ return _definition;
+ }
+
+ bool get isClass => false;
+
+ bool get isAbstract => false;
+
+ String toString() => 'Mirror on typedef $_type';
+}
+
+class Dart2JsTypedefDeclarationMirror
+ extends Dart2JsTypedefMirror
+ with DeclarationMixin {
+ Dart2JsTypedefDeclarationMirror(Dart2JsMirrorSystem system,
+ TypedefType type)
+ : super(system, type);
+
+ String toString() => 'Mirror on typedef ${_type.name}';
+}
+
+class Dart2JsTypeVariableMirror extends Dart2JsTypeMirror
+ implements TypeVariableMirror {
+ Dart2JsDeclarationMirror _owner;
+
+ Dart2JsTypeVariableMirror(Dart2JsMirrorSystem system,
+ TypeVariableType typeVariableType)
+ : super(system, typeVariableType);
+
+ TypeVariableType get _type => super._type;
+
+ Dart2JsDeclarationMirror get owner {
+ if (_owner == null) {
+ _owner = mirrorSystem._getTypeDeclarationMirror(
+ _type.element.enclosingElement);
+ }
+ return _owner;
+ }
+
+ TypeMirror get upperBound => owner._getTypeMirror(_type.element.bound);
+
+ bool operator ==(var other) {
+ if (identical(this, other)) {
+ return true;
+ }
+ if (other is! TypeVariableMirror) {
+ return false;
+ }
+ if (owner != other.owner) {
+ return false;
+ }
+ return qualifiedName == other.qualifiedName;
+ }
+
+ String toString() => 'Mirror on type variable $_type';
+}
+
+class Dart2JsFunctionTypeMirror extends Dart2JsTypeMirror
+ with ObjectMirrorMixin, InstanceMirrorMixin,
+ ClassMirrorMixin, DeclarationMixin
+ implements FunctionTypeMirror {
+ final FunctionSignature _functionSignature;
+ List<ParameterMirror> _parameters;
+
+ Dart2JsFunctionTypeMirror(Dart2JsMirrorSystem system,
+ FunctionType functionType, this._functionSignature)
+ : super(system, functionType) {
+ assert (_functionSignature != null);
+ }
+
+ FunctionType get _type => super._type;
+
+ // TODO(johnniwinther): Is this the qualified name of a function type?
+ Symbol get qualifiedName => originalDeclaration.qualifiedName;
+
+ // TODO(johnniwinther): Substitute type arguments for type variables.
+ Map<Symbol, DeclarationMirror> get declarations {
+ var method = callMethod;
+ if (method != null) {
+ var map = new Map<Symbol, DeclarationMirror>.from(
+ originalDeclaration.declarations);
+ var name = method.qualifiedName;
+ assert(!map.containsKey(name));
+ map[name] = method;
+ return new ImmutableMapWrapper<Symbol, DeclarationMirror>(map);
+ }
+ return originalDeclaration.declarations;
+ }
+
+ bool get isFunction => true;
+
+ MethodMirror get callMethod => _convertElementMethodToMethodMirror(
+ mirrorSystem._getLibrary(_type.element.getLibrary()),
+ _type.element);
+
+ ClassMirror get originalDeclaration =>
+ mirrorSystem._getTypeDeclarationMirror(
+ mirrorSystem.compiler.functionClass);
+
+ // TODO(johnniwinther): Substitute type arguments for type variables.
+ ClassMirror get superclass => originalDeclaration.superclass;
+
+ // TODO(johnniwinther): Substitute type arguments for type variables.
+ List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces;
+
+ Map<Symbol, MethodMirror> get instanceMembers => null;
+ Map<Symbol, MethodMirror> get staticMembers => null;
+
+ ClassMirror get mixin => this;
+
+ bool get isPrivate => false;
+
+ bool get isAbstract => false;
+
+ List<TypeVariableMirror> get typeVariables =>
+ originalDeclaration.typeVariables;
+
+ TypeMirror get returnType => owner._getTypeMirror(_type.returnType);
+
+ List<ParameterMirror> get parameters {
+ if (_parameters == null) {
+ _parameters = _parametersFromFunctionSignature(owner,
+ _functionSignature);
+ }
+ return _parameters;
+ }
+
+ String toString() => 'Mirror on function type $_type';
+}
+
+class Dart2JsVoidMirror extends Dart2JsTypeMirror {
+
+ Dart2JsVoidMirror(Dart2JsMirrorSystem system, VoidType voidType)
+ : super(system, voidType);
+
+ VoidType get _voidType => _type;
+
+ Symbol get qualifiedName => simpleName;
+
+ /**
+ * The void type has no location.
+ */
+ SourceLocation get location => null;
+
+ /**
+ * The void type has no library.
+ */
+ LibraryMirror get library => null;
+
+ List<InstanceMirror> get metadata => const <InstanceMirror>[];
+
+ bool get isVoid => true;
+
+ bool operator ==(other) {
+ if (identical(this, other)) {
+ return true;
+ }
+ if (other is! TypeMirror) {
+ return false;
+ }
+ return other.isVoid;
+ }
+
+ int get hashCode => 13 * _element.hashCode;
+
+ String toString() => 'Mirror on void';
+}
+
+class Dart2JsDynamicMirror extends Dart2JsTypeMirror {
+ Dart2JsDynamicMirror(Dart2JsMirrorSystem system, InterfaceType voidType)
+ : super(system, voidType);
+
+ InterfaceType get _dynamicType => _type;
+
+ Symbol get qualifiedName => simpleName;
+
+ /**
+ * The dynamic type has no location.
+ */
+ SourceLocation get location => null;
+
+ /**
+ * The dynamic type has no library.
+ */
+ LibraryMirror get library => null;
+
+ bool get isDynamic => true;
+
+ bool operator ==(other) {
+ if (identical(this, other)) {
+ return true;
+ }
+ if (other is! TypeMirror) {
+ return false;
+ }
+ return other.isDynamic;
+ }
+
+ int get hashCode => 13 * _element.hashCode;
+
+ String toString() => 'Mirror on dynamic';
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart
deleted file mode 100644
index 5acdfa0..0000000
--- a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart
+++ /dev/null
@@ -1,752 +0,0 @@
-// Copyright (c) 2012, 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 mirrors;
-
-/**
- * The main interface for the whole mirror system.
- */
-abstract class MirrorSystem {
- /**
- * Returns an unmodifiable map of all libraries in this mirror system.
- */
- Map<Uri, LibraryMirror> get libraries;
-
- /**
- * Returns an iterable of all libraries in the mirror system whose library
- * name is [libraryName].
- */
- LibraryMirror findLibrary(String libraryName) {
- return libraries.values.singleWhere(
- (library) => library.simpleName == libraryName);
- }
-
- /**
- * A mirror on the [:dynamic:] type.
- */
- TypeMirror get dynamicType;
-
- /**
- * A mirror on the [:void:] type.
- */
- TypeMirror get voidType;
-}
-
-
-/**
- * An entity in the mirror system.
- */
-abstract class Mirror {
- static const String UNARY_MINUS = 'unary-';
-
- // TODO(johnniwinther): Do we need this on all mirrors?
- /**
- * Returns the mirror system which contains this mirror.
- */
- MirrorSystem get mirrors;
-}
-
-abstract class DeclarationMirror implements Mirror {
- /**
- * The simple name of the entity. The simple name is unique within the
- * scope of the entity declaration.
- *
- * The simple name is in most cases the declared single identifier name of
- * the entity, such as 'method' for a method [:void method() {...}:]. For an
- * unnamed constructor for [:class Foo:] the simple name is ''. For a
- * constructor for [:class Foo:] named 'named' the simple name is 'named'.
- * For a property [:foo:] the simple name of the getter method is 'foo' and
- * the simple name of the setter is 'foo='. For operators the simple name is
- * the operator itself, for example '+' for [:operator +:].
- *
- * The simple name for the unary minus operator is [Mirror.UNARY_MINUS].
- */
- String get simpleName;
-
- /// Returns `true` if the name of this declaration is generated by the
- /// provider of the mirror system.
- bool get isNameSynthetic;
-
- /**
- * Returns the name of this entity qualified by is enclosing context. For
- * instance, the qualified name of a method 'method' in class 'Class' in
- * library 'library' is 'library.Class.method'.
- */
- String get qualifiedName;
-
- /**
- * The source location of this Dart language entity.
- */
- SourceLocation get location;
-
- /**
- * A mirror on the owner of this function. This is the declaration immediately
- * surrounding the reflectee.
- *
- * Note that for libraries, the owner will be [:null:].
- */
- DeclarationMirror get owner;
-
- /**
- * Is this declaration private?
- *
- * Note that for libraries, this will be [:false:].
- */
- bool get isPrivate;
-
- /**
- * Is this declaration top-level?
- *
- * This is defined to be equivalent to:
- * [:mirror.owner != null && mirror.owner is LibraryMirror:]
- */
- bool get isTopLevel;
-
- /**
- * A list of the metadata associated with this declaration.
- */
- List<InstanceMirror> get metadata;
-
- /**
- * Looks up [name] in the scope of this declaration.
- *
- * [name] may be either a single identifier, like 'foo', or of the
- * a prefixed identifier, like 'foo.bar', where 'foo' must be a prefix.
- * For methods and constructors, the scope includes the parameters. For
- * classes and typedefs, the scope includes the type variables.
- * For classes and class members, the scope includes inherited members.
- *
- * See also:
- *
- * * [Lexical Scope](https://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-lexical-scope)
- * in Dart Up and Running.
- * * [Lexical Scoping](http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.jb82efuudrc5)
- * in the Dart Specification.
- */
- DeclarationMirror lookupInScope(String name);
-}
-
-abstract class ObjectMirror implements Mirror {
- /**
- * Invokes a getter and returns a mirror on the result. The getter
- * can be the implicit getter for a field or a user-defined getter
- * method.
- */
- InstanceMirror getField(String fieldName);
-}
-
-/**
- * An [InstanceMirror] reflects an instance of a Dart language object.
- */
-abstract class InstanceMirror implements ObjectMirror {
- /**
- * A mirror on the type of the reflectee.
- */
- ClassMirror get type;
-
- /**
- * Does [reflectee] contain the instance reflected by this mirror?
- * This will always be true in the local case (reflecting instances
- * in the same isolate), but only true in the remote case if this
- * mirror reflects a simple value.
- *
- * A value is simple if one of the following holds:
- * - the value is null
- * - the value is of type [num]
- * - the value is of type [bool]
- * - the value is of type [String]
- */
- bool get hasReflectee;
-
- /**
- * If the [InstanceMirror] reflects an instance it is meaningful to
- * have a local reference to, we provide access to the actual
- * instance here.
- *
- * If you access [reflectee] when [hasReflectee] is false, an
- * exception is thrown.
- */
- get reflectee;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on constant lists.
- */
-abstract class ListInstanceMirror implements InstanceMirror {
- /**
- * Returns an instance mirror of the value at [index] or throws a [RangeError]
- * if the [index] is out of bounds.
- */
- InstanceMirror operator[](int index);
-
- /**
- * The number of elements in the list.
- */
- int get length;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on constant maps.
- */
-abstract class MapInstanceMirror implements InstanceMirror {
- /**
- * Returns a collection containing all the keys in the map.
- */
- Iterable<String> get keys;
-
- /**
- * Returns an instance mirror of the value for the given key or
- * null if key is not in the map.
- */
- InstanceMirror operator[](String key);
-
- /**
- * The number of {key, value} pairs in the map.
- */
- int get length;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on type constants.
- */
-abstract class TypeInstanceMirror implements InstanceMirror {
- /**
- * Returns the type mirror for the type represented by the reflected type
- * constant.
- */
- TypeMirror get representedType;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on comments as metadata.
- */
-abstract class CommentInstanceMirror implements InstanceMirror {
- /**
- * The comment text as written in the source text.
- */
- String get text;
-
- /**
- * The comment text without the start, end, and padding text.
- *
- * For example, if [text] is [: /** Comment text. */ :] then the [trimmedText]
- * is [: Comment text. :].
- */
- String get trimmedText;
-
- /**
- * Is [:true:] if this comment is a documentation comment.
- *
- * That is, that the comment is either enclosed in [: /** ... */ :] or starts
- * with [: /// :].
- */
- bool get isDocComment;
-}
-
-/**
- * Common interface for classes and libraries.
- */
-abstract class ContainerMirror implements Mirror {
-
- /**
- * An immutable map from from names to mirrors for all members in this
- * container.
- */
- Map<String, MemberMirror> get members;
-}
-
-/**
- * A library.
- */
-abstract class LibraryMirror implements ContainerMirror, DeclarationMirror {
- /**
- * An immutable map from from names to mirrors for all members in this
- * library.
- *
- * The members of a library are its top-level classes, functions, variables,
- * getters, and setters.
- */
- Map<String, MemberMirror> get members;
-
- /**
- * An immutable map from names to mirrors for all class
- * declarations in this library.
- */
- Map<String, ClassMirror> get classes;
-
- /**
- * An immutable map from names to mirrors for all function, getter,
- * and setter declarations in this library.
- */
- Map<String, MethodMirror> get functions;
-
- /**
- * An immutable map from names to mirrors for all getter
- * declarations in this library.
- */
- Map<String, MethodMirror> get getters;
-
- /**
- * An immutable map from names to mirrors for all setter
- * declarations in this library.
- */
- Map<String, MethodMirror> get setters;
-
- /**
- * An immutable map from names to mirrors for all variable
- * declarations in this library.
- */
- Map<String, VariableMirror> get variables;
-
- /**
- * Returns the canonical URI for this library.
- */
- Uri get uri;
-
- /**
- * Returns a list of the imports and exports in this library;
- */
- List<LibraryDependencyMirror> get libraryDependencies;
-}
-
-/// A mirror on an import or export declaration.
-abstract class LibraryDependencyMirror {
- /// Is `true` if this dependency is an import.
- bool get isImport;
-
- /// Is `true` if this dependency is an export.
- bool get isExport;
-
- /// Returns the library mirror of the library that imports or exports the
- /// [targetLibrary].
- LibraryMirror get sourceLibrary;
-
- /// Returns the library mirror of the library that is imported or exported.
- LibraryMirror get targetLibrary;
-
- /// Returns the prefix if this is a prefixed import and `null` otherwise.
- String get prefix;
-
- /// Returns the list of show/hide combinators on the import/export
- /// declaration.
- List<CombinatorMirror> get combinators;
-
- /// Returns the source location for this import/export declaration.
- SourceLocation get location;
-}
-
-/// A mirror on a show/hide combinator declared on a library dependency.
-abstract class CombinatorMirror {
- /// The list of identifiers on the combinator.
- List<String> get identifiers;
-
- /// Is `true` if this is a 'show' combinator.
- bool get isShow;
-
- /// Is `true` if this is a 'hide' combinator.
- bool get isHide;
-}
-
-/**
- * Common interface for classes, interfaces, typedefs and type variables.
- */
-abstract class TypeMirror implements DeclarationMirror {
- /**
- * Returns the library in which this member resides.
- */
- LibraryMirror get library;
-
- /**
- * Is [:true:] iff this type is the [:Object:] type.
- */
- bool get isObject;
-
- /**
- * Is [:true:] iff this type is the [:dynamic:] type.
- */
- bool get isDynamic;
-
- /**
- * Is [:true:] iff this type is the void type.
- */
- bool get isVoid;
-
- /**
- * Is [:true:] iff this type is a type variable.
- */
- bool get isTypeVariable;
-
- /**
- * Is [:true:] iff this type is a typedef.
- */
- bool get isTypedef;
-
- /**
- * Is [:true:] iff this type is a function type.
- */
- bool get isFunction;
-}
-
-/**
- * A class or interface type.
- */
-abstract class ClassMirror implements TypeMirror, ContainerMirror {
- /**
- * A mirror on the original declaration of this type.
- *
- * For most classes, they are their own original declaration. For
- * generic classes, however, there is a distinction between the
- * original class declaration, which has unbound type variables, and
- * the instantiations of generic classes, which have bound type
- * variables.
- */
- ClassMirror get originalDeclaration;
-
- /**
- * Returns the super class of this type, or null if this type is [Object] or a
- * typedef.
- */
- ClassMirror get superclass;
-
- /**
- * Returns a list of the interfaces directly implemented by this type.
- */
- List<ClassMirror> get superinterfaces;
-
- /**
- * The mixin of this class. If this class is the result of a mixin application
- * of the form S with M, returns a class mirror on M. Otherwise return the
- * class mirror itself.
- */
- ClassMirror get mixin;
-
- /**
- * Is [:true:] iff this type is a class.
- */
- bool get isClass;
-
- /**
- * Is this the original declaration of this type?
- *
- * For most classes, they are their own original declaration. For
- * generic classes, however, there is a distinction between the
- * original class declaration, which has unbound type variables, and
- * the instantiations of generic classes, which have bound type
- * variables.
- */
- bool get isOriginalDeclaration;
-
- /**
- * Is [:true:] if this class is declared abstract.
- */
- bool get isAbstract;
-
- /**
- * Returns a list of the type arguments for this type.
- */
- List<TypeMirror> get typeArguments;
-
- /**
- * Returns the list of type variables for this type.
- */
- List<TypeVariableMirror> get typeVariables;
-
- /**
- * An immutable map from from names to mirrors for all members of
- * this type.
- *
- * The members of a type are its methods, fields, getters, and
- * setters. Note that constructors and type variables are not
- * considered to be members of a type.
- *
- * This does not include inherited members.
- */
- Map<String, MemberMirror> get members;
-
- /**
- * An immutable map from names to mirrors for all method,
- * declarations for this type. This does not include getters and
- * setters.
- */
- Map<String, MethodMirror> get methods;
-
- /**
- * An immutable map from names to mirrors for all getter
- * declarations for this type.
- */
- Map<String, MethodMirror> get getters;
-
- /**
- * An immutable map from names to mirrors for all setter
- * declarations for this type.
- */
- Map<String, MethodMirror> get setters;
-
- /**
- * An immutable map from names to mirrors for all variable
- * declarations for this type.
- */
- Map<String, VariableMirror> get variables;
-
- /**
- * An immutable map from names to mirrors for all constructor
- * declarations for this type.
- */
- Map<String, MethodMirror> get constructors;
-}
-
-/**
- * A type parameter as declared on a generic type.
- */
-abstract class TypeVariableMirror implements TypeMirror {
- /**
- * Returns the bound of the type parameter.
- */
- TypeMirror get upperBound;
-}
-
-/**
- * A function type.
- */
-abstract class FunctionTypeMirror implements ClassMirror {
- /**
- * Returns the return type of this function type.
- */
- TypeMirror get returnType;
-
- /**
- * Returns the parameters for this function type.
- */
- List<ParameterMirror> get parameters;
-
- /**
- * Returns the call method for this function type.
- */
- MethodMirror get callMethod;
-}
-
-/**
- * A typedef.
- */
-abstract class TypedefMirror implements ClassMirror {
- /**
- * The defining type for this typedef.
- *
- * For instance [:void f(int):] for a [:typedef void f(int):].
- */
- TypeMirror get value;
-}
-
-/**
- * A member of a type, i.e. a field, method or constructor.
- */
-abstract class MemberMirror implements DeclarationMirror {
- /**
- * Is this member a constructor?
- */
- bool get isConstructor;
-
- /**
- * Is this member a variable?
- *
- * This is [:false:] for locals.
- */
- bool get isVariable;
-
- /**
- * Is this member a method?.
- *
- * This is [:false:] for constructors.
- */
- bool get isMethod;
-
- /**
- * Is this member declared static?
- */
- bool get isStatic;
-
- /**
- * Is this member a parameter?
- */
- bool get isParameter;
-}
-
-/**
- * A field.
- */
-abstract class VariableMirror implements MemberMirror {
-
- /**
- * Returns true if this field is final.
- */
- bool get isFinal;
-
- /**
- * Returns true if this field is const.
- */
- bool get isConst;
-
- /**
- * Returns the type of this field.
- */
- TypeMirror get type;
-}
-
-/**
- * Common interface constructors and methods, including factories, getters and
- * setters.
- */
-abstract class MethodMirror implements MemberMirror {
- /**
- * Returns the list of parameters for this method.
- */
- List<ParameterMirror> get parameters;
-
- /**
- * Returns the return type of this method.
- */
- TypeMirror get returnType;
-
- /**
- * Is the reflectee abstract?
- */
- bool get isAbstract;
-
- /**
- * Is the reflectee a regular function or method?
- *
- * A function or method is regular if it is not a getter, setter, or
- * constructor. Note that operators, by this definition, are
- * regular methods.
- */
- bool get isRegularMethod;
-
- /**
- * Is the reflectee a const constructor?
- */
- bool get isConstConstructor;
-
- /**
- * Is the reflectee a generative constructor?
- */
- bool get isGenerativeConstructor;
-
- /**
- * Is the reflectee a redirecting constructor?
- */
- bool get isRedirectingConstructor;
-
- /**
- * Is the reflectee a factory constructor?
- */
- bool get isFactoryConstructor;
-
- /**
- * Is [:true:] if this method is a getter method.
- */
- bool get isGetter;
-
- /**
- * Is [:true:] if this method is a setter method.
- */
- bool get isSetter;
-
- /**
- * Is [:true:] if this method is an operator method.
- */
- bool get isOperator;
-}
-
-/**
- * A formal parameter.
- */
-abstract class ParameterMirror implements VariableMirror {
- /**
- * Returns the type of this parameter.
- */
- TypeMirror get type;
-
- /**
- * Returns the default value for this parameter.
- */
- String get defaultValue;
-
- /**
- * Does this parameter have a default value?
- */
- bool get hasDefaultValue;
-
- /**
- * Is this parameter optional?
- */
- bool get isOptional;
-
- /**
- * Is this parameter named?
- */
- bool get isNamed;
-
- /**
- * Returns [:true:] iff this parameter is an initializing formal of a
- * constructor. That is, if it is of the form [:this.x:] where [:x:] is a
- * field.
- */
- bool get isInitializingFormal;
-
- /**
- * Returns the initialized field, if this parameter is an initializing formal.
- */
- VariableMirror get initializedField;
-}
-
-/**
- * A [SourceLocation] describes the span of an entity in Dart source code.
- * A [SourceLocation] with a non-zero [length] should be the minimum span that
- * encloses the declaration of the mirrored entity.
- */
-abstract class SourceLocation {
- /**
- * The 1-based line number for this source location.
- *
- * A value of 0 means that the line number is unknown.
- */
- int get line;
-
- /**
- * The 1-based column number for this source location.
- *
- * A value of 0 means that the column number is unknown.
- */
- int get column;
-
- /**
- * The 0-based character offset into the [sourceText] where this source
- * location begins.
- *
- * A value of -1 means that the offset is unknown.
- */
- int get offset;
-
- /**
- * The number of characters in this source location.
- *
- * A value of 0 means that the [offset] is approximate.
- */
- int get length;
-
- /**
- * The text of the location span.
- */
- String get text;
-
- /**
- * Returns the URI where the source originated.
- */
- Uri get sourceUri;
-
- /**
- * Returns the text of this source.
- */
- String get sourceText;
-}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart
index 1c7323f..fca92c4 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart
@@ -6,13 +6,20 @@
import 'dart:collection' show Queue, IterableBase;
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'mirrors.dart';
+import 'source_mirrors.dart';
//------------------------------------------------------------------------------
// Utility functions for using the Mirror API
//------------------------------------------------------------------------------
+String nameOf(DeclarationMirror mirror) =>
+ MirrorSystem.getName(mirror.simpleName);
+
+String qualifiedNameOf(DeclarationMirror mirror) =>
+ MirrorSystem.getName(mirror.qualifiedName);
+
+// TODO(johnniwinther): Handle private names.
+Symbol symbolOf(String name, [LibraryMirror library]) => new Symbol(name);
/**
* Return the display name for [mirror].
@@ -32,15 +39,14 @@
return library.uri.toString();
}
} else if (mirror is MethodMirror) {
- MethodMirror methodMirror = mirror;
- String simpleName = methodMirror.simpleName;
- if (methodMirror.isSetter) {
+ String simpleName = nameOf(mirror);
+ if (mirror.isSetter) {
// Remove trailing '='.
return simpleName.substring(0, simpleName.length-1);
- } else if (methodMirror.isOperator) {
- return 'operator ${operatorName(methodMirror)}';
- } else if (methodMirror.isConstructor) {
- String className = displayName(methodMirror.owner);
+ } else if (mirror.isOperator) {
+ return 'operator ${operatorName(mirror)}';
+ } else if (mirror.isConstructor) {
+ String className = displayName(mirror.owner);
if (simpleName == '') {
return className;
} else {
@@ -48,7 +54,7 @@
}
}
}
- return mirror.simpleName;
+ return MirrorSystem.getName(mirror.simpleName);
}
/**
@@ -57,12 +63,11 @@
* operator. Return [:null:] if [methodMirror] is not an operator method.
*/
String operatorName(MethodMirror methodMirror) {
- String simpleName = methodMirror.simpleName;
if (methodMirror.isOperator) {
- if (simpleName == Mirror.UNARY_MINUS) {
+ if (methodMirror.simpleName == const Symbol('unary-')) {
return '-';
} else {
- return simpleName;
+ return nameOf(methodMirror);
}
}
return null;
@@ -70,47 +75,35 @@
/**
* Returns an iterable over the type declarations directly inheriting from
- * the declaration of this type.
+ * the declaration of [type] within [mirrors].
*/
-Iterable<ClassMirror> computeSubdeclarations(ClassMirror type) {
+Iterable<ClassMirror> computeSubdeclarations(MirrorSystem mirrors,
+ ClassMirror type) {
type = type.originalDeclaration;
var subtypes = <ClassMirror>[];
- type.mirrors.libraries.forEach((_, library) {
- for (ClassMirror otherType in library.classes.values) {
+ mirrors.libraries.forEach((_, library) {
+ library.declarations.values
+ .where((mirror) => mirror is ClassMirror)
+ .forEach((ClassMirror otherType) {
var superClass = otherType.superclass;
if (superClass != null) {
superClass = superClass.originalDeclaration;
- if (type.library == superClass.library) {
- if (superClass == type) {
- subtypes.add(otherType);
- }
+ if (superClass == type) {
+ subtypes.add(otherType);
}
}
final superInterfaces = otherType.superinterfaces;
for (ClassMirror superInterface in superInterfaces) {
superInterface = superInterface.originalDeclaration;
- if (type.library == superInterface.library) {
- if (superInterface == type) {
- subtypes.add(otherType);
- }
+ if (superInterface == type) {
+ subtypes.add(otherType);
}
}
- }
+ });
});
return subtypes;
}
-LibraryMirror findLibrary(MemberMirror member) {
- DeclarationMirror owner = member.owner;
- if (owner is LibraryMirror) {
- return owner;
- } else if (owner is TypeMirror) {
- TypeMirror mirror = owner;
- return mirror.library;
- }
- throw new Exception('Unexpected owner: ${owner}');
-}
-
class HierarchyIterable extends IterableBase<ClassMirror> {
final bool includeType;
final ClassMirror type;
@@ -146,7 +139,7 @@
ClassMirror push(ClassMirror type) {
if (type.superclass != null) {
- if (type.superclass.isObject) {
+ if (isObject(type.superclass)) {
object = type.superclass;
} else {
queue.addFirst(type.superclass);
@@ -172,10 +165,67 @@
}
}
+LibraryMirror getLibrary(DeclarationMirror declaration) {
+ while (declaration != null && declaration is! LibraryMirror) {
+ declaration = declaration.owner;
+ }
+ return declaration;
+}
+
+Iterable<DeclarationMirror> membersOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where(
+ (mirror) => mirror is MethodMirror || mirror is VariableMirror);
+}
+
+Iterable<TypeMirror> classesOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where((mirror) => mirror is ClassMirror);
+}
+
+Iterable<TypeMirror> typesOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where((mirror) => mirror is TypeMirror);
+}
+
+Iterable<MethodMirror> methodsOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where(
+ (mirror) => mirror is MethodMirror && mirror.isRegularMethod);
+}
+
+Iterable<MethodMirror> constructorsOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where(
+ (mirror) => mirror is MethodMirror && mirror.isConstructor);
+}
+
+Iterable<MethodMirror> settersOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where(
+ (mirror) => mirror is MethodMirror && mirror.isSetter);
+}
+
+Iterable<MethodMirror> gettersOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where(
+ (mirror) => mirror is MethodMirror && mirror.isGetter);
+}
+
+Iterable<VariableMirror> variablesOf(
+ Map<Symbol, DeclarationMirror> declarations) {
+ return declarations.values.where((mirror) => mirror is VariableMirror);
+}
+
+
+
+bool isObject(TypeMirror mirror) =>
+ mirror is ClassMirror && mirror.superclass == null;
+
/// Returns `true` if [cls] is declared in a private dart library.
bool isFromPrivateDartLibrary(ClassMirror cls) {
if (isMixinApplication(cls)) cls = cls.mixin;
- var uri = cls.library.uri;
+ var uri = getLibrary(cls).uri;
return uri.scheme == 'dart' && uri.path.startsWith('_');
}
@@ -196,8 +246,8 @@
* class A = B with C1, C2;
* abstract class A = B with C1, C2 implements D1, D2;
*/
-ClassMirror getSuperclass(ClassMirror cls) {
- ClassMirror superclass = cls.superclass;
+ClassSourceMirror getSuperclass(ClassSourceMirror cls) {
+ ClassSourceMirror superclass = cls.superclass;
while (isMixinApplication(superclass) && superclass.isNameSynthetic) {
superclass = superclass.superclass;
}
@@ -215,15 +265,15 @@
* class A = B with C1, C2;
* abstract class A = B with C1, C2 implements D1, D2;
*/
-Iterable<ClassMirror> getAppliedMixins(ClassMirror cls) {
- List<ClassMirror> mixins = <ClassMirror>[];
- ClassMirror superclass = cls.superclass;
+Iterable<ClassSourceMirror> getAppliedMixins(ClassSourceMirror cls) {
+ List<ClassSourceMirror> mixins = <ClassSourceMirror>[];
+ ClassSourceMirror superclass = cls.superclass;
while (isMixinApplication(superclass) && superclass.isNameSynthetic) {
mixins.add(superclass.mixin);
superclass = superclass.superclass;
}
if (mixins.length > 1) {
- mixins = new List<ClassMirror>.from(mixins.reversed);
+ mixins = new List<ClassSourceMirror>.from(mixins.reversed);
}
if (isMixinApplication(cls)) {
mixins.add(cls.mixin);
@@ -314,7 +364,7 @@
* variable of [:Iterable:] and 'col.Iterable.contains.element' finds the
* [:element:] parameter of the [:contains:] method on [:Iterable:].
*/
-DeclarationMirror lookupQualifiedInScope(DeclarationMirror declaration,
+DeclarationMirror lookupQualifiedInScope(DeclarationSourceMirror declaration,
String name) {
// TODO(11653): Support lookup of constructors using the [:new Foo:]
// syntax.
@@ -327,28 +377,27 @@
offset = 2;
}
if (result == null) return null;
+ LibraryMirror library = getLibrary(result);
while (result != null && offset < parts.length) {
- result = _lookupLocal(result, parts[offset++]);
+ result = _lookupLocal(result, symbolOf(parts[offset++], library));
}
return result;
}
-DeclarationMirror _lookupLocal(Mirror mirror, String id) {
+DeclarationMirror _lookupLocal(Mirror mirror, Symbol id) {
DeclarationMirror result;
- if (mirror is ContainerMirror) {
- ContainerMirror containerMirror = mirror;
+ if (mirror is LibraryMirror) {
// Try member lookup.
- result = containerMirror.members[id];
- }
- if (result != null) return result;
- if (mirror is ClassMirror) {
- ClassMirror classMirror = mirror;
+ result = mirror.declarations[id];
+ } else if (mirror is ClassMirror) {
+ // Try member lookup.
+ result = mirror.declarations[id];
+ if (result != null) return result;
// Try type variables.
- result = classMirror.typeVariables.firstWhere(
+ result = mirror.typeVariables.firstWhere(
(TypeVariableMirror v) => v.simpleName == id, orElse: () => null);
} else if (mirror is MethodMirror) {
- MethodMirror methodMirror = mirror;
- result = methodMirror.parameters.firstWhere(
+ result = mirror.parameters.firstWhere(
(ParameterMirror p) => p.simpleName == id, orElse: () => null);
}
return result;
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart
new file mode 100644
index 0000000..1a80852
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart
@@ -0,0 +1,249 @@
+// Copyright (c) 2012, 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 mirrors;
+
+import 'dart:mirrors';
+import 'dart:mirrors' as api show SourceLocation;
+export 'dart:mirrors';
+
+abstract class DeclarationSourceMirror implements DeclarationMirror {
+ /// Returns `true` if the name of this declaration is generated by the
+ /// provider of the mirror system.
+ bool get isNameSynthetic;
+
+ /**
+ * Looks up [name] in the scope of this declaration.
+ *
+ * [name] may be either a single identifier, like 'foo', or of the
+ * a prefixed identifier, like 'foo.bar', where 'foo' must be a prefix.
+ * For methods and constructors, the scope includes the parameters. For
+ * classes and typedefs, the scope includes the type variables.
+ * For classes and class members, the scope includes inherited members.
+ *
+ * See also:
+ *
+ * * [Lexical Scope](https://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-lexical-scope)
+ * in Dart Up and Running.
+ * * [Lexical Scoping](http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.jb82efuudrc5)
+ * in the Dart Specification.
+ */
+ DeclarationMirror lookupInScope(String name);
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on constant lists.
+ */
+abstract class ListInstanceMirror implements InstanceMirror {
+ /**
+ * Returns an instance mirror of the value at [index] or throws a [RangeError]
+ * if the [index] is out of bounds.
+ */
+ InstanceMirror getElement(int index);
+
+ /**
+ * The number of elements in the list.
+ */
+ int get length;
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on constant maps.
+ */
+abstract class MapInstanceMirror implements InstanceMirror {
+ /**
+ * Returns a collection containing all the keys in the map.
+ */
+ Iterable<String> get keys;
+
+ /**
+ * Returns an instance mirror of the value for the given key or
+ * null if key is not in the map.
+ */
+ InstanceMirror getValue(String key);
+
+ /**
+ * The number of {key, value} pairs in the map.
+ */
+ int get length;
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on type constants.
+ */
+abstract class TypeInstanceMirror implements InstanceMirror {
+ /**
+ * Returns the type mirror for the type represented by the reflected type
+ * constant.
+ */
+ TypeMirror get representedType;
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on comments as metadata.
+ */
+abstract class CommentInstanceMirror implements InstanceMirror {
+ /**
+ * The comment text as written in the source text.
+ */
+ String get text;
+
+ /**
+ * The comment text without the start, end, and padding text.
+ *
+ * For example, if [text] is [: /** Comment text. */ :] then the [trimmedText]
+ * is [: Comment text. :].
+ */
+ String get trimmedText;
+
+ /**
+ * Is [:true:] if this comment is a documentation comment.
+ *
+ * That is, that the comment is either enclosed in [: /** ... */ :] or starts
+ * with [: /// :].
+ */
+ bool get isDocComment;
+}
+
+/**
+ * A library.
+ */
+abstract class LibrarySourceMirror
+ implements DeclarationSourceMirror, LibraryMirror {
+ /**
+ * Returns a list of the imports and exports in this library;
+ */
+ List<LibraryDependencyMirror> get libraryDependencies;
+}
+
+/// A mirror on an import or export declaration.
+abstract class LibraryDependencyMirror extends Mirror {
+ /// Is `true` if this dependency is an import.
+ bool get isImport;
+
+ /// Is `true` if this dependency is an export.
+ bool get isExport;
+
+ /// Returns the library mirror of the library that imports or exports the
+ /// [targetLibrary].
+ LibraryMirror get sourceLibrary;
+
+ /// Returns the library mirror of the library that is imported or exported.
+ LibraryMirror get targetLibrary;
+
+ /// Returns the prefix if this is a prefixed import and `null` otherwise.
+ String get prefix;
+
+ /// Returns the list of show/hide combinators on the import/export
+ /// declaration.
+ List<CombinatorMirror> get combinators;
+
+ /// Returns the source location for this import/export declaration.
+ SourceLocation get location;
+}
+
+/// A mirror on a show/hide combinator declared on a library dependency.
+abstract class CombinatorMirror extends Mirror {
+ /// The list of identifiers on the combinator.
+ List<String> get identifiers;
+
+ /// Is `true` if this is a 'show' combinator.
+ bool get isShow;
+
+ /// Is `true` if this is a 'hide' combinator.
+ bool get isHide;
+}
+
+/**
+ * Common interface for classes, interfaces, typedefs and type variables.
+ */
+abstract class TypeSourceMirror implements DeclarationSourceMirror, TypeMirror {
+ /// Returns `true` is this is a mirror on the void type.
+ bool get isVoid;
+
+ /// Returns `true` is this is a mirror on the dynamic type.
+ bool get isDynamic;
+
+ /// Create a type mirror on the instantiation of the declaration of this type
+ /// with [typeArguments] as type arguments.
+ TypeMirror createInstantiation(List<TypeMirror> typeArguments);
+}
+
+/**
+ * A class or interface type.
+ */
+abstract class ClassSourceMirror implements TypeSourceMirror, ClassMirror {
+ /**
+ * Is [:true:] if this class is declared abstract.
+ */
+ bool get isAbstract;
+}
+
+/**
+ * A formal parameter.
+ */
+abstract class ParameterSourceMirror implements ParameterMirror {
+ /**
+ * Returns [:true:] iff this parameter is an initializing formal of a
+ * constructor. That is, if it is of the form [:this.x:] where [:x:] is a
+ * field.
+ */
+ bool get isInitializingFormal;
+
+ /**
+ * Returns the initialized field, if this parameter is an initializing formal.
+ */
+ VariableMirror get initializedField;
+}
+
+/**
+ * A [SourceLocation] describes the span of an entity in Dart source code.
+ * A [SourceLocation] with a non-zero [length] should be the minimum span that
+ * encloses the declaration of the mirrored entity.
+ */
+abstract class SourceLocation implements api.SourceLocation {
+ /**
+ * The 1-based line number for this source location.
+ *
+ * A value of 0 means that the line number is unknown.
+ */
+ int get line;
+
+ /**
+ * The 1-based column number for this source location.
+ *
+ * A value of 0 means that the column number is unknown.
+ */
+ int get column;
+
+ /**
+ * The 0-based character offset into the [sourceText] where this source
+ * location begins.
+ *
+ * A value of -1 means that the offset is unknown.
+ */
+ int get offset;
+
+ /**
+ * The number of characters in this source location.
+ *
+ * A value of 0 means that the [offset] is approximate.
+ */
+ int get length;
+
+ /**
+ * The text of the location span.
+ */
+ String get text;
+
+ /**
+ * Returns the URI where the source originated.
+ */
+ Uri get sourceUri;
+
+ /**
+ * Returns the text of this source.
+ */
+ String get sourceText;
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/util.dart b/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
index db94f02..7d9ad77 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
@@ -2,7 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library util;
+library dart2js.mirrors.util;
+
+import 'dart:collection' show Maps;
/**
* An abstract map implementation. This class can be used as a superclass for
@@ -24,7 +26,7 @@
void clear() {
throw new UnsupportedError('clear() is not supported');
}
-
+
void addAll(Map<K, V> other) {
throw new UnsupportedError('addAll() is not supported');
}
@@ -75,6 +77,8 @@
V remove(K key) {
throw new UnsupportedError('V remove(K key) is not supported');
}
+
+ String toString() => Maps.mapToString(this);
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 06430af..ea8ba1e 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -385,6 +385,8 @@
PatchMetadataAnnotation() : super(STATE_DONE);
+ tree.Node parseNode(leg.DiagnosticListener listener) => null;
+
Token get beginToken => null;
Token get endToken => null;
}
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index af629c4..8f75bf1 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -326,8 +326,20 @@
Link<Element> originParameters,
Link<Element> patchParameters) {
while (!originParameters.isEmpty) {
- Element originParameter = originParameters.head;
- Element patchParameter = patchParameters.head;
+ VariableElementX originParameter = originParameters.head;
+ VariableElementX patchParameter = patchParameters.head;
+ // TODO(johnniwinther): Remove the case for reassignment of
+ // [patch]/[origin] when resolution is ensure to be done only once.
+ assert(invariant(originParameter, originParameter.origin == null));
+ assert(invariant(originParameter,
+ originParameter.patch == null ||
+ originParameter.patch == patchParameter));
+ originParameter.patch = patchParameter;
+ assert(invariant(patchParameter,
+ patchParameter.origin == null ||
+ patchParameter.origin == originParameter));
+ assert(invariant(patchParameter, patchParameter.patch == null));
+ patchParameter.origin = originParameter;
// Hack: Use unparser to test parameter equality. This only works because
// we are restricting patch uses and the approach cannot be used
// elsewhere.
@@ -1196,7 +1208,7 @@
namedParameterTypes);
}
- void resolveMetadataAnnotation(PartialMetadataAnnotation annotation) {
+ void resolveMetadataAnnotation(MetadataAnnotationX annotation) {
compiler.withCurrentElement(annotation.annotatedElement, () => measure(() {
assert(annotation.resolutionState == STATE_NOT_STARTED);
annotation.resolutionState = STATE_STARTED;
@@ -2959,14 +2971,15 @@
VariableDefinitionsVisitor visitor =
new VariableDefinitionsVisitor(compiler, node, this,
ElementKind.VARIABLE);
+ VariableListElement variables = visitor.variables;
// Ensure that we set the type of the [VariableListElement] since it depends
// on the current scope. If the current scope is a [MethodScope] or
// [BlockScope] it will not be available for the
// [VariableListElement.computeType] method.
if (node.type != null) {
- visitor.variables.type = resolveTypeAnnotation(node.type);
+ variables.type = resolveTypeAnnotation(node.type);
} else {
- visitor.variables.type = compiler.types.dynamicType;
+ variables.type = compiler.types.dynamicType;
}
Modifiers modifiers = node.modifiers;
@@ -2998,6 +3011,17 @@
reportExtraModifier('static');
}
}
+ if (node.metadata != null) {
+ // TODO(johnniwinther): Unify handling of metadata on locals/formals.
+ for (Link<Node> link = node.metadata.nodes;
+ !link.isEmpty;
+ link = link.tail) {
+ ParameterMetadataAnnotation metadata =
+ new ParameterMetadataAnnotation(link.head);
+ variables.addMetadata(metadata);
+ metadata.ensureResolved(compiler);
+ }
+ }
visitor.visit(node.definitions);
}
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
index 3499562..460f6da 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
@@ -24,9 +24,10 @@
MixinApplicationElementX,
TypeVariableElementX,
TypedefElementX,
- SynthesizedConstructorElementX;
+ SynthesizedConstructorElementX,
+ MetadataAnnotationX,
+ ParameterMetadataAnnotation;
import '../util/util.dart';
-import '../scanner/scannerlib.dart' show PartialMetadataAnnotation;
import 'secret_tree_element.dart' show getTreeElement, setTreeElement;
import '../ordered_typeset.dart' show OrderedTypeSet, OrderedTypeSetBuilder;
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
index c2aab56..5e7c834 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
@@ -63,6 +63,17 @@
}
currentDefinitions = node;
Element element = definition.accept(this);
+ if (currentDefinitions.metadata != null) {
+ // TODO(johnniwinther): Unify handling of metadata on locals/formals.
+ for (Link<Node> link = currentDefinitions.metadata.nodes;
+ !link.isEmpty;
+ link = link.tail) {
+ ParameterMetadataAnnotation metadata =
+ new ParameterMetadataAnnotation(link.head);
+ element.addMetadata(metadata);
+ metadata.ensureResolved(compiler);
+ }
+ }
currentDefinitions = null;
return element;
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
index 1d17df3..1cfc71c 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
@@ -43,7 +43,8 @@
Token token = parser.parseTopLevelDeclaration(beginToken);
assert(identical(token, endToken.next));
cachedNode = listener.popNode();
- assert(listener.nodes.isEmpty);
+ assert(invariant(beginToken, listener.nodes.isEmpty,
+ message: "Non-empty listener stack: ${listener.nodes}"));
});
compiler.patchParser.measure(() {
if (isPatched) {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index 1be0e2a..67fc779 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -252,6 +252,12 @@
void endMethod(Token getOrSet, Token beginToken, Token endToken) {
}
+ void beginMetadataStar(Token token) {
+ }
+
+ void endMetadataStar(int count, bool forParameter) {
+ }
+
void beginMetadata(Token token) {
}
@@ -1264,8 +1270,9 @@
}
TypeAnnotation type = popNode();
Modifiers modifiers = popNode();
- pushNode(
- new VariableDefinitions(type, modifiers, new NodeList.singleton(name)));
+ NodeList metadata = popNode();
+ pushNode(new VariableDefinitions.forParameter(
+ metadata, type, modifiers, new NodeList.singleton(name)));
}
void endFormalParameters(int count, Token beginToken, Token endToken) {
@@ -1812,6 +1819,17 @@
beginToken, inKeyword));
}
+ void endMetadataStar(int count, bool forParameter) {
+ // TODO(johnniwinther): Handle metadata for all node kinds.
+ if (forParameter) {
+ if (0 == count) {
+ pushNode(null);
+ } else {
+ pushNode(makeNodeList(count, null, null, ' '));
+ }
+ }
+ }
+
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
NodeList arguments = popNode();
if (arguments == null) {
@@ -1839,13 +1857,14 @@
if (name != null) {
send = new Send(receiver, name);
}
- pushNode(send);
+ pushNode(new Metadata(beginToken, send));
} else {
// This is a const constructor call.
endConstructorReference(beginToken, periodBeforeName, endToken);
Node constructor = popNode();
- pushNode(new NewExpression(beginToken,
- new Send(null, constructor, arguments)));
+ pushNode(new Metadata(beginToken,
+ new NewExpression(null,
+ new Send(null, constructor, arguments))));
}
}
@@ -1993,7 +2012,6 @@
final Token beginToken;
final Token tokenAfterEndToken;
Expression cachedNode;
- Constant value;
PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken);
@@ -2007,9 +2025,10 @@
Node parseNode(DiagnosticListener listener) {
if (cachedNode != null) return cachedNode;
- cachedNode = parse(listener,
- annotatedElement.getCompilationUnit(),
- (p) => p.parseMetadata(beginToken));
+ Metadata metadata = parse(listener,
+ annotatedElement.getCompilationUnit(),
+ (p) => p.parseMetadata(beginToken));
+ cachedNode = metadata.expression;
return cachedNode;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index 53f04db..365a92b 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -215,10 +215,14 @@
return token;
}
- Token parseMetadataStar(Token token) {
+ Token parseMetadataStar(Token token, {bool forParameter: false}) {
+ listener.beginMetadataStar(token);
+ int count = 0;
while (optional('@', token)) {
token = parseMetadata(token);
+ count++;
}
+ listener.endMetadataStar(count, forParameter);
return token;
}
@@ -326,6 +330,7 @@
}
Token parseFormalParameter(Token token, FormalParameterType type) {
+ token = parseMetadataStar(token, forParameter: true);
listener.beginFormalParameter(token);
token = parseModifiers(token);
// TODO(ahe): Validate that there are formal parameters if void.
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index cd96172..8116646 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -1706,14 +1706,22 @@
MemorySet(this.compiler);
/**
- * Returns whether [first] and [second] may alias to the same
- * object.
+ * Returns whether [first] and [second] always alias to the same object.
+ */
+ bool mustAlias(HInstruction first, HInstruction second) {
+ return first == second;
+ }
+
+ /**
+ * Returns whether [first] and [second] may alias to the same object.
*/
bool mayAlias(HInstruction first, HInstruction second) {
- if (first == second) return true;
+ if (mustAlias(first, second)) return true;
if (isConcrete(first) && isConcrete(second)) return false;
if (nonEscapingReceivers.contains(first)) return false;
if (nonEscapingReceivers.contains(second)) return false;
+ // Typed arrays of different types might have a shared buffer.
+ if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true;
TypeMask intersection = first.instructionType.intersection(
second.instructionType, compiler);
if (intersection.isEmpty) return false;
@@ -1730,6 +1738,11 @@
|| instruction is HLiteralList;
}
+ bool couldBeTypedArray(HInstruction receiver) {
+ JavaScriptBackend backend = compiler.backend;
+ return backend.couldBeTypedArray(receiver.instructionType);
+ }
+
/**
* Returns whether [receiver] escapes the current function.
*/
@@ -1849,15 +1862,19 @@
nonEscapingReceivers.remove(value);
keyedValues.forEach((key, values) {
if (mayAlias(receiver, key)) {
+ // Typed arrays that are views of the same buffer may have different
+ // offsets or element sizes, unless they are the same typed array.
+ bool weakIndex = couldBeTypedArray(key) && !mustAlias(receiver, key);
values.forEach((otherIndex, otherValue) {
- if (mayAlias(index, otherIndex)) values[otherIndex] = null;
+ if (weakIndex || mayAlias(index, otherIndex)) {
+ values[otherIndex] = null;
+ }
});
}
});
- JavaScriptBackend backend = compiler.backend;
// Typed arrays may narrow incoming values.
- if (backend.couldBeTypedArray(receiver.instructionType)) return;
+ if (couldBeTypedArray(receiver)) return;
Map<HInstruction, HInstruction> map = keyedValues.putIfAbsent(
receiver, () => <HInstruction, HInstruction> {});
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index e64cbf6..80f0b13 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -48,6 +48,7 @@
R visitLiteralString(LiteralString node) => visitStringNode(node);
R visitStringJuxtaposition(StringJuxtaposition node) => visitStringNode(node);
R visitLoop(Loop node) => visitStatement(node);
+ R visitMetadata(Metadata node) => visitNode(node);
R visitMixinApplication(MixinApplication node) => visitNode(node);
R visitModifiers(Modifiers node) => visitNode(node);
R visitNamedArgument(NamedArgument node) => visitExpression(node);
@@ -173,6 +174,7 @@
LiteralNull asLiteralNull() => null;
LiteralString asLiteralString() => null;
LiteralSymbol asLiteralSymbol() => null;
+ Metadata asMetadata() => null;
MixinApplication asMixinApplication() => null;
Modifiers asModifiers() => null;
NamedArgument asNamedArgument() => null;
@@ -479,7 +481,7 @@
}
class NewExpression extends Expression {
- /** The token NEW or CONST */
+ /** The token NEW or CONST or `null` for metadata */
final Token newToken;
// Note: we expect that send.receiver is null.
@@ -496,11 +498,10 @@
}
bool isConst() {
- return identical(newToken.stringValue, 'const')
- || identical(newToken.stringValue, '@');
+ return newToken == null || identical(newToken.stringValue, 'const');
}
- Token getBeginToken() => newToken;
+ Token getBeginToken() => newToken != null ? newToken : send.getBeginToken();
Token getEndToken() => send.getEndToken();
}
@@ -1136,10 +1137,23 @@
}
class VariableDefinitions extends Statement {
+ final NodeList metadata;
final TypeAnnotation type;
final Modifiers modifiers;
final NodeList definitions;
- VariableDefinitions(this.type, this.modifiers, this.definitions) {
+
+ VariableDefinitions(this.type,
+ this.modifiers,
+ this.definitions)
+ : this.metadata = null {
+ assert(modifiers != null);
+ }
+
+ // TODO(johnniwinther): Make this its own node type.
+ VariableDefinitions.forParameter(this.metadata,
+ this.type,
+ this.modifiers,
+ this.definitions) {
assert(modifiers != null);
}
@@ -2048,6 +2062,25 @@
Token getEndToken() => block.getEndToken();
}
+class Metadata extends Node {
+ final Token token;
+ final Expression expression;
+
+ Metadata(this.token, this.expression);
+
+ Metadata asMetadata() => this;
+
+ accept(Visitor visitor) => visitor.visitMetadata(this);
+
+ visitChildren(Visitor visitor) {
+ expression.accept(visitor);
+ }
+
+ Token getBeginToken() => token;
+
+ Token getEndToken() => expression.getEndToken();
+}
+
class Initializers {
static bool isSuperConstructorCall(Send node) {
return (node.receiver == null && node.selector.isSuper()) ||
diff --git a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
index 516cc7a..03c48e5 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
@@ -410,6 +410,14 @@
visitNodeWithChildren(node, "While");
}
+ visitMetadata(Metadata node) {
+ openNode(node, "Metadata", {
+ "token": node.token
+ });
+ visitChildNode(node.expression, "expression");
+ closeNode();
+ }
+
visitNode(Node node) {
unimplemented('visitNode', node: node);
}
diff --git a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
index 960c8b6..ebe8648 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
@@ -359,6 +359,10 @@
}
visitVariableDefinitions(VariableDefinitions node) {
+ if (node.metadata != null) {
+ visit(node.metadata);
+ sb.write(' ');
+ }
visit(node.modifiers);
if (!node.modifiers.nodes.isEmpty) {
sb.write(' ');
@@ -573,6 +577,11 @@
visit(node.identifiers);
}
+ visitMetadata(Metadata node) {
+ addToken(node.token);
+ visit(node.expression);
+ }
+
visitNode(Node node) {
throw 'internal error'; // Should not be called.
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 5e3e8e3..5d310ce 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -466,6 +466,10 @@
throw new UnsupportedError("");
}
+ bool get isMap {
+ throw new UnsupportedError("");
+ }
+
bool get isForwarding {
throw new UnsupportedError("");
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
index b013f68..2b426cf 100644
--- a/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
@@ -49,6 +49,7 @@
}
bool get isContainer => true;
+ bool get isMap => false;
bool get isExact => true;
bool equalsDisregardNull(other) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index 1938dfc..39b99c2 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -48,6 +48,7 @@
bool get isUnion => false;
bool get isContainer => false;
+ bool get isMap => false;
bool get isForwarding => false;
// TODO(kasperl): Get rid of these. They should not be a visible
@@ -603,7 +604,12 @@
static bool isSubtypeOf(ClassElement x, ClassElement y, Compiler compiler) {
assert(x.isDeclaration && y.isDeclaration);
Set<ClassElement> subtypes = compiler.world.subtypesOf(y);
- return (subtypes != null) ? subtypes.contains(x) : false;
+ if (subtypes != null && subtypes.contains(x)) return true;
+ if (y != compiler.functionClass) return false;
+ // TODO(johnniwinther): Clean this up (function inheritance).
+ Member member =
+ x.lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME));
+ return member != null && member.isMethod;
}
static Set<ClassElement> commonContainedClasses(FlatTypeMask x,
diff --git a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
index ec6acab..724c27c 100644
--- a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
@@ -5,7 +5,7 @@
part of types;
/**
- * A type mask that wraps an other one, and delecate all its
+ * A type mask that wraps an other one, and delegate all its
* implementation methods to it.
*/
abstract class ForwardingTypeMask implements TypeMask {
diff --git a/sdk/lib/_internal/compiler/implementation/types/map_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/map_type_mask.dart
new file mode 100644
index 0000000..266eede
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/map_type_mask.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2013, 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.
+
+part of types;
+
+/// A [MapTypeMask] is a [TypeMask] for a specific allocation
+/// site of a map (currently only internal Map class) that will get specialized
+/// once the [TypeGraphInferrer] phase finds a key and/or value type for it.
+class MapTypeMask extends ForwardingTypeMask {
+ final TypeMask forwardTo;
+
+ // The [Node] where this type mask was created.
+ final Node allocationNode;
+
+ // The [Element] where this type mask was created.
+ final Element allocationElement;
+
+ // The value type of this map.
+ final TypeMask valueType;
+
+ // The key type of this map.
+ final TypeMask keyType;
+
+ MapTypeMask(this.forwardTo,
+ this.allocationNode,
+ this.allocationElement,
+ this.keyType,
+ this.valueType);
+
+ TypeMask nullable() {
+ return isNullable
+ ? this
+ : new MapTypeMask(forwardTo.nullable(),
+ allocationNode,
+ allocationElement,
+ keyType,
+ valueType);
+ }
+
+ TypeMask nonNullable() {
+ return isNullable
+ ? new MapTypeMask(forwardTo.nonNullable(),
+ allocationNode,
+ allocationElement,
+ keyType,
+ valueType)
+ : this;
+ }
+
+ bool get isContainer => false;
+ bool get isMap => true;
+ bool get isExact => true;
+
+ bool equalsDisregardNull(other) {
+ if (other is! MapTypeMask) return false;
+ return allocationNode == other.allocationNode
+ && keyType == other.keyType
+ && valueType == other.valueType;
+ }
+
+ TypeMask intersection(TypeMask other, Compiler compiler) {
+ TypeMask forwardIntersection = forwardTo.intersection(other, compiler);
+ if (forwardIntersection.isEmpty) return forwardIntersection;
+ return forwardIntersection.isNullable
+ ? nullable()
+ : nonNullable();
+ }
+
+ TypeMask union(other, Compiler compiler) {
+ if (this == other) {
+ return this;
+ } else if (equalsDisregardNull(other)) {
+ return other.isNullable ? other : this;
+ } else if (other.isEmpty) {
+ return other.isNullable ? this.nullable() : this;
+ } else if (other.isMap
+ && keyType != null
+ && other.keyType != null
+ && valueType != null
+ && other.valueType != null) {
+ TypeMask newKeyType =
+ keyType.union(other.keyType, compiler);
+ TypeMask newValueType =
+ valueType.union(other.valueType, compiler);
+ TypeMask newForwardTo = forwardTo.union(other.forwardTo, compiler);
+ return new MapTypeMask(
+ newForwardTo, null, null, newKeyType, newValueType);
+ } else {
+ return forwardTo.union(other, compiler);
+ }
+ }
+
+ bool operator==(other) {
+ if (other is! MapTypeMask) return false;
+ return allocationNode == other.allocationNode
+ && isNullable == other.isNullable
+ && keyType == other.keyType
+ && valueType == other.valueType
+ && forwardTo == other.forwardTo;
+ }
+
+ int get hashCode {
+ return computeHashCode(
+ allocationNode, isNullable, keyType, valueType, forwardTo);
+ }
+
+ String toString() {
+ return 'Map mask: [$keyType/$valueType] type: $forwardTo';
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index 24b60b4..22dca73 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -52,6 +52,7 @@
bool get isUnion;
bool get isContainer;
+ bool get isMap;
bool get isForwarding;
bool containsOnlyInt(Compiler compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index a5c9a9a..5b9999e 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -5,7 +5,6 @@
library types;
import '../dart2jslib.dart' hide Selector, TypedSelector;
-import '../dart_types.dart';
import '../elements/elements.dart';
import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
import '../tree/tree.dart';
@@ -14,6 +13,7 @@
import 'concrete_types_inferrer.dart' show ConcreteTypesInferrer;
part 'container_type_mask.dart';
+part 'map_type_mask.dart';
part 'flat_type_mask.dart';
part 'forwarding_type_mask.dart';
part 'type_mask.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
index b632e9b..b17938d 100644
--- a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
@@ -195,6 +195,7 @@
bool get isExact => false;
bool get isUnion => true;
bool get isContainer => false;
+ bool get isMap => false;
bool get isForwarding => false;
bool isInMask(TypeMask other, Compiler compiler) {
diff --git a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
index 33897e0..7dfac97 100644
--- a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
+++ b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
@@ -88,6 +88,7 @@
..asLiteralMapEntry()
..asLiteralNull()
..asLiteralSymbol()
+ ..asMetadata()
..asModifiers()
..asPart()
..asPartOf()
diff --git a/sdk/lib/_internal/compiler/samples/darttags/darttags.dart b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
index 752c0e0..3a00fc6 100644
--- a/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
+++ b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
@@ -25,14 +25,16 @@
import 'dart:io';
-// TODO(ahe): Should be dart:mirrors.
-import '../../implementation/mirrors/mirrors.dart';
+import 'dart:mirrors';
import '../../../libraries.dart'
show LIBRARIES, LibraryInfo;
-import '../../implementation/mirrors/dart2js_mirror.dart'
- show analyze, BackDoor;
+import '../../implementation/mirrors/analyze.dart'
+ show analyze;
+import '../../implementation/mirrors/dart2js_mirrors.dart'
+ show BackDoor;
+import '../../implementation/mirrors/mirrors_util.dart' show nameOf;
import '../../implementation/filenames.dart';
import '../../implementation/source_file.dart';
@@ -40,7 +42,7 @@
import '../../implementation/util/uri_extras.dart';
const DART2JS = '../../implementation/dart2js.dart';
-const DART2JS_MIRROR = '../../implementation/mirrors/dart2js_mirror.dart';
+const DART2JS_MIRROR = '../../implementation/mirrors/dart2js_mirrors.dart';
const SDK_ROOT = '../../../../../';
bool isPublicDart2jsLibrary(String name) {
@@ -106,9 +108,9 @@
var buffer = new StringBuffer();
SourceFile file = handler.provider.sourceFiles['$uri'];
- compilationUnit.members.forEach((DeclarationMirror mirror) {
- var tagname = mirror.simpleName;
- var byte_offset = mirror.getBeginToken().charOffset;
+ compilationUnit.declarations.forEach((_, DeclarationMirror mirror) {
+ var tagname = nameOf(mirror);
+ var byte_offset = mirror.location.offset;
var line_number = file.getLine(byte_offset) + 1;
var lineStart = file.lineStarts[line_number - 1];
diff --git a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
index e639c4e..9306368 100644
--- a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
+++ b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
@@ -5,14 +5,15 @@
import 'dart:io';
import 'dart:convert';
-// TODO(ahe): Should be dart:mirrors.
-import '../../implementation/mirrors/mirrors.dart';
+import 'dart:mirrors';
import '../../../libraries.dart'
show LIBRARIES, LibraryInfo;
-import '../../implementation/mirrors/dart2js_mirror.dart'
- show analyze, BackDoor;
+import '../../implementation/mirrors/analyze.dart'
+ show analyze;
+import '../../implementation/mirrors/dart2js_mirrors.dart'
+ show BackDoor;
import '../../implementation/filenames.dart';
import '../../implementation/source_file.dart';
diff --git a/sdk/lib/_internal/dartdoc/.gitignore b/sdk/lib/_internal/dartdoc/.gitignore
deleted file mode 100644
index e68c6ca..0000000
--- a/sdk/lib/_internal/dartdoc/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Generated output.
-/docs/
-
-# Compiled .js output.
-static/client-static.js
-static/client-live-nav.js
\ No newline at end of file
diff --git a/sdk/lib/_internal/dartdoc/README.txt b/sdk/lib/_internal/dartdoc/README.txt
deleted file mode 100644
index ad4ddad..0000000
--- a/sdk/lib/_internal/dartdoc/README.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-Dartdoc generates static HTML documentation from Dart code.
-
-To use it, from this directory, run:
-
- $ dartdoc <path to .dart file>
-
-This will create a "docs" directory with the docs for your libraries.
-
-
-How docs are generated
-----------------------
-
-To make beautiful docs from your library, dartdoc parses it and every library it
-imports (recursively). From each library, it parses all classes and members,
-finds the associated doc comments and builds crosslinked docs from them.
-
-"Doc comments" can be in one of a few forms:
-
- /**
- * JavaDoc style block comments.
- */
-
- /** Which can also be single line. */
-
- /// Triple-slash line comments.
- /// Which can be multiple lines.
-
-The body of a doc comment will be parsed as markdown which means you can apply
-most of the formatting and structuring you want while still having docs that
-look nice in plain text. For example:
-
- /// This is a doc comment. This is the first paragraph in the comment. It
- /// can span multiple lines.
- ///
- /// A blank line starts a new paragraph like this one.
- ///
- /// * Unordered lists start with `*` or `-` or `+`.
- /// * And can have multiple items.
- /// 1. You can nest lists.
- /// 2. Like this numbered one.
- ///
- /// ---
- ///
- /// Three dashes, underscores, or tildes on a line by themselves create a
- /// horizontal rule.
- ///
- /// to.get(a.block + of.code) {
- /// indent(it, 4.spaces);
- /// like(this);
- /// }
- ///
- /// There are a few inline styles you can apply: *emphasis*, **strong**,
- /// and `inline code`. You can also use underscores for _emphasis_ and
- /// __strong__.
- ///
- /// An H1 header using equals on the next line
- /// ==========================================
- ///
- /// And an H2 in that style using hyphens
- /// -------------------------------------
- ///
- /// # Or an H1 - H6 using leading hashes
- /// ## H2
- /// ### H3
- /// #### H4 you can also have hashes at then end: ###
- /// ##### H5
- /// ###### H6
-
-There is also an extension to markdown specific to dartdoc: A name inside
-square brackets that is not a markdown link (i.e. doesn't have square brackets
-or parentheses following it) like:
-
- Calls [someMethod], passing in [arg].
-
-is understood to be the name of some member or type that's in the scope of the
-member where that comment appears. Dartdoc will automatically figure out what
-the name refers to and generate an approriate link to that member or type.
-
-
-Attribution
------------
-
-dartdoc uses the delightful Silk icon set by Mark James.
-http://www.famfamfam.com/lab/icons/silk/
diff --git a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart b/sdk/lib/_internal/dartdoc/bin/dartdoc.dart
deleted file mode 100644
index 4ae00ab..0000000
--- a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/**
- * To generate docs for a library, run this script with the path to an
- * entrypoint .dart file, like:
- *
- * $ dart dartdoc.dart foo.dart
- *
- * This will create a "docs" directory with the docs for your libraries. To
- * create these beautiful docs, dartdoc parses your library and every library
- * it imports (recursively). From each library, it parses all classes and
- * members, finds the associated doc comments and builds crosslinked docs from
- * them.
- */
-library dartdoc;
-
-import 'dart:async';
-import 'dart:io';
-
-import '../lib/dartdoc.dart';
-import '../lib/src/dartdoc/utils.dart';
-import 'package:args/args.dart';
-import 'package:path/path.dart' as path;
-
-/**
- * Run this from the `lib/_internal/dartdoc` directory.
- */
-main(List<String> arguments) {
- // Need this because ArgParser.getUsage doesn't show command invocation.
- final USAGE = 'Usage dartdoc [options] <entrypoint(s)>\n[options] include:';
-
- final dartdoc = new Dartdoc();
-
- final argParser = new ArgParser();
-
- String libPath = path.join(scriptDir, '..', '..', '..', '..');
-
- String packageRoot;
-
- argParser.addFlag('no-code',
- help: 'Do not include source code in the documentation.',
- defaultsTo: false, negatable: false,
- callback: (noCode) => dartdoc.includeSource = !noCode);
-
- argParser.addOption('mode', abbr: 'm',
- help: 'Define how HTML pages are generated.',
- allowed: ['static', 'live-nav'], allowedHelp: {
- 'static': 'Generates completely static HTML containing\n'
- 'everything you need to browse the docs. The only\n'
- 'client side behavior is trivial stuff like syntax\n'
- 'highlighting code, and the find-as-you-type search\n'
- 'box.',
- 'live-nav': '(Default) Generated docs do not included baked HTML\n'
- 'navigation. Instead a single `nav.json` file is\n'
- 'created and the appropriate navigation is generated\n'
- 'client-side by parsing that and building HTML.\n'
- '\tThis dramatically reduces the generated size of\n'
- 'the HTML since a large fraction of each static page\n'
- 'is just redundant navigation links.\n'
- '\tIn this mode, the browser will do a XHR for\n'
- 'nav.json which means that to preview docs locallly,\n'
- 'you will need to enable requesting file:// links in\n'
- 'your browser or run a little local server like\n'
- '`python -m SimpleHTTPServer`.'},
- defaultsTo: 'live-nav',
- callback: (genMode) {
- dartdoc.mode = (genMode == 'static' ? MODE_STATIC : MODE_LIVE_NAV);
- });
-
- argParser.addFlag('generate-app-cache',
- help: 'Generates the App Cache manifest file, enabling\n'
- 'offline doc viewing.',
- defaultsTo: false, negatable: false,
- callback: (generate) => dartdoc.generateAppCache = generate);
-
- argParser.addFlag('omit-generation-time',
- help: 'Omits generation timestamp from output.',
- defaultsTo: false, negatable: false,
- callback: (genTimestamp) => dartdoc.omitGenerationTime = genTimestamp);
-
- argParser.addFlag('verbose', abbr: 'v',
- help: 'Print verbose information during generation.',
- defaultsTo: false, negatable: false,
- callback: (verb) => dartdoc.verbose = verb);
-
- argParser.addFlag('include-api',
- help: 'Include the used API libraries in the generated\n'
- 'documentation. If the --link-api option is used,\n'
- 'this option is ignored.',
- defaultsTo: false, negatable: false,
- callback: (incApi) => dartdoc.includeApi = incApi);
-
- argParser.addFlag('link-api',
- help: 'Link to the online language API in the generated\n'
- 'documentation. The option overrides inclusion\n'
- 'through --include-api or --include-lib.',
- defaultsTo: false, negatable: false,
- callback: (linkApi) => dartdoc.linkToApi = linkApi);
-
- argParser.addFlag('show-private',
- help: 'Document private types and members.',
- defaultsTo: false,
- callback: (showPrivate) => dartdoc.showPrivate = showPrivate);
-
- argParser.addFlag('inherit-from-object',
- help: 'Show members inherited from Object.',
- defaultsTo: false, negatable: false,
- callback: (inherit) => dartdoc.inheritFromObject = inherit);
-
- argParser.addFlag('enable-diagnostic-colors', negatable: false);
-
- argParser.addOption('out',
- help: 'Generates files into directory specified. If\n'
- 'omitted the files are generated into ./docs/',
- callback: (outDir) {
- if(outDir != null) {
- dartdoc.outputDir = outDir;
- }
- });
-
- argParser.addOption('include-lib',
- help: 'Use this option to explicitly specify which\n'
- 'libraries to include in the documentation. If\n'
- 'omitted, all used libraries are included by\n'
- 'default. Specify a comma-separated list of\n'
- 'library names, or call this option multiple times.',
- callback: (incLibs) {
- if(!incLibs.isEmpty) {
- List<String> allLibs = new List<String>();
- for(final lst in incLibs) {
- var someLibs = lst.split(',');
- for(final lib in someLibs) {
- allLibs.add(lib);
- }
- }
- dartdoc.includedLibraries = allLibs;
- }
- }, allowMultiple: true);
-
- argParser.addOption('exclude-lib',
- help: 'Use this option to explicitly specify which\n'
- 'libraries to exclude from the documentation. If\n'
- 'omitted, no libraries are excluded. Specify a\n'
- 'comma-separated list of library names, or call\n'
- 'this option multiple times.',
- callback: (excLibs) {
- if(!excLibs.isEmpty) {
- List<String> allLibs = new List<String>();
- for(final lst in excLibs) {
- var someLibs = lst.split(',');
- for(final lib in someLibs) {
- allLibs.add(lib);
- }
- }
- dartdoc.excludedLibraries = allLibs;
- }
- }, allowMultiple: true);
-
- argParser.addOption('package-root',
- help: 'Sets the package directory to the specified directory.\n'
- 'If omitted the package directory is the closest packages directory to'
- ' the entrypoint.',
- callback: (packageDir) {
- if(packageDir != null) {
- packageRoot = packageDir;
- }
- });
-
- argParser.addOption('library-root',
- help: 'Sets the library root directory to the specified directory.',
- callback: (libraryRoot) {
- if (libraryRoot != null) {
- libPath = libraryRoot;
- }
- });
-
- // TODO(amouravski): This method is deprecated. Remove on April 22.
- argParser.addOption('pkg',
- help: 'Deprecated: same as --package-root.',
- callback: (packageDir) {
- if(packageDir != null) {
- packageRoot = packageDir;
- }
- });
-
- dartdoc.dartdocPath = path.join(libPath, 'lib', '_internal', 'dartdoc');
-
- if (arguments.isEmpty) {
- print('No arguments provided.');
- print(USAGE);
- print(argParser.getUsage());
- exit(1);
- }
-
- final entrypoints = <Uri>[];
- try {
- final option = argParser.parse(arguments, allowTrailingOptions: true);
-
- // This checks to see if the root of all entrypoints is the same.
- // If it is not, then we display a warning, as package imports might fail.
- var entrypointRoot;
- for (final entrypoint in option.rest) {
- var uri = Uri.parse(entrypoint);
-
- // If it looks like it was a file path (no scheme, or a one letter scheme
- // which is likely a drive letter on Windows), turn it into a file URL.
- if (uri.scheme == '' || uri.scheme.length == 1) {
- uri = path.toUri(entrypoint);
- }
-
- entrypoints.add(uri);
-
- if (uri.scheme != 'file') continue;
- if (entrypointRoot == null) {
- entrypointRoot = path.dirname(entrypoint);
- } else if (entrypointRoot != path.dirname(entrypoint)) {
- print('Warning: entrypoints are at different directories. "package:"'
- ' imports may fail.');
- }
- }
- } on FormatException catch (e) {
- print(e.message);
- print(USAGE);
- print(argParser.getUsage());
- exit(1);
- }
-
- if (entrypoints.isEmpty) {
- print('No entrypoints provided.');
- print(argParser.getUsage());
- exit(1);
- }
-
- if (packageRoot == null) packageRoot = _getPackageRoot(entrypoints);
-
- cleanOutputDirectory(dartdoc.outputDir);
-
- // Start the analysis and documentation.
- dartdoc.documentLibraries(entrypoints, libPath, packageRoot)
- // Prepare the dart2js script code and copy static resources.
- // TODO(amouravski): move compileScript out and pre-generate the client
- // scripts. This takes a long time and the js hardly ever changes.
- .then((_) => compileScript(dartdoc.mode, dartdoc.outputDir, libPath,
- dartdoc.tmpPath))
- .then((_) => copyDirectory(
- path.join(libPath, 'lib', '_internal', 'dartdoc', 'static'),
- dartdoc.outputDir))
- .then((_) {
- print(dartdoc.status);
- if (dartdoc.totals == 0) {
- exit(1);
- }
- })
- .catchError((e, trace) {
- print('Error: generation failed: ${e}');
- if (trace != null) print("StackTrace: $trace");
- dartdoc.cleanup();
- exit(1);
- })
- .whenComplete(() => dartdoc.cleanup());
-}
-
-String _getPackageRoot(List<Uri> entrypoints) {
- // Check if there's a `packages` directory in the entry point directory.
- var fileEntrypoint = entrypoints.firstWhere(
- (entrypoint) => entrypoint.scheme == 'file',
- orElse: () => null);
- if (fileEntrypoint == null) return;
-
- var script = path.normalize(path.absolute(path.fromUri(fileEntrypoint)));
- var dir = path.join(path.dirname(script), 'packages/');
- if (new Directory(dir).existsSync()) return dir;
-
- // If there is not, then check if the entrypoint is somewhere in a `lib`
- // directory.
- var parts = path.split(path.dirname(script));
- var libDir = parts.lastIndexOf('lib');
- if (libDir > 0) {
- return path.join(path.joinAll(parts.take(libDir)), 'packages');
- } else {
- return null;
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/dartdoc.status b/sdk/lib/_internal/dartdoc/dartdoc.status
deleted file mode 100644
index 336e19b..0000000
--- a/sdk/lib/_internal/dartdoc/dartdoc.status
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (c) 2013, 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.
-
-test/markdown_test: Pass
-test/dartdoc_test: Pass, Slow # Issue 16311
-test/dartdoc_search_test: Pass, Skip
-
-# Dartdoc only runs on the VM, so just rule out all compilers.
-[ $compiler == dart2js || $compiler == dart2dart ]
-*: Skip
-
-# Dartdoc only runs on the standalone VM, not in dartium.
-[ $runtime == drt || $runtime == dartium ]
-*: Skip
diff --git a/sdk/lib/_internal/dartdoc/lib/classify.dart b/sdk/lib/_internal/dartdoc/lib/classify.dart
deleted file mode 100644
index e4ed4db..0000000
--- a/sdk/lib/_internal/dartdoc/lib/classify.dart
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright (c) 2012, 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 classify;
-
-import '../../compiler/implementation/scanner/scannerlib.dart';
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'markdown.dart' as md;
-
-/**
- * Kinds of tokens that we care to highlight differently. The values of the
- * fields here will be used as CSS class names for the generated spans.
- */
-class Classification {
- static const NONE = null;
- static const ERROR = "e";
- static const COMMENT = "c";
- static const IDENTIFIER = "i";
- static const KEYWORD = "k";
- static const OPERATOR = "o";
- static const STRING = "s";
- static const NUMBER = "n";
- static const PUNCTUATION = "p";
-
- // A few things that are nice to make different:
- static const TYPE_IDENTIFIER = "t";
-
- // Between a keyword and an identifier
- static const SPECIAL_IDENTIFIER = "r";
-
- static const ARROW_OPERATOR = "a";
-
- static const STRING_INTERPOLATION = 'si';
-}
-
-/// Returns a marked up HTML string. If the code does not appear to be valid
-/// Dart code, returns the original [text].
-String classifySource(String text) {
- try {
- var html = new StringBuffer();
- var tokenizer = new StringScanner.fromString(text, includeComments: true);
-
- var whitespaceOffset = 0;
- var token = tokenizer.tokenize();
- var inString = false;
- while (token.kind != EOF_TOKEN) {
- html.write(text.substring(whitespaceOffset, token.charOffset));
- whitespaceOffset = token.charOffset + token.slowCharCount;
-
- // Track whether or not we're in a string.
- switch (token.kind) {
- case STRING_TOKEN:
- case STRING_INTERPOLATION_TOKEN:
- inString = true;
- break;
- }
-
- final kind = classify(token);
- final escapedText = md.escapeHtml(token.value);
- if (kind != null) {
- // Add a secondary class to tokens appearing within a string so that
- // we can highlight tokens in an interpolation specially.
- var stringClass = inString ? Classification.STRING_INTERPOLATION : '';
- html.write('<span class="$kind $stringClass">$escapedText</span>');
- } else {
- html.write(escapedText);
- }
-
- // Track whether or not we're in a string.
- if (token.kind == STRING_TOKEN) {
- inString = false;
- }
- token = token.next;
- }
- return html.toString();
- } catch (e) {
- return text;
- }
-}
-
-bool _looksLikeType(String name) {
- // If the name looks like an UppercaseName, assume it's a type.
- return _looksLikePublicType(name) || _looksLikePrivateType(name);
-}
-
-bool _looksLikePublicType(String name) {
- // If the name looks like an UppercaseName, assume it's a type.
- return name.length >= 2 && isUpper(name[0]) && isLower(name[1]);
-}
-
-bool _looksLikePrivateType(String name) {
- // If the name looks like an _UppercaseName, assume it's a type.
- return (name.length >= 3 && name[0] == '_' && isUpper(name[1])
- && isLower(name[2]));
-}
-
-// These ensure that they don't return "true" if the string only has symbols.
-bool isUpper(String s) => s.toLowerCase() != s;
-bool isLower(String s) => s.toUpperCase() != s;
-
-String classify(Token token) {
- switch (token.kind) {
- case IDENTIFIER_TOKEN:
- // Special case for names that look like types.
- final text = token.value;
- if (_looksLikeType(text)
- || text == 'num'
- || text == 'bool'
- || text == 'int'
- || text == 'double') {
- return Classification.TYPE_IDENTIFIER;
- }
- return Classification.IDENTIFIER;
-
- case STRING_TOKEN:
- case STRING_INTERPOLATION_TOKEN:
- return Classification.STRING;
-
- case INT_TOKEN:
- case HEXADECIMAL_TOKEN:
- case DOUBLE_TOKEN:
- return Classification.NUMBER;
-
- case COMMENT_TOKEN:
- return Classification.COMMENT;
-
- // => is so awesome it is in a class of its own.
- case FUNCTION_TOKEN:
- return Classification.ARROW_OPERATOR;
-
- case OPEN_PAREN_TOKEN:
- case CLOSE_PAREN_TOKEN:
- case OPEN_SQUARE_BRACKET_TOKEN:
- case CLOSE_SQUARE_BRACKET_TOKEN:
- case OPEN_CURLY_BRACKET_TOKEN:
- case CLOSE_CURLY_BRACKET_TOKEN:
- case COLON_TOKEN:
- case SEMICOLON_TOKEN:
- case COMMA_TOKEN:
- case PERIOD_TOKEN:
- case PERIOD_PERIOD_TOKEN:
- return Classification.PUNCTUATION;
-
- case PLUS_PLUS_TOKEN:
- case MINUS_MINUS_TOKEN:
- case TILDE_TOKEN:
- case BANG_TOKEN:
- case EQ_TOKEN:
- case BAR_EQ_TOKEN:
- case CARET_EQ_TOKEN:
- case AMPERSAND_EQ_TOKEN:
- case LT_LT_EQ_TOKEN:
- case GT_GT_EQ_TOKEN:
- case PLUS_EQ_TOKEN:
- case MINUS_EQ_TOKEN:
- case STAR_EQ_TOKEN:
- case SLASH_EQ_TOKEN:
- case TILDE_SLASH_EQ_TOKEN:
- case PERCENT_EQ_TOKEN:
- case QUESTION_TOKEN:
- case BAR_BAR_TOKEN:
- case AMPERSAND_AMPERSAND_TOKEN:
- case BAR_TOKEN:
- case CARET_TOKEN:
- case AMPERSAND_TOKEN:
- case LT_LT_TOKEN:
- case GT_GT_TOKEN:
- case PLUS_TOKEN:
- case MINUS_TOKEN:
- case STAR_TOKEN:
- case SLASH_TOKEN:
- case TILDE_SLASH_TOKEN:
- case PERCENT_TOKEN:
- case EQ_EQ_TOKEN:
- case BANG_EQ_TOKEN:
- case EQ_EQ_EQ_TOKEN:
- case BANG_EQ_EQ_TOKEN:
- case LT_TOKEN:
- case GT_TOKEN:
- case LT_EQ_TOKEN:
- case GT_EQ_TOKEN:
- case INDEX_TOKEN:
- case INDEX_EQ_TOKEN:
- return Classification.OPERATOR;
-
- // Color keyword token. Most are colored as keywords.
- case HASH_TOKEN:
- case KEYWORD_TOKEN:
- if (token.stringValue == 'void') {
- // Color "void" as a type.
- return Classification.TYPE_IDENTIFIER;
- }
- if (token.stringValue == 'this' || token.stringValue == 'super') {
- // Color "this" and "super" as identifiers.
- return Classification.SPECIAL_IDENTIFIER;
- }
- return Classification.KEYWORD;
-
- case EOF_TOKEN:
- return Classification.NONE;
-
- default:
- return Classification.NONE;
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
deleted file mode 100644
index 5ba7f0e..0000000
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ /dev/null
@@ -1,2333 +0,0 @@
-// Copyright (c) 2013, 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.
-
-/**
- * To generate docs for a library, run this script with the path to an
- * entrypoint .dart file, like:
- *
- * $ dart dartdoc.dart foo.dart
- *
- * This will create a "docs" directory with the docs for your libraries. To
- * create these beautiful docs, dartdoc parses your library and every library
- * it imports (recursively). From each library, it parses all classes and
- * members, finds the associated doc comments and builds crosslinked docs from
- * them.
- */
-library dartdoc;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:isolate';
-import 'dart:math';
-
-import 'package:path/path.dart' as path;
-
-import 'classify.dart';
-import 'markdown.dart' as md;
-import 'universe_serializer.dart';
-
-import 'src/dartdoc/nav.dart';
-import 'src/dartdoc/utils.dart';
-import 'src/export_map.dart';
-import 'src/json_serializer.dart' as json_serializer;
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'src/dart2js_mirrors.dart' as dart2js;
-import '../../compiler/implementation/mirrors/mirrors.dart';
-import '../../compiler/implementation/mirrors/mirrors_util.dart';
-import '../../libraries.dart';
-
-/**
- * Generates completely static HTML containing everything you need to browse
- * the docs. The only client side behavior is trivial stuff like syntax
- * highlighting code.
- */
-const MODE_STATIC = 0;
-
-/**
- * Generated docs do not include baked HTML navigation. Instead, a single
- * `nav.json` file is created and the appropriate navigation is generated
- * client-side by parsing that and building HTML.
- *
- * This dramatically reduces the generated size of the HTML since a large
- * fraction of each static page is just redundant navigation links.
- *
- * In this mode, the browser will do a XHR for nav.json which means that to
- * preview docs locally, you will need to enable requesting file:// links in
- * your browser or run a little local server like `python -m SimpleHTTPServer`.
- */
-const MODE_LIVE_NAV = 1;
-
-const API_LOCATION = 'http://api.dartlang.org/';
-
-/**
- * Gets the full path to the directory containing the entrypoint of the current
- * script. In other words, if you invoked dartdoc, directly, it will be the
- * path to the directory containing `dartdoc.dart`. If you're running a script
- * that imports dartdoc, it will be the path to that script.
- */
-// TODO(johnniwinther): Convert to final (lazily initialized) variables when
-// the feature is supported.
-String get scriptDir => path.dirname(Platform.script.toFilePath());
-
-/**
- * Deletes and recreates the output directory at [path] if it exists.
- */
-void cleanOutputDirectory(String path) {
- final outputDir = new Directory(path);
- if (outputDir.existsSync()) {
- outputDir.deleteSync(recursive: true);
- }
- outputDir.createSync();
-}
-
-/**
- * Copies all of the files in the directory [from] to [to]. Does *not*
- * recursively copy subdirectories.
- *
- * Note: runs asynchronously, so you won't see any files copied until after the
- * event loop has had a chance to pump (i.e. after `main()` has returned).
- */
-Future copyDirectory(String from, String to) {
- print('Copying static files...');
- final completer = new Completer();
- final fromDir = new Directory(from);
- var futureList = [];
- fromDir.list(recursive: false).listen(
- (FileSystemEntity entity) {
- if (entity is File) {
- final name = path.basename(entity.path);
- // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store.
- if (name.startsWith('.')) return;
-
- File fromFile = entity;
- File toFile = new File(path.join(to, name));
- futureList.add(fromFile.openRead().pipe(toFile.openWrite()));
- }
- },
- onDone: () => Future.wait(futureList).then((_) => completer.complete()),
- onError: completer.completeError);
- return completer.future;
-}
-
-/**
- * Compiles the dartdoc client-side code to JavaScript using Dart2js.
- */
-Future compileScript(int mode, String outputDir, String libPath, String tmpPath) {
- print('Compiling client JavaScript...');
- var clientScript = (mode == MODE_STATIC) ? 'static' : 'live-nav';
- var dartdocLibPath = path.join(libPath, 'lib', '_internal', 'dartdoc', 'lib');
- var dartPath = mode == MODE_STATIC ?
- path.join(tmpPath, 'client.dart') :
- path.join(dartdocLibPath, 'src', 'client', 'client-live-nav.dart');
-
- var jsPath = path.join(outputDir, 'client-$clientScript.js');
-
- // dart2js takes a String, but it expects that to be a Uri, not a file
- // system path.
- libPath = path.toUri(libPath).toString();
- dartPath = path.toUri(dartPath).toString();
-
- return dart2js.compile(
- dartPath, libPath,
- options: const <String>['--categories=Client,Server', '--minify'])
- .then((jsCode) {
- if (jsCode == null) throw new StateError("No javascript was generated.");
- writeString(new File(jsPath), jsCode);
- });
-}
-
-/**
- * Package manifest containing all information required to render the main page
- * for a package.
- *
- * The manifest specifies where to load the [LibraryElement]s describing each
- * library rather than including them directly.
- * For our purposes we treat the core Dart libraries as a package.
- */
-class PackageManifest {
- /** Package name. */
- final name;
- /** Package description */
- final description;
- /** Libraries contained in this package. */
- final List<Reference> libraries = <Reference>[];
- /**
- * Descriptive string describing the version# of the package.
- *
- * The current format for dart-sdk versions is
- * $MAJOR.$MINOR.$BUILD.$PATCH$revisionString$userNameString
- * For example: 0.1.2.0_r18233_johndoe
- */
- final String fullVersion;
- /**
- * Source control revision number for the package. For SVN this is a number
- * while for GIT it is a hash.
- */
- final String revision;
- /**
- * Path to the directory containing data files for each library.
- *
- * Currently this is the serialized json version of the LibraryElement for
- * the library.
- */
- String location;
- /**
- * Packages depended on by this package.
- * We currently store the entire manifest for the depency here the manifests
- * are small. We may want to change this to a reference in the future.
- */
- final List<PackageManifest> dependencies = <PackageManifest>[];
-
- PackageManifest(this.name, this.description, this.fullVersion, this.revision);
-}
-
-class Dartdoc {
-
- /** Set to `false` to not include the source code in the generated docs. */
- bool includeSource = true;
-
- /**
- * Dartdoc can generate docs in a few different ways based on how dynamic you
- * want the client-side behavior to be. The value for this should be one of
- * the `MODE_` constants.
- */
- int mode = MODE_LIVE_NAV;
-
- /**
- * Generates the App Cache manifest file, enabling offline doc viewing.
- */
- bool generateAppCache = false;
-
- /** Path to the dartdoc directory. */
- String dartdocPath;
-
- /** Path to generate HTML files into. */
- String outputDir = 'docs';
-
- /**
- * The title used for the overall generated output. Set this to change it.
- */
- String mainTitle = 'Dart Documentation';
-
- /**
- * The URL that the Dart logo links to. Defaults "index.html", the main
- * page for the generated docs, but can be anything.
- */
- String mainUrl = 'index.html';
-
- /**
- * The Google Custom Search ID that should be used for the search box. If
- * this is `null` then no search box will be shown.
- */
- String searchEngineId = null;
-
- /* The URL that the embedded search results should be displayed on. */
- String searchResultsUrl = 'results.html';
-
- /** Set this to add footer text to each generated page. */
- String footerText = null;
-
- /** Set this to omit generation timestamp from output */
- bool omitGenerationTime = false;
-
- /** Set by Dartdoc user to print extra information during generation. */
- bool verbose = false;
-
- /** Set this to include API libraries in the documentation. */
- bool includeApi = false;
-
- /** Set this to generate links to the online API. */
- bool linkToApi = false;
-
- /** Set this to generate docs for private types and members. */
- bool showPrivate = false;
-
- /** Set this to inherit from Object. */
- bool inheritFromObject = false;
-
- /** Version of the sdk or package docs are being generated for. */
- String version;
-
- /** Set this to select the libraries to include in the documentation. */
- List<String> includedLibraries = const <String>[];
-
- /** Set this to select the libraries to exclude from the documentation. */
- List<String> excludedLibraries = const <String>[];
-
- /** The package root for `package:` imports. */
- String _packageRoot;
-
- /** The map containing all the exports for each library. */
- ExportMap _exports;
-
- /** The path to a temporary directory used by Dartdoc. */
- String tmpPath;
-
- /**
- * This list contains the libraries sorted in by the library name.
- */
- List<LibraryMirror> _sortedLibraries;
-
- /**
- * A map from hidden libraries to lists of [Export]s that export those
- * libraries from visible libraries. This is used to determine what public
- * library any given entity belongs to.
- *
- * The lists of exports are sorted so that exports that hide the fewest number
- * of members come first.
- */
- Map<LibraryMirror, List<Export>> _hiddenLibraryExports;
-
- /** The library that we're currently generating docs for. */
- LibraryMirror _currentLibrary;
-
- /** The type that we're currently generating docs for. */
- ClassMirror _currentType;
-
- /** The member that we're currently generating docs for. */
- MemberMirror _currentMember;
-
- /** The path to the file currently being written to, relative to [outdir]. */
- String _filePath;
-
- /** The file currently being written to. */
- StringBuffer _file;
-
- int _totalLibraries = 0;
- int _totalTypes = 0;
- int _totalMembers = 0;
-
- int get totalLibraries => _totalLibraries;
- int get totalTypes => _totalTypes;
- int get totalMembers => _totalMembers;
-
- // Check if the compilation has started and finished.
- bool _started = false;
- bool _finished = false;
-
- /**
- * Prints the status of dartdoc.
- *
- * Prints whether dartdoc is running, whether dartdoc has finished
- * succesfully or not, and how many libraries, types, and members were
- * documented.
- */
- String get status {
- // TODO(amouravski): Make this more full featured and remove all other
- // prints and put them under verbose flag.
- if (!_started) {
- return 'Documentation has not yet started.';
- } else if (!_finished) {
- return 'Documentation in progress -- documented $_statisticsSummary so far.';
- } else {
- if (totals == 0) {
- return 'Documentation complete -- warning: nothing was documented!';
- } else {
- return 'Documentation complete -- documented $_statisticsSummary.';
- }
- }
- }
-
- int get totals => totalLibraries + totalTypes + totalMembers;
-
- String get _statisticsSummary =>
- '${totalLibraries} libraries, ${totalTypes} types, and '
- '${totalMembers} members';
-
- static const List<String> COMPILER_OPTIONS =
- const <String>['--preserve-comments', '--categories=Client,Server'];
-
- /// Resolves Dart links to the correct Node.
- md.Resolver dartdocResolver;
-
- // Add support for [:...:]-style code to the markdown parser.
- List<md.InlineSyntax> dartdocSyntaxes =
- [new md.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')];
-
- Dartdoc() {
- tmpPath = Directory.systemTemp.createTempSync('dartdoc_').path;
- dartdocResolver = (String name) => resolveNameReference(name,
- currentLibrary: _currentLibrary, currentType: _currentType,
- currentMember: _currentMember);
- }
-
- /**
- * Returns `true` if [library] is included in the generated documentation.
- */
- bool shouldIncludeLibrary(LibraryMirror library) {
- if (shouldLinkToPublicApi(library)) {
- return false;
- }
- var includeByDefault = true;
- String libraryName = displayName(library);
- if (excludedLibraries.contains(libraryName)) {
- return false;
- }
- if (!includedLibraries.isEmpty) {
- includeByDefault = false;
- if (includedLibraries.contains(libraryName)) {
- return true;
- }
- }
- Uri uri = library.uri;
- if (uri.scheme == 'dart') {
- String suffix = uri.path;
- LibraryInfo info = LIBRARIES[suffix];
- if (info != null) {
- return info.documented && includeApi;
- }
- }
- return includeByDefault;
- }
-
- /**
- * Returns `true` if links to the public API should be generated for
- * [library].
- */
- bool shouldLinkToPublicApi(LibraryMirror library) {
- if (linkToApi) {
- Uri uri = library.uri;
- if (uri.scheme == 'dart') {
- String suffix = uri.path;
- LibraryInfo info = LIBRARIES[suffix];
- if (info != null) {
- return info.documented;
- }
- }
- }
- return false;
- }
-
- String get footerContent{
- var footerItems = [];
- if (!omitGenerationTime) {
- footerItems.add("This page was generated at ${new DateTime.now()}");
- }
- if (footerText != null) {
- footerItems.add(footerText);
- }
- var content = '';
- for (int i = 0; i < footerItems.length; i++) {
- if (i > 0) {
- content += '\n';
- }
- content += '<div>${footerItems[i]}</div>';
- }
- return content;
- }
-
- Future documentLibraries(List<Uri> libraryList, String libPath,
- String packageRoot) {
- _packageRoot = packageRoot;
-
- // dart2js takes a String, but it expects that to be a Uri, not a file
- // system path.
- libPath = path.toUri(libPath).toString();
-
- if (packageRoot != null) {
- packageRoot = path.toUri(packageRoot).toString();
- }
-
- // TODO(amouravski): make all of these print statements into logging
- // statements.
- print('Analyzing libraries...');
- return dart2js.analyze(
- libraryList.map((uri) => uri.toString()).toList(),
- libPath, packageRoot: packageRoot, options: COMPILER_OPTIONS)
- .then((MirrorSystem mirrors) {
- print('Generating documentation...');
- _document(mirrors);
- });
- }
-
- void _document(MirrorSystem mirrors) {
- _exports = new ExportMap(mirrors);
- _started = true;
-
-
- // Remove duplicated libraries. This is a hack because libraries can
- // get picked up multiple times (dartbug.com/11826) which will go away
- // with the new docgen. The reason we hit this issue is that we attempt
- // to dart2js.analyze all packages in the repo together, which results
- // in packages getting referenced with different URI's (../../pkg versus
- // ../../out/ReleaseIA32/packages versus package:).
- _sortedLibraries = new Map.fromIterable(
- mirrors.libraries.values.where(shouldIncludeLibrary),
- key: displayName).values.toList();
-
- // Sort the libraries by name (not key).
- _sortedLibraries.sort((x, y) {
- return displayName(x).toUpperCase().compareTo(
- displayName(y).toUpperCase());
- });
-
- _hiddenLibraryExports = _generateHiddenLibraryExports();
-
- // Generate the docs.
- if (mode == MODE_LIVE_NAV) {
- docNavigationJson();
- } else {
- docNavigationDart();
- }
-
- docIndex();
- for (final library in _sortedLibraries) {
- docLibrary(library);
- }
-
- if (generateAppCache) {
- generateAppCacheManifest();
- }
-
- // TODO(nweiz): properly handle exports when generating JSON.
- // TODO(jacobr): handle arbitrary pub packages rather than just the system
- // libraries.
- var revision = '0';
- if (version != null) {
- var match = new RegExp(r"_r(\d+)").firstMatch(version);
- if (match != null) {
- revision = match.group(1);
- } else {
- print("Warning: could not parse version: $version");
- }
- }
- var packageManifest = new PackageManifest('dart:', 'Dart System Libraries',
- version, revision);
-
- for (final lib in _sortedLibraries) {
- var libraryElement = new LibraryElement(
- lib, lookupMdnComment: lookupMdnComment)
- ..stripDuplicateUris(null, null);
- packageManifest.libraries.add(new Reference.fromElement(libraryElement));
- startFile("$revision/${libraryElement.id}.json");
- write(json_serializer.serialize(libraryElement));
- endFile();
- }
-
- startFile("$revision/apidoc.json");
- write(json_serializer.serialize(packageManifest));
- endFile();
-
- // Write out top level json file with a relative path to the library json
- // files.
- startFile("apidoc.json");
- packageManifest.location = revision;
- write(json_serializer.serialize(packageManifest));
- endFile();
-
- _finished = true;
- }
-
- /**
- * Generate [_hiddenLibraryExports] from [_exports].
- */
- Map<LibraryMirror, List<Export>> _generateHiddenLibraryExports() {
- // First generate a map `exported library => exporter library => Export`.
- // The inner map makes it easier to merge multiple exports of the same
- // library by the same exporter.
- var hiddenLibraryExportMaps =
- new Map<LibraryMirror, Map<LibraryMirror, Export>>();
-
- _exports.exports.forEach((exporter, exports) {
- if (!shouldIncludeLibrary(exporter)) return;
- for (var export in exports) {
- var exported = export.exported;
- if (shouldIncludeLibrary(exported)) continue;
-
- var hiddenExports = _exports.transitiveExports(exported)
- .map((transitiveExport) => export.compose(transitiveExport))
- .toList();
- hiddenExports.add(export);
-
- for (var hiddenExport in hiddenExports) {
- var exportsByExporter = hiddenLibraryExportMaps.putIfAbsent(
- hiddenExport.exported, () => new Map<LibraryMirror, Export>());
- addOrMergeExport(exportsByExporter, exporter, hiddenExport);
- }
- }
- });
-
- // Now sort the values of the inner maps of `hiddenLibraryExportMaps` to get
- // the final value of `_hiddenLibraryExports`.
- var hiddenLibraryExports = new Map<LibraryMirror, List<Export>>();
- hiddenLibraryExportMaps.forEach((exportee, exportsByExporter) {
- int rank(Export export) {
- if (export.show.isEmpty && export.hide.isEmpty) return 0;
- if (export.show.isEmpty) return export.hide.length;
- // Multiply by 1000 to ensure this sorts after an export with hides.
- return 1000 * export.show.length;
- }
-
- var exports = exportsByExporter.values.toList();
- exports.sort((export1, export2) {
- var comparison = Comparable.compare(rank(export1), rank(export2));
- if (comparison != 0) return comparison;
-
- var library1 = export1.exporter;
- var library2 = export2.exporter;
- return Comparable.compare(displayName(library1), displayName(library2));
- });
- hiddenLibraryExports[exportee] = exports;
- });
- return hiddenLibraryExports;
- }
-
- MdnComment lookupMdnComment(Mirror mirror) => null;
-
- void startFile(String path) {
- _filePath = path;
- _file = new StringBuffer();
- }
-
- void endFile() {
- final outPath = path.join(outputDir, _filePath);
- final dir = new Directory(path.dirname(outPath));
- if (!dir.existsSync()) {
- // TODO(3914): Hack to avoid 'file already exists' exception
- // thrown due to invalid result from dir.existsSync() (probably due to
- // race conditions).
- try {
- dir.createSync();
- } on FileSystemException catch (e) {
- // Ignore.
- }
- }
-
- writeString(new File(outPath), _file.toString());
- _filePath = null;
- _file = null;
- }
-
- void write(String s) {
- _file.write(s);
- }
-
- void writeln(String s) {
- write(s);
- write('\n');
- }
-
- /**
- * Writes the page header with the given [title] and [breadcrumbs]. The
- * breadcrumbs are an interleaved list of links and titles. If a link is null,
- * then no link will be generated. For example, given:
- *
- * ['foo', 'foo.html', 'bar', null]
- *
- * It will output:
- *
- * <a href="foo.html">foo</a> › bar
- */
- void writeHeader(String title, List<String> breadcrumbs) {
- final htmlAttributes = generateAppCache ?
- 'manifest="/appcache.manifest"' : '';
-
- write(
- '''
- <!DOCTYPE html>
- <html${htmlAttributes == '' ? '' : ' $htmlAttributes'}>
- <head>
- ''');
- writeHeadContents(title);
-
- // Add data attributes describing what the page documents.
- var data = '';
- if (_currentLibrary != null) {
- data = '$data data-library='
- '"${md.escapeHtml(displayName(_currentLibrary))}"';
- }
-
- if (_currentType != null) {
- data = '$data data-type="${md.escapeHtml(typeName(_currentType))}"';
- }
-
- write(
- '''
- </head>
- <body$data>
- <div class="page">
- <div class="header">
- ${a(mainUrl, '<div class="logo"></div>')}
- ${a('index.html', mainTitle)}
- ''');
-
- // Write the breadcrumb trail.
- for (int i = 0; i < breadcrumbs.length; i += 2) {
- if (breadcrumbs[i + 1] == null) {
- write(' › ${breadcrumbs[i]}');
- } else {
- write(' › ${a(breadcrumbs[i + 1], breadcrumbs[i])}');
- }
- }
-
- if (searchEngineId != null) {
- writeln(
- '''
- <form action="$searchResultsUrl" id="search-box">
- <input type="hidden" name="cx" value="$searchEngineId">
- <input type="hidden" name="ie" value="UTF-8">
- <input type="hidden" name="hl" value="en">
- <input type="search" name="q" id="q" autocomplete="off"
- class="search-input" placeholder="Search API">
- </form>
- ''');
- } else {
- writeln(
- '''
- <div id="search-box">
- <input type="search" name="q" id="q" autocomplete="off"
- class="search-input" placeholder="Search API">
- </div>
- ''');
- }
-
- writeln(
- '''
- </div>
- <div class="drop-down" id="drop-down"></div>
- ''');
-
- docNavigation();
- writeln('<div class="content">');
- }
-
- String get clientScript {
- switch (mode) {
- case MODE_STATIC: return 'client-static';
- case MODE_LIVE_NAV: return 'client-live-nav';
- default: throw 'Unknown mode $mode.';
- }
- }
-
- void writeHeadContents(String title) {
- writeln(
- '''
- <meta charset="utf-8">
- <title>$title / $mainTitle</title>
- <link rel="stylesheet" type="text/css"
- href="${relativePath('styles.css')}">
- <link href="//fonts.googleapis.com/css?family=Open+Sans:400,600,700,800" rel="stylesheet" type="text/css">
- <link rel="shortcut icon" href="${relativePath('favicon.ico')}">
- ''');
- }
-
- void writeFooter() {
- writeln(
- '''
- </div>
- <div class="clear"></div>
- </div>
- <div class="footer">
- $footerContent
- </div>
- <script async src="${relativePath('$clientScript.js')}"></script>
- </body></html>
- ''');
- }
-
- void docIndex() {
- startFile('index.html');
-
- writeHeader(mainTitle, []);
-
- writeln('<h2>$mainTitle</h2>');
- writeln('<h3>Libraries</h3>');
-
- for (final library in _sortedLibraries) {
- docIndexLibrary(library);
- }
-
- writeFooter();
- endFile();
- }
-
- void docIndexLibrary(LibraryMirror library) {
- writeln('<h4>${a(libraryUrl(library), displayName(library))}</h4>');
- }
-
- /**
- * Walks the libraries and creates a JSON object containing the data needed
- * to generate navigation for them.
- */
- void docNavigationJson() {
- startFile('nav.json');
- writeln(JSON.encode(createNavigationInfo()));
- endFile();
- }
- /// Whether dartdoc is running from within the Dart SDK or the
- /// Dart source repository.
- bool get runningFromSdk =>
- path.extension(Platform.script.toFilePath()) == '.snapshot';
-
- /// Gets the path to the root directory of the SDK.
- String get sdkDir =>
- path.dirname(path.dirname(Platform.executable));
-
- /// Gets the path to the dartdoc directory normalized for running in different
- /// places.
- String get normalizedDartdocPath => path.normalize(
- path.absolute(runningFromSdk ?
- path.join(sdkDir, 'lib', '_internal', 'dartdoc') :
- dartdocPath.toString()));
-
- void docNavigationDart() {
- var tmpDir = new Directory(tmpPath);
- if (!tmpDir.existsSync()) {
- tmpDir.createSync();
- }
- String jsonString = JSON.encode(createNavigationInfo());
- String dartString = jsonString.replaceAll(r"$", r"\$");
- var filePath = path.join(tmpPath, 'client.dart');
-
- var clientDir = path.join(normalizedDartdocPath,'lib', 'src', 'client');
-
- writeString(new File(filePath),
- '''library client;
- import 'dart:html';
- import r'${path.toUri(path.join(clientDir, 'client-shared.dart'))}';
- import r'${path.toUri(path.join(clientDir, 'dropdown.dart'))}';
-
- main() {
- setup();
- setupSearch(json);
- }
-
- get json => $dartString;''');
- }
-
- void cleanup() {
- var tmpDir = new Directory(tmpPath);
- if (tmpDir.existsSync()) {
- tmpDir.deleteSync(recursive: true);
- }
- tmpPath = null;
- }
-
- List createNavigationInfo() {
- final libraryList = [];
- for (final library in _sortedLibraries) {
- docLibraryNavigationJson(library, libraryList);
- }
- return libraryList;
- }
-
- void docLibraryNavigationJson(LibraryMirror library, List libraryList) {
- var libraryInfo = {};
- libraryInfo[NAME] = displayName(library);
- final List members = docMembersJson(library.members);
- if (!members.isEmpty) {
- libraryInfo[MEMBERS] = members;
- }
-
- final types = [];
- for (ClassMirror type in orderByName(library.classes.values)) {
- if (!showPrivate && type.isPrivate) continue;
-
- var typeInfo = {};
- typeInfo[NAME] = displayName(type);
- if (type.isClass) {
- typeInfo[KIND] = CLASS;
- } else {
- assert(type.isTypedef);
- typeInfo[KIND] = TYPEDEF;
- }
- final List typeMembers = docMembersJson(type.members);
- if (!typeMembers.isEmpty) {
- typeInfo[MEMBERS] = typeMembers;
- }
-
- if (!type.originalDeclaration.typeVariables.isEmpty) {
- final typeVariables = [];
- for (final typeVariable in type.originalDeclaration.typeVariables) {
- typeVariables.add(displayName(typeVariable));
- }
- typeInfo[ARGS] = typeVariables.join(', ');
- }
- types.add(typeInfo);
- }
- if (!types.isEmpty) {
- libraryInfo[TYPES] = types;
- }
-
- libraryList.add(libraryInfo);
- }
-
- List docMembersJson(Map<Object,MemberMirror> memberMap) {
- final members = [];
- for (MemberMirror member in orderByName(memberMap.values)) {
- if (!showPrivate && member.isPrivate) continue;
-
- var memberInfo = {};
- if (member.isVariable) {
- memberInfo[KIND] = FIELD;
- } else {
- MethodMirror method = member;
- if (method.isConstructor) {
- memberInfo[KIND] = CONSTRUCTOR;
- } else if (method.isSetter) {
- memberInfo[KIND] = SETTER;
- } else if (method.isGetter) {
- memberInfo[KIND] = GETTER;
- } else {
- memberInfo[KIND] = METHOD;
- }
- if (method.parameters.isEmpty) {
- memberInfo[NO_PARAMS] = true;
- }
- }
- memberInfo[NAME] = displayName(member);
- var anchor = memberAnchor(member);
- if (anchor != memberInfo[NAME]) {
- memberInfo[LINK_NAME] = anchor;
- }
- members.add(memberInfo);
- }
- return members;
- }
-
- void docNavigation() {
- writeln(
- '''
- <div class="nav">
- ''');
-
- if (mode == MODE_STATIC) {
- for (final library in _sortedLibraries) {
- write('<h2><div class="icon-library"></div>');
-
- if ((_currentLibrary == library) && (_currentType == null)) {
- write('<strong>${displayName(library)}</strong>');
- } else {
- write('${a(libraryUrl(library), displayName(library))}');
- }
- write('</h2>');
-
- // Only expand classes in navigation for current library.
- if (_currentLibrary == library) docLibraryNavigation(library);
- }
- }
-
- writeln('</div>');
- }
-
- /** Writes the navigation for the types contained by the given library. */
- void docLibraryNavigation(LibraryMirror library) {
- // Show the exception types separately.
- final types = <ClassMirror>[];
- final exceptions = <ClassMirror>[];
-
- for (ClassMirror type in orderByName(library.classes.values)) {
- if (!showPrivate && type.isPrivate) continue;
-
- if (isException(type)) {
- exceptions.add(type);
- } else {
- types.add(type);
- }
- }
-
- if ((types.length == 0) && (exceptions.length == 0)) return;
-
- writeln('<ul class="icon">');
- types.forEach(docTypeNavigation);
- exceptions.forEach(docTypeNavigation);
- writeln('</ul>');
- }
-
- /** Writes a linked navigation list item for the given type. */
- void docTypeNavigation(ClassMirror type) {
- var icon = 'interface';
- if (isException(type)) {
- icon = 'exception';
- } else if (type.isClass) {
- icon = 'class';
- }
-
- write('<li>');
- if (_currentType == type) {
- write(
- '<div class="icon-$icon"></div><strong>${typeName(type)}</strong>');
- } else {
- write(a(typeUrl(type),
- '<div class="icon-$icon"></div>${typeName(type)}'));
- }
- writeln('</li>');
- }
-
- void docLibrary(LibraryMirror library) {
- if (verbose) {
- print('Library \'${displayName(library)}\':');
- }
- _totalLibraries++;
- _currentLibrary = library;
-
- startFile(libraryUrl(library));
- writeHeader('${displayName(library)} Library',
- [displayName(library), libraryUrl(library)]);
- writeln('<h2><strong>${displayName(library)}</strong> library</h2>');
-
- // Look for a comment for the entire library.
- final comment = getLibraryComment(library);
- if (comment != null) {
- writeln('<div class="doc">${comment.html}</div>');
- }
-
- // Document the visible libraries exported by this library.
- docExports(library);
-
- // Document the top-level members.
- docMembers(library);
-
- // Document the types.
- final abstractClasses = <ClassMirror>[];
- final classes = <ClassMirror>[];
- final typedefs = <TypedefMirror>[];
- final exceptions = <ClassMirror>[];
-
- var allClasses = _libraryClasses(library);
- for (ClassMirror type in orderByName(allClasses)) {
- if (!showPrivate && type.isPrivate) continue;
-
- if (isException(type)) {
- exceptions.add(type);
- } else if (type.isClass) {
- if (type.isAbstract) {
- abstractClasses.add(type);
- } else {
- classes.add(type);
- }
- } else if (type is TypedefMirror) {
- typedefs.add(type);
- } else {
- throw new InternalError("internal error: unknown type $type.");
- }
- }
-
- docTypes(abstractClasses, 'Abstract Classes');
- docTypes(classes, 'Classes');
- docTypes(typedefs, 'Typedefs');
- docTypes(exceptions, 'Exceptions');
-
- writeFooter();
- endFile();
-
- for (final type in allClasses) {
- if (!showPrivate && type.isPrivate) continue;
-
- docType(type);
- }
-
- _currentLibrary = null;
- }
-
- void docTypes(List types, String header) {
- if (types.length == 0) return;
-
- writeln('<div>');
- writeln('<h3>$header</h3>');
-
- for (final type in types) {
- writeln(
- '''
- <div class="type">
- <h4>
- ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")}
- </h4>
- </div>
- ''');
- }
- writeln('</div>');
- }
-
- void docType(ClassMirror type) {
- if (verbose) {
- print('- ${type.simpleName}');
- }
- _totalTypes++;
- _currentType = type;
-
- startFile(typePath(type));
-
- var kind;
- if (type.isTypedef) {
- kind = 'typedef';
- } else {
- assert(type.isClass);
- if (type.isAbstract) {
- kind = 'abstract class';
- } else {
- kind = 'class';
- }
- }
-
- final typeTitle =
- '${typeName(type)} ${kind}';
- var library = _libraryFor(type);
- writeHeader('$typeTitle / ${displayName(library)} Library',
- [displayName(library), libraryUrl(library),
- typeName(type), typeUrl(type)]);
- writeln(
- '''
- <h2><strong>${typeName(type, showBounds: true)}</strong>
- $kind
- </h2>
- ''');
- writeln('<button id="show-inherited" class="show-inherited">'
- 'Hide inherited</button>');
-
- writeln('<div class="doc">');
- docComment(type, getTypeComment(type));
- docCode(type.location);
- writeln('</div>');
-
- docInheritance(type);
- docTypedef(type);
-
- docMembers(type);
-
- writeTypeFooter();
- writeFooter();
- endFile();
-
- _currentType = null;
- }
-
- /** Override this to write additional content at the end of a type's page. */
- void writeTypeFooter() {
- // Do nothing.
- }
-
- /**
- * Writes an inline type span for the given type. This is a little box with
- * an icon and the type's name. It's similar to how types appear in the
- * navigation, but is suitable for inline (as opposed to in a `<ul>`) use.
- */
- void typeSpan(ClassMirror type) {
- var icon = 'interface';
- if (isException(type)) {
- icon = 'exception';
- } else if (type.isClass) {
- icon = 'class';
- }
-
- write('<span class="type-box"><span class="icon-$icon"></span>');
- if (_currentType == type) {
- write('<strong>${typeName(type)}</strong>');
- } else {
- write(a(typeUrl(type), typeName(type)));
- }
- write('</span>');
- }
-
- /**
- * Document the other types that touch [Type] in the inheritance hierarchy:
- * subclasses, superclasses, subinterfaces, superinferfaces, and default
- * class.
- */
- void docInheritance(ClassMirror type) {
- // Don't show the inheritance details for Object. It doesn't have any base
- // class (obviously) and it has too many subclasses to be useful.
- if (type.isObject) return;
- if (type.isTypedef) return;
-
- // Writes an unordered list of references to types with an optional header.
- listTypes(types, header) {
- if (types == null) return;
-
- // Filter out types from private dart libraries.
- types = new List.from(types.where((t) => !isFromPrivateDartLibrary(t)));
-
- var publicTypes;
- if (showPrivate) {
- publicTypes = types;
- } else {
- // Skip private types.
- publicTypes = new List.from(types.where((t) => !t.isPrivate));
- }
- if (publicTypes.length == 0) return;
-
- writeln('<h3>$header</h3>');
- writeln('<p>');
- bool first = true;
- for (final t in publicTypes) {
- if (!first) write(', ');
- typeSpan(t);
- first = false;
- }
- writeln('</p>');
- }
-
- final subtypes = [];
- for (final subtype in computeSubdeclarations(type)) {
- subtypes.add(subtype);
- }
- subtypes.sort((x, y) => x.simpleName.compareTo(y.simpleName));
-
- // Show the chain of superclasses.
- var superclass = getSuperclass(type);
- if (!superclass.isObject) {
- final supertypes = [];
- var thisType = superclass;
- do {
- if (!isFromPrivateDartLibrary(thisType)) {
- supertypes.add(thisType);
- }
- thisType = getSuperclass(thisType);
- } while (!thisType.isObject);
-
- writeln('<h3>Extends</h3>');
- writeln('<p>');
- for (var i = supertypes.length - 1; i >= 0; i--) {
- typeSpan(supertypes[i]);
- write(' > ');
- }
-
- // Write this class.
- typeSpan(type);
- writeln('</p>');
- }
-
- listTypes(subtypes, 'Subclasses');
- listTypes(getAppliedMixins(type), 'Mixins');
- listTypes(getExplicitInterfaces(type), 'Implements');
- }
-
- /**
- * Documents the definition of [type] if it is a typedef.
- */
- void docTypedef(TypeMirror type) {
- if (type is! TypedefMirror) {
- return;
- }
- writeln('<div class="method"><h4 id="${type.simpleName}">');
-
- if (includeSource) {
- writeln('<button class="show-code">Code</button>');
- }
-
- write('typedef ');
- annotateType(type, type.value, type.simpleName);
-
- write(''' <a class="anchor-link" href="#${type.simpleName}"
- title="Permalink to ${type.simpleName}">#</a>''');
- writeln('</h4>');
-
- writeln('<div class="doc">');
- docCode(type.location);
- writeln('</div>');
-
- writeln('</div>');
- }
-
- static const operatorOrder = const <String>[
- '[]', '[]=', // Indexing.
- '+', Mirror.UNARY_MINUS, '-', '*', '/', '~/', '%', // Arithmetic.
- '&', '|', '^', '~', // Bitwise.
- '<<', '>>', // Shift.
- '<', '<=', '>', '>=', // Relational.
- '==', // Equality.
- ];
-
- static final Map<String, int> operatorOrderMap = (){
- var map = new Map<String, int>();
- var index = 0;
- for (String operator in operatorOrder) {
- map[operator] = index++;
- }
- return map;
- }();
-
- void docExports(LibraryMirror library) {
- var exportLinks = _exports.transitiveExports(library).map((export) {
- var library = export.exported;
- // Only link to publically visible libraries.
- if (!shouldIncludeLibrary(library)) return null;
-
- var memberNames = export.show.isEmpty ? export.hide : export.show;
- var memberLinks = memberNames.map((name) {
- return md.renderToHtml([resolveNameReference(
- name, currentLibrary: library)]);
- }).join(', ');
- var combinator = '';
- if (!export.show.isEmpty) {
- combinator = ' show $memberLinks';
- } else if (!export.hide.isEmpty) {
- combinator = ' hide $memberLinks';
- }
-
- return '<ul>${a(libraryUrl(library), displayName(library))}'
- '$combinator</ul>';
- }).where((link) => link != null);
-
- if (!exportLinks.isEmpty) {
- writeln('<h3>Exports</h3>');
- writeln('<ul>');
- writeln(exportLinks.join('\n'));
- writeln('</ul>');
- }
- }
-
- void docMembers(ContainerMirror host) {
- // Collect the different kinds of members.
- final staticMethods = [];
- final staticGetters = new Map<String,MemberMirror>();
- final staticSetters = new Map<String,MemberMirror>();
- final memberMap = new Map<String,MemberMirror>();
- final instanceMethods = [];
- final instanceOperators = [];
- final instanceGetters = new Map<String,MemberMirror>();
- final instanceSetters = new Map<String,MemberMirror>();
- final constructors = [];
-
- var hostMembers = host is LibraryMirror ?
- _libraryMembers(host) : host.members.values;
- for (var member in hostMembers) {
- if (!showPrivate && member.isPrivate) continue;
- if (host is LibraryMirror || member.isStatic) {
- if (member is MethodMirror) {
- if (member.isGetter) {
- staticGetters[displayName(member)] = member;
- } else if (member.isSetter) {
- staticSetters[displayName(member)] = member;
- } else {
- staticMethods.add(member);
- }
- } else if (member is VariableMirror) {
- staticGetters[displayName(member)] = member;
- }
- }
- }
-
- if (host is ClassMirror) {
- var iterable = new HierarchyIterable(host, includeType: true);
- for (ClassMirror type in iterable) {
- if (!host.isObject && !inheritFromObject && type.isObject) continue;
- if (isFromPrivateDartLibrary(type)) continue;
-
- type.members.forEach((_, MemberMirror member) {
- if (member.isStatic) return;
- if (!showPrivate && member.isPrivate) return;
-
- bool inherit = true;
- if (type != host) {
- if (member.isPrivate) {
- // Don't inherit private members.
- inherit = false;
- }
- if (member.isConstructor) {
- // Don't inherit constructors.
- inherit = false;
- }
- }
- if (!inherit) return;
-
- if (member.isVariable) {
- // Fields override both getters and setters.
- memberMap.putIfAbsent(member.simpleName, () => member);
- memberMap.putIfAbsent('${member.simpleName}=', () => member);
- } else if (member.isConstructor) {
- constructors.add(member);
- } else {
- memberMap.putIfAbsent(member.simpleName, () => member);
- }
- });
- }
- }
-
- bool allMethodsInherited = true;
- bool allPropertiesInherited = true;
- bool allOperatorsInherited = true;
- memberMap.forEach((_, MemberMirror member) {
- if (member is MethodMirror) {
- if (member.isGetter) {
- instanceGetters[displayName(member)] = member;
- if (_ownerFor(member) == host) {
- allPropertiesInherited = false;
- }
- } else if (member.isSetter) {
- instanceSetters[displayName(member)] = member;
- if (_ownerFor(member) == host) {
- allPropertiesInherited = false;
- }
- } else if (member.isOperator) {
- instanceOperators.add(member);
- if (_ownerFor(member) == host) {
- allOperatorsInherited = false;
- }
- } else {
- instanceMethods.add(member);
- if (_ownerFor(member) == host) {
- allMethodsInherited = false;
- }
- }
- } else if (member is VariableMirror) {
- instanceGetters[displayName(member)] = member;
- if (_ownerFor(member) == host) {
- allPropertiesInherited = false;
- }
- }
- });
-
- instanceOperators.sort((MethodMirror a, MethodMirror b) {
- return operatorOrderMap[a.simpleName].compareTo(
- operatorOrderMap[b.simpleName]);
- });
-
- docProperties(host,
- host is LibraryMirror ? 'Properties' : 'Static Properties',
- staticGetters, staticSetters, allInherited: false);
- docMethods(host,
- host is LibraryMirror ? 'Functions' : 'Static Methods',
- staticMethods, allInherited: false);
-
- docMethods(host, 'Constructors', orderByName(constructors),
- allInherited: false);
- docProperties(host, 'Properties', instanceGetters, instanceSetters,
- allInherited: allPropertiesInherited);
- docMethods(host, 'Operators', instanceOperators,
- allInherited: allOperatorsInherited);
- docMethods(host, 'Methods', orderByName(instanceMethods),
- allInherited: allMethodsInherited);
- }
-
- /**
- * Documents fields, getters, and setters as properties.
- */
- void docProperties(ContainerMirror host, String title,
- Map<String,MemberMirror> getters,
- Map<String,MemberMirror> setters,
- {bool allInherited}) {
- if (getters.isEmpty && setters.isEmpty) return;
-
- var nameSet = new Set<String>.from(getters.keys);
- nameSet.addAll(setters.keys);
- var nameList = new List<String>.from(nameSet);
- nameList.sort((String a, String b) {
- return a.toLowerCase().compareTo(b.toLowerCase());
- });
-
- writeln('<div${allInherited ? ' class="inherited"' : ''}>');
- writeln('<h3>$title</h3>');
- for (String name in nameList) {
- MemberMirror getter = getters[name];
- MemberMirror setter = setters[name];
- if (setter == null) {
- if (getter is VariableMirror) {
- // We have a field.
- docField(host, getter);
- } else {
- // We only have a getter.
- assert(getter is MethodMirror);
- docProperty(host, getter, null);
- }
- } else if (getter == null) {
- // We only have a setter => Document as a method.
- assert(setter is MethodMirror);
- docMethod(host, setter);
- } else {
- DocComment getterComment = getMemberComment(getter);
- DocComment setterComment = getMemberComment(setter);
- if (_ownerFor(getter) != _ownerFor(setter) ||
- getterComment != null && setterComment != null) {
- // Both have comments or are not declared in the same class
- // => Documents separately.
- if (getter is VariableMirror) {
- // Document field as a getter (setter is inherited).
- docField(host, getter, asGetter: true);
- } else {
- docMethod(host, getter);
- }
- if (setter is VariableMirror) {
- // Document field as a setter (getter is inherited).
- docField(host, setter, asSetter: true);
- } else {
- docMethod(host, setter);
- }
- } else {
- // Document as field.
- docProperty(host, getter, setter);
- }
- }
- }
- writeln('</div>');
- }
-
- void docMethods(ContainerMirror host, String title, List<Mirror> methods,
- {bool allInherited}) {
- if (methods.length > 0) {
- writeln('<div${allInherited ? ' class="inherited"' : ''}>');
- writeln('<h3>$title</h3>');
- for (MethodMirror method in methods) {
- docMethod(host, method);
- }
- writeln('</div>');
- }
- }
-
- /**
- * Documents the [member] declared in [host]. Handles all kinds of members
- * including getters, setters, and constructors. If [member] is a
- * [FieldMirror] it is documented as a getter or setter depending upon the
- * value of [asGetter].
- */
- void docMethod(ContainerMirror host, MemberMirror member,
- {bool asGetter: false}) {
- _totalMembers++;
- _currentMember = member;
-
- bool isAbstract = false;
- String name = displayName(member);
- if (member is VariableMirror) {
- if (asGetter) {
- // Getter.
- name = 'get $name';
- } else {
- // Setter.
- name = 'set $name';
- }
- } else {
- assert(member is MethodMirror);
- isAbstract = member.isAbstract;
- if (member.isGetter) {
- // Getter.
- name = 'get $name';
- } else if (member.isSetter) {
- // Setter.
- name = 'set $name';
- }
- }
-
- bool showCode = includeSource && !isAbstract;
- bool inherited = host != member.owner && member.owner is! LibraryMirror;
-
- writeln('<div class="method${inherited ? ' inherited': ''}">'
- '<h4 id="${memberAnchor(member)}">');
-
- if (showCode) {
- writeln('<button class="show-code">Code</button>');
- }
-
- if (member is MethodMirror) {
- if (member.isConstructor) {
- if (member.isFactoryConstructor) {
- write('factory ');
- } else {
- write(member.isConstConstructor ? 'const ' : 'new ');
- }
- } else if (member.isAbstract) {
- write('abstract ');
- }
-
- if (!member.isConstructor) {
- annotateDynamicType(host, member.returnType);
- }
- } else {
- assert(member is VariableMirror);
- if (asGetter) {
- annotateDynamicType(host, member.type);
- } else {
- write('void ');
- }
- }
-
- write('<strong>$name</strong>');
-
- if (member is MethodMirror) {
- if (!member.isGetter) {
- docParamList(host, member.parameters);
- }
- } else {
- assert(member is VariableMirror);
- if (!asGetter) {
- write('(');
- annotateType(host, member.type);
- write(' value)');
- }
- }
-
- var prefix = host is LibraryMirror ? '' : '${typeName(host)}.';
- write(''' <a class="anchor-link" href="#${memberAnchor(member)}"
- title="Permalink to $prefix$name">#</a>''');
- writeln('</h4>');
-
- if (inherited) {
- docInherited(host, member.owner);
- }
-
- writeln('<div class="doc">');
- docComment(host, getMemberComment(member));
- if (showCode) {
- docCode(member.location);
- }
- writeln('</div>');
-
- writeln('</div>');
-
- _currentMember = null;
- }
-
- /**
- * Annotate a member as inherited or mixed in from [owner].
- */
- void docInherited(ContainerMirror host, ClassMirror owner) {
- if (isMixinApplication(owner)) {
- write('<div class="inherited-from">mixed in from ');
- annotateType(host, owner.mixin);
- write('</div>');
- } else {
- write('<div class="inherited-from">inherited from ');
- annotateType(host, owner);
- write('</div>');
- }
- }
-
- void docField(ContainerMirror host, VariableMirror field,
- {bool asGetter: false, bool asSetter: false}) {
- if (asGetter) {
- docMethod(host, field, asGetter: true);
- } else if (asSetter) {
- docMethod(host, field, asGetter: false);
- } else {
- docProperty(host, field, null);
- }
- }
-
- /**
- * Documents the property defined by [getter] and [setter] of declared in
- * [host]. If [getter] is a [FieldMirror], [setter] must be [:null:].
- * Otherwise, if [getter] is a [MethodMirror], the property is considered
- * final if [setter] is [:null:].
- */
- void docProperty(ContainerMirror host,
- MemberMirror getter, MemberMirror setter) {
- assert(getter != null);
- _totalMembers++;
- _currentMember = getter;
-
- bool inherited = host != getter.owner && getter.owner is! LibraryMirror;
-
- writeln('<div class="field${inherited ? ' inherited' : ''}">'
- '<h4 id="${memberAnchor(getter)}">');
-
- if (includeSource) {
- writeln('<button class="show-code">Code</button>');
- }
-
- bool isConst = false;
- bool isFinal;
- TypeMirror type;
- if (getter is VariableMirror) {
- assert(setter == null);
- isConst = getter.isConst;
- isFinal = getter.isFinal;
- type = getter.type;
- } else {
- assert(getter is MethodMirror);
- isFinal = setter == null;
- type = getter.returnType;
- }
-
- if (isConst) {
- write('const ');
- } else if (isFinal) {
- write('final ');
- } else if (type.isDynamic) {
- write('var ');
- }
-
- annotateType(host, type);
- var prefix = host is LibraryMirror ? '' : '${typeName(host)}.';
- write(
- '''
- <strong>${getter.simpleName}</strong> <a class="anchor-link"
- href="#${memberAnchor(getter)}"
- title="Permalink to $prefix${getter.simpleName}">#</a>
- </h4>
- ''');
-
- if (inherited) {
- docInherited(host, getter.owner);
- }
-
- DocComment comment = getMemberComment(getter);
- if (comment == null && setter != null) {
- comment = getMemberComment(setter);
- }
- writeln('<div class="doc">');
- docComment(host, comment);
- docCode(getter.location);
- if (setter != null) {
- docCode(setter.location);
- }
- writeln('</div>');
-
- writeln('</div>');
-
- _currentMember = null;
- }
-
- void docParamList(ContainerMirror enclosingType,
- List<ParameterMirror> parameters) {
- write('(');
- bool first = true;
- bool inOptionals = false;
- bool isNamed = false;
- for (final parameter in parameters) {
- if (!first) write(', ');
-
- if (!inOptionals && parameter.isOptional) {
- isNamed = parameter.isNamed;
- write(isNamed ? '{' : '[');
- inOptionals = true;
- }
-
- annotateType(enclosingType, parameter.type, parameter.simpleName);
-
- // Show the default value for named optional parameters.
- if (parameter.isOptional && parameter.hasDefaultValue) {
- write(isNamed ? ': ' : ' = ');
- write(parameter.defaultValue);
- }
-
- first = false;
- }
-
- if (inOptionals) {
- write(isNamed ? '}' : ']');
- }
- write(')');
- }
-
- void docComment(ContainerMirror host, DocComment comment) {
- if (comment != null) {
- var html = comment.html;
-
- if (comment.inheritedFrom != null) {
- writeln('<div class="inherited">');
- writeln(html);
- write('<div class="docs-inherited-from">docs inherited from ');
- annotateType(host, comment.inheritedFrom);
- write('</div>');
- writeln('</div>');
- } else {
- writeln(html);
- }
- }
- }
-
- /**
- * Documents the source code contained within [location].
- */
- void docCode(SourceLocation location) {
- if (includeSource) {
- writeln('<pre class="source">');
- writeln(md.escapeHtml(unindentCode(location)));
- writeln('</pre>');
- }
- }
-
- /** Get the doc comment associated with the given library. */
- DocComment getLibraryComment(LibraryMirror library) => getComment(library);
-
- /** Get the doc comment associated with the given type. */
- DocComment getTypeComment(TypeMirror type) => getComment(type);
-
- /**
- * Get the doc comment associated with the given member.
- *
- * If no comment was found on the member, the hierarchy is traversed to find
- * an inherited comment, favouring comments inherited from classes over
- * comments inherited from interfaces.
- */
- DocComment getMemberComment(MemberMirror member) => getComment(member);
-
- /**
- * Get the doc comment associated with the given declaration.
- *
- * If no comment was found on a member, the hierarchy is traversed to find
- * an inherited comment, favouring comments inherited from classes over
- * comments inherited from interfaces.
- */
- DocComment getComment(DeclarationMirror mirror) {
- String comment = computeComment(mirror);
- ClassMirror inheritedFrom = null;
- if (comment == null) {
- if (mirror.owner is ClassMirror) {
- var iterable =
- new HierarchyIterable(mirror.owner,
- includeType: false);
- for (ClassMirror type in iterable) {
- if (isFromPrivateDartLibrary(type)) continue;
- var inheritedMember = type.members[mirror.simpleName];
- if (inheritedMember is MemberMirror) {
- comment = computeComment(inheritedMember);
- if (comment != null) {
- inheritedFrom = type;
- break;
- }
- }
- }
- }
- }
- if (comment == null) return null;
- if (isMixinApplication(inheritedFrom)) {
- inheritedFrom = inheritedFrom.mixin;
- }
- return new DocComment(comment, inheritedFrom, dartdocSyntaxes,
- dartdocResolver);
- }
-
- /**
- * Converts [fullPath] which is understood to be a full path from the root of
- * the generated docs to one relative to the current file.
- */
- String relativePath(String fullPath) {
- // Don't make it relative if it's an absolute path.
- if (isAbsolute(fullPath)) return fullPath;
-
- // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do
- // this if the paths overlap.
- return '${repeat('../',
- countOccurrences(_filePath.toString(), '/'))}$fullPath';
- }
-
- /** Gets whether or not the given URL is absolute or relative. */
- bool isAbsolute(String url) {
- // TODO(rnystrom): Why don't we have a nice type in the platform for this?
- // TODO(rnystrom): This is a bit hackish. We consider any URL that lacks
- // a scheme to be relative.
- return new RegExp(r'^\w+:').hasMatch(url);
- }
-
- /** Gets the URL to the documentation for [library]. */
- String libraryUrl(LibraryMirror library) {
- return '${sanitize(displayName(library))}.html';
- }
-
- /**
- * Gets the URL for the documentation for [type] or `null` if there is no
- * link to the documentation of [type].
- */
- String typeUrl(ContainerMirror type) {
- var library = type is LibraryMirror ? type : _libraryFor(type);
- if (shouldLinkToPublicApi(library)) {
- return "$API_LOCATION${typePath(type)}";
- } else if (shouldIncludeLibrary(library)) {
- return typePath(type);
- } else {
- return null;
- }
- }
-
- /** Gets the relative path for the documentation for [type]. */
- String typePath(ContainerMirror type) {
- if (type is LibraryMirror) {
- return '${sanitize(type.simpleName)}.html';
- }
- if (type.library == null) {
- return '';
- }
- // Always get the generic type to strip off any type parameters or
- // arguments. If the type isn't generic, genericType returns `this`, so it
- // works for non-generic types too.
- return '${sanitize(displayName(_libraryFor(type)))}/'
- '${type.originalDeclaration.simpleName}.html';
- }
-
- /** Gets the URL for the documentation for [member]. */
- String memberUrl(MemberMirror member) {
- String url = typeUrl(_ownerFor(member));
- return url != null ? '$url#${memberAnchor(member)}' : null;
- }
-
- /** Gets the anchor id for the document for [member]. */
- String memberAnchor(MemberMirror member) {
- return member.simpleName;
- }
-
- /**
- * Creates a hyperlink. Handles turning the [href] into an appropriate
- * relative path from the current file. If [href] is `null`, [contents] is
- * not embedded in an anchor tag, and thus no link is created.
- */
- String a(String href, String contents, [String css]) {
- if (href != null) {
- // Mark outgoing external links, mainly so we can style them.
- final rel = isAbsolute(href) ? ' ref="external"' : '';
- final cssClass = css == null ? '' : ' class="$css"';
- return '<a href="${relativePath(href)}"$cssClass$rel>$contents</a>';
- }
- return contents;
- }
-
- /**
- * Writes a type annotation, preferring to print dynamic.
- */
- annotateDynamicType(ContainerMirror enclosingType,
- TypeMirror type) {
- annotateType(enclosingType, type, type.isDynamic ? 'dynamic ' : null);
- }
-
- /**
- * Writes a type annotation for the given type and (optional) parameter name.
- */
- annotateType(ContainerMirror enclosingType,
- TypeMirror type,
- [String paramName = null]) {
- // Don't bother explicitly displaying dynamic.
- if (type.isDynamic) {
- if (paramName != null) write(paramName);
- return;
- }
-
- // For parameters, handle non-typedefed function types.
- if (paramName != null && type is FunctionTypeMirror) {
- annotateType(enclosingType, type.returnType);
- write(paramName);
-
- docParamList(enclosingType, type.parameters);
- return;
- }
-
- linkToType(enclosingType, type);
-
- write(' ');
- if (paramName != null) write(paramName);
- }
-
- /** Writes a link to a human-friendly string representation for a type. */
- linkToType(ContainerMirror enclosingType, TypeMirror type) {
- if (type.isVoid) {
- // Do not generate links for void.
- // TODO(johnniwinter): Generate span for specific style?
- write('void');
- return;
- }
- if (type.isDynamic) {
- // Do not generate links for dynamic.
- write('dynamic');
- return;
- }
-
- if (type.isTypeVariable) {
- // If we're using a type parameter within the body of a generic class then
- // just link back up to the class.
- write(a(typeUrl(enclosingType), type.simpleName));
- return;
- }
-
- assert(type is ClassMirror);
-
- // Link to the type.
- write(a(typeUrl(type), type.simpleName));
-
- if (type.isOriginalDeclaration) {
- // Avoid calling [:typeArguments():] on a declaration.
- return;
- }
-
- // See if it's an instantiation of a generic type.
- final typeArgs = type.typeArguments;
- if (typeArgs.length > 0) {
- write('<');
- bool first = true;
- for (final arg in typeArgs) {
- if (!first) write(', ');
- first = false;
- linkToType(enclosingType, arg);
- }
- write('>');
- }
- }
-
- /** Creates a linked cross reference to [type]. */
- typeReference(ClassMirror type) {
- // TODO(rnystrom): Do we need to handle ParameterTypes here like
- // annotation() does?
- return a(typeUrl(type), typeName(type), 'crossref');
- }
-
- /** Generates a human-friendly string representation for a type. */
- typeName(TypeMirror type, {bool showBounds: false}) {
- if (type.isVoid) {
- return 'void';
- }
- if (type.isDynamic) {
- return 'dynamic';
- }
- if (type is TypeVariableMirror) {
- return type.simpleName;
- }
- assert(type is ClassMirror);
-
- // See if it's a generic type.
- if (type.isOriginalDeclaration) {
- final typeParams = [];
- for (final typeParam in type.originalDeclaration.typeVariables) {
- if (showBounds &&
- (typeParam.upperBound != null) &&
- !typeParam.upperBound.isObject) {
- final bound = typeName(typeParam.upperBound, showBounds: true);
- typeParams.add('${typeParam.simpleName} extends $bound');
- } else {
- typeParams.add(typeParam.simpleName);
- }
- }
- if (typeParams.isEmpty) {
- return type.simpleName;
- }
- final params = typeParams.join(', ');
- return '${type.simpleName}<$params>';
- }
-
- // See if it's an instantiation of a generic type.
- final typeArgs = type.typeArguments;
- if (typeArgs.length > 0) {
- final args = typeArgs.map((arg) => typeName(arg)).join(', ');
- return '${type.originalDeclaration.simpleName}<$args>';
- }
-
- // Regular type.
- return type.simpleName;
- }
-
- /**
- * Remove leading indentation to line up with first line.
- */
- unindentCode(SourceLocation span) {
- final column = span.column;
- final lines = span.text.split('\n');
- // TODO(rnystrom): Dirty hack.
- for (var i = 1; i < lines.length; i++) {
- lines[i] = unindent(lines[i], column);
- }
-
- final code = lines.join('\n');
- return code;
- }
-
- /**
- * Takes a string of Dart code and turns it into sanitized HTML.
- */
- formatCode(SourceLocation span) {
- final code = unindentCode(span);
-
- // Syntax highlight.
- return classifySource(code);
- }
-
- /**
- * This will be called whenever a doc comment hits a `[name]` in square
- * brackets. It will try to figure out what the name refers to and link or
- * style it appropriately.
- */
- md.Node resolveNameReference(String name,
- {MemberMirror currentMember,
- ContainerMirror currentType,
- LibraryMirror currentLibrary}) {
- makeLink(String href) {
- if (href != null) {
- final anchor = new md.Element.text('a', name);
- anchor.attributes['href'] = relativePath(href);
- anchor.attributes['class'] = 'crossref';
- return anchor;
- } else {
- return new md.Element.text('code', name);
- }
- }
-
- DeclarationMirror declaration = currentMember;
- if (declaration == null) declaration = currentType;
- if (declaration == null) declaration = currentLibrary;
- if (declaration != null) {
- declaration = lookupQualifiedInScope(declaration, name);
- }
-
- if (declaration != null) {
- if (declaration is TypeVariableMirror) {
- return makeLink(typeUrl(declaration.owner));
- } if (declaration is TypeMirror) {
- return makeLink(typeUrl(declaration));
- } else if (declaration is MethodMirror) {
- return makeLink(memberUrl(declaration));
- }
- }
-
- // See if it's a parameter of the current method.
- if (currentMember is MethodMirror) {
- for (final parameter in currentMember.parameters) {
- if (parameter.simpleName == name) {
- final element = new md.Element.text('span', name);
- element.attributes['class'] = 'param';
- return element;
- }
- }
- }
-
- // See if it's another member of the current type.
- if (currentType != null) {
- final foundMember = currentType.members[name];
- if (foundMember != null) {
- return makeLink(memberUrl(foundMember));
- }
- }
-
- // See if it's another type or a member of another type in the current
- // library.
- if (currentLibrary != null) {
- // See if it's a constructor
- final constructorLink = (() {
- final match =
- new RegExp(r'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name);
- if (match == null) return;
- String typeName = match[1];
- ClassMirror foundtype = currentLibrary.classes[typeName];
- if (foundtype == null) return;
- String constructorName =
- (match[2] == null) ? typeName : '$typeName.${match[2]}';
- final constructor =
- foundtype.constructors[constructorName];
- if (constructor == null) return;
- return makeLink(memberUrl(constructor));
- })();
- if (constructorLink != null) return constructorLink;
-
- // See if it's a member of another type
- final foreignMemberLink = (() {
- final match = new RegExp(r'([\w$]+)\.([\w$]+)').firstMatch(name);
- if (match == null) return;
- ClassMirror foundtype = currentLibrary.classes[match[1]];
- if (foundtype == null) return;
- MemberMirror foundMember = foundtype.members[match[2]];
- if (foundMember == null) return;
- return makeLink(memberUrl(foundMember));
- })();
- if (foreignMemberLink != null) return foreignMemberLink;
-
- ClassMirror foundType = currentLibrary.classes[name];
- if (foundType != null) {
- return makeLink(typeUrl(foundType));
- }
-
- // See if it's a top-level member in the current library.
- MemberMirror foundMember = currentLibrary.members[name];
- if (foundMember != null) {
- return makeLink(memberUrl(foundMember));
- }
- }
-
- // TODO(rnystrom): Should also consider:
- // * Names imported by libraries this library imports.
- // * Type parameters of the enclosing type.
-
- return new md.Element.text('code', name);
- }
-
- generateAppCacheManifest() {
- if (verbose) {
- print('Generating app cache manifest from output $outputDir');
- }
- startFile('appcache.manifest');
- write("CACHE MANIFEST\n\n");
- write("# VERSION: ${new DateTime.now()}\n\n");
- write("NETWORK:\n*\n\n");
- write("CACHE:\n");
- var toCache = new Directory(outputDir);
- toCache.list(recursive: true).listen(
- (FileSystemEntity entity) {
- if (entity is File) {
- var filename = entity.path;
- if (filename.endsWith('appcache.manifest')) {
- return;
- }
- String relativeFilePath = path.relative(filename, from: outputDir);
- write("$relativeFilePath\n");
- }
- },
- onDone: () => endFile());
- }
-
- /**
- * Returns [:true:] if [type] should be regarded as an exception.
- */
- bool isException(TypeMirror type) {
- return type.simpleName.endsWith('Exception') ||
- type.simpleName.endsWith('Error');
- }
-
- /**
- * Returns the absolute path to [library] on the filesystem, or `null` if the
- * library doesn't exist on the local filesystem.
- */
- String _libraryPath(LibraryMirror library) =>
- importUriToPath(library.uri, packageRoot: _packageRoot);
-
- /**
- * Returns a list of classes in [library], including classes it exports from
- * hidden libraries.
- */
- List<ClassMirror> _libraryClasses(LibraryMirror library) =>
- _libraryContents(library, (lib) => lib.classes.values);
-
- /**
- * Returns a list of top-level members in [library], including members it
- * exports from hidden libraries.
- */
- List<MemberMirror> _libraryMembers(LibraryMirror library) =>
- _libraryContents(library, (lib) => lib.members.values);
-
-
- /**
- * Returns a list of elements in [library], including elements it exports from
- * hidden libraries. [fn] should return the element list for a single library,
- * which will then be merged across all exported libraries.
- */
- List<DeclarationMirror> _libraryContents(LibraryMirror library,
- List<DeclarationMirror> fn(LibraryMirror)) {
- var contents = fn(library).toList();
- var exports = _exports.exports[library];
- if (exports == null) return contents;
-
- contents.addAll(exports.expand((export) {
- var exportedLibrary = export.exported;
- if (shouldIncludeLibrary(exportedLibrary)) return [];
- return fn(exportedLibrary).where((declaration) =>
- export.isMemberVisible(displayName(declaration)));
- }));
- return contents;
- }
-
- /**
- * Returns the library in which [type] was defined. If [type] was defined in a
- * hidden library that was exported by another library, this returns the
- * exporter.
- */
- LibraryMirror _libraryFor(TypeMirror type) =>
- _visibleLibrary(type.library, displayName(type));
-
- /**
- * Returns the owner of [declaration]. If [declaration]'s owner is a hidden
- * library that was exported by another library, this returns the exporter.
- */
- DeclarationMirror _ownerFor(DeclarationMirror declaration) {
- var owner = declaration.owner;
- if (owner is! LibraryMirror) return owner;
- return _visibleLibrary(owner, displayName(declaration));
- }
-
- /**
- * Returns the best visible library that exports [name] from [library]. If
- * [library] is public, it will be returned.
- */
- LibraryMirror _visibleLibrary(LibraryMirror library, String name) {
- if (library == null) return null;
-
- var exports = _hiddenLibraryExports[library];
- if (exports == null) return library;
-
- var export = exports.firstWhere(
- (exp) => exp.isMemberVisible(name),
- orElse: () => null);
- if (export == null) return library;
- return export.exporter;
- }
-}
-
-/**
- * Used to report an unexpected error in the DartDoc tool or the
- * underlying data
- */
-class InternalError {
- final String message;
- const InternalError(this.message);
- String toString() => "InternalError: '$message'";
-}
-
-/**
- * Computes the doc comment for the declaration mirror.
- *
- * Multiple comments are concatenated with newlines in between.
- */
-String computeComment(DeclarationMirror mirror) {
- String text;
- for (InstanceMirror metadata in mirror.metadata) {
- if (metadata is CommentInstanceMirror) {
- CommentInstanceMirror comment = metadata;
- if (comment.isDocComment) {
- if (text == null) {
- text = comment.trimmedText;
- } else {
- text = '$text\n${comment.trimmedText}';
- }
- }
- }
- }
- return text;
-}
-
-/**
- * Computes the doc comment for the declaration mirror as a list.
- */
-List<String> computeUntrimmedCommentAsList(DeclarationMirror mirror) {
- var text = <String>[];
- for (InstanceMirror metadata in mirror.metadata) {
- if (metadata is CommentInstanceMirror) {
- CommentInstanceMirror comment = metadata;
- if (comment.isDocComment) {
- text.add(comment.text);
- }
- }
- }
- return text;
-}
-
-class DocComment {
- final String text;
- md.Resolver dartdocResolver;
- List<md.InlineSyntax> dartdocSyntaxes;
-
- /**
- * Non-null if the comment is inherited from another declaration.
- */
- final ClassMirror inheritedFrom;
-
- DocComment(this.text, [this.inheritedFrom = null, this.dartdocSyntaxes,
- this.dartdocResolver]) {
- assert(text != null && !text.trim().isEmpty);
- }
-
- String toString() => text;
-
- String get html {
- return md.markdownToHtml(text,
- inlineSyntaxes: dartdocSyntaxes,
- linkResolver: dartdocResolver);
- }
-}
-
-class MdnComment implements DocComment {
- final String mdnComment;
- final String mdnUrl;
-
- MdnComment(String this.mdnComment, String this.mdnUrl);
-
- String get text => mdnComment;
-
- ClassMirror get inheritedFrom => null;
-
- String get html {
- // Wrap the mdn comment so we can highlight it and so we handle MDN scraped
- // content that lacks a top-level block tag.
- return '''
- <div class="mdn">
- $mdnComment
- <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
- </div>
- ''';
- }
-
- String toString() => mdnComment;
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/markdown.dart b/sdk/lib/_internal/dartdoc/lib/markdown.dart
deleted file mode 100644
index 01de970..0000000
--- a/sdk/lib/_internal/dartdoc/lib/markdown.dart
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/// Parses text in a markdown-like format and renders to HTML.
-library markdown;
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-part 'src/markdown/ast.dart';
-part 'src/markdown/block_parser.dart';
-part 'src/markdown/html_renderer.dart';
-part 'src/markdown/inline_parser.dart';
-
-typedef Node Resolver(String name);
-
-/// Converts the given string of markdown to HTML.
-String markdownToHtml(String markdown, {inlineSyntaxes, linkResolver}) {
- final document = new Document(inlineSyntaxes: inlineSyntaxes,
- linkResolver: linkResolver);
-
- // Replace windows line endings with unix line endings, and split.
- final lines = markdown.replaceAll('\r\n','\n').split('\n');
- document.parseRefLinks(lines);
- final blocks = document.parseLines(lines);
- return renderToHtml(blocks);
-}
-
-/// Replaces `<`, `&`, and `>`, with their HTML entity equivalents.
-String escapeHtml(String html) {
- return html.replaceAll('&', '&')
- .replaceAll('<', '<')
- .replaceAll('>', '>');
-}
-
-/// Maintains the context needed to parse a markdown document.
-class Document {
- final Map<String, Link> refLinks;
- List<InlineSyntax> inlineSyntaxes;
- Resolver linkResolver;
-
- Document({this.inlineSyntaxes, this.linkResolver})
- : refLinks = <String, Link>{};
-
- parseRefLinks(List<String> lines) {
- // This is a hideous regex. It matches:
- // [id]: http:foo.com "some title"
- // Where there may whitespace in there, and where the title may be in
- // single quotes, double quotes, or parentheses.
- final indent = r'^[ ]{0,3}'; // Leading indentation.
- final id = r'\[([^\]]+)\]'; // Reference id in [brackets].
- final quote = r'"[^"]+"'; // Title in "double quotes".
- final apos = r"'[^']+'"; // Title in 'single quotes'.
- final paren = r"\([^)]+\)"; // Title in (parentheses).
- final pattern = new RegExp(
- '$indent$id:\\s+(\\S+)\\s*($quote|$apos|$paren|)\\s*\$');
-
- for (int i = 0; i < lines.length; i++) {
- final match = pattern.firstMatch(lines[i]);
- if (match != null) {
- // Parse the link.
- var id = match[1];
- var url = match[2];
- var title = match[3];
-
- if (title == '') {
- // No title.
- title = null;
- } else {
- // Remove "", '', or ().
- title = title.substring(1, title.length - 1);
- }
-
- // References are case-insensitive.
- id = id.toLowerCase();
-
- refLinks[id] = new Link(id, url, title);
-
- // Remove it from the output. We replace it with a blank line which will
- // get consumed by later processing.
- lines[i] = '';
- }
- }
- }
-
- /// Parse the given [lines] of markdown to a series of AST nodes.
- List<Node> parseLines(List<String> lines) {
- final parser = new BlockParser(lines, this);
-
- final blocks = [];
- while (!parser.isDone) {
- for (final syntax in BlockSyntax.syntaxes) {
- if (syntax.canParse(parser)) {
- final block = syntax.parse(parser);
- if (block != null) blocks.add(block);
- break;
- }
- }
- }
-
- return blocks;
- }
-
- /// Takes a string of raw text and processes all inline markdown tags,
- /// returning a list of AST nodes. For example, given ``"*this **is** a*
- /// `markdown`"``, returns:
- /// `<em>this <strong>is</strong> a</em> <code>markdown</code>`.
- List<Node> parseInline(String text) => new InlineParser(text, this).parse();
-}
-
-class Link {
- final String id;
- final String url;
- final String title;
- Link(this.id, this.url, this.title);
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
deleted file mode 100644
index 958fcb1..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/** Provides client-side behavior for generated docs. */
-library client;
-
-import 'dart:html';
-import 'dart:convert';
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../../classify.dart';
-import '../../markdown.dart' as md;
-import '../dartdoc/nav.dart';
-import 'dropdown.dart';
-import 'search.dart';
-import 'client-shared.dart';
-
-main() {
- setup();
-
- // Request the navigation data so we can build the HTML for it.
- HttpRequest.getString('${prefix}nav.json').then((text) {
- var json = JSON.decode(text);
- buildNavigation(json);
- setupSearch(json);
- });
-}
-
-
-/**
- * Takes [libraries], a JSON array representing a set of libraries and builds
- * the appropriate navigation DOM for it relative to the current library and
- * type.
- */
-buildNavigation(List libraries) {
- final html = new StringBuffer();
- for (Map libraryInfo in libraries) {
- String libraryName = libraryInfo[NAME];
- html.write('<h2><div class="icon-library"></div>');
- if (currentLibrary == libraryName && currentType == null) {
- html.write('<strong>${md.escapeHtml(libraryName)}</strong>');
- } else {
- final url = getLibraryUrl(libraryName);
- html.write('<a href="$url">${md.escapeHtml(libraryName)}</a>');
- }
- html.write('</h2>');
-
- // Only list the types for the current library.
- if (currentLibrary == libraryName && libraryInfo.containsKey(TYPES)) {
- buildLibraryNavigation(html, libraryInfo);
- }
- }
-
- // Insert it into the DOM.
- final navElement = document.query('.nav');
- navElement.innerHtml = html.toString();
-}
-
-/** Writes the navigation for the types contained by [library] to [html]. */
-buildLibraryNavigation(StringBuffer html, Map libraryInfo) {
- // Show the exception types separately.
- final types = [];
- final exceptions = [];
-
- for (Map typeInfo in libraryInfo[TYPES]) {
- var name = typeInfo[NAME];
- if (name.endsWith('Exception') || name.endsWith('Error')) {
- exceptions.add(typeInfo);
- } else {
- types.add(typeInfo);
- }
- }
-
- if (types.length == 0 && exceptions.length == 0) return;
-
- writeType(String icon, Map typeInfo) {
- html.write('<li>');
- if (currentType == typeInfo[NAME]) {
- html.write(
- '<div class="icon-$icon"></div><strong>${getTypeName(typeInfo)}</strong>');
- } else {
- html.write(
- '''
- <a href="${getTypeUrl(currentLibrary, typeInfo)}">
- <div class="icon-$icon"></div>${getTypeName(typeInfo)}
- </a>
- ''');
- }
- html.write('</li>');
- }
-
- html.write('<ul class="icon">');
- types.forEach((typeInfo) =>
- writeType(kindToString(typeInfo[KIND]), typeInfo));
- exceptions.forEach((typeInfo) => writeType('exception', typeInfo));
- html.write('</ul>');
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
deleted file mode 100644
index d6e8daa..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2012, 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 client_shared;
-
-import 'dart:html';
-import 'dropdown.dart';
-import '../../classify.dart';
-import '../dartdoc/nav.dart';
-
-
-// Code shared between the different client-side libraries.
-
-// The names of the library and type that this page documents.
-String currentLibrary = null;
-String currentType = null;
-
-// What we need to prefix relative URLs with to get them to work.
-String prefix = '';
-
-void setup() {
- setupLocation();
- setupShortcuts();
- enableCodeBlocks();
- enableShowHideInherited();
-}
-
-void setupLocation() {
- // Figure out where we are.
- final body = document.query('body');
- currentLibrary = body.dataset['library'];
- currentType = body.dataset['type'];
- prefix = (currentType != null) ? '../' : '';
-}
-
-/**
- * Finds all code blocks and makes them toggleable. Syntax highlights each
- * code block the first time it's shown.
- */
-enableCodeBlocks() {
- for (var elem in document.queryAll('.method, .field')) {
- var showCode = elem.query('.show-code');
-
- // Skip it if we don't have a code link. Will happen if source code is
- // disabled.
- if (showCode == null) continue;
-
- var preList = elem.queryAll('pre.source');
-
- showCode.onClick.listen((e) {
- for (final pre in preList) {
- if (pre.classes.contains('expanded')) {
- pre.classes.remove('expanded');
- } else {
- // Syntax highlight.
- if (!pre.classes.contains('formatted')) {
- pre.innerHtml = classifySource(pre.text);
- pre.classes.add('formatted');
- };
- pre.classes.add('expanded');
- }
- }
- });
- }
-}
-
-/**
- * Enables show/hide functionality for inherited members and comments.
- */
-void enableShowHideInherited() {
- var showInherited = document.query('#show-inherited');
- if (showInherited == null) return;
- showInherited.dataset.putIfAbsent('show-inherited', () => 'block');
- showInherited.onClick.listen((e) {
- String display = showInherited.dataset['show-inherited'];
- if (display == 'block') {
- display = 'none';
- showInherited.innerHtml = 'Show inherited';
- } else {
- display = 'block';
- showInherited.innerHtml = 'Hide inherited';
- }
- showInherited.dataset['show-inherited'] = display;
- for (var elem in document.queryAll('.inherited')) {
- elem.style.display = display;
- }
- });
-
-}
-
-/** Turns [name] into something that's safe to use as a file name. */
-String sanitize(String name) => name.replaceAll(':', '_').replaceAll('/', '_');
-
-String getTypeName(Map typeInfo) =>
- typeInfo.containsKey('args')
- ? '${typeInfo[NAME]}<${typeInfo[NAME]}>'
- : typeInfo[NAME];
-
-String getLibraryUrl(String libraryName) =>
- '$prefix${sanitize(libraryName)}.html';
-
-String getTypeUrl(String libraryName, Map typeInfo) =>
- '$prefix${sanitize(libraryName)}/${sanitize(typeInfo[NAME])}.html';
-
-String getLibraryMemberUrl(String libraryName, Map memberInfo) =>
- '$prefix${sanitize(libraryName)}.html#${getMemberAnchor(memberInfo)}';
-
-String getTypeMemberUrl(String libraryName, String typeName, Map memberInfo) =>
- '$prefix${sanitize(libraryName)}/${sanitize(typeName)}.html#'
- '${getMemberAnchor(memberInfo)}';
-
-String getMemberAnchor(Map memberInfo) => memberInfo.containsKey(LINK_NAME)
- ? memberInfo[LINK_NAME] : memberInfo[NAME];
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart b/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
deleted file mode 100644
index 8101f5d..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright (c) 2012, 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 dropdown;
-
-import 'dart:html';
-import 'search.dart';
-import 'client-shared.dart';
-import '../dartdoc/nav.dart';
-
-List libraryList;
-InputElement searchInput;
-DivElement dropdown;
-
-/**
- * Update the search drop down based on the current search text.
- */
-updateDropDown(Event event) {
- if (libraryList == null) return;
- if (searchInput == null) return;
- if (dropdown == null) return;
-
- var results = <Result>[];
- String text = searchInput.value;
- if (text == currentSearchText) {
- return;
- }
- if (text.isEmpty) {
- updateResults(text, results);
- hideDropDown();
- return;
- }
- if (text.contains('.')) {
- // Search type members.
- String typeText = text.substring(0, text.indexOf('.'));
- String memberText = text.substring(text.indexOf('.') + 1);
-
- if (typeText.isEmpty && memberText.isEmpty) {
- // Don't search on '.'.
- } else if (typeText.isEmpty) {
- // Search text is of the form '.id' => Look up members.
- matchAllMembers(results, memberText);
- } else if (memberText.isEmpty) {
- // Search text is of the form 'Type.' => Look up members in 'Type'.
- matchAllMembersInType(results, typeText, memberText);
- } else {
- // Search text is of the form 'Type.id' => Look up member 'id' in 'Type'.
- matchMembersInType(results, text, typeText, memberText);
- }
- } else {
- // Search all entities.
- var searchText = new SearchText(text);
- for (Map<String,dynamic> library in libraryList) {
- matchLibrary(results, searchText, library);
- matchLibraryMembers(results, searchText, library);
- matchTypes(results, searchText, library);
- }
- }
- var elements = <Element>[];
- var table = new TableElement();
- table.classes.add('drop-down-table');
- elements.add(table);
-
- if (results.isEmpty) {
- var row = table.insertRow(0);
- row.innerHtml = "<tr><td>No matches found for '$text'.</td></tr>";
- } else {
- results.sort(resultComparator);
-
- var count = 0;
- for (Result result in results) {
- result.addRow(table);
- if (++count >= 10) {
- break;
- }
- }
- if (results.length >= 10) {
- var row = table.insertRow(table.rows.length);
- row.innerHtml = '<tr><td>+ ${results.length-10} more.</td></tr>';
- results = results.sublist(0, 10);
- }
- }
- dropdown.children = elements;
- updateResults(text, results);
- showDropDown();
-}
-
-void matchAllMembers(List<Result> results, String memberText) {
- var searchText = new SearchText(memberText);
- for (Map<String,dynamic> library in libraryList) {
- String libraryName = library[NAME];
- if (library.containsKey(TYPES)) {
- for (Map<String,dynamic> type in library[TYPES]) {
- String typeName = type[NAME];
- if (type.containsKey(MEMBERS)) {
- for (Map<String,dynamic> member in type[MEMBERS]) {
- StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
- if (memberMatch != null) {
- results.add(new Result(memberMatch, member[KIND],
- getTypeMemberUrl(libraryName, typeName, member),
- library: libraryName, type: typeName, args: type[ARGS],
- noargs: member[NO_PARAMS]));
- }
- }
- }
- }
- }
- }
-}
-
-void matchAllMembersInType(List<Result> results,
- String typeText, String memberText) {
- var searchText = new SearchText(typeText);
- var emptyText = new SearchText(memberText);
- for (Map<String,dynamic> library in libraryList) {
- String libraryName = library[NAME];
- if (library.containsKey(TYPES)) {
- for (Map<String,dynamic> type in library[TYPES]) {
- String typeName = type[NAME];
- StringMatch typeMatch = obtainMatch(searchText, typeName);
- if (typeMatch != null) {
- if (type.containsKey(MEMBERS)) {
- for (Map<String,dynamic> member in type[MEMBERS]) {
- StringMatch memberMatch = obtainMatch(emptyText,
- member[NAME]);
- results.add(new Result(memberMatch, member[KIND],
- getTypeMemberUrl(libraryName, typeName, member),
- library: libraryName, prefix: typeMatch,
- noargs: member[NO_PARAMS]));
- }
- }
- }
- }
- }
- }
-}
-
-void matchMembersInType(List<Result> results,
- String text, String typeText, String memberText) {
- var searchText = new SearchText(text);
- var typeSearchText = new SearchText(typeText);
- var memberSearchText = new SearchText(memberText);
- for (Map<String,dynamic> library in libraryList) {
- String libraryName = library[NAME];
- if (library.containsKey(TYPES)) {
- for (Map<String,dynamic> type in library[TYPES]) {
- String typeName = type[NAME];
- StringMatch typeMatch = obtainMatch(typeSearchText, typeName);
- if (typeMatch != null) {
- if (type.containsKey(MEMBERS)) {
- for (Map<String,dynamic> member in type[MEMBERS]) {
- // Check for constructor match.
- StringMatch constructorMatch = obtainMatch(searchText,
- member[NAME]);
- if (constructorMatch != null) {
- results.add(new Result(constructorMatch, member[KIND],
- getTypeMemberUrl(libraryName, typeName, member),
- library: libraryName, noargs: member[NO_PARAMS]));
- } else {
- // Try member match.
- StringMatch memberMatch = obtainMatch(memberSearchText,
- member[NAME]);
- if (memberMatch != null) {
- results.add(new Result(memberMatch, member[KIND],
- getTypeMemberUrl(libraryName, typeName, member),
- library: libraryName, prefix: typeMatch,
- args: type[ARGS], noargs: member[NO_PARAMS]));
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-void matchLibrary(List<Result> results, SearchText searchText, Map library) {
- String libraryName = library[NAME];
- StringMatch libraryMatch = obtainMatch(searchText, libraryName);
- if (libraryMatch != null) {
- results.add(new Result(libraryMatch, LIBRARY,
- getLibraryUrl(libraryName)));
- }
-}
-
-void matchLibraryMembers(List<Result> results, SearchText searchText,
- Map library) {
- if (library.containsKey(MEMBERS)) {
- String libraryName = library[NAME];
- for (Map<String,dynamic> member in library[MEMBERS]) {
- StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
- if (memberMatch != null) {
- results.add(new Result(memberMatch, member[KIND],
- getLibraryMemberUrl(libraryName, member),
- library: libraryName, noargs: member[NO_PARAMS]));
- }
- }
- }
-}
-
-void matchTypes(List<Result> results, SearchText searchText,
- Map library) {
- if (library.containsKey(TYPES)) {
- String libraryName = library[NAME];
- for (Map<String,dynamic> type in library[TYPES]) {
- String typeName = type[NAME];
- matchType(results, searchText, libraryName, type);
- matchTypeMembers(results, searchText, libraryName, type);
- }
- }
-}
-
-void matchType(List<Result> results, SearchText searchText,
- String libraryName, Map type) {
- String typeName = type[NAME];
- StringMatch typeMatch = obtainMatch(searchText, typeName);
- if (typeMatch != null) {
- results.add(new Result(typeMatch, type[KIND],
- getTypeUrl(libraryName, type),
- library: libraryName, args: type[ARGS]));
- }
-}
-
-void matchTypeMembers(List<Result> results, SearchText searchText,
- String libraryName, Map type) {
- if (type.containsKey(MEMBERS)) {
- String typeName = type[NAME];
- for (Map<String,dynamic> member in type[MEMBERS]) {
- StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
- if (memberMatch != null) {
- results.add(new Result(memberMatch, member[KIND],
- getTypeMemberUrl(libraryName, typeName, member),
- library: libraryName, type: typeName, args: type[ARGS],
- noargs: member[NO_PARAMS]));
- }
- }
- }
-}
-
-String currentSearchText;
-Result _currentResult;
-List<Result> currentResults = const <Result>[];
-
-void updateResults(String searchText, List<Result> results) {
- currentSearchText = searchText;
- currentResults = results;
- if (currentResults.isEmpty) {
- _currentResultIndex = -1;
- currentResult = null;
- } else {
- _currentResultIndex = 0;
- currentResult = currentResults[0];
- }
-}
-
-int _currentResultIndex;
-
-void set currentResultIndex(int index) {
- if (index < -1) {
- return;
- }
- if (index >= currentResults.length) {
- return;
- }
- if (index != _currentResultIndex) {
- _currentResultIndex = index;
- if (index >= 0) {
- currentResult = currentResults[_currentResultIndex];
- } else {
- currentResult = null;
- }
- }
-}
-
-int get currentResultIndex => _currentResultIndex;
-
-void set currentResult(Result result) {
- if (_currentResult != result) {
- if (_currentResult != null) {
- _currentResult.row.classes.remove('drop-down-link-select');
- }
- _currentResult = result;
- if (_currentResult != null) {
- _currentResult.row.classes.add('drop-down-link-select');
- }
- }
-}
-
-Result get currentResult => _currentResult;
-
-/**
- * Navigate the search drop down using up/down inside the search field. Follow
- * the result link on enter.
- */
-void handleUpDown(KeyboardEvent event) {
- if (event.keyCode == KeyCode.UP) {
- currentResultIndex--;
- event.preventDefault();
- } else if (event.keyCode == KeyCode.DOWN) {
- currentResultIndex++;
- event.preventDefault();
- } else if (event.keyCode == KeyCode.ENTER) {
- if (currentResult != null) {
- window.location.href = currentResult.url;
- event.preventDefault();
- hideDropDown();
- }
- }
-}
-
-/** Show the search drop down unless there are no current results. */
-void showDropDown() {
- if (currentResults.isEmpty) {
- hideDropDown();
- } else {
- dropdown.style.visibility = 'visible';
- }
-}
-
-/** Used to prevent hiding the drop down when it is clicked. */
-bool hideDropDownSuspend = false;
-
-/** Hide the search drop down unless suspended. */
-void hideDropDown() {
- if (hideDropDownSuspend) return;
-
- dropdown.style.visibility = 'hidden';
-}
-
-/** Activate search on Ctrl+3 and S. */
-void shortcutHandler(KeyboardEvent event) {
- if (event.keyCode == KeyCode.THREE && event.ctrlKey) {
- searchInput.focus();
- event.preventDefault();
- } else if (event.target != searchInput && event.keyCode == KeyCode.S) {
- // Allow writing 's' in the search input.
- searchInput.focus();
- event.preventDefault();
- }
-}
-
-/**
- * Setup window shortcuts.
- */
-void setupShortcuts() {
- window.onKeyDown.listen(shortcutHandler);
-}
-
-/** Setup search hooks. */
-void setupSearch(var libraries) {
- libraryList = libraries;
- searchInput = query('#q');
- dropdown = query('#drop-down');
-
- searchInput.onKeyDown.listen(handleUpDown);
- searchInput.onKeyUp.listen(updateDropDown);
- searchInput.onChange.listen(updateDropDown);
- searchInput.onReset.listen(updateDropDown);
- searchInput.onFocus.listen((event) => showDropDown());
- searchInput.onBlur.listen((event) => hideDropDown());
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart b/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
deleted file mode 100644
index ee5f922..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright (c) 2012, 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 search;
-
-import 'dart:html';
-import 'dropdown.dart';
-import '../dartdoc/nav.dart';
-
-/**
- * [SearchText] represent the search field text. The text is viewed in three
- * ways: [text] holds the original search text, used for performing
- * case-sensitive matches, [lowerCase] holds the lower-case search text, used
- * for performing case-insenstive matches, [camelCase] holds a camel-case
- * interpretation of the search text, used to order matches in camel-case.
- */
-class SearchText {
- final String text;
- final String lowerCase;
- final String camelCase;
-
- SearchText(String searchText)
- : text = searchText,
- lowerCase = searchText.toLowerCase(),
- camelCase = searchText.isEmpty ? ''
- : '${searchText.substring(0, 1).toUpperCase()}'
- '${searchText.substring(1)}';
-
- int get length => text.length;
-
- bool get isEmpty => length == 0;
-}
-
-/**
- * [StringMatch] represents the case-insensitive matching of [searchText] as a
- * substring within a [text].
- */
-class StringMatch {
- final SearchText searchText;
- final String text;
- final int matchOffset;
- final int matchEnd;
-
- StringMatch(this.searchText,
- this.text, this.matchOffset, this.matchEnd);
-
- /**
- * Returns the HTML representation of the match.
- */
- String toHtml() {
- return '${text.substring(0, matchOffset)}'
- '<span class="drop-down-link-highlight">$matchText</span>'
- '${text.substring(matchEnd)}';
- }
-
- String get matchText =>
- text.substring(matchOffset, matchEnd);
-
- /**
- * Is [:true:] iff [searchText] matches the full [text] case-sensitively.
- */
- bool get isFullMatch => text == searchText.text;
-
- /**
- * Is [:true:] iff [searchText] matches a substring of [text]
- * case-sensitively.
- */
- bool get isExactMatch => matchText == searchText.text;
-
- /**
- * Is [:true:] iff [searchText] matches a substring of [text] when
- * [searchText] is interpreted as camel case.
- */
- bool get isCamelCaseMatch => matchText == searchText.camelCase;
-}
-
-/**
- * [Result] represents a match of the search text on a library, type or member.
- */
-class Result {
- final StringMatch prefix;
- final StringMatch match;
-
- final String library;
- final String type;
- final String args;
- final String kind;
- final String url;
- final bool noargs;
-
- TableRowElement row;
-
- Result(this.match, this.kind, this.url,
- {this.library: null, this.type: null, String args: null,
- this.prefix: null, this.noargs: false})
- : this.args = args != null ? '<$args>' : '';
-
- bool get isTopLevel => prefix == null && type == null;
-
- void addRow(TableElement table) {
- if (row != null) return;
-
- clickHandler(Event event) {
- window.location.href = url;
- hideDropDown();
- }
-
- row = table.insertRow(table.rows.length);
- row.classes.add('drop-down-link-tr');
- row.onMouseDown.listen((event) => hideDropDownSuspend = true);
- row.onClick.listen(clickHandler);
- row.onMouseUp.listen((event) => hideDropDownSuspend = false);
- var sb = new StringBuffer();
- sb.write('<td class="drop-down-link-td">');
- sb.write('<table class="drop-down-table"><tr><td colspan="2">');
- if (kind == GETTER) {
- sb.write('get ');
- } else if (kind == SETTER) {
- sb.write('set ');
- }
- sb.write(match.toHtml());
- if (kind == CLASS || kind == TYPEDEF) {
- sb.write(args);
- } else if (kind == CONSTRUCTOR || kind == METHOD) {
- if (noargs) {
- sb.write("()");
- } else {
- sb.write('(...)');
- }
- }
- sb.write('</td></tr><tr><td class="drop-down-link-kind">');
- sb.write(kindToString(kind));
- if (prefix != null) {
- sb.write(' in ');
- sb.write(prefix.toHtml());
- sb.write(args);
- } else if (type != null) {
- sb.write(' in ');
- sb.write(type);
- sb.write(args);
- }
-
- sb.write('</td><td class="drop-down-link-library">');
- if (library != null) {
- sb.write('library $library');
- }
- sb.write('</td></tr></table></td>');
- row.innerHtml = sb.toString();
- }
-}
-
-/**
- * Creates a [StringMatch] object for [text] if a substring matches
- * [searchText], or returns [: null :] if no match is found.
- */
-StringMatch obtainMatch(SearchText searchText, String text) {
- if (searchText.isEmpty) {
- return new StringMatch(searchText, text, 0, 0);
- }
- int offset = text.toLowerCase().indexOf(searchText.lowerCase);
- if (offset != -1) {
- return new StringMatch(searchText, text,
- offset, offset + searchText.length);
- }
- return null;
-}
-
-/**
- * Compares [a] and [b], regarding [:true:] smaller than [:false:].
- *
- * [:null:]-values are not handled.
- */
-int compareBools(bool a, bool b) {
- if (a == b) return 0;
- return a ? -1 : 1;
-}
-
-/**
- * Used to sort the search results heuristically to show the more relevant match
- * in the top of the dropdown.
- */
-int resultComparator(Result a, Result b) {
- // Favor top level entities.
- int result = compareBools(a.isTopLevel, b.isTopLevel);
- if (result != 0) return result;
-
- if (a.prefix != null && b.prefix != null) {
- // Favor full prefix matches.
- result = compareBools(a.prefix.isFullMatch, b.prefix.isFullMatch);
- if (result != 0) return result;
- }
-
- // Favor matches in the start.
- result = compareBools(a.match.matchOffset == 0,
- b.match.matchOffset == 0);
- if (result != 0) return result;
-
- // Favor matches to the end. For example, prefer 'cancel' over 'cancelable'
- result = compareBools(a.match.matchEnd == a.match.text.length,
- b.match.matchEnd == b.match.text.length);
- if (result != 0) return result;
-
- // Favor exact case-sensitive matches.
- result = compareBools(a.match.isExactMatch, b.match.isExactMatch);
- if (result != 0) return result;
-
- // Favor matches that do not break camel-case.
- result = compareBools(a.match.isCamelCaseMatch, b.match.isCamelCaseMatch);
- if (result != 0) return result;
-
- // Favor matches close to the begining.
- result = a.match.matchOffset.compareTo(b.match.matchOffset);
- if (result != 0) return result;
-
- if (a.type != null && b.type != null) {
- // Favor short type names over long.
- result = a.type.length.compareTo(b.type.length);
- if (result != 0) return result;
-
- // Sort type alphabetically.
- // TODO(4805): Use [:type.compareToIgnoreCase] when supported.
- result = a.type.toLowerCase().compareTo(b.type.toLowerCase());
- if (result != 0) return result;
- }
-
- // Sort match alphabetically.
- // TODO(4805): Use [:text.compareToIgnoreCase] when supported.
- return a.match.text.toLowerCase().compareTo(b.match.text.toLowerCase());
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart b/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart
deleted file mode 100644
index 7ee8828..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2012, 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 dart2js_util;
-
-import 'dart:async' show Future;
-import 'dart:io' show Path;
-
-import '../../../compiler/compiler.dart' as api;
-import '../../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js
- show analyze, Dart2JsMirrorSystem;
-import '../../../compiler/implementation/mirrors/mirrors.dart'
- show MirrorSystem;
-import '../../../compiler/implementation/source_file_provider.dart'
- show FormattingDiagnosticHandler, SourceFileProvider,
- CompilerSourceFileProvider;
-import '../../../compiler/implementation/filenames.dart'
- show appendSlash, currentDirectory;
-
-// TODO(johnniwinther): Support client configurable providers.
-
-/**
- * Returns a future that completes to a non-null String when [script]
- * has been successfully compiled.
- */
-// TODO(amouravski): Remove this method and call dart2js via a process instead.
-Future<String> compile(String script,
- String libraryRoot,
- {String packageRoot,
- List<String> options: const <String>[],
- api.DiagnosticHandler diagnosticHandler}) {
- SourceFileProvider provider = new CompilerSourceFileProvider();
- if (diagnosticHandler == null) {
- diagnosticHandler =
- new FormattingDiagnosticHandler(provider).diagnosticHandler;
- }
- Uri scriptUri = currentDirectory.resolve(script.toString());
- Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
- Uri packageUri = null;
- if (packageRoot != null) {
- packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
- }
- return api.compile(scriptUri, libraryUri, packageUri,
- provider.readStringFromUri, diagnosticHandler, options);
-}
-
-/**
- * Analyzes set of libraries and provides a mirror system which can be used for
- * static inspection of the source code.
- */
-Future<MirrorSystem> analyze(List<String> libraries,
- String libraryRoot,
- {String packageRoot,
- List<String> options: const <String>[],
- api.DiagnosticHandler diagnosticHandler}) {
- SourceFileProvider provider = new CompilerSourceFileProvider();
- if (diagnosticHandler == null) {
- diagnosticHandler =
- new FormattingDiagnosticHandler(provider).diagnosticHandler;
- }
- Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
- Uri packageUri = null;
- if (packageRoot != null) {
- packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
- }
- List<Uri> librariesUri = <Uri>[];
- for (String library in libraries) {
- librariesUri.add(currentDirectory.resolve(library));
- }
- return dart2js.analyze(librariesUri, libraryUri, packageUri,
- provider.readStringFromUri, diagnosticHandler,
- options);
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/nav.dart b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/nav.dart
deleted file mode 100644
index 3948f8e..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/nav.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2012, 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 dartdoc_nav;
-
-/*
- * Constant values used for encoding navigation info.
- *
- * The generated JSON data is a list of LibraryInfo maps, defined as follows:
- *
- * LibraryInfo = {
- * String NAME, // Library name.
- * List<TypeInfo> TYPES, // Library types.
- * List<MemberInfo> MEMBERS, // Library functions and variables.
- * };
- * TypeInfo = {
- * String NAME, // Type name.
- * String ARGS, // Type variables, e.g. "<K,V>". Optional.
- * String KIND, // One of CLASS or TYPEDEF.
- * List<MemberInfo> MEMBERS, // Type fields and methods.
- * };
- * MemberInfo = {
- * String NAME, // Member name.
- * String KIND, // One of FIELD, CONSTRUCTOR, METHOD, GETTER, or SETTER.
- * String LINK_NAME, // Anchor name for the member if different from
- * // NAME.
- * bool NO_PARAMS, // Is true if member takes no arguments?
- * };
- *
- *
- * TODO(johnniwinther): Shorten the string values to reduce JSON output size.
- */
-
-const String LIBRARY = 'library';
-const String CLASS = 'class';
-const String TYPEDEF = 'typedef';
-const String MEMBERS = 'members';
-const String TYPES = 'types';
-const String ARGS = 'args';
-const String NAME = 'name';
-const String KIND = 'kind';
-const String FIELD = 'field';
-const String CONSTRUCTOR = 'constructor';
-const String METHOD = 'method';
-const String NO_PARAMS = 'noparams';
-const String GETTER = 'getter';
-const String SETTER = 'setter';
-const String LINK_NAME = 'link_name';
-
-/**
- * Translation of const values to strings. Used to facilitate shortening of
- * constant value strings.
- */
-String kindToString(String kind) {
- if (kind == LIBRARY) {
- return 'library';
- } else if (kind == CLASS) {
- return 'class';
- } else if (kind == TYPEDEF) {
- return 'typedef';
- } else if (kind == FIELD) {
- return 'field';
- } else if (kind == CONSTRUCTOR) {
- return 'constructor';
- } else if (kind == METHOD) {
- return 'method';
- } else if (kind == GETTER) {
- return 'getter';
- } else if (kind == SETTER) {
- return 'setter';
- }
- return '';
-}
\ No newline at end of file
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart
deleted file mode 100644
index 3f876b6..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2013, 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.
-
-// Generic utility functions.
-library utils;
-
-import 'dart:io';
-import 'dart:math' as math;
-
-import 'package:path/path.dart' as pathos;
-
-import '../../../../compiler/implementation/mirrors/mirrors.dart';
-
-import '../export_map.dart';
-
-/** Turns [name] into something that's safe to use as a file name. */
-String sanitize(String name) => name.replaceAll(':', '_').replaceAll('/', '_');
-
-/** Returns the number of times [search] occurs in [text]. */
-int countOccurrences(String text, String search) {
- int start = 0;
- int count = 0;
-
- while (true) {
- start = text.indexOf(search, start);
- if (start == -1) break;
- count++;
- // Offsetting by search length means overlapping results are not counted.
- start += search.length;
- }
-
- return count;
-}
-
-/** Repeats [text] [count] times, separated by [separator] if given. */
-String repeat(String text, int count, {String separator}) {
- // TODO(rnystrom): Should be in corelib.
- final buffer = new StringBuffer();
- for (int i = 0; i < count; i++) {
- buffer.write(text);
- if ((i < count - 1) && (separator != null)) buffer.write(separator);
- }
-
- return buffer.toString();
-}
-
-/** Removes up to [indentation] leading whitespace characters from [text]. */
-String unindent(String text, int indentation) {
- var start;
- for (start = 0; start < math.min(indentation, text.length); start++) {
- // Stop if we hit a non-whitespace character.
- if (text[start] != ' ') break;
- }
-
- return text.substring(start);
-}
-
-/** Sorts the map by the key, doing a case-insensitive comparison. */
-List<Mirror> orderByName(Iterable<Mirror> list) {
- final elements = new List<Mirror>.from(list);
- elements.sort((a,b) {
- String aName = a.simpleName.toLowerCase();
- String bName = b.simpleName.toLowerCase();
- bool doma = aName.startsWith(r"$dom");
- bool domb = bName.startsWith(r"$dom");
- return doma == domb ? aName.compareTo(bName) : doma ? 1 : -1;
- });
- return elements;
-}
-
-/**
- * Joins [items] into a single, comma-separated string using [conjunction].
- * E.g. `['A', 'B', 'C']` becomes `"A, B, and C"`.
- */
-String joinWithCommas(List<String> items, [String conjunction = 'and']) {
- if (items.length == 1) return items[0];
- if (items.length == 2) return "${items[0]} $conjunction ${items[1]}";
- return '${items.take(items.length - 1).join(', ')}'
- ', $conjunction ${items[items.length - 1]}';
-}
-
-void writeString(File file, String text) {
- var randomAccessFile = file.openSync(mode: FileMode.WRITE);
- randomAccessFile.writeStringSync(text);
- randomAccessFile.closeSync();
-}
-
-/**
- * Converts [uri], which should come from a Dart import or export, to a local
- * filesystem path. [basePath] is the base directory to use when converting
- * relative URIs; without it, relative URIs will not be converted. [packageRoot]
- * is the `packages` directory to use when converting `package:` URIs; without
- * it, `package:` URIs will not be converted.
- *
- * If a URI cannot be converted, this will return `null`.
- */
-String importUriToPath(Uri uri, {String basePath, String packageRoot}) {
- if (uri.scheme == 'file') return pathos.fromUri(uri);
-
- if (basePath != null && uri.scheme == '') {
- return pathos.normalize(pathos.absolute(pathos.join(basePath, uri.path)));
- }
-
- if (packageRoot != null && uri.scheme == 'package') {
- return pathos.normalize(pathos.absolute(
- pathos.join(packageRoot, uri.path)));
- }
-
- // Ignore unsupported schemes.
- return null;
-}
-
-/**
- * If [map] contains an [Export] under [key], this merges that with [export].
- * Otherwise, it sets [key] to [export].
- */
-void addOrMergeExport(Map<LibraryMirror, Export> map,
- LibraryMirror key, Export export) {
- if (map.containsKey(key)) {
- map[key] = map[key].merge(export);
- } else {
- map[key] = export;
- }
-}
-
-/// A pair of values.
-class Pair<E, F> {
- E first;
- F last;
-
- Pair(this.first, this.last);
-
- String toString() => '($first, $last)';
-
- bool operator==(other) {
- if (other is! Pair) return false;
- return other.first == first && other.last == last;
- }
-
- int get hashCode => first.hashCode ^ last.hashCode;
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/export_map.dart b/sdk/lib/_internal/dartdoc/lib/src/export_map.dart
deleted file mode 100644
index 09f894c..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/export_map.dart
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright (c) 2013, 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.
-
-/// This library uses the Dart analyzer to find the exports for a set of
-/// libraries. It stores these exports in an [ExportMap]. This is used to
-/// display exported members as part of the exporting library, since dart2js
-/// doesn't provide this information itself.
-library export_map;
-
-import '../../../compiler/implementation/mirrors/mirrors.dart';
-import '../../../compiler/implementation/mirrors/mirrors_util.dart';
-
-/// A class that tracks which libraries export which other libraries.
-class ExportMap {
- /// A map from libraries to their [Export]s.
- ///
- /// Each key is a library and each value is a list of [Export]s for that
- /// library. There's guaranteed to be only one [Export] of a given library
- /// in a given list.
- final Map<LibraryMirror, List<Export>> exports = {};
-
- /// A cache of the transitive exports for each library. The values are maps
- /// from the exported libraries to the [Export] objects, to make it easier to
- /// merge multiple exports of the same library.
- Map<LibraryMirror, Map<LibraryMirror, Export>> _transitiveExports = {};
-
- ExportMap(MirrorSystem mirrors) {
- mirrors.libraries.values.where((lib) => !_isDartLibrary(lib))
- .forEach(_computeExports);
- }
-
- bool _isDartLibrary(LibraryMirror lib) => lib.uri.scheme == 'dart';
-
- /// Compute all non-dart: exports in [library].
- void _computeExports(LibraryMirror library) {
- var exportMap = {};
- library.libraryDependencies
- .where((mirror) =>
- mirror.isExport && !_isDartLibrary(mirror.targetLibrary))
- .map((mirror) => new Export.fromMirror(mirror))
- .forEach((export) {
- var target = export.exported;
- if (exportMap.containsKey(target)) {
- exportMap[target] = exportMap[target].merge(export);
- } else {
- exportMap[target] = export;
- }
- });
- exports[library] = exportMap.values.toList();
- }
-
- /// Returns a list of all exports that [library] transitively exports. This
- /// means that if [library] exports another library that in turn exports a
- /// third, the third library will be included in the returned list.
- ///
- /// This will automatically handle nested `hide` and `show` directives on the
- /// exports, as well as merging multiple exports of the same library.
- List<Export> transitiveExports(LibraryMirror library) {
- Map<LibraryMirror, Export> _getTransitiveExports(LibraryMirror library) {
- if (_transitiveExports.containsKey(library)) {
- return _transitiveExports[library];
- }
-
- var exportsByPath = <LibraryMirror, Export>{};
- _transitiveExports[library] = exportsByPath;
- if (exports[library] == null) return exportsByPath;
-
- for (var export in exports[library]) {
- exportsByPath[export.exported] = export;
- }
-
- for (var export in exports[library]) {
- for (var subExport in _getTransitiveExports(export.exported).values) {
- subExport = export.compose(subExport);
- if (exportsByPath.containsKey(subExport.exported)) {
- subExport = subExport.merge(exportsByPath[subExport.exported]);
- }
- exportsByPath[subExport.exported] = subExport;
- }
- }
- return exportsByPath;
- }
-
- return _getTransitiveExports(library).values.toList();
- }
-}
-
-/// A class that represents one library exporting another.
-class Export {
- /// The library that contains this export.
- final LibraryMirror exporter;
-
- /// The library being exported.
- final LibraryMirror exported;
-
- /// The set of identifiers that are explicitly being exported. If this is
- /// non-empty, no identifiers other than these will be visible.
- ///
- /// One or both of [show] and [hide] will always be empty.
- Set<String> get show => _show;
- Set<String> _show;
-
- /// The set of identifiers that are not exported.
- ///
- /// One or both of [show] and [hide] will always be empty.
- Set<String> get hide => _hide;
- Set<String> _hide;
-
- /// Whether or not members exported are hidden by default.
- bool get _hideByDefault => !show.isEmpty;
-
- /// Creates a new export.
- ///
- /// This will normalize [show] and [hide] so that if both are non-empty, only
- /// [show] will be set.
- factory Export.fromMirror(LibraryDependencyMirror mirror) {
- var show = <String>[];
- var hide = <String>[];
- for (var combinator in mirror.combinators) {
- if (combinator.isShow) {
- show.addAll(combinator.identifiers);
- }
- if (combinator.isHide) {
- hide.addAll(combinator.identifiers);
- }
- }
- return new Export(
- mirror.sourceLibrary, mirror.targetLibrary, show: show, hide: hide);
- }
-
- Export(this.exporter, this.exported,
- {Iterable<String> show, Iterable<String> hide}) {
- _show = new Set<String>.from(show == null ? [] : show);
- _hide = new Set<String>.from(hide == null ? [] : hide);
-
- if (!_show.isEmpty) {
- _show.removeAll(_hide);
- _hide = new Set<String>();
- }
- }
-
- /// Returns a new [Export] that represents [this] composed with [nested], as
- /// though [this] was used to export a library that in turn exported [nested].
- Export compose(Export nested) {
- var show = new Set<String>();
- var hide = new Set<String>();
-
- if (this._hideByDefault) {
- show.addAll(this.show);
- if (nested._hideByDefault) {
- show.retainAll(nested.show);
- } else {
- show.removeAll(nested.hide);
- }
- } else if (nested._hideByDefault) {
- show.addAll(nested.show);
- show.removeAll(this.hide);
- } else {
- hide.addAll(this.hide);
- hide.addAll(nested.hide);
- }
-
- return new Export(this.exporter, nested.exported, show: show, hide: hide);
- }
-
- /// Returns a new [Export] that merges [this] with [nested], as though both
- /// exports were included in the same library.
- ///
- /// [this] and [other] must have the same values for [exporter] and [path].
- Export merge(Export other) {
- if (this.exported != other.exported) {
- throw new ArgumentError("Can't merge two Exports with different paths: "
- "export '$exported' from '$exporter' and export '${other.exported}' "
- "from '${other.exporter}'.");
- } if (this.exporter != other.exporter) {
- throw new ArgumentError("Can't merge two Exports with different "
- "exporters: export '$exported' from '$exporter' and export "
- "'${other.exported}' from '${other.exporter}'.");
- }
-
- var show = new Set<String>();
- var hide = new Set<String>();
-
- if (this._hideByDefault) {
- if (other._hideByDefault) {
- show.addAll(this.show);
- show.addAll(other.show);
- } else {
- hide.addAll(other.hide);
- hide.removeAll(this.show);
- }
- } else {
- hide.addAll(this.hide);
- if (other._hideByDefault) {
- hide.removeAll(other.show);
- } else {
- hide.retainAll(other.hide);
- }
- }
-
- return new Export(exporter, exported, show: show, hide: hide);
- }
-
- /// Returns whether or not a member named [name] is visible through this
- /// import, as goverend by [show] and [hide].
- bool isMemberVisible(String name) =>
- _hideByDefault ? show.contains(name) : !hide.contains(name);
-
- bool operator==(other) => other is Export && other.exporter == exporter &&
- other.exported == exported && show.containsAll(other.show) &&
- other.show.containsAll(show) && hide.containsAll(other.hide) &&
- other.hide.containsAll(hide);
-
- int get hashCode {
- var hashCode = exporter.hashCode ^ exported.hashCode;
- combineHashCode(name) => hashCode ^= name.hashCode;
- show.forEach(combineHashCode);
- hide.forEach(combineHashCode);
- return hashCode;
- }
-
- String toString() {
- var combinator = '';
- if (!show.isEmpty) {
- combinator = ' show ${show.join(', ')}';
- } else if (!hide.isEmpty) {
- combinator = ' hide ${hide.join(', ')}';
- }
- return "export '${displayName(exported)}'"
- "$combinator (from ${displayName(exporter)})";
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart b/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart
deleted file mode 100755
index 67f4fb4..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/**
- * Simple library to serialize acyclic Dart types to JSON.
- * This library is not intended for broad consumption and should be replaced
- * with a more generic Dart serialization library when one is available.
- */
-library json_serializer;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:mirrors';
-
-String serialize(Object o) {
- var printer = new JsonPrinter();
- _serialize(null, o, printer);
- return printer.toString();
-}
-
-/// Serialize the object with pretty printing.
-String prettySerialize(Object o) {
- var printer = new JsonPrinter(prettyPrint: true);
- _serialize(null, o, printer);
- return printer.toString();
-}
-
-
-void _serialize(String name, Object o, JsonPrinter printer) {
- if (o == null) return;
-
- if (o is List) {
- _serializeList(name, o, printer);
- } else if (o is Map) {
- _serializeMap(name, o, printer);
- } else if (o is String) {
- printer.addString(name, o);
- } else if (o is bool) {
- printer.addBool(name, o);
- } else {
- _serializeObject(name, o, printer);
- }
-}
-
-void _serializeObject(String name, Object o, JsonPrinter printer) {
- printer.startObject(name);
-
- var mirror = reflect(o);
- var classMirror = mirror.type;
- var members = <String>[];
- determineAllMembers(classMirror, members);
-
- // TODO(jacobr): this code works only because futures for mirrors return
- // immediately.
- for(String memberName in members) {
- var result = mirror.getField(new Symbol(memberName));
- _serialize(memberName, result.reflectee, printer);
- }
- printer.endObject();
-}
-
-void determineAllMembers(ClassMirror classMirror,
- List<String> members) {
- for (var mirror in classMirror.declarations.values) {
- if (mirror is VariableMirror ||
- (mirror is MethodMirror && mirror.isGetter)) {
- if (!members.contains(MirrorSystem.getName(mirror.simpleName))) {
- members.add(MirrorSystem.getName(mirror.simpleName));
- }
- }
- }
- if (classMirror.superclass != null &&
-
- // TODO(ahe): What is this test for? Consider removing it,
- // dart2js will issue an error if there is a cycle in superclass
- // hierarchy.
- classMirror.superclass.qualifiedName != classMirror.qualifiedName &&
-
- MirrorSystem.getName(classMirror.superclass.qualifiedName) !=
- 'dart.core.Object') {
- determineAllMembers(classMirror.superclass, members);
- }
-}
-
-void _serializeList(String name, List l, JsonPrinter printer) {
- printer.startList(name);
- for(var o in l) {
- _serialize(null, o, printer);
- }
- printer.endList();
-}
-
-void _serializeMap(String name, Map m, JsonPrinter printer) {
- printer.startObject(name);
- m.forEach((key, value) =>
- _serialize(key, value, printer));
- printer.endObject();
-}
-
-class JsonPrinter {
- static const int BACKSPACE = 8;
- static const int TAB = 9;
- static const int NEW_LINE = 10;
- static const int FORM_FEED = 12;
- static const int CARRIAGE_RETURN = 13;
- static const int QUOTE = 34;
- static const int BACKSLASH = 92;
- static const int CHAR_B = 98;
- static const int CHAR_F = 102;
- static const int CHAR_N = 110;
- static const int CHAR_R = 114;
- static const int CHAR_T = 116;
- static const int CHAR_U = 117;
-
- StringBuffer _sb;
- int _indent = 0;
- bool _inSet = false;
-
- bool prettyPrint;
- JsonPrinter({this.prettyPrint: false}) {
- _sb = new StringBuffer();
- }
-
- void startObject(String name) {
- _start(name);
- _sb.write('{');
-
- _indent += 1;
- _inSet = false;
- }
-
- void endObject() {
- _indent -= 1;
- if (_inSet) {
- _newline();
- }
- _sb.write('}');
- _inSet = true;
- }
-
- void startList(String name) {
- _start(name);
- _inSet = false;
-
- _sb.write('[');
- _indent += 1;
- }
-
- void endList() {
- _indent -= 1;
- if (_inSet) {
- _newline();
- }
- _sb.write(']');
- _inSet = true;
- }
-
- void addString(String name, String value) {
- _start(name);
- _sb.write('"');
- _escape(_sb, value);
- _sb.write('"');
- _inSet = true;
- }
-
- void addBool(String name, bool value) {
- _start(name);
- _sb.write(value.toString());
- _inSet = true;
- }
-
- void addNum(String name, num value) {
- _start(name);
- _sb.write(value.toString());
- _inSet = true;
- }
-
- void _start(String name) {
- if (_inSet) {
- _sb.write(',');
- }
- // Do not print a newline at the beginning of the file.
- if (!_sb.isEmpty) {
- _newline();
- }
- if (name != null) {
- _sb.write('"$name": ');
- }
- }
-
- void _newline([int indent = 0]) {
- _sb.write('\n');
- _indent += indent;
-
- for (var i = 0; i < _indent; ++i) {
- _sb.write(' ');
- }
- }
-
- String toString() {
- if (prettyPrint) {
- return _sb.toString();
- } else {
- // Convenient hack to remove the pretty printing this serializer adds by
- // default.
- return JSON.encode(JSON.decode(_sb.toString()));
- }
- }
-
- static int _hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
-
- static void _escape(StringBuffer sb, String s) {
- final int length = s.length;
- bool needsEscape = false;
- final codeUnits = new List<int>();
- for (int i = 0; i < length; i++) {
- int codeUnit = s.codeUnitAt(i);
- if (codeUnit < 32) {
- needsEscape = true;
- codeUnits.add(JsonPrinter.BACKSLASH);
- switch (codeUnit) {
- case JsonPrinter.BACKSPACE:
- codeUnits.add(JsonPrinter.CHAR_B);
- break;
- case JsonPrinter.TAB:
- codeUnits.add(JsonPrinter.CHAR_T);
- break;
- case JsonPrinter.NEW_LINE:
- codeUnits.add(JsonPrinter.CHAR_N);
- break;
- case JsonPrinter.FORM_FEED:
- codeUnits.add(JsonPrinter.CHAR_F);
- break;
- case JsonPrinter.CARRIAGE_RETURN:
- codeUnits.add(JsonPrinter.CHAR_R);
- break;
- default:
- codeUnits.add(JsonPrinter.CHAR_U);
- codeUnits.add(_hexDigit((codeUnit >> 12) & 0xf));
- codeUnits.add(_hexDigit((codeUnit >> 8) & 0xf));
- codeUnits.add(_hexDigit((codeUnit >> 4) & 0xf));
- codeUnits.add(_hexDigit(codeUnit & 0xf));
- break;
- }
- } else if (codeUnit == JsonPrinter.QUOTE ||
- codeUnit == JsonPrinter.BACKSLASH) {
- needsEscape = true;
- codeUnits.add(JsonPrinter.BACKSLASH);
- codeUnits.add(codeUnit);
- } else {
- codeUnits.add(codeUnit);
- }
- }
- sb.write(needsEscape ? new String.fromCharCodes(codeUnits) : s);
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/ast.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/ast.dart
deleted file mode 100644
index c966cea..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/ast.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2012, 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.
-
-part of markdown;
-
-/// Base class for any AST item. Roughly corresponds to Node in the DOM. Will
-/// be either an Element or Text.
-abstract class Node {
- void accept(NodeVisitor visitor);
-}
-
-/// A named tag that can contain other nodes.
-class Element implements Node {
- final String tag;
- final List<Node> children;
- final Map<String, String> attributes;
-
- Element(this.tag, this.children)
- : attributes = <String, String>{};
-
- Element.empty(this.tag)
- : children = null,
- attributes = <String, String>{};
-
- Element.withTag(this.tag)
- : children = [],
- attributes = <String, String>{};
-
- Element.text(this.tag, String text)
- : children = [new Text(text)],
- attributes = <String, String>{};
-
- bool get isEmpty => children == null;
-
- void accept(NodeVisitor visitor) {
- if (visitor.visitElementBefore(this)) {
- for (final child in children) child.accept(visitor);
- visitor.visitElementAfter(this);
- }
- }
-}
-
-/// A plain text element.
-class Text implements Node {
- final String text;
- Text(this.text);
-
- void accept(NodeVisitor visitor) => visitor.visitText(this);
-}
-
-/// Visitor pattern for the AST. Renderers or other AST transformers should
-/// implement this.
-abstract class NodeVisitor {
- /// Called when a Text node has been reached.
- void visitText(Text text);
-
- /// Called when an Element has been reached, before its children have been
- /// visited. Return `false` to skip its children.
- bool visitElementBefore(Element element);
-
- /// Called when an Element has been reached, after its children have been
- /// visited. Will not be called if [visitElementBefore] returns `false`.
- void visitElementAfter(Element element);
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart
deleted file mode 100644
index bd14f36..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart
+++ /dev/null
@@ -1,463 +0,0 @@
-// Copyright (c) 2012, 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.
-
-part of markdown;
-
-/// The line contains only whitespace or is empty.
-final _RE_EMPTY = new RegExp(r'^([ \t]*)$');
-
-/// A series of `=` or `-` (on the next line) define setext-style headers.
-final _RE_SETEXT = new RegExp(r'^((=+)|(-+))$');
-
-/// Leading (and trailing) `#` define atx-style headers.
-final _RE_HEADER = new RegExp(r'^(#{1,6})(.*?)#*$');
-
-/// The line starts with `>` with one optional space after.
-final _RE_BLOCKQUOTE = new RegExp(r'^[ ]{0,3}>[ ]?(.*)$');
-
-/// A line indented four spaces. Used for code blocks and lists.
-final _RE_INDENT = new RegExp(r'^(?: |\t)(.*)$');
-
-/// Three or more hyphens, asterisks or underscores by themselves. Note that
-/// a line like `----` is valid as both HR and SETEXT. In case of a tie,
-/// SETEXT should win.
-final _RE_HR = new RegExp(r'^[ ]{0,3}((-+[ ]{0,2}){3,}|'
- r'(_+[ ]{0,2}){3,}|'
- r'(\*+[ ]{0,2}){3,})$');
-
-/// Really hacky way to detect block-level embedded HTML. Just looks for
-/// "<somename".
-final _RE_HTML = new RegExp(r'^<[ ]*\w+[ >]');
-
-/// A line starting with one of these markers: `-`, `*`, `+`. May have up to
-/// three leading spaces before the marker and any number of spaces or tabs
-/// after.
-final _RE_UL = new RegExp(r'^[ ]{0,3}[*+-][ \t]+(.*)$');
-
-/// A line starting with a number like `123.`. May have up to three leading
-/// spaces before the marker and any number of spaces or tabs after.
-final _RE_OL = new RegExp(r'^[ ]{0,3}\d+\.[ \t]+(.*)$');
-
-/// Maintains the internal state needed to parse a series of lines into blocks
-/// of markdown suitable for further inline parsing.
-class BlockParser {
- final List<String> lines;
-
- /// The markdown document this parser is parsing.
- final Document document;
-
- /// Index of the current line.
- int pos;
-
- BlockParser(this.lines, this.document)
- : pos = 0;
-
- /// Gets the current line.
- String get current => lines[pos];
-
- /// Gets the line after the current one or `null` if there is none.
- String get next {
- // Don't read past the end.
- if (pos >= lines.length - 1) return null;
- return lines[pos + 1];
- }
-
- void advance() {
- pos++;
- }
-
- bool get isDone => pos >= lines.length;
-
- /// Gets whether or not the current line matches the given pattern.
- bool matches(RegExp regex) {
- if (isDone) return false;
- return regex.firstMatch(current) != null;
- }
-
- /// Gets whether or not the current line matches the given pattern.
- bool matchesNext(RegExp regex) {
- if (next == null) return false;
- return regex.firstMatch(next) != null;
- }
-}
-
-abstract class BlockSyntax {
- /// Gets the collection of built-in block parsers. To turn a series of lines
- /// into blocks, each of these will be tried in turn. Order matters here.
- static List<BlockSyntax> get syntaxes {
- // Lazy initialize.
- if (_syntaxes == null) {
- _syntaxes = [
- new EmptyBlockSyntax(),
- new BlockHtmlSyntax(),
- new SetextHeaderSyntax(),
- new HeaderSyntax(),
- new CodeBlockSyntax(),
- new BlockquoteSyntax(),
- new HorizontalRuleSyntax(),
- new UnorderedListSyntax(),
- new OrderedListSyntax(),
- new ParagraphSyntax()
- ];
- }
-
- return _syntaxes;
- }
-
- static List<BlockSyntax> _syntaxes;
-
- /// Gets the regex used to identify the beginning of this block, if any.
- RegExp get pattern => null;
-
- bool get canEndBlock => true;
-
- bool canParse(BlockParser parser) {
- return pattern.firstMatch(parser.current) != null;
- }
-
- Node parse(BlockParser parser);
-
- List<String> parseChildLines(BlockParser parser) {
- // Grab all of the lines that form the blockquote, stripping off the ">".
- final childLines = <String>[];
-
- while (!parser.isDone) {
- final match = pattern.firstMatch(parser.current);
- if (match == null) break;
- childLines.add(match[1]);
- parser.advance();
- }
-
- return childLines;
- }
-
- /// Gets whether or not [parser]'s current line should end the previous block.
- static bool isAtBlockEnd(BlockParser parser) {
- if (parser.isDone) return true;
- return syntaxes.any((s) => s.canParse(parser) && s.canEndBlock);
- }
-}
-
-class EmptyBlockSyntax extends BlockSyntax {
- RegExp get pattern => _RE_EMPTY;
-
- Node parse(BlockParser parser) {
- parser.advance();
-
- // Don't actually emit anything.
- return null;
- }
-}
-
-/// Parses setext-style headers.
-class SetextHeaderSyntax extends BlockSyntax {
- bool canParse(BlockParser parser) {
- // Note: matches *next* line, not the current one. We're looking for the
- // underlining after this line.
- return parser.matchesNext(_RE_SETEXT);
- }
-
- Node parse(BlockParser parser) {
- final match = _RE_SETEXT.firstMatch(parser.next);
-
- final tag = (match[1][0] == '=') ? 'h1' : 'h2';
- final contents = parser.document.parseInline(parser.current);
- parser.advance();
- parser.advance();
-
- return new Element(tag, contents);
- }
-}
-
-/// Parses atx-style headers: `## Header ##`.
-class HeaderSyntax extends BlockSyntax {
- RegExp get pattern => _RE_HEADER;
-
- Node parse(BlockParser parser) {
- final match = pattern.firstMatch(parser.current);
- parser.advance();
- final level = match[1].length;
- final contents = parser.document.parseInline(match[2].trim());
- return new Element('h$level', contents);
- }
-}
-
-/// Parses email-style blockquotes: `> quote`.
-class BlockquoteSyntax extends BlockSyntax {
- RegExp get pattern => _RE_BLOCKQUOTE;
-
- Node parse(BlockParser parser) {
- final childLines = parseChildLines(parser);
-
- // Recursively parse the contents of the blockquote.
- final children = parser.document.parseLines(childLines);
-
- return new Element('blockquote', children);
- }
-}
-
-/// Parses preformatted code blocks that are indented four spaces.
-class CodeBlockSyntax extends BlockSyntax {
- RegExp get pattern => _RE_INDENT;
-
- List<String> parseChildLines(BlockParser parser) {
- final childLines = <String>[];
-
- while (!parser.isDone) {
- var match = pattern.firstMatch(parser.current);
- if (match != null) {
- childLines.add(match[1]);
- parser.advance();
- } else {
- // If there's a codeblock, then a newline, then a codeblock, keep the
- // code blocks together.
- var nextMatch = parser.next != null ?
- pattern.firstMatch(parser.next) : null;
- if (parser.current.trim() == '' && nextMatch != null) {
- childLines.add('');
- childLines.add(nextMatch[1]);
- parser.advance();
- parser.advance();
- } else {
- break;
- }
- }
- }
- return childLines;
- }
-
- Node parse(BlockParser parser) {
- final childLines = parseChildLines(parser);
-
- // The Markdown tests expect a trailing newline.
- childLines.add('');
-
- // Escape the code.
- final escaped = escapeHtml(childLines.join('\n'));
-
- return new Element('pre', [new Element.text('code', escaped)]);
- }
-}
-
-/// Parses horizontal rules like `---`, `_ _ _`, `* * *`, etc.
-class HorizontalRuleSyntax extends BlockSyntax {
- RegExp get pattern => _RE_HR;
-
- Node parse(BlockParser parser) {
- final match = pattern.firstMatch(parser.current);
- parser.advance();
- return new Element.empty('hr');
- }
-}
-
-/// Parses inline HTML at the block level. This differs from other markdown
-/// implementations in several ways:
-///
-/// 1. This one is way way WAY simpler.
-/// 2. All HTML tags at the block level will be treated as blocks. If you
-/// start a paragraph with `<em>`, it will not wrap it in a `<p>` for you.
-/// As soon as it sees something like HTML, it stops mucking with it until
-/// it hits the next block.
-/// 3. Absolutely no HTML parsing or validation is done. We're a markdown
-/// parser not an HTML parser!
-class BlockHtmlSyntax extends BlockSyntax {
- RegExp get pattern => _RE_HTML;
-
- bool get canEndBlock => false;
-
- Node parse(BlockParser parser) {
- final childLines = [];
-
- // Eat until we hit a blank line.
- while (!parser.isDone && !parser.matches(_RE_EMPTY)) {
- childLines.add(parser.current);
- parser.advance();
- }
-
- return new Text(childLines.join('\n'));
- }
-}
-
-class ListItem {
- bool forceBlock = false;
- final List<String> lines;
-
- ListItem(this.lines);
-}
-
-/// Base class for both ordered and unordered lists.
-abstract class ListSyntax extends BlockSyntax {
- bool get canEndBlock => false;
-
- String get listTag;
-
- Node parse(BlockParser parser) {
- final items = <ListItem>[];
- var childLines = <String>[];
-
- endItem() {
- if (childLines.length > 0) {
- items.add(new ListItem(childLines));
- childLines = <String>[];
- }
- }
-
- var match;
- tryMatch(RegExp pattern) {
- match = pattern.firstMatch(parser.current);
- return match != null;
- }
-
- bool afterEmpty = false;
- while (!parser.isDone) {
- if (tryMatch(_RE_EMPTY)) {
- // Add a blank line to the current list item.
- childLines.add('');
- } else if (tryMatch(_RE_UL) || tryMatch(_RE_OL)) {
- // End the current list item and start a new one.
- endItem();
- childLines.add(match[1]);
- } else if (tryMatch(_RE_INDENT)) {
- // Strip off indent and add to current item.
- childLines.add(match[1]);
- } else if (BlockSyntax.isAtBlockEnd(parser)) {
- // Done with the list.
- break;
- } else {
- // Anything else is paragraph text or other stuff that can be in a list
- // item. However, if the previous item is a blank line, this means we're
- // done with the list and are starting a new top-level paragraph.
- if ((childLines.length > 0) && (childLines.last == '')) break;
- childLines.add(parser.current);
- }
- parser.advance();
- }
-
- endItem();
-
- // Markdown, because it hates us, specifies two kinds of list items. If you
- // have a list like:
- //
- // * one
- // * two
- //
- // Then it will insert the conents of the lines directly in the <li>, like:
- // <ul>
- // <li>one</li>
- // <li>two</li>
- // <ul>
- //
- // If, however, there are blank lines between the items, each is wrapped in
- // paragraphs:
- //
- // * one
- //
- // * two
- //
- // <ul>
- // <li><p>one</p></li>
- // <li><p>two</p></li>
- // <ul>
- //
- // In other words, sometimes we parse the contents of a list item like a
- // block, and sometimes line an inline. The rules our parser implements are:
- //
- // - If it has more than one line, it's a block.
- // - If the line matches any block parser (BLOCKQUOTE, HEADER, HR, INDENT,
- // UL, OL) it's a block. (This is for cases like "* > quote".)
- // - If there was a blank line between this item and the previous one, it's
- // a block.
- // - If there was a blank line between this item and the next one, it's a
- // block.
- // - Otherwise, parse it as an inline.
-
- // Remove any trailing empty lines and note which items are separated by
- // empty lines. Do this before seeing which items are single-line so that
- // trailing empty lines on the last item don't force it into being a block.
- for (int i = 0; i < items.length; i++) {
- for (int j = items[i].lines.length - 1; j > 0; j--) {
- if (_RE_EMPTY.firstMatch(items[i].lines[j]) != null) {
- // Found an empty line. Item and one after it are blocks.
- if (i < items.length - 1) {
- items[i].forceBlock = true;
- items[i + 1].forceBlock = true;
- }
- items[i].lines.removeLast();
- } else {
- break;
- }
- }
- }
-
- // Convert the list items to Nodes.
- final itemNodes = <Node>[];
- for (final item in items) {
- bool blockItem = item.forceBlock || (item.lines.length > 1);
-
- // See if it matches some block parser.
- final blocksInList = [
- _RE_BLOCKQUOTE,
- _RE_HEADER,
- _RE_HR,
- _RE_INDENT,
- _RE_UL,
- _RE_OL
- ];
-
- if (!blockItem) {
- for (final pattern in blocksInList) {
- if (pattern.firstMatch(item.lines[0]) != null) {
- blockItem = true;
- break;
- }
- }
- }
-
- // Parse the item as a block or inline.
- if (blockItem) {
- // Block list item.
- final children = parser.document.parseLines(item.lines);
- itemNodes.add(new Element('li', children));
- } else {
- // Raw list item.
- final contents = parser.document.parseInline(item.lines[0]);
- itemNodes.add(new Element('li', contents));
- }
- }
-
- return new Element(listTag, itemNodes);
- }
-}
-
-/// Parses unordered lists.
-class UnorderedListSyntax extends ListSyntax {
- RegExp get pattern => _RE_UL;
- String get listTag => 'ul';
-}
-
-/// Parses ordered lists.
-class OrderedListSyntax extends ListSyntax {
- RegExp get pattern => _RE_OL;
- String get listTag => 'ol';
-}
-
-/// Parses paragraphs of regular text.
-class ParagraphSyntax extends BlockSyntax {
- bool get canEndBlock => false;
-
- bool canParse(BlockParser parser) => true;
-
- Node parse(BlockParser parser) {
- final childLines = [];
-
- // Eat until we hit something that ends a paragraph.
- while (!BlockSyntax.isAtBlockEnd(parser)) {
- childLines.add(parser.current);
- parser.advance();
- }
-
- final contents = parser.document.parseInline(childLines.join('\n'));
- return new Element('p', contents);
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart
deleted file mode 100644
index 5494394..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2012, 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.
-
-part of markdown;
-
-String renderToHtml(List<Node> nodes) => new HtmlRenderer().render(nodes);
-
-/// Translates a parsed AST to HTML.
-class HtmlRenderer implements NodeVisitor {
- static final _BLOCK_TAGS = new RegExp(
- 'blockquote|h1|h2|h3|h4|h5|h6|hr|p|pre');
-
- StringBuffer buffer;
-
- HtmlRenderer();
-
- String render(List<Node> nodes) {
- buffer = new StringBuffer();
-
- for (final node in nodes) node.accept(this);
-
- return buffer.toString();
- }
-
- void visitText(Text text) {
- buffer.write(text.text);
- }
-
- bool visitElementBefore(Element element) {
- // Hackish. Separate block-level elements with newlines.
- if (!buffer.isEmpty &&
- _BLOCK_TAGS.firstMatch(element.tag) != null) {
- buffer.write('\n');
- }
-
- buffer.write('<${element.tag}');
-
- // Sort the keys so that we generate stable output.
- // TODO(rnystrom): This assumes keys returns a fresh mutable
- // collection.
- final attributeNames = element.attributes.keys.toList();
- attributeNames.sort((a, b) => a.compareTo(b));
- for (final name in attributeNames) {
- buffer.write(' $name="${element.attributes[name]}"');
- }
-
- if (element.isEmpty) {
- // Empty element like <hr/>.
- buffer.write(' />');
- return false;
- } else {
- buffer.write('>');
- return true;
- }
- }
-
- void visitElementAfter(Element element) {
- buffer.write('</${element.tag}>');
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/inline_parser.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/inline_parser.dart
deleted file mode 100644
index d3ec7ae..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/inline_parser.dart
+++ /dev/null
@@ -1,419 +0,0 @@
-// Copyright (c) 2012, 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.
-
-part of markdown;
-
-/// Maintains the internal state needed to parse inline span elements in
-/// markdown.
-class InlineParser {
- static List<InlineSyntax> defaultSyntaxes = <InlineSyntax>[
- // This first regexp matches plain text to accelerate parsing. It must
- // be written so that it does not match any prefix of any following
- // syntax. Most markdown is plain text, so it is faster to match one
- // regexp per 'word' rather than fail to match all the following regexps
- // at each non-syntax character position. It is much more important
- // that the regexp is fast than complete (for example, adding grouping
- // is likely to slow the regexp down enough to negate its benefit).
- // Since it is purely for optimization, it can be removed for debugging.
-
- // TODO(amouravski): this regex will glom up any custom syntaxes unless
- // they're at the beginning.
- new TextSyntax(r'\s*[A-Za-z0-9]+'),
-
- // The real syntaxes.
-
- new AutolinkSyntax(),
- new LinkSyntax(),
- // "*" surrounded by spaces is left alone.
- new TextSyntax(r' \* '),
- // "_" surrounded by spaces is left alone.
- new TextSyntax(r' _ '),
- // Leave already-encoded HTML entities alone. Ensures we don't turn
- // "&" into "&amp;"
- new TextSyntax(r'&[#a-zA-Z0-9]*;'),
- // Encode "&".
- new TextSyntax(r'&', sub: '&'),
- // Encode "<". (Why not encode ">" too? Gruber is toying with us.)
- new TextSyntax(r'<', sub: '<'),
- // Parse "**strong**" tags.
- new TagSyntax(r'\*\*', tag: 'strong'),
- // Parse "__strong__" tags.
- new TagSyntax(r'__', tag: 'strong'),
- // Parse "*emphasis*" tags.
- new TagSyntax(r'\*', tag: 'em'),
- // Parse "_emphasis_" tags.
- // TODO(rnystrom): Underscores in the middle of a word should not be
- // parsed as emphasis like_in_this.
- new TagSyntax(r'_', tag: 'em'),
- // Parse inline code within double backticks: "``code``".
- new CodeSyntax(r'``\s?((?:.|\n)*?)\s?``'),
- // Parse inline code within backticks: "`code`".
- new CodeSyntax(r'`([^`]*)`')
- // We will add the LinkSyntax once we know about the specific link resolver.
- ];
-
- /// The string of markdown being parsed.
- final String source;
-
- /// The markdown document this parser is parsing.
- final Document document;
-
- List<InlineSyntax> syntaxes;
-
- /// The current read position.
- int pos = 0;
-
- /// Starting position of the last unconsumed text.
- int start = 0;
-
- final List<TagState> _stack;
-
- InlineParser(this.source, this.document)
- : _stack = <TagState>[] {
- /// User specified syntaxes will be the first syntaxes to be evaluated.
- if (document.inlineSyntaxes != null) {
- syntaxes = [];
- syntaxes.addAll(document.inlineSyntaxes);
- syntaxes.addAll(defaultSyntaxes);
- } else {
- syntaxes = defaultSyntaxes;
- }
- // Custom link resolver goes after the generic text syntax.
- syntaxes.insert(1, new LinkSyntax(linkResolver: document.linkResolver));
- }
-
- List<Node> parse() {
- // Make a fake top tag to hold the results.
- _stack.add(new TagState(0, 0, null));
-
- while (!isDone) {
- bool matched = false;
-
- // See if any of the current tags on the stack match. We don't allow tags
- // of the same kind to nest, so this takes priority over other possible // matches.
- for (int i = _stack.length - 1; i > 0; i--) {
- if (_stack[i].tryMatch(this)) {
- matched = true;
- break;
- }
- }
- if (matched) continue;
-
- // See if the current text matches any defined markdown syntax.
- for (final syntax in syntaxes) {
- if (syntax.tryMatch(this)) {
- matched = true;
- break;
- }
- }
- if (matched) continue;
-
- // If we got here, it's just text.
- advanceBy(1);
- }
-
- // Unwind any unmatched tags and get the results.
- return _stack[0].close(this, null);
- }
-
- writeText() {
- writeTextRange(start, pos);
- start = pos;
- }
-
- writeTextRange(int start, int end) {
- if (end > start) {
- final text = source.substring(start, end);
- final nodes = _stack.last.children;
-
- // If the previous node is text too, just append.
- if ((nodes.length > 0) && (nodes.last is Text)) {
- final newNode = new Text('${nodes.last.text}$text');
- nodes[nodes.length - 1] = newNode;
- } else {
- nodes.add(new Text(text));
- }
- }
- }
-
- addNode(Node node) {
- _stack.last.children.add(node);
- }
-
- // TODO(rnystrom): Only need this because RegExp doesn't let you start
- // searching from a given offset.
- String get currentSource => source.substring(pos, source.length);
-
- bool get isDone => pos == source.length;
-
- void advanceBy(int length) {
- pos += length;
- }
-
- void consume(int length) {
- pos += length;
- start = pos;
- }
-}
-
-/// Represents one kind of markdown tag that can be parsed.
-abstract class InlineSyntax {
- final RegExp pattern;
-
- InlineSyntax(String pattern)
- : pattern = new RegExp(pattern, multiLine: true);
-
- bool tryMatch(InlineParser parser) {
- final startMatch = pattern.firstMatch(parser.currentSource);
- if ((startMatch != null) && (startMatch.start == 0)) {
- // Write any existing plain text up to this point.
- parser.writeText();
-
- if (onMatch(parser, startMatch)) {
- parser.consume(startMatch[0].length);
- }
- return true;
- }
- return false;
- }
-
- bool onMatch(InlineParser parser, Match match);
-}
-
-/// Matches stuff that should just be passed through as straight text.
-class TextSyntax extends InlineSyntax {
- String substitute;
- TextSyntax(String pattern, {String sub})
- : super(pattern),
- substitute = sub;
-
- bool onMatch(InlineParser parser, Match match) {
- if (substitute == null) {
- // Just use the original matched text.
- parser.advanceBy(match[0].length);
- return false;
- }
-
- // Insert the substitution.
- parser.addNode(new Text(substitute));
- return true;
- }
-}
-
-/// Matches autolinks like `<http://foo.com>`.
-class AutolinkSyntax extends InlineSyntax {
- AutolinkSyntax()
- : super(r'<((http|https|ftp)://[^>]*)>');
- // TODO(rnystrom): Make case insensitive.
-
- bool onMatch(InlineParser parser, Match match) {
- final url = match[1];
-
- final anchor = new Element.text('a', escapeHtml(url));
- anchor.attributes['href'] = url;
- parser.addNode(anchor);
-
- return true;
- }
-}
-
-/// Matches syntax that has a pair of tags and becomes an element, like `*` for
-/// `<em>`. Allows nested tags.
-class TagSyntax extends InlineSyntax {
- final RegExp endPattern;
- final String tag;
-
- TagSyntax(String pattern, {String tag, String end})
- : super(pattern),
- endPattern = new RegExp((end != null) ? end : pattern, multiLine: true),
- tag = tag;
- // TODO(rnystrom): Doing this.field doesn't seem to work with named args.
-
- bool onMatch(InlineParser parser, Match match) {
- parser._stack.add(new TagState(parser.pos,
- parser.pos + match[0].length, this));
- return true;
- }
-
- bool onMatchEnd(InlineParser parser, Match match, TagState state) {
- parser.addNode(new Element(tag, state.children));
- return true;
- }
-}
-
-/// Matches inline links like `[blah] [id]` and `[blah] (url)`.
-class LinkSyntax extends TagSyntax {
- Resolver linkResolver;
-
- /// The regex for the end of a link needs to handle both reference style and
- /// inline styles as well as optional titles for inline links. To make that
- /// a bit more palatable, this breaks it into pieces.
- static get linkPattern {
- final refLink = r'\s?\[([^\]]*)\]'; // "[id]" reflink id.
- final title = r'(?:[ ]*"([^"]+)"|)'; // Optional title in quotes.
- final inlineLink = '\\s?\\(([^ )]+)$title\\)'; // "(url "title")" link.
- return '\](?:($refLink|$inlineLink)|)';
-
- // The groups matched by this are:
- // 1: Will be non-empty if it's either a ref or inline link. Will be empty
- // if it's just a bare pair of square brackets with nothing after them.
- // 2: Contains the id inside [] for a reference-style link.
- // 3: Contains the URL for an inline link.
- // 4: Contains the title, if present, for an inline link.
- }
-
- LinkSyntax({this.linkResolver})
- : super(r'\[', end: linkPattern);
-
- bool onMatchEnd(InlineParser parser, Match match, TagState state) {
- var url;
- var title;
-
- // If we didn't match refLink or inlineLink, then it means there was
- // nothing after the first square bracket, so it isn't a normal markdown
- // link at all. Instead, we allow users of the library to specify a special
- // resolver function ([linkResolver]) that may choose to handle
- // this. Otherwise, it's just treated as plain text.
- if ((match[1] == null) || (match[1] == '')) {
- if (linkResolver == null) return false;
-
- // Only allow implicit links if the content is just text.
- // TODO(rnystrom): Do we want to relax this?
- if (state.children.length != 1) return false;
- if (state.children[0] is! Text) return false;
-
- Text link = state.children[0];
-
- // See if we have a resolver that will generate a link for us.
- final node = linkResolver(link.text);
- if (node == null) return false;
-
- parser.addNode(node);
- return true;
- }
-
- if ((match[3] != null) && (match[3] != '')) {
- // Inline link like [foo](url).
- url = match[3];
- title = match[4];
-
- // For whatever reason, markdown allows angle-bracketed URLs here.
- if (url.startsWith('<') && url.endsWith('>')) {
- url = url.substring(1, url.length - 1);
- }
- } else {
- // Reference link like [foo] [bar].
- var id = match[2];
- if (id == '') {
- // The id is empty ("[]") so infer it from the contents.
- id = parser.source.substring(state.startPos + 1, parser.pos);
- }
-
- // References are case-insensitive.
- id = id.toLowerCase();
-
- // Look up the link.
- final link = parser.document.refLinks[id];
- // If it's an unknown link just emit plaintext.
- if (link == null) return false;
-
- url = link.url;
- title = link.title;
- }
-
- final anchor = new Element('a', state.children);
- anchor.attributes['href'] = escapeHtml(url);
- if ((title != null) && (title != '')) {
- anchor.attributes['title'] = escapeHtml(title);
- }
-
- parser.addNode(anchor);
- return true;
- }
-}
-
-/// Matches backtick-enclosed inline code blocks.
-class CodeSyntax extends InlineSyntax {
- CodeSyntax(String pattern)
- : super(pattern);
-
- bool onMatch(InlineParser parser, Match match) {
- parser.addNode(new Element.text('code', escapeHtml(match[1])));
- return true;
- }
-}
-
-/// Keeps track of a currently open tag while it is being parsed. The parser
-/// maintains a stack of these so it can handle nested tags.
-class TagState {
- /// The point in the original source where this tag started.
- int startPos;
-
- /// The point in the original source where open tag ended.
- int endPos;
-
- /// The syntax that created this node.
- final TagSyntax syntax;
-
- /// The children of this node. Will be `null` for text nodes.
- final List<Node> children;
-
- TagState(this.startPos, this.endPos, this.syntax)
- : children = <Node>[];
-
- /// Attempts to close this tag by matching the current text against its end
- /// pattern.
- bool tryMatch(InlineParser parser) {
- Match endMatch = syntax.endPattern.firstMatch(parser.currentSource);
- if ((endMatch != null) && (endMatch.start == 0)) {
- // Close the tag.
- close(parser, endMatch);
- return true;
- }
-
- return false;
- }
-
- /// Pops this tag off the stack, completes it, and adds it to the output.
- /// Will discard any unmatched tags that happen to be above it on the stack.
- /// If this is the last node in the stack, returns its children.
- List<Node> close(InlineParser parser, Match endMatch) {
- // If there are unclosed tags on top of this one when it's closed, that
- // means they are mismatched. Mismatched tags are treated as plain text in
- // markdown. So for each tag above this one, we write its start tag as text
- // and then adds its children to this one's children.
- int index = parser._stack.indexOf(this);
-
- // Remove the unmatched children.
- final unmatchedTags = parser._stack.sublist(index + 1);
- parser._stack.removeRange(index + 1, parser._stack.length);
-
- // Flatten them out onto this tag.
- for (final unmatched in unmatchedTags) {
- // Write the start tag as text.
- parser.writeTextRange(unmatched.startPos, unmatched.endPos);
-
- // Bequeath its children unto this tag.
- children.addAll(unmatched.children);
- }
-
- // Pop this off the stack.
- parser.writeText();
- parser._stack.removeLast();
-
- // If the stack is empty now, this is the special "results" node.
- if (parser._stack.length == 0) return children;
-
- // We are still parsing, so add this to its parent's children.
- if (syntax.onMatchEnd(parser, endMatch, this)) {
- parser.consume(endMatch[0].length);
- } else {
- // Didn't close correctly so revert to text.
- parser.start = startPos;
- parser.advanceBy(endMatch[0].length);
- }
-
- return null;
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart b/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
deleted file mode 100755
index ba57411..0000000
--- a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
+++ /dev/null
@@ -1,532 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/**
- * This library serializes the Dart2Js AST into a compact and easy to use
- * [Element] tree useful for code exploration tools such as DartDoc.
- */
-library universe_serializer;
-
-import 'dartdoc.dart';
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'package:path/path.dart' as path;
-import '../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js;
-import '../../compiler/implementation/mirrors/mirrors.dart';
-import '../../compiler/implementation/mirrors/mirrors_util.dart';
-import '../../libraries.dart';
-
-String _stripUri(String uri) {
- String prefix = "/dart/";
- int start = uri.indexOf(prefix);
- if (start != -1) {
- return uri.substring(start + prefix.length);
- } else {
- return uri;
- }
-}
-
-String _escapeId(String id) {
- return id.replaceAll(new RegExp('[/]'), '#slash');
-}
-
-/**
- * Base class for all elements in the AST.
- */
-class Element {
- /** Human readable type name for the node. */
- final String kind;
- /** Human readable name for the element. */
- final String name;
- /** Id for the node that is unique within its parent's children. */
- final String id;
- /** Raw text of the comment associated with the Element if any. */
- final String comment;
- /** Raw html comment for the Element from MDN. */
- String mdnCommentHtml;
- /**
- * The URL to the page on MDN that content was pulled from for the current
- * type being documented. Will be `null` if the type doesn't use any MDN
- * content.
- */
- String mdnUrl;
- /** Children of the node. */
- List<Element> children;
- /** Whether the element is private. */
- final bool isPrivate;
-
- /**
- * Uri containing the definition of the element.
- */
- String uri;
- /**
- * Line in the original source file that starts the definition of the element.
- */
- String line;
-
- // TODO(jacobr): refactor the code so that lookupMdnComment does not need to
- // be passed to every Element constructor.
- Element(Mirror mirror, this.kind, this.name, String id, this.comment,
- MdnComment lookupMdnComment(Mirror))
- : line = mirror.location.line.toString(),
- id = _escapeId(id),
- isPrivate = _optionalBool(mirror.isPrivate),
- uri = _stripUri(mirror.location.sourceUri.toString()) {
- if (lookupMdnComment != null) {
- var mdnComment = lookupMdnComment(mirror);
- if (mdnComment != null) {
- mdnCommentHtml = mdnComment.mdnComment;
- mdnUrl = mdnComment.mdnUrl;
- }
- }
- }
-
- void addChild(Element child) {
- if (children == null) {
- children = <Element>[];
- }
- children.add(child);
- }
-
- /**
- * Remove all URIs that exactly match the parent node's URI.
- * This reduces output file size by about 20%.
- */
- void stripDuplicateUris(String parentUri, parentLine) {
- if (children != null) {
- for (var child in children) {
- child.stripDuplicateUris(uri, line);
- }
- }
- if (parentUri == uri) {
- uri = null;
- }
- if (line == parentLine) {
- line = null;
- }
- }
-}
-
-/**
- * Converts false to null. Useful as the serialization scheme we use
- * omits null values.
- */
-bool _optionalBool(bool value) => value == true ? true : null;
-
-Reference _optionalReference(Mirror mirror) {
- return (mirror != null && mirror.simpleName != "Dynamic_" &&
- mirror.simpleName != "dynamic") ?
- new Reference(mirror) : null;
-}
-
-/**
- * Helper class to track what members of a library should be included.
- */
-class LibrarySubset {
- final LibraryMirror library;
- Set<String> includedChildren;
-
- LibrarySubset(this.library) : includedChildren = new Set<String>();
-}
-
-/**
- * [Element] describing a Dart library.
- */
-class LibraryElement extends Element {
- /**
- * Partial versions of LibraryElements containing classes that are extended
- * or implemented by classes in this library.
- */
- List<LibraryElement> dependencies;
-
- /**
- * Construct a LibraryElement from a [mirror].
- *
- * If [includedChildren] is specified, only elements matching names in
- * [includedChildren] are included and no dependencies are included.
- * [lookupMdnComment] is an optional function that returns the MDN
- * documentation for elements. [dependencies] is an optional map
- * tracking all classes dependend on by this [ClassElement].
- */
- LibraryElement(LibraryMirror mirror,
- {MdnComment lookupMdnComment(Mirror), Set<String> includedChildren})
- : super(mirror, 'library', _libraryName(mirror), mirror.simpleName,
- computeComment(mirror), lookupMdnComment) {
- var requiredDependencies;
- // We don't need to track our required dependencies when generating a
- // filtered version of this library which will be used as a dependency for
- // another library.
- if (includedChildren == null)
- requiredDependencies = new Map<String, LibrarySubset>();
- mirror.functions.forEach((childName, childMirror) {
- if (includedChildren == null || includedChildren.contains(childName))
- addChild(new MethodElement(childName, childMirror, lookupMdnComment));
- });
-
- mirror.getters.forEach((childName, childMirror) {
- if (includedChildren == null || includedChildren.contains(childName))
- addChild(new GetterElement(childName, childMirror, lookupMdnComment));
- });
-
- mirror.variables.forEach((childName, childMirror) {
- if (includedChildren == null || includedChildren.contains(childName))
- addChild(new VariableElement(childName, childMirror, lookupMdnComment));
- });
-
- mirror.classes.forEach((className, classMirror) {
- if (includedChildren == null || includedChildren.contains(className)) {
- if (classMirror is TypedefMirror) {
- addChild(new TypedefElement(className, classMirror));
- } else {
- addChild(new ClassElement(classMirror,
- dependencies: requiredDependencies,
- lookupMdnComment: lookupMdnComment));
- }
- }
- });
-
- if (requiredDependencies != null && !requiredDependencies.isEmpty) {
- dependencies = requiredDependencies.values.map((librarySubset) =>
- new LibraryElement(
- librarySubset.library,
- lookupMdnComment: lookupMdnComment,
- includedChildren: librarySubset.includedChildren)).toList();
- }
- }
-
- static String _libraryName(LibraryMirror mirror) {
- if (mirror.uri.scheme == 'file') {
- // TODO(jacobr): this is a hack. Remove once these libraries are removed
- // from the sdk.
- var uri = mirror.uri;
- var uriPath = uri.path;
-
- var parts = path.split(uriPath);
-
- // Find either pkg/ or packages/
- var pkgDir = parts.lastIndexOf('pkg');
- var packageDir = parts.lastIndexOf('packages');
-
- if (pkgDir >= 0) {
- packageDir = pkgDir;
- }
-
- var libDir = parts.lastIndexOf('lib');
- var rest = parts.sublist(libDir + 1);
-
- // If there's no lib, we can't find the package.
- if (libDir < 0 || libDir < packageDir) {
- // TODO(jacobr): this is a lousy fallback.
- print("Unable to determine package for $uriPath.");
- return mirror.uri.toString();
- } else if (packageDir >= 0 && rest.length >= 1) {
- // For URI: foo/bar/packages/widget/lib/sprocket.dart will return:
- // 'package:widget/sprocket.dart'
- return 'package:${parts[packageDir + 1]}/${rest.join('/')}';
- }
- } else {
- return mirror.uri.toString();
- }
- }
-
- void stripDuplicateUris(String parentUri, parentLine) {
- super.stripDuplicateUris(parentUri, parentLine);
-
- if (dependencies != null) {
- for (var child in dependencies) {
- child.stripDuplicateUris(null, null);
- }
- }
- }
-}
-
-/**
- * Returns whether the class implements or extends [Error] or [Exception].
- */
-bool _isThrowable(ClassMirror mirror) {
- if (mirror.library.uri.toString() == 'dart:core' &&
- mirror.simpleName == 'Error' || mirror.simpleName == 'Exception')
- return true;
- if (mirror.superclass != null && _isThrowable(mirror.superclass))
- return true;
- return mirror.superinterfaces.any(_isThrowable);
-}
-
-/**
- * [Element] describing a Dart class.
- */
-class ClassElement extends Element {
- /** Base class.*/
- final Reference superclass;
- /** Whether the class is abstract. */
- final bool isAbstract;
- /** Interfaces the class implements. */
- List<Reference> interfaces;
- /** Whether the class implements or extends [Error] or [Exception]. */
- bool isThrowable;
-
- /**
- * Constructs a [ClassElement] from a [ClassMirror].
- *
- * [dependencies] is an optional map updated as a side effect of running
- * this constructor that tracks what classes from other libraries are
- * dependencies of classes in this library. A class is considered a
- * dependency if it implements or extends another class.
- * [lookupMdnComment] is an optional function that returns the MDN
- * documentation for elements. [dependencies] is an optional map
- * tracking all classes dependend on by this [ClassElement].
- */
- ClassElement(ClassMirror mirror,
- {Map<String, LibrarySubset> dependencies,
- MdnComment lookupMdnComment(Mirror)})
- : super(mirror, 'class', mirror.simpleName, mirror.simpleName, computeComment(mirror),
- lookupMdnComment),
- superclass = _optionalReference(mirror.superclass),
- isAbstract = _optionalBool(mirror.isAbstract),
- isThrowable = _optionalBool(_isThrowable(mirror)){
-
- addCrossLibraryDependencies(clazz) {
- if (clazz == null) return;
-
- if (mirror.library != clazz.library) {
- var libraryStub = dependencies.putIfAbsent(clazz.library.simpleName,
- () => new LibrarySubset(clazz.library));
- libraryStub.includedChildren.add(clazz.simpleName);
- }
-
- for (var interface in clazz.superinterfaces) {
- addCrossLibraryDependencies(interface);
- }
- addCrossLibraryDependencies(clazz.superclass);
- }
-
- if (dependencies != null) {
- addCrossLibraryDependencies(mirror);
- }
-
- for (var interface in mirror.superinterfaces) {
- if (this.interfaces == null) {
- this.interfaces = <Reference>[];
- }
- this.interfaces.add(_optionalReference(interface));
- }
-
- mirror.methods.forEach((childName, childMirror) {
- if (!childMirror.isConstructor && !childMirror.isGetter) {
- addChild(new MethodElement(childName, childMirror, lookupMdnComment));
- }
- });
-
- mirror.getters.forEach((childName, childMirror) {
- addChild(new GetterElement(childName, childMirror, lookupMdnComment));
- });
-
- mirror.variables.forEach((childName, childMirror) {
- addChild(new VariableElement(childName, childMirror,
- lookupMdnComment));
- });
-
- mirror.constructors.forEach((constructorName, methodMirror) {
- addChild(new MethodElement(constructorName, methodMirror,
- lookupMdnComment, 'constructor'));
- });
-
- for (var typeVariable in mirror.originalDeclaration.typeVariables) {
- addChild(new TypeParameterElement(typeVariable));
- }
- }
-}
-
-/**
- * [Element] describing a getter.
- */
-class GetterElement extends Element {
- /** Type of the getter. */
- final Reference ref;
- final bool isStatic;
-
- GetterElement(String name, MethodMirror mirror,
- MdnComment lookupMdnComment(Mirror))
- : super(mirror, 'property', mirror.simpleName, name, computeComment(mirror),
- lookupMdnComment),
- ref = _optionalReference(mirror.returnType),
- isStatic = _optionalBool(mirror.isStatic);
-}
-
-/**
- * [Element] describing a method which may be a regular method, a setter, or an
- * operator.
- */
-class MethodElement extends Element {
- final Reference returnType;
- final bool isSetter;
- final bool isOperator;
- final bool isStatic;
-
- MethodElement(String name, MethodMirror mirror,
- MdnComment lookupMdnComment(Mirror), [String kind = 'method'])
- : super(mirror, kind, name, '$name${mirror.parameters.length}()',
- computeComment(mirror), lookupMdnComment),
- returnType = _optionalReference(mirror.returnType),
- isSetter = _optionalBool(mirror.isSetter),
- isOperator = _optionalBool(mirror.isOperator),
- isStatic = _optionalBool(mirror.isStatic) {
-
- for (var param in mirror.parameters) {
- addChild(new ParameterElement(param));
- }
- }
-}
-
-/**
- * Element describing a parameter.
- */
-class ParameterElement extends Element {
- /** Type of the parameter. */
- final Reference ref;
-
- /**
- * Returns the default value for this parameter.
- */
- final String defaultValue;
-
- /**
- * Is this parameter optional?
- */
- final bool isOptional;
-
- /**
- * Is this parameter named?
- */
- final bool isNamed;
-
- /**
- * Returns the initialized field, if this parameter is an initializing formal.
- */
- final Reference initializedField;
-
- ParameterElement(ParameterMirror mirror)
- : super(mirror, 'param', mirror.simpleName, mirror.simpleName, null,
- null),
- ref = _optionalReference(mirror.type),
- isOptional = _optionalBool(mirror.isOptional),
- defaultValue = mirror.defaultValue,
- isNamed = _optionalBool(mirror.isNamed),
- initializedField = _optionalReference(mirror.initializedField) {
-
- if (mirror.type is FunctionTypeMirror) {
- addChild(new FunctionTypeElement(mirror.type));
- }
- }
-}
-
-class FunctionTypeElement extends Element {
- final Reference returnType;
-
- FunctionTypeElement(FunctionTypeMirror mirror)
- : super(mirror, 'functiontype', mirror.simpleName, mirror.simpleName, null, null),
- returnType = _optionalReference(mirror.returnType) {
- for (var param in mirror.parameters) {
- addChild(new ParameterElement(param));
- }
- // TODO(jacobr): can a FunctionTypeElement really have type variables?
- for (var typeVariable in mirror.originalDeclaration.typeVariables) {
- addChild(new TypeParameterElement(typeVariable));
- }
- }
-}
-
-/**
- * Element describing a generic type parameter.
- */
-class TypeParameterElement extends Element {
- /**
- * Upper bound for the parameter.
- *
- * In the following code sample, [:Bar:] is an upper bound:
- * [: class Bar<T extends Foo> { } :]
- */
- final Reference upperBound;
-
- TypeParameterElement(TypeMirror mirror)
- : super(mirror, 'typeparam', mirror.simpleName, mirror.simpleName, null,
- null),
- upperBound = mirror.upperBound != null && !mirror.upperBound.isObject ?
- new Reference(mirror.upperBound) : null;
-}
-
-/**
- * Element describing a variable.
- */
-class VariableElement extends Element {
- /** Type of the variable. */
- final Reference ref;
- /** Whether the variable is static. */
- final bool isStatic;
- /** Whether the variable is final. */
- final bool isFinal;
-
- VariableElement(String name, VariableMirror mirror,
- MdnComment lookupMdnComment(Mirror))
- : super(mirror, 'variable', mirror.simpleName, name,
- computeComment(mirror), lookupMdnComment),
- ref = _optionalReference(mirror.type),
- isStatic = _optionalBool(mirror.isStatic),
- isFinal = _optionalBool(mirror.isFinal);
-}
-
-/**
- * Element describing a typedef.
- */
-
-class TypedefElement extends Element {
- /** Return type of the typedef. */
- final Reference returnType;
-
- TypedefElement(String name, TypedefMirror mirror)
- : super(mirror, 'typedef', mirror.simpleName, name,
- computeComment(mirror), null),
- returnType = _optionalReference(mirror.value.returnType) {
- for (var param in mirror.value.parameters) {
- addChild(new ParameterElement(param));
- }
- for (var typeVariable in mirror.originalDeclaration.typeVariables) {
- addChild(new TypeParameterElement(typeVariable));
- }
- }
-}
-
-/**
- * Reference to an Element with type argument if the reference is parameterized.
- */
-class Reference {
- final String name;
- final String refId;
- List<Reference> arguments;
-
- Reference(Mirror mirror)
- : name = displayName(mirror),
- refId = getId(mirror) {
- if (mirror is ClassMirror) {
- if (mirror is !TypedefMirror && !mirror.typeArguments.isEmpty) {
- arguments = <Reference>[];
- for (var typeArg in mirror.typeArguments) {
- arguments.add(_optionalReference(typeArg));
- }
- }
- }
- }
-
- // TODO(jacobr): compute the referenceId correctly for the general case so
- // that this method can work with all element types not just LibraryElements.
- Reference.fromElement(LibraryElement e) : name = e.name, refId = e.id;
-
- static String getId(Mirror mirror) {
- String id = _escapeId(mirror.simpleName);
- if (mirror.owner != null) {
- id = '${getId(mirror.owner)}/$id';
- }
- return id;
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/pubspec.yaml b/sdk/lib/_internal/dartdoc/pubspec.yaml
deleted file mode 100644
index fe775e4..0000000
--- a/sdk/lib/_internal/dartdoc/pubspec.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-name: dartdoc
-description: >
- Libraries for generating documentation from Dart source code.
-
-dependencies:
- args: ">=0.4.2 <1.0.0"
- path: ">=0.4.2 <1.0.0"
-
-dev_dependencies:
- unittest: ">=0.4.2 <1.0.0"
diff --git a/sdk/lib/_internal/dartdoc/static/body-bg.png b/sdk/lib/_internal/dartdoc/static/body-bg.png
deleted file mode 100644
index 4fe447c..0000000
--- a/sdk/lib/_internal/dartdoc/static/body-bg.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/class.png b/sdk/lib/_internal/dartdoc/static/class.png
deleted file mode 100644
index 214fc21..0000000
--- a/sdk/lib/_internal/dartdoc/static/class.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/content-bg.png b/sdk/lib/_internal/dartdoc/static/content-bg.png
deleted file mode 100644
index e5320c7..0000000
--- a/sdk/lib/_internal/dartdoc/static/content-bg.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/dart-logo-small.png b/sdk/lib/_internal/dartdoc/static/dart-logo-small.png
deleted file mode 100644
index f6d9791..0000000
--- a/sdk/lib/_internal/dartdoc/static/dart-logo-small.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/exception.png b/sdk/lib/_internal/dartdoc/static/exception.png
deleted file mode 100644
index ee0815a..0000000
--- a/sdk/lib/_internal/dartdoc/static/exception.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/external-link.png b/sdk/lib/_internal/dartdoc/static/external-link.png
deleted file mode 100644
index 0d847d7..0000000
--- a/sdk/lib/_internal/dartdoc/static/external-link.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/favicon.ico b/sdk/lib/_internal/dartdoc/static/favicon.ico
deleted file mode 100644
index 50ea5b0..0000000
--- a/sdk/lib/_internal/dartdoc/static/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/header-bg.png b/sdk/lib/_internal/dartdoc/static/header-bg.png
deleted file mode 100644
index 9cadb55..0000000
--- a/sdk/lib/_internal/dartdoc/static/header-bg.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/interface.png b/sdk/lib/_internal/dartdoc/static/interface.png
deleted file mode 100644
index 421a07b..0000000
--- a/sdk/lib/_internal/dartdoc/static/interface.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/library.png b/sdk/lib/_internal/dartdoc/static/library.png
deleted file mode 100644
index eb20c8e..0000000
--- a/sdk/lib/_internal/dartdoc/static/library.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/styles.css b/sdk/lib/_internal/dartdoc/static/styles.css
deleted file mode 100644
index c9813c8..0000000
--- a/sdk/lib/_internal/dartdoc/static/styles.css
+++ /dev/null
@@ -1,487 +0,0 @@
-/* Reset */
-body, h1, h2, h3, h4, li, ol, p, pre, section, ul {
- margin: 0;
- padding: 0;
-}
-
-body {
- font-family: Georgia, serif;
- background: #e8e8e8;
- color: #333;
- background-image: url('body-bg.png');
- background-repeat: repeat;
-}
-
-h2 {
- font: 400 28px/44px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
-}
-
-h3 {
- font: 600 14px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- color: #999;
- margin: 22px 0 0 0;
-}
-
-h4 {
- font: 600 16px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
-}
-
-p {
- font-size: 16px;
- line-height: 22px;
- margin: 0 0 22px 0;
-}
-
-h3 + p {
- /* Text immediately following a subheader should be snug with it. */
- margin-top: 0;
-}
-
-strong {
- font-weight: 700;
-}
-
-pre, code {
- font: 14px/22px Menlo, Monaco, Consolas, Courier, monospace;
- color: hsl(220, 20%, 30%);
- background: hsl(220, 20%, 95%);
- margin: 22px 0;
- padding: 0 4px;
- border-radius: 4px;
- overflow-x:auto;
- overflow-y:hidden;
-}
-
-pre > code {
- padding: 0;
-}
-
-a {
- color: #15c;
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-a:visited {
- color: #15c;
-}
-
-li {
- font-size: 16px;
- line-height: 22px;
-}
-
-/* First paragraph in an li is snug, but others are spaced out. */
-li p:first-child {
- margin: 0 0 0 0;
-}
-
-li > p {
- margin: 22px 0 0 0;
-}
-
-ol, ul {
- padding-left: 22px;
-}
-
-hr {
- border: none;
- height: 1px;
- background: #ccc;
- margin: 22px 0 21px 0;
-}
-
-hr + h2 {
- margin-top: 21px; /* To compensate for the thickness of the hr. */
-}
-
-.page {
- max-width: 1000px;
- background: #fff;
- margin: 0 auto 22px auto;
- border: solid 1px #ccc;
- border-top: none;
- box-shadow: 0 0 50px #888;
-
- background-image: url('content-bg.png');
- background-repeat: repeat-y;
-
- position: relative;
-}
-
-.header {
- background: #333;
- background-image: url('header-bg.png');
- height: 44px;
- color: hsl(0, 0%, 50%);
- font: 400 15px/44px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
-}
-
-.header .logo {
- background-image: url('dart-logo-small.png');
- width: 66px;
- height: 44px;
- float: left;
-}
-
-.header a {
- color: hsl(0, 0%, 80%);
-}
-
-.header a:hover {
- color: hsl(0, 0%, 100%);
-}
-
-.header #search-box {
- display: inline;
- float: right;
- margin-right: 11px;
-}
-
-.search-input, .drop-down {
- font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- width: 300px;
-}
-
-.drop-down {
- visibility: hidden;
- z-index: 1000;
- position: absolute;
- right: 10px;
- top: 36px;
- border: 1px #CCC solid;
- background-color: white;
- -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-}
-
-.drop-down-table {
- width: 100%;
-}
-
-.drop-down-link-tr {
- padding: 4px 0px;
- cursor: pointer;
-}
-.drop-down-link-td {
- border-bottom: 1px solid #EEE;
-}
-
-.drop-down-link-tr:hover {
- background: #EEE;
- color: #333;
-}
-
-.drop-down-link-select {
- background: #15C;
- color: white;
-}
-
-.drop-down-link-select:hover {
- background: #2AF;
- color: white;
-}
-
-.drop-down-link-kind, .drop-down-link-library {
- font: 400 10px/10px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
-}
-
-.drop-down-link-library {
- text-align: right;
-}
-
-.drop-down-link-highlight {
- font-weight:bold;
-}
-
-.nav {
- float: left;
- width: 263px; /* 12 x 22px - 1 for border */
- padding: 0 22px;
- overflow: hidden;
- background: #f4f4f4;
- border-right: solid 1px #ccc;
-}
-
-.nav h2 {
- font: 400 16px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- margin: 0 -21px;
- padding: 11px 22px;
-
- /* Using http://www.colorzilla.com/gradient-editor/ */
- background: -moz-linear-gradient(top, hsla(0,0%,0%,0.05) 0%, hsla(0,0%,0%,0) 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsla(0,0%,0%,0.05)), color-stop(100%,hsla(0,0%,0%,0)));
- background: -webkit-linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
- background: -o-linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
- background: -ms-linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
- background: linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
-}
-
-ul.icon {
- margin: 0 0 22px 0;
- padding: 0;
-}
-
-ul.icon li {
- font: 600 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- list-style-type: none;
- white-space: nowrap;
-}
-
-/* Indent nested lists. */
-ul.icon ul {
- margin-left: 22px;
-}
-
-.icon-class,
-.icon-exception,
-.icon-interface {
- display: inline-block;
- width: 14px;
- height: 14px;
- margin: 5px 10px 0 2px;
- vertical-align: top;
-}
-
-.icon-class { background: url('class.png'); }
-.icon-exception { background: url('exception.png'); }
-.icon-interface { background: url('interface.png'); }
-
-.icon-library {
- background: url('library.png');
- width: 16px;
- height: 14px;
- display: inline-block;
- margin: 4px 8px 0 0;
- vertical-align: top;
-}
-
-.type-box {
- display: inline-block;
- font: 600 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- background: #f4f4f4;
- padding: 0 6px 0 3px;
- border-radius: 4px;
-}
-
-.type-box .icon-class,
-.type-box .icon-exception,
-.type-box .icon-interface {
- /* Make a little snugger with the text. */
- margin-right: 5px;
-}
-
-.content {
- margin-left: 308px; /* 14 x 22 */
- padding: 22px 22px;
-}
-
-.clear {
- clear: both;
-}
-
-.footer {
- max-width: 956px; /* 1000 - 22 - 22 */
- text-align: center;
- margin: 22px auto;
- color: #888;
-}
-
-.footer p {
- font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
-}
-
-.inherited {
-}
-
-.inherited-from {
- font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- text-align: right;
- opacity: 0.7;
-}
-
-.inherited-from, .docs-inherited-from {
- font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- text-align: right;
- opacity: 0.7;
-}
-
-.docs-inherited-from {
- margin-top: -22px;
-}
-
-.method .doc,
-.field .doc {
- padding-left: 44px;
- /* Ensure there is some space between members with no documentation. */
- margin-bottom: 22px;
-}
-
-.param {
- font: 600 14px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
-}
-
-.crossref {
- font: 600 15px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
-}
-
-.doc h1 {
- font: 700 17px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- color: #666;
-}
-
-.doc h2 {
- font: 600 16px/22px 'Open Sans', 'Lucida Sans Unicode',
- 'Lucida Grande', sans-serif;
- color: #666;
-}
-
-/* Style external links in docs differently. */
-.doc a[href^="http:"]:after,
-.doc a[href^="https:"]:after {
- content: url('external-link.png');
-}
-
-/* Highlight members on hover so you can see which docs are for which member. */
-.method:hover,
-.field:hover {
- margin: 0 -22px;
- border: solid 4px hsl(40, 100%, 85%);
- padding: 0 18px;
- border-top: none;
- border-bottom: none;
-}
-
-/* Only show the "code" link for the highlighted member. */
-.show-code, .show-inherited {
- float: right;
- font: 600 11px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
- sans-serif;
- padding: 0 0 0 6px; /* In case it gets too close to the member. */
- border: none;
- background: transparent;
- margin: 0;
-}
-
-.method:hover .show-code,
-.field:hover .show-code {
- display: inline;
-}
-
-/* Only show permalinks when hovered over. */
-.anchor-link {
- display: none;
-}
-
-h2:hover > .anchor-link,
-h4:hover > .anchor-link {
- display: inline;
-}
-
-/* Only show code when expanded. */
-pre.source {
- display: none;
-}
-
-pre.source.expanded {
- display: block;
-}
-
-/* Links that don't cause a page refresh. */
-.anchor-link, .anchor-link:visited,
-.show-code, .show-code:visited,
-.show-inherited, .show-inherited:visited {
- color: hsl(40, 100%, 40%);
- cursor: pointer;
-}
-
-.anchor-link, .anchor-link:visited,
-.show-code, .show-code:visited {
- display: none;
-}
-
-.anchor-link:hover,
-.show-code:hover,
-.show-inherited:hover {
- color: hsl(40, 100%, 60%);
-}
-
-/* Syntax highlighting. */
-/* Note: these correspond to the constants in classify.dart. */
-.doc pre .e, pre.source .e { color: hsl( 0, 100%, 70%); } /* Error */
-.doc pre .c, pre.source .c { color: hsl(220, 20%, 65%); } /* Comment */
-.doc pre .i, pre.source .i { color: hsl(220, 20%, 20%); } /* Identifier */
-.doc pre .k, pre.source .k { color: hsl(220, 100%, 50%); } /* Keyword */
-.doc pre .p, pre.source .p { color: hsl(220, 20%, 50%); } /* Punctuation */
-.doc pre .o, pre.source .o { color: hsl(220, 40%, 50%); } /* Operator */
-.doc pre .s, pre.source .s { color: hsl( 40, 90%, 40%); } /* String */
-.doc pre .n, pre.source .n { color: hsl( 30, 70%, 50%); } /* Number */
-.doc pre .t, pre.source .t { color: hsl(180, 40%, 40%); } /* Type Name */
-.doc pre .r, pre.source .r { color: hsl(200, 100%, 50%); } /* Special Identifier */
-.doc pre .a, pre.source .a { color: hsl(220, 100%, 45%); } /* Arrow */
-
-/* Interpolated expressions within strings. */
-.doc pre .si, pre.source .si {
- background: hsl(40, 100%, 90%);
-}
-
-.doc pre .s.si, pre.source .s.si { background: hsl(40, 80%, 95%); }
-.doc pre .i.si, pre.source .i.si { color: hsl(40, 30%, 30%); }
-.doc pre .p.si, pre.source .p.si { color: hsl(40, 60%, 40%); }
-
-/* Enable these to debug the grid: */
-
-/*
-body {
- background: -webkit-linear-gradient(top, #eee 0, #fff 10%, #fff 90%, #eee 100%);
- background-size: 22px 22px;
- background-repeat: repeat;
-}
-
-.page {
- background: none;
-}
-
-h1 {
- border-left: solid 4px green;
-}
-
-h2 {
- border-left: solid 4px blue;
-}
-
-h3 {
- border-left: solid 4px red;
-}
-
-h4 {
- border-left: solid 4px orange;
-}
-
-p {
- border-left: solid 4px purple;
-}
-
-section {
- border-left: solid 4px gray;
-}
-*/
diff --git a/sdk/lib/_internal/dartdoc/test/dartdoc_search_test.dart b/sdk/lib/_internal/dartdoc/test/dartdoc_search_test.dart
deleted file mode 100644
index 9374c06..0000000
--- a/sdk/lib/_internal/dartdoc/test/dartdoc_search_test.dart
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2012, 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 dartdoc_search_test;
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../../../../../pkg/expect/lib/expect.dart';
-import '../lib/src/dartdoc/nav.dart';
-import '../lib/src/client/search.dart';
-
-const String URL = 'dummy-url';
-
-testTopLevelVsMembers() {
- var search = new SearchText('timer');
- var match = obtainMatch(search, 'timer');
- // Matching a top-level field 'timer';
- var topLevelResult = new Result(match, FIELD, URL);
- // Matching a member field 'timer' in 'Foo';
- var memberResult = new Result(match, FIELD, URL, type: 'Foo');
- Expect.equals(-1, resultComparator(topLevelResult, memberResult),
- "Top level fields should be preferred to member fields");
-}
-
-testTopLevelFullVsPrefix() {
- var search = new SearchText('cancel');
- var fullMatch = obtainMatch(search, 'cancel');
- var prefixMatch = obtainMatch(search, 'cancelable');
- // Matching a top-level method 'cancel';
- var fullResult = new Result(fullMatch, METHOD, URL);
- // Matching a top-level method 'cancelable';
- var prefixResult = new Result(prefixMatch, METHOD, URL);
- Expect.equals(-1, resultComparator(fullResult, prefixResult),
- "Full matches should be preferred to prefix matches");
-}
-
-testMemberFullVsPrefix() {
- var search = new SearchText('cancel');
- var fullMatch = obtainMatch(search, 'cancel');
- var prefixMatch = obtainMatch(search, 'cancelable');
- // Matching a member method 'cancel' in 'Isolate';
- var fullResult = new Result(fullMatch, METHOD, URL, type: 'Isolate');
- // Matching a member field 'cancelable' in 'Event';
- var prefixResult = new Result(prefixMatch, FIELD, URL, type: 'Event');
- Expect.equals(-1, resultComparator(fullResult, prefixResult),
- "Full matches should be preferred to prefix matches");
-}
-
-void main() {
- testTopLevelVsMembers();
- testTopLevelFullVsPrefix();
- testMemberFullVsPrefix();
-}
diff --git a/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart b/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart
deleted file mode 100644
index 0bc58a3..0000000
--- a/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/// Unit tests for doc.
-library dartdocTests;
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:path/path.dart' as path;
-import 'package:unittest/unittest.dart';
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../lib/dartdoc.dart' as dd;
-import '../lib/markdown.dart';
-import 'markdown_test.dart';
-
-main() {
- // Some tests take more than the default 20 second unittest timeout.
- unittestConfiguration.timeout = null;
- group('isAbsolute', () {
- final doc = new dd.Dartdoc();
-
- test('returns false if there is no scheme', () {
- expect(doc.isAbsolute('index.html'), isFalse);
- expect(doc.isAbsolute('foo/index.html'), isFalse);
- expect(doc.isAbsolute('foo/bar/index.html'), isFalse);
- });
-
- test('returns true if there is a scheme', () {
- expect(doc.isAbsolute('http://google.com'), isTrue);
- expect(doc.isAbsolute('hTtPs://google.com'), isTrue);
- expect(doc.isAbsolute('mailto:fake@email.com'), isTrue);
- });
- });
-
- group('relativePath', () {
- final doc = new dd.Dartdoc();
-
- test('absolute path is unchanged', () {
- doc.startFile('dir/sub/file.html');
- expect(doc.relativePath('http://foo.com'), equals('http://foo.com'));
- });
-
- test('from root to root', () {
- doc.startFile('root.html');
- expect(doc.relativePath('other.html'), equals('other.html'));
- });
-
- test('from root to directory', () {
- doc.startFile('root.html');
- expect(doc.relativePath('dir/file.html'), equals('dir/file.html'));
- });
-
- test('from root to nested', () {
- doc.startFile('root.html');
- expect(doc.relativePath('dir/sub/file.html'), equals(
- 'dir/sub/file.html'));
- });
-
- test('from directory to root', () {
- doc.startFile('dir/file.html');
- expect(doc.relativePath('root.html'), equals('../root.html'));
- });
-
- test('from nested to root', () {
- doc.startFile('dir/sub/file.html');
- expect(doc.relativePath('root.html'), equals('../../root.html'));
- });
-
- test('from dir to dir with different path', () {
- doc.startFile('dir/file.html');
- expect(doc.relativePath('other/file.html'), equals('../other/file.html'));
- });
-
- test('from nested to nested with different path', () {
- doc.startFile('dir/sub/file.html');
- expect(doc.relativePath('other/sub/file.html'), equals(
- '../../other/sub/file.html'));
- });
-
- test('from nested to directory with different path', () {
- doc.startFile('dir/sub/file.html');
- expect(doc.relativePath('other/file.html'), equals(
- '../../other/file.html'));
- });
- });
-
- group('dartdoc markdown', () {
- group('[::] blocks', () {
-
- validateDartdocMarkdown('simple case', '''
- before [:source:] after
- ''', '''
- <p>before <code>source</code> after</p>
- ''');
-
- validateDartdocMarkdown('unmatched [:', '''
- before [: after
- ''', '''
- <p>before [: after</p>
- ''');
- validateDartdocMarkdown('multiple spans in one text', '''
- a [:one:] b [:two:] c
- ''', '''
- <p>a <code>one</code> b <code>two</code> c</p>
- ''');
-
- validateDartdocMarkdown('multi-line', '''
- before [:first
- second:] after
- ''', '''
- <p>before <code>first
- second</code> after</p>
- ''');
-
- validateDartdocMarkdown('contain backticks', '''
- before [:can `contain` backticks:] after
- ''', '''
- <p>before <code>can `contain` backticks</code> after</p>
- ''');
-
- validateDartdocMarkdown('contain double backticks', '''
- before [:can ``contain`` backticks:] after
- ''', '''
- <p>before <code>can ``contain`` backticks</code> after</p>
- ''');
-
- validateDartdocMarkdown('contain backticks with spaces', '''
- before [: `tick` :] after
- ''', '''
- <p>before <code>`tick`</code> after</p>
- ''');
-
- validateDartdocMarkdown('multiline with spaces', '''
- before [:in `tick`
- another:] after
- ''', '''
- <p>before <code>in `tick`
- another</code> after</p>
- ''');
-
- validateDartdocMarkdown('ignore markup inside code', '''
- before [:*b* _c_:] after
- ''', '''
- <p>before <code>*b* _c_</code> after</p>
- ''');
-
- validateDartdocMarkdown('escape HTML characters', '''
- [:<&>:]
- ''', '''
- <p><code><&></code></p>
- ''');
-
- validateDartdocMarkdown('escape HTML tags', '''
- '*' [:<em>:]
- ''', '''
- <p>'*' <code><em></code></p>
- ''');
- });
- });
-
- group('integration tests', () {
- test('no entrypoints', () {
- _testRunDartDoc([], (result) {
- expect(result.exitCode, 1);
- });
- });
-
- test('entrypoint in lib', () {
- _testRunDartDoc(['test_files/lib/no_package_test_file.dart'], (result) {
- expect(result.exitCode, 0);
- _expectDocumented(result.stdout, libCount: 1, typeCount: 1, memberCount: 0);
- });
- });
-
- test('entrypoint somewhere with packages locally', () {
- _testRunDartDoc(['test_files/package_test_file.dart'], (result) {
- expect(result.exitCode, 0);
- _expectDocumented(result.stdout, libCount: 1, typeCount: 1, memberCount: 0);
- });
- });
-
- test('file does not exist', () {
- _testRunDartDoc(['test_files/this_file_does_not_exist.dart'], (result) {
- expect(result.exitCode, 1);
- });
- });
- });
-}
-
-void _testRunDartDoc(List<String> libraryPaths, void eval(ProcessResult)) {
- expect(_runDartdoc(libraryPaths).then(eval), completes);
-}
-
-/// The path to the root directory of the dartdoc entrypoint.
-String get _dartdocDir {
- var dir = path.absolute(Platform.script.toFilePath());
- while (path.basename(dir) != 'dartdoc') {
- if (!path.absolute(dir).contains('dartdoc') || dir == path.dirname(dir)) {
- fail('Unable to find root dartdoc directory.');
- }
- dir = path.dirname(dir);
- }
- return path.absolute(dir);
-}
-
-/// The path to use for the package root for subprocesses.
-String get _packageRoot {
- var sdkVersionPath = path.join(_dartdocDir, '..', '..', '..', 'version');
- if (new File(sdkVersionPath).existsSync()) {
- // It looks like dartdoc is being run from the SDK, so we should set the
- // package root to the SDK's packages directory.
- return path.absolute(path.join(_dartdocDir, '..', '..', '..', 'packages'));
- }
-
- // It looks like Dartdoc is being run from the Dart repo, so the package root
- // is in the build output directory. We can find that directory relative to
- // the Dart executable, but that could be in one of two places: in
- // "$BUILD/dart" or "$BUILD/dart-sdk/bin/dart".
- var executableDir = path.dirname(Platform.executable);
- if (new Directory(path.join(executableDir, 'dart-sdk')).existsSync()) {
- // The executable is in "$BUILD/dart".
- return path.absolute(path.join(executableDir, 'packages'));
- } else {
- // The executable is in "$BUILD/dart-sdk/bin/dart".
- return path.absolute(path.join(executableDir, '..', '..', 'packages'));
- }
-}
-
-/// Runs dartdoc with the libraryPaths provided, and completes to dartdoc's
-/// ProcessResult.
-Future<ProcessResult> _runDartdoc(List<String> libraryPaths) {
- var dartBin = Platform.executable;
-
- var dartdoc = path.join(_dartdocDir, 'bin/dartdoc.dart');
-
- final runArgs = ['--package-root=$_packageRoot/', dartdoc];
-
- // Turn relative libraryPaths to absolute ones.
- runArgs.addAll(libraryPaths
- .map((e) => path.join(path.absolute(dd.scriptDir), e)));
-
- return Process.run(dartBin, runArgs);
-}
-
-final _dartdocCompletionRegExp =
- new RegExp(r'Documentation complete -- documented (\d+) libraries, (\d+) types, and (\d+) members\.');
-
-void _expectDocumented(String output, { int libCount, int typeCount,
- int memberCount}) {
-
- final completionMatches = _dartdocCompletionRegExp.allMatches(output)
- .toList();
-
- expect(completionMatches, hasLength(1),
- reason: 'dartdoc output should contain one summary');
-
- final completionMatch = completionMatches.single;
-
- if(libCount != null) {
- expect(int.parse(completionMatch[1]), libCount,
- reason: 'expected library count');
- }
-
- if(typeCount != null) {
- expect(int.parse(completionMatch[2]), typeCount,
- reason: 'expected type count');
- }
-
- if(memberCount != null) {
- expect(int.parse(completionMatch[3]), memberCount,
- reason: 'expected member count');
- }
-}
-
-
-validateDartdocMarkdown(String description, String markdown,
- String html) {
- var dartdoc = new dd.Dartdoc();
- validate(description, markdown, html, linkResolver: dartdoc.dartdocResolver,
- inlineSyntaxes: dartdoc.dartdocSyntaxes);
-}
diff --git a/sdk/lib/_internal/dartdoc/test/export_map_test.dart b/sdk/lib/_internal/dartdoc/test/export_map_test.dart
deleted file mode 100644
index 12aa98a..0000000
--- a/sdk/lib/_internal/dartdoc/test/export_map_test.dart
+++ /dev/null
@@ -1,467 +0,0 @@
-// Copyright (c) 2013, 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:unittest/unittest.dart';
-
-import 'dart:async' show Future;
-import 'dart:io' show Platform;
-
-import '../lib/src/export_map.dart';
-import '../../../../../tests/compiler/dart2js/memory_source_file_helper.dart'
- show MemorySourceFileProvider;
-import '../../compiler/implementation/mirrors/mirrors.dart'
- show MirrorSystem, LibraryMirror;
-import '../../compiler/implementation/mirrors/dart2js_mirror.dart'
- as source_mirrors;
-
-Future<MirrorSystem> mirrorSystemFor(Map<String, String> memorySourceFiles) {
- var provider = new MemorySourceFileProvider(memorySourceFiles);
- handler(Uri uri, int begin, int end, String message, kind) {}
-
- var script = Uri.base.resolveUri(Platform.script);
- var libraryRoot = script.resolve('../../../../');
- // Read packages from 'memory:packages/'.
- var packageRoot = Uri.parse('memory:packages/');
-
- var libraries = <Uri>[];
- memorySourceFiles.forEach((String path, _) {
- if (path.startsWith('packages/')) {
- // Analyze files from 'packages/' as packages.
- libraries.add(new Uri(scheme: 'package', path: path.substring(9)));
- } else {
- libraries.add(new Uri(scheme: 'memory', path: path));
- }
- });
- libraries.add(new Uri(scheme: 'dart', path: 'async'));
- return source_mirrors.analyze(
- libraries, libraryRoot, packageRoot, provider, handler);
-}
-
-Future<ExportMap> testExports(Map<String, String> sourceFiles) {
- return mirrorSystemFor(sourceFiles).then((mirrors) {
- libMirror = (uri) => mirrors.libraries[Uri.parse(uri)];
- return new ExportMap(mirrors);
- });
-}
-
-Function libMirror;
-
-main() {
- group('ExportMap', () {
- test('with an empty library', () {
- return testExports({'lib.dart': ''}).then((map) {
- var lib = libMirror('memory:lib.dart');
- var nonexistent = libMirror('memory:nonexistent.dart');
-
- var expectedExports = {};
- expectedExports[lib] = [];
- expect(map.exports, equals(expectedExports));
- expect(map.transitiveExports(lib), isEmpty);
- expect(map.transitiveExports(nonexistent), isEmpty);
- });
- });
-
- test('with one library with one export', () {
- return testExports({
- 'a.dart': 'export "b.dart";',
- 'b.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b)
- ]));
-
- expect(map.transitiveExports(a), unorderedEquals([
- new Export(a, b)
- ]));
-
- expect(map.exports[b], isEmpty);
-
- expect(map.transitiveExports(b), isEmpty);
- });
- });
-
- test('with one library with multiple exports', () {
- return testExports({
- 'a.dart': 'export "b.dart";\nexport "c.dart";',
- 'b.dart': '', 'c.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
- var c = libMirror('memory:c.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b),
- new Export(a, c)
- ]));
-
- expect(map.transitiveExports(a), unorderedEquals([
- new Export(a, b),
- new Export(a, c)
- ]));
-
- expect(map.exports[b], isEmpty);
- expect(map.transitiveExports(b), isEmpty);
- expect(map.exports[c], isEmpty);
- expect(map.transitiveExports(c), isEmpty);
- });
- });
-
- test('with two libraries each with one export', () {
- return testExports({
- 'a.dart': 'export "a_export.dart";',
- 'b.dart': 'export "b_export.dart";',
- 'a_export.dart': '',
- 'b_export.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
- var a_export = libMirror('memory:a_export.dart');
- var b_export = libMirror('memory:b_export.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, a_export),
- ]));
- expect(map.transitiveExports(a), unorderedEquals([
- new Export(a, a_export),
- ]));
-
- expect(map.transitiveExports(b), unorderedEquals([
- new Export(b, b_export),
- ]));
- expect(map.exports[b], unorderedEquals([
- new Export(b, b_export)
- ]));
-
- expect(map.exports[a_export], isEmpty);
- expect(map.transitiveExports(a_export), isEmpty);
- expect(map.exports[b_export], isEmpty);
- expect(map.transitiveExports(b_export), isEmpty);
- });
- });
-
- test('with a transitive export', () {
- return testExports({
- 'a.dart': 'export "b.dart";',
- 'b.dart': 'export "c.dart";',
- 'c.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
- var c = libMirror('memory:c.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b),
- ]));
- expect(map.transitiveExports(a), unorderedEquals([
- new Export(a, b),
- new Export(a, c),
- ]));
-
- expect(map.exports[b], unorderedEquals([
- new Export(b, c),
- ]));
- expect(map.transitiveExports(b), unorderedEquals([
- new Export(b, c),
- ]));
-
- expect(map.exports[c], isEmpty);
- expect(map.transitiveExports(c), isEmpty);
- });
- });
-
- test('with an export through an import', () {
- return testExports({
- 'a.dart': 'import "b.dart";',
- 'b.dart': 'export "c.dart";',
- 'c.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
- var c = libMirror('memory:c.dart');
-
- expect(map.exports[b], unorderedEquals([
- new Export(b, c),
- ]));
- expect(map.transitiveExports(b), unorderedEquals([
- new Export(b, c),
- ]));
-
- expect(map.exports[a], isEmpty);
- expect(map.exports[c], isEmpty);
- expect(map.transitiveExports(a), isEmpty);
- expect(map.transitiveExports(c), isEmpty);
- });
- });
-
- test('with an export with a show combinator', () {
- return testExports({
- 'a.dart': 'export "b.dart" show x, y;',
- 'b.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b, show: ['x', 'y'])
- ]));
- });
- });
-
- test('with an export with a hide combinator', () {
- return testExports({
- 'a.dart': 'export "b.dart" hide x, y;',
- 'b.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b, hide: ['x', 'y'])
- ]));
- });
- });
-
- test('with an export with a show and a hide combinator', () {
- return testExports({
- 'a.dart': 'export "b.dart" show x, y hide y, z;',
- 'b.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b, show: ['x'])
- ]));
- });
- });
-
- test('composes transitive exports', () {
- return testExports({
- 'a.dart': 'export "b.dart" hide x;',
- 'b.dart': 'export "c.dart" hide y;',
- 'c.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
- var c = libMirror('memory:c.dart');
-
- expect(map.transitiveExports(a), unorderedEquals([
- new Export(a, b, hide: ['x']),
- new Export(a, c, hide: ['x', 'y'])
- ]));
- });
- });
-
- test('merges adjacent exports', () {
- return testExports({
- 'a.dart': '''
- export "b.dart" show x, y;
- export "b.dart" hide y, z;
- ''',
- 'b.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b, hide: ['z']),
- ]));
- expect(map.transitiveExports(a), unorderedEquals([
- new Export(a, b, hide: ['z']),
- ]));
- });
- });
-
- test('merges adjacent exports transitively', () {
- return testExports({
- 'a.dart': 'export "b.dart";\nexport "c.dart";',
- 'b.dart': 'export "d.dart" show x, y;',
- 'c.dart': 'export "d.dart" hide y, z;',
- 'd.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('memory:b.dart');
- var c = libMirror('memory:c.dart');
- var d = libMirror('memory:d.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b),
- new Export(a, c),
- ]));
- expect(map.transitiveExports(a), unorderedEquals([
- new Export(a, b),
- new Export(a, c),
- new Export(a, d, hide: ['z']),
- ]));
- });
- });
-
- test('resolves package: exports', () {
- return testExports({
- 'a.dart': 'export "package:b/b.dart";',
- 'packages/b/b.dart': ''
- }).then((map) {
- var a = libMirror('memory:a.dart');
- var b = libMirror('package:b/b.dart');
- expect(map.exports[a], unorderedEquals([
- new Export(a, b)
- ]));
- });
- });
-
- test('ignores dart: exports', () {
- return testExports({'a.dart': 'export "dart:async";'}).then((map) {
- var a = libMirror('memory:a.dart');
-
- expect(map.exports[a], isEmpty);
- });
- });
-
- test('.parse() resolves package: imports', () {
- return testExports({
- 'packages/a/a.dart': 'export "package:b/b.dart";',
- 'packages/b/b.dart': ''
- }).then((map) {
- var a = libMirror('package:a/a.dart');
- var b = libMirror('package:b/b.dart');
-
- expect(map.exports[a], unorderedEquals([
- new Export(a, b)
- ]));
- });
- });
-
- test('.parse() ignores dart: imports', () {
- return testExports({}).then((map) {
- expect(map.exports, isEmpty);
- });
- });
- });
-
- group('Export', () {
- test('normalizes hide and show', () {
- expect(new Export(null, null, show: ['x', 'y'], hide: ['y', 'z']),
- equals(new Export(null, null, show: ['x'])));
- });
-
- test("doesn't care about the order of show or hide", () {
- expect(new Export(null, null, show: ['x', 'y']),
- equals(new Export(null, null, show: ['y', 'x'])));
- expect(new Export(null, null, hide: ['x', 'y']),
- equals(new Export(null, null, hide: ['y', 'x'])));
- });
-
- test('with no combinators considers anything visible', () {
- var export = new Export(null, null);
- expect(export.isMemberVisible('x'), isTrue);
- expect(export.isMemberVisible('y'), isTrue);
- expect(export.isMemberVisible('z'), isTrue);
- });
-
- test('with hide combinators considers anything not hidden visible', () {
- var export = new Export(null, null, hide: ['x', 'y']);
- expect(export.isMemberVisible('x'), isFalse);
- expect(export.isMemberVisible('y'), isFalse);
- expect(export.isMemberVisible('z'), isTrue);
- });
-
- test('with show combinators considers anything not shown invisible', () {
- var export = new Export(null, null, show: ['x', 'y']);
- expect(export.isMemberVisible('x'), isTrue);
- expect(export.isMemberVisible('y'), isTrue);
- expect(export.isMemberVisible('z'), isFalse);
- });
-
- test('composing uses the parent exporter and child path', () {
- return testExports({
- 'exporter1.dart': '',
- 'exporter2.dart': '',
- 'path1.dart': '',
- 'path2.dart': ''
- }).then((map) {
- var exporter1 = libMirror('memory:exporter1.dart');
- var exporter2 = libMirror('memory:exporter2.dart');
- var path1 = libMirror('memory:path1.dart');
- var path2 = libMirror('memory:path2.dart');
- expect(new Export(exporter1, path1)
- .compose(new Export(exporter2, path2)),
- equals(new Export(exporter1, path2)));
- });
- });
-
- test('composing show . show takes the intersection', () {
- expect(new Export(null, null, show: ['x', 'y'])
- .compose(new Export(null, null, show: ['y', 'z'])),
- equals(new Export(null, null, show: ['y'])));
- });
-
- test('composing show . hide takes the difference', () {
- expect(new Export(null, null, show: ['x', 'y'])
- .compose(new Export(null, null, hide: ['y', 'z'])),
- equals(new Export(null, null, show: ['x'])));
- });
-
- test('composing hide . show takes the reverse difference', () {
- expect(new Export(null, null, hide: ['x', 'y'])
- .compose(new Export(null, null, show: ['y', 'z'])),
- equals(new Export(null, null, show: ['z'])));
- });
-
- test('composing hide . hide takes the union', () {
- expect(new Export(null, null, hide: ['x', 'y'])
- .compose(new Export(null, null, hide: ['y', 'z'])),
- equals(new Export(null, null, hide: ['x', 'y', 'z'])));
- });
-
- test('merging requires identical exporters and paths', () {
- return testExports({
- 'exporter1.dart': '',
- 'exporter2.dart': '',
- 'path1.dart': '',
- 'path2.dart': ''
- }).then((map) {
- var exporter1 = libMirror('memory:exporter1.dart');
- var exporter2 = libMirror('memory:exporter2.dart');
- var path1 = libMirror('memory:path1.dart');
- var path2 = libMirror('memory:path2.dart');
- expect(() => new Export(exporter1, null)
- .merge(new Export(exporter2, null)),
- throwsA(isArgumentError));
- expect(() => new Export(null, path1)
- .merge(new Export(null, path2)),
- throwsA(isArgumentError));
- expect(new Export(null, null)
- .merge(new Export(null, null)),
- equals(new Export(null, null)));
- });
- });
-
- test('merging show + show takes the union', () {
- expect(new Export(null, null, show: ['x', 'y'])
- .merge(new Export(null, null, show: ['y', 'z'])),
- equals(new Export(null, null, show: ['x', 'y', 'z'])));
- });
-
- test('merging show + hide takes the difference', () {
- expect(new Export(null, null, show: ['x', 'y'])
- .merge(new Export(null, null, hide: ['y', 'z'])),
- equals(new Export(null, null, hide: ['z'])));
- });
-
- test('merging hide + show takes the difference', () {
- expect(new Export(null, null, hide: ['x', 'y'])
- .merge(new Export(null, null, show: ['y', 'z'])),
- equals(new Export(null, null, hide: ['x'])));
- });
-
- test('merging hide + hide takes the intersection', () {
- expect(new Export(null, null, hide: ['x', 'y'])
- .merge(new Export(null, null, hide: ['y', 'z'])),
- equals(new Export(null, null, hide: ['y'])));
- });
- });
-}
diff --git a/sdk/lib/_internal/dartdoc/test/markdown_test.dart b/sdk/lib/_internal/dartdoc/test/markdown_test.dart
deleted file mode 100644
index aff43da..0000000
--- a/sdk/lib/_internal/dartdoc/test/markdown_test.dart
+++ /dev/null
@@ -1,912 +0,0 @@
-// Copyright (c) 2011, 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.
-
-/// Unit tests for markdown.
-library markdownTests;
-
-import 'package:unittest/unittest.dart';
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../lib/markdown.dart';
-
-/// Most of these tests are based on observing how showdown behaves:
-/// http://softwaremaniacs.org/playground/showdown-highlight/
-void main() {
- group('Paragraphs', () {
- validate('consecutive lines form a single paragraph', '''
- This is the first line.
- This is the second line.
- ''', '''
- <p>This is the first line.
- This is the second line.</p>
- ''');
-
- // TODO(rnystrom): The rules here for what happens to lines following a
- // paragraph appear to be completely arbitrary in markdown. If it makes the
- // code significantly cleaner, we should consider ourselves free to change
- // these tests.
-
- validate('are terminated by a header', '''
- para
- # header
- ''', '''
- <p>para</p>
- <h1>header</h1>
- ''');
-
- validate('are terminated by a setext header', '''
- para
- header
- ==
- ''', '''
- <p>para</p>
- <h1>header</h1>
- ''');
-
- validate('are terminated by a hr', '''
- para
- ___
- ''', '''
- <p>para</p>
- <hr />
- ''');
-
- validate('consume an unordered list', '''
- para
- * list
- ''', '''
- <p>para
- * list</p>
- ''');
-
- validate('consume an ordered list', '''
- para
- 1. list
- ''', '''
- <p>para
- 1. list</p>
- ''');
-
- // Windows line endings have a \r\n format
- // instead of the unix \n format.
- validate('take account of windows line endings', '''
- line1\r\n\r\n line2\r\n
- ''', '''
- <p>line1</p>
- <p>line2</p>
- ''');
- });
-
- group('Setext headers', () {
- validate('h1', '''
- text
- ===
- ''', '''
- <h1>text</h1>
- ''');
-
- validate('h2', '''
- text
- ---
- ''', '''
- <h2>text</h2>
- ''');
-
- validate('h1 on first line becomes text', '''
- ===
- ''', '''
- <p>===</p>
- ''');
-
- validate('h2 on first line becomes text', '''
- -
- ''', '''
- <p>-</p>
- ''');
-
- validate('h1 turns preceding list into text', '''
- - list
- ===
- ''', '''
- <h1>- list</h1>
- ''');
-
- validate('h2 turns preceding list into text', '''
- - list
- ===
- ''', '''
- <h1>- list</h1>
- ''');
-
- validate('h1 turns preceding blockquote into text', '''
- > quote
- ===
- ''', '''
- <h1>> quote</h1>
- ''');
-
- validate('h2 turns preceding blockquote into text', '''
- > quote
- ===
- ''', '''
- <h1>> quote</h1>
- ''');
- });
-
- group('Headers', () {
- validate('h1', '''
- # header
- ''', '''
- <h1>header</h1>
- ''');
-
- validate('h2', '''
- ## header
- ''', '''
- <h2>header</h2>
- ''');
-
- validate('h3', '''
- ### header
- ''', '''
- <h3>header</h3>
- ''');
-
- validate('h4', '''
- #### header
- ''', '''
- <h4>header</h4>
- ''');
-
- validate('h5', '''
- ##### header
- ''', '''
- <h5>header</h5>
- ''');
-
- validate('h6', '''
- ###### header
- ''', '''
- <h6>header</h6>
- ''');
-
- validate('trailing "#" are removed', '''
- # header ######
- ''', '''
- <h1>header</h1>
- ''');
-
- });
-
- group('Unordered lists', () {
- validate('asterisk, plus and hyphen', '''
- * star
- - dash
- + plus
- ''', '''
- <ul>
- <li>star</li>
- <li>dash</li>
- <li>plus</li>
- </ul>
- ''');
-
- validate('allow numbered lines after first', '''
- * a
- 1. b
- ''', '''
- <ul>
- <li>a</li>
- <li>b</li>
- </ul>
- ''');
-
- validate('allow a tab after the marker', '''
- *\ta
- +\tb
- -\tc
- 1.\td
- ''', '''
- <ul>
- <li>a</li>
- <li>b</li>
- <li>c</li>
- <li>d</li>
- </ul>
- ''');
-
- validate('wrap items in paragraphs if blank lines separate', '''
- * one
-
- * two
- ''', '''
- <ul>
- <li><p>one</p></li>
- <li><p>two</p></li>
- </ul>
- ''');
-
- validate('force paragraph on item before and after blank lines', '''
- * one
- * two
-
- * three
- ''', '''
- <ul>
- <li>one</li>
- <li>
- <p>two</p>
- </li>
- <li>
- <p>three</p>
- </li>
- </ul>
- ''');
-
- validate('do not force paragraph if item is already block', '''
- * > quote
-
- * # header
- ''', '''
- <ul>
- <li><blockquote><p>quote</p></blockquote></li>
- <li><h1>header</h1></li>
- </ul>
- ''');
-
- validate('can contain multiple paragraphs', '''
- * one
-
- two
-
- * three
- ''', '''
- <ul>
- <li>
- <p>one</p>
- <p>two</p>
- </li>
- <li>
- <p>three</p>
- </li>
- </ul>
- ''');
-
- validate('can span newlines', '''
- * one
- two
- * three
- ''', '''
- <ul>
- <li>
- <p>one
- two</p>
- </li>
- <li>
- three
- </li>
- </ul>
- ''');
-
- // TODO(rnystrom): This is how most other markdown parsers handle
- // this but that seems like a nasty special case. For now, let's not
- // worry about it.
- /*
- validate('can nest using indentation', '''
- * parent
- * child
- ''', '''
- <ul>
- <li>parent
- <ul><li>child</li></ul></li>
- </ul>
- ''');
- */
- });
-
- group('Ordered lists', () {
- validate('start with numbers', '''
- 1. one
- 45. two
- 12345. three
- ''', '''
- <ol>
- <li>one</li>
- <li>two</li>
- <li>three</li>
- </ol>
- ''');
-
- validate('allow unordered lines after first', '''
- 1. a
- * b
- ''', '''
- <ol>
- <li>a</li>
- <li>b</li>
- </ol>
- ''');
- });
-
- group('Blockquotes', () {
- validate('single line', '''
- > blah
- ''', '''
- <blockquote>
- <p>blah</p>
- </blockquote>
- ''');
-
- validate('with two paragraphs', '''
- > first
- >
- > second
- ''', '''
- <blockquote>
- <p>first</p>
- <p>second</p>
- </blockquote>
- ''');
-
- validate('nested', '''
- > one
- >> two
- > > > three
- ''', '''
- <blockquote>
- <p>one</p>
- <blockquote>
- <p>two</p>
- <blockquote>
- <p>three</p>
- </blockquote>
- </blockquote>
- </blockquote>
- ''');
- });
-
- group('Code blocks', () {
- validate('single line', '''
- code
- ''', '''
- <pre><code>code</code></pre>
- ''');
-
- validate('include leading whitespace after indentation', '''
- zero
- one
- two
- three
- ''', '''
- <pre><code>zero
- one
- two
- three</code></pre>
- ''');
-
- validate('code blocks separated by newlines form one block', '''
- zero
- one
-
- two
-
- three
- ''', '''
- <pre><code>zero
- one
-
- two
-
- three</code></pre>
- ''');
-
- validate('code blocks separated by two newlines form multiple blocks', '''
- zero
- one
-
-
- two
-
-
- three
- ''', '''
- <pre><code>zero
- one</code></pre>
- <pre><code>two</code></pre>
- <pre><code>three</code></pre>
- ''');
-
- validate('escape HTML characters', '''
- <&>
- ''', '''
- <pre><code><&></code></pre>
- ''');
- });
-
- group('Horizontal rules', () {
- validate('from dashes', '''
- ---
- ''', '''
- <hr />
- ''');
-
- validate('from asterisks', '''
- ***
- ''', '''
- <hr />
- ''');
-
- validate('from underscores', '''
- ___
- ''', '''
- <hr />
- ''');
-
- validate('can include up to two spaces', '''
- _ _ _
- ''', '''
- <hr />
- ''');
- });
-
- group('Block-level HTML', () {
- validate('single line', '''
- <table></table>
- ''', '''
- <table></table>
- ''');
-
- validate('multi-line', '''
- <table>
- blah
- </table>
- ''', '''
- <table>
- blah
- </table>
- ''');
-
- validate('blank line ends block', '''
- <table>
- blah
- </table>
-
- para
- ''', '''
- <table>
- blah
- </table>
- <p>para</p>
- ''');
-
- validate('HTML can be bogus', '''
- <bogus>
- blah
- </weird>
-
- para
- ''', '''
- <bogus>
- blah
- </weird>
- <p>para</p>
- ''');
- });
-
- group('Strong', () {
- validate('using asterisks', '''
- before **strong** after
- ''', '''
- <p>before <strong>strong</strong> after</p>
- ''');
-
- validate('using underscores', '''
- before __strong__ after
- ''', '''
- <p>before <strong>strong</strong> after</p>
- ''');
-
- validate('unmatched asterisks', '''
- before ** after
- ''', '''
- <p>before ** after</p>
- ''');
-
- validate('unmatched underscores', '''
- before __ after
- ''', '''
- <p>before __ after</p>
- ''');
-
- validate('multiple spans in one text', '''
- a **one** b __two__ c
- ''', '''
- <p>a <strong>one</strong> b <strong>two</strong> c</p>
- ''');
-
- validate('multi-line', '''
- before **first
- second** after
- ''', '''
- <p>before <strong>first
- second</strong> after</p>
- ''');
- });
-
- group('Emphasis and strong', () {
- validate('single asterisks', '''
- before *em* after
- ''', '''
- <p>before <em>em</em> after</p>
- ''');
-
- validate('single underscores', '''
- before _em_ after
- ''', '''
- <p>before <em>em</em> after</p>
- ''');
-
- validate('double asterisks', '''
- before **strong** after
- ''', '''
- <p>before <strong>strong</strong> after</p>
- ''');
-
- validate('double underscores', '''
- before __strong__ after
- ''', '''
- <p>before <strong>strong</strong> after</p>
- ''');
-
- validate('unmatched asterisk', '''
- before *after
- ''', '''
- <p>before *after</p>
- ''');
-
- validate('unmatched underscore', '''
- before _after
- ''', '''
- <p>before _after</p>
- ''');
-
- validate('multiple spans in one text', '''
- a *one* b _two_ c
- ''', '''
- <p>a <em>one</em> b <em>two</em> c</p>
- ''');
-
- validate('multi-line', '''
- before *first
- second* after
- ''', '''
- <p>before <em>first
- second</em> after</p>
- ''');
-
- validate('not processed when surrounded by spaces', '''
- a * b * c _ d _ e
- ''', '''
- <p>a * b * c _ d _ e</p>
- ''');
-
- validate('strong then emphasis', '''
- **strong***em*
- ''', '''
- <p><strong>strong</strong><em>em</em></p>
- ''');
-
- validate('emphasis then strong', '''
- *em***strong**
- ''', '''
- <p><em>em</em><strong>strong</strong></p>
- ''');
-
- validate('emphasis inside strong', '''
- **strong *em***
- ''', '''
- <p><strong>strong <em>em</em></strong></p>
- ''');
-
- validate('mismatched in nested', '''
- *a _b* c_
- ''', '''
- <p><em>a _b</em> c_</p>
- ''');
-
- validate('cannot nest tags of same type', '''
- *a _b *c* d_ e*
- ''', '''
- <p><em>a _b </em>c<em> d_ e</em></p>
- ''');
- });
-
- group('Inline code', () {
- validate('simple case', '''
- before `source` after
- ''', '''
- <p>before <code>source</code> after</p>
- ''');
-
- validate('unmatched backtick', '''
- before ` after
- ''', '''
- <p>before ` after</p>
- ''');
- validate('multiple spans in one text', '''
- a `one` b `two` c
- ''', '''
- <p>a <code>one</code> b <code>two</code> c</p>
- ''');
-
- validate('multi-line', '''
- before `first
- second` after
- ''', '''
- <p>before <code>first
- second</code> after</p>
- ''');
-
- validate('simple double backticks', '''
- before ``source`` after
- ''', '''
- <p>before <code>source</code> after</p>
- ''');
-
- validate('double backticks', '''
- before ``can `contain` backticks`` after
- ''', '''
- <p>before <code>can `contain` backticks</code> after</p>
- ''');
-
- validate('double backticks with spaces', '''
- before `` `tick` `` after
- ''', '''
- <p>before <code>`tick`</code> after</p>
- ''');
-
- validate('multiline double backticks with spaces', '''
- before ``in `tick`
- another`` after
- ''', '''
- <p>before <code>in `tick`
- another</code> after</p>
- ''');
-
- validate('ignore markup inside code', '''
- before `*b* _c_` after
- ''', '''
- <p>before <code>*b* _c_</code> after</p>
- ''');
-
- validate('escape HTML characters', '''
- `<&>`
- ''', '''
- <p><code><&></code></p>
- ''');
-
- validate('escape HTML tags', '''
- '*' `<em>`
- ''', '''
- <p>'*' <code><em></code></p>
- ''');
- });
-
- group('HTML encoding', () {
- validate('less than and ampersand are escaped', '''
- < &
- ''', '''
- <p>< &</p>
- ''');
- validate('greater than is not escaped', '''
- not you >
- ''', '''
- <p>not you ></p>
- ''');
- validate('existing entities are untouched', '''
- &
- ''', '''
- <p>&</p>
- ''');
- });
-
- group('Autolinks', () {
- validate('basic link', '''
- before <http://foo.com/> after
- ''', '''
- <p>before <a href="http://foo.com/">http://foo.com/</a> after</p>
- ''');
- validate('handles ampersand in url', '''
- <http://foo.com/?a=1&b=2>
- ''', '''
- <p><a href="http://foo.com/?a=1&b=2">http://foo.com/?a=1&b=2</a></p>
- ''');
- });
-
- group('Reference links', () {
- validate('double quotes for title', '''
- links [are] [a] awesome
-
- [a]: http://foo.com "woo"
- ''', '''
- <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
- ''');
- validate('single quoted title', """
- links [are] [a] awesome
-
- [a]: http://foo.com 'woo'
- """, '''
- <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
- ''');
- validate('parentheses for title', '''
- links [are] [a] awesome
-
- [a]: http://foo.com (woo)
- ''', '''
- <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
- ''');
- validate('no title', '''
- links [are] [a] awesome
-
- [a]: http://foo.com
- ''', '''
- <p>links <a href="http://foo.com">are</a> awesome</p>
- ''');
- validate('unknown link becomes plaintext', '''
- [not] [known]
- ''', '''
- <p>[not] [known]</p>
- ''');
- validate('can style link contents', '''
- links [*are*] [a] awesome
-
- [a]: http://foo.com
- ''', '''
- <p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
- ''');
- validate('inline styles after a bad link are processed', '''
- [bad] `code`
- ''', '''
- <p>[bad] <code>code</code></p>
- ''');
- validate('empty reference uses text from link', '''
- links [are][] awesome
-
- [are]: http://foo.com
- ''', '''
- <p>links <a href="http://foo.com">are</a> awesome</p>
- ''');
- validate('references are case-insensitive', '''
- links [ARE][] awesome
-
- [are]: http://foo.com
- ''', '''
- <p>links <a href="http://foo.com">ARE</a> awesome</p>
- ''');
- });
-
- group('Inline links', () {
- validate('double quotes for title', '''
- links [are](http://foo.com "woo") awesome
- ''', '''
- <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
- ''');
- validate('no title', '''
- links [are] (http://foo.com) awesome
- ''', '''
- <p>links <a href="http://foo.com">are</a> awesome</p>
- ''');
- validate('can style link contents', '''
- links [*are*](http://foo.com) awesome
- ''', '''
- <p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
- ''');
- });
-
- group('Resolver', () {
- var nyanResolver = (text) => new Text('~=[,,_${text}_,,]:3');
- validate('simple resolver', '''
- resolve [this] thing
- ''', '''
- <p>resolve ~=[,,_this_,,]:3 thing</p>
- ''', linkResolver: nyanResolver);
- });
-
- group('Custom inline syntax', () {
- List<InlineSyntax> nyanSyntax =
- [new TextSyntax('nyan', sub: '~=[,,_,,]:3')];
- validate('simple inline syntax', '''
- nyan
- ''', '''
- <p>~=[,,_,,]:3</p>
- ''', inlineSyntaxes: nyanSyntax);
-
- // TODO(amouravski): need more tests here for custom syntaxes, as some
- // things are not quite working properly. The regexps are sometime a little
- // too greedy, I think.
- });
-}
-
-/**
- * Removes eight spaces of leading indentation from a multiline string.
- *
- * Note that this is very sensitive to how the literals are styled. They should
- * be:
- * '''
- * Text starts on own line. Lines up with subsequent lines.
- * Lines are indented exactly 8 characters from the left margin.'''
- *
- * This does nothing if text is only a single line.
- */
-// TODO(nweiz): Make this auto-detect the indentation level from the first
-// non-whitespace line.
-String cleanUpLiteral(String text) {
- var lines = text.split('\n');
- if (lines.length <= 1) return text;
-
- for (var j = 0; j < lines.length; j++) {
- if (lines[j].length > 8) {
- lines[j] = lines[j].substring(8, lines[j].length);
- } else {
- lines[j] = '';
- }
- }
-
- return lines.join('\n');
-}
-
-validate(String description, String markdown, String html,
- {bool verbose: false, inlineSyntaxes, linkResolver}) {
- test(description, () {
- markdown = cleanUpLiteral(markdown);
- html = cleanUpLiteral(html);
-
- var result = markdownToHtml(markdown, inlineSyntaxes: inlineSyntaxes,
- linkResolver: linkResolver);
- var passed = compareOutput(html, result);
-
- if (!passed) {
- // Remove trailing newline.
- html = html.substring(0, html.length - 1);
-
- print('FAIL: $description');
- print(' expect: ${html.replaceAll("\n", "\n ")}');
- print(' actual: ${result.replaceAll("\n", "\n ")}');
- print('');
- }
-
- expect(passed, isTrue, verbose: verbose);
- });
-}
-
-/// Does a loose comparison of the two strings of HTML. Ignores differences in
-/// newlines and indentation.
-compareOutput(String a, String b) {
- int i = 0;
- int j = 0;
-
- skipIgnored(String s, int i) {
- // Ignore newlines.
- while ((i < s.length) && (s[i] == '\n')) {
- i++;
- // Ignore indentation.
- while ((i < s.length) && (s[i] == ' ')) i++;
- }
-
- return i;
- }
-
- while (true) {
- i = skipIgnored(a, i);
- j = skipIgnored(b, j);
-
- // If one string runs out of non-ignored strings, the other must too.
- if (i == a.length) return j == b.length;
- if (j == b.length) return i == a.length;
-
- if (a[i] != b[j]) return false;
- i++;
- j++;
- }
-}
diff --git a/sdk/lib/_internal/dartdoc/test/test_files/lib/no_package_test_file.dart b/sdk/lib/_internal/dartdoc/test/test_files/lib/no_package_test_file.dart
deleted file mode 100644
index 99a30ba..0000000
--- a/sdk/lib/_internal/dartdoc/test/test_files/lib/no_package_test_file.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-library no_package_test;
-
-class NoPackageTestFile {
-
-}
diff --git a/sdk/lib/_internal/dartdoc/test/test_files/package_test_file.dart b/sdk/lib/_internal/dartdoc/test/test_files/package_test_file.dart
deleted file mode 100644
index de09194..0000000
--- a/sdk/lib/_internal/dartdoc/test/test_files/package_test_file.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-library package_test;
-
-class PackageTestFile {
-
-}
diff --git a/sdk/lib/_internal/dartdoc/test/utils_test.dart b/sdk/lib/_internal/dartdoc/test/utils_test.dart
deleted file mode 100644
index fae4eec..0000000
--- a/sdk/lib/_internal/dartdoc/test/utils_test.dart
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012, 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:unittest/unittest.dart';
-
-import '../lib/src/dartdoc/utils.dart';
-
-void main() {
- group('countOccurrences', () {
- test('empty text returns 0', () {
- expect(countOccurrences('', 'needle'), equals(0));
- });
-
- test('one occurrence', () {
- expect(countOccurrences('bananarama', 'nara'), equals(1));
- });
-
- test('multiple occurrences', () {
- expect(countOccurrences('bananarama', 'a'), equals(5));
- });
-
- test('overlapping matches do not count', () {
- expect(countOccurrences('bananarama', 'ana'), equals(1));
- });
- });
-
- group('repeat', () {
- test('zero times returns an empty string', () {
- expect(repeat('ba', 0), isEmpty);
- });
-
- test('one time returns the string', () {
- expect(repeat('ba', 1), equals('ba'));
- });
-
- test('multiple times', () {
- expect(repeat('ba', 3), equals('bababa'));
- });
-
- test('multiple times with a separator', () {
- expect(repeat('ba', 3, separator: ' '), equals('ba ba ba'));
- });
- });
-}
diff --git a/sdk/lib/_internal/lib/constant_map.dart b/sdk/lib/_internal/lib/constant_map.dart
index 398d37c..7dbedbc 100644
--- a/sdk/lib/_internal/lib/constant_map.dart
+++ b/sdk/lib/_internal/lib/constant_map.dart
@@ -5,6 +5,8 @@
part of _js_helper;
abstract class ConstantMap<K, V> implements Map<K, V> {
+ const ConstantMap._();
+
bool get isEmpty => length == 0;
bool get isNotEmpty => !isEmpty;
@@ -21,10 +23,13 @@
void addAll(Map<K, V> other) => _throwUnmodifiable();
}
-// This class has no constructor. This is on purpose since the instantiation
-// is shortcut by the compiler.
class ConstantStringMap<K, V> extends ConstantMap<K, V>
implements _symbol_dev.EfficientLength {
+
+ // This constructor is not used. The instantiation is shortcut by the
+ // compiler. It is here to make the uninitialized final fields legal.
+ const ConstantStringMap._(this.length, this._jsObject, _keys) : super._();
+
final int length;
// A constant map is backed by a JavaScript object.
final _jsObject;
@@ -62,6 +67,10 @@
// This class has no constructor. This is on purpose since the instantiation
// is shortcut by the compiler.
class ConstantProtoMap<K, V> extends ConstantStringMap<K, V> {
+ // This constructor is not used. The instantiation is shortcut by the
+ // compiler. It is here to make the uninitialized final fields legal.
+ ConstantProtoMap._(length, jsObject, keys) : super._(length, jsObject, keys);
+
final V _protoValue;
bool containsKey(Object key) {
@@ -82,9 +91,11 @@
Iterator<K> get iterator => _map._keys.iterator;
}
-// This class has no constructor. This is on purpose since the instantiation
-// is shortcut by the compiler.
class GeneralConstantMap<K, V> extends ConstantMap<K, V> {
+ // This constructor is not used. The instantiation is shortcut by the
+ // compiler. It is here to make the uninitialized final fields legal.
+ GeneralConstantMap(this._jsData) : super._();
+
// [_jsData] holds a key-value pair list.
final _jsData;
diff --git a/sdk/lib/_internal/lib/convert_patch.dart b/sdk/lib/_internal/lib/convert_patch.dart
index 1f0b0575..70b4d5f 100644
--- a/sdk/lib/_internal/lib/convert_patch.dart
+++ b/sdk/lib/_internal/lib/convert_patch.dart
@@ -92,3 +92,8 @@
return revive(null, walk(json));
}
+
+patch class _Utf8Encoder {
+ // Use Uint8List when supported on all platforms.
+ patch static List<int> _createBuffer(int size) => new List<int>(size);
+}
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index 88e4f86..a07fe16 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -41,7 +41,7 @@
}
patch class FileStat {
- patch static List<int> _statSync(String path) {
+ patch static _statSync(String path) {
throw new UnsupportedError("FileStat.stat");
}
}
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
index 6debde7..0520864 100644
--- a/sdk/lib/_internal/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/lib/isolate_helper.dart
@@ -11,7 +11,8 @@
Closure,
Null,
Primitives,
- convertDartClosureToJS;
+ convertDartClosureToJS,
+ random64;
import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
JS,
JS_CREATE_ISOLATE,
@@ -921,6 +922,13 @@
throw "Illegal underlying port $x";
}
+ visitCapability(Capability x) {
+ if (x is CapabilityImpl) {
+ return ['capability', x._id];
+ }
+ throw "Capability not serializable: $x";
+ }
+
visitNativeJsSendPort(_NativeJsSendPort port) {
return ['sendport', _globalState.currentManagerId,
port._isolateId, port._receivePort._id];
@@ -942,6 +950,13 @@
throw "Illegal underlying port $x";
}
+ visitCapability(Capability x) {
+ if (x is CapabilityImpl) {
+ return new CapabilityImpl._internal(x._id);
+ }
+ throw "Capability not serializable: $x";
+ }
+
SendPort visitNativeJsSendPort(_NativeJsSendPort port) {
return new _NativeJsSendPort(port._receivePort, port._isolateId);
}
@@ -970,6 +985,10 @@
return new _WorkerSendPort(managerId, isolateId, receivePortId);
}
}
+
+ Capability deserializeCapability(List list) {
+ return new CapabilityImpl._internal(list[1]);
+ }
}
class _JsVisitedMap implements _MessageTraverserVisitedMap {
@@ -1062,10 +1081,13 @@
}
_dispatch(var x) {
+ // This code likely fails for user classes implementing
+ // SendPort and Capability because it assumes the internal classes.
if (isPrimitive(x)) return visitPrimitive(x);
if (x is List) return visitList(x);
if (x is Map) return visitMap(x);
if (x is SendPort) return visitSendPort(x);
+ if (x is Capability) return visitCapability(x);
// Overridable fallback.
return visitObject(x);
@@ -1075,6 +1097,7 @@
visitList(List x);
visitMap(Map x);
visitSendPort(SendPort x);
+ visitCapability(Capability x);
visitObject(Object x) {
// TODO(floitsch): make this a real exception. (which one)?
@@ -1121,6 +1144,8 @@
}
visitSendPort(SendPort x) => throw new UnimplementedError();
+
+ visitCapability(Capability x) => throw new UnimplementedError();
}
/** Visitor that serializes a message as a JSON array. */
@@ -1164,6 +1189,8 @@
}
visitSendPort(SendPort x) => throw new UnimplementedError();
+
+ visitCapability(Capability x) => throw new UnimplementedError();
}
/** Deserializes arrays created with [_Serializer]. */
@@ -1191,6 +1218,7 @@
case 'list': return _deserializeList(x);
case 'map': return _deserializeMap(x);
case 'sendport': return deserializeSendPort(x);
+ case 'capability': return deserializeCapability(x);
default: return deserializeObject(x);
}
}
@@ -1232,6 +1260,8 @@
deserializeSendPort(List x);
+ deserializeCapability(List x);
+
deserializeObject(List x) {
// TODO(floitsch): Use real exception (which one?).
throw "Unexpected serialized object";
@@ -1319,3 +1349,41 @@
}
bool hasTimer() => JS('', '#.setTimeout', globalThis) != null;
+
+
+/**
+ * Implementation class for [Capability].
+ *
+ * It has the same name to make it harder for users to distinguish.
+ */
+class CapabilityImpl implements Capability {
+ /** Internal random secret identifying the capability. */
+ final int _id;
+
+ CapabilityImpl() : this._internal(random64());
+
+ CapabilityImpl._internal(this._id);
+
+ int get hashCode {
+ // Thomas Wang 32 bit Mix.
+ // http://www.concentric.net/~Ttwang/tech/inthash.htm
+ // (via https://gist.github.com/badboy/6267743)
+ int hash = _id;
+ hash = (hash >> 0) ^ (hash ~/ 0x100000000); // To 32 bit from ~64.
+ hash = (~hash + (hash << 15)) & 0xFFFFFFFF;
+ hash ^= hash >> 12;
+ hash = (hash * 5) & 0xFFFFFFFF;
+ hash ^= hash >> 4;
+ hash = (hash * 2057) & 0xFFFFFFFF;
+ hash ^= hash >> 16;
+ return hash;
+ }
+
+ bool operator==(Object other) {
+ if (identical(other, this)) return true;
+ if (other is CapabilityImpl) {
+ return identical(_id, other._id);
+ }
+ return false;
+ }
+}
diff --git a/sdk/lib/_internal/lib/isolate_patch.dart b/sdk/lib/_internal/lib/isolate_patch.dart
index 45de5af..09b7955 100644
--- a/sdk/lib/_internal/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/lib/isolate_patch.dart
@@ -4,11 +4,12 @@
// Patch file for the dart:isolate library.
-import 'dart:_isolate_helper' show IsolateNatives,
- ReceivePortImpl,
- RawReceivePortImpl,
+import 'dart:_isolate_helper' show CapabilityImpl,
CloseToken,
- JsIsolateSink;
+ IsolateNatives,
+ JsIsolateSink,
+ ReceivePortImpl,
+ RawReceivePortImpl;
patch class Isolate {
patch static Future<Isolate> spawn(void entryPoint(message), var message) {
@@ -54,3 +55,7 @@
return new RawReceivePortImpl(handler);
}
}
+
+patch class Capability {
+ patch factory Capability() = CapabilityImpl;
+}
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index 54fb1b8..8be9ee5 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -407,7 +407,7 @@
FIRST_DEFAULT_ARGUMENT, parameter, requiredParameterCount);
}
- @NoInline
+ @NoInline()
computeFunctionRti(jsConstructor) {
if (JS('bool', 'typeof # == "number"', functionType)) {
return getMetadata(functionType);
@@ -2173,12 +2173,12 @@
return receiverHashCode ^ Primitives.objectHashCode(_target);
}
- @NoInline
+ @NoInline()
static selfOf(BoundClosure closure) => closure._self;
static targetOf(BoundClosure closure) => closure._target;
- @NoInline
+ @NoInline()
static receiverOf(BoundClosure closure) => closure._receiver;
static nameOf(BoundClosure closure) => closure._name;
@@ -2695,7 +2695,7 @@
@NoInline() @NoSideEffects()
_assertCheck(expression) {
- if (inAssert) return;
+ if (inAssert) return null;
inAssert = true; // Don't try to check this library itself.
try {
// Type inferrer don't think this is called with dynamic arguments.
@@ -3038,3 +3038,15 @@
String toString() => "Unsupported operation: $_message";
}
+
+/**
+ * Creates a random number with 64 bits of randomness.
+ *
+ * This will be truncated to the 53 bits available in a double.
+ */
+int random64() {
+ // TODO(lrn): Use a secure random source.
+ int int32a = JS("int", "(Math.random() * 0x100000000) >>> 0");
+ int int32b = JS("int", "(Math.random() * 0x100000000) >>> 0");
+ return int32a + int32b * 0x100000000;
+}
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index 24e7840..067b616 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -934,21 +934,26 @@
// JS helpers for getField optimizations.
static bool isUndefined(x)
=> JS('bool', 'typeof # == "undefined"', x);
+ static bool isMissingCache(x)
+ => JS('bool', 'typeof # == "number"', x);
static bool isMissingProbe(Symbol symbol)
=> JS('bool', 'typeof #.\$p == "undefined"', symbol);
- static bool isNewFunctionAllowed()
+ static bool isEvalAllowed()
=> JS('bool', 'typeof dart_precompiled != "function"');
- /// The getter cache is specific to this [InstanceMirror]
- /// and maps reflective names to functions that will invoke
- /// the corresponding getter on the reflectee. The reflectee
- /// is passed to the function as the first argument to avoid
- /// the overhead of fetching it from this mirror repeatedly.
+ /// The getter cache is lazily allocated after a couple
+ /// of invocations of [InstanceMirror.getField]. The delay is
+ /// used to avoid too aggressive caching and dynamic function
+ /// generation for rarely used mirrors. The cache is specific to
+ /// this [InstanceMirror] and maps reflective names to functions
+ /// that will invoke the corresponding getter on the reflectee.
+ /// The reflectee is passed to the function as the first argument
+ /// to avoid the overhead of fetching it from this mirror repeatedly.
/// The cache is lazily initialized to a JS object so we can
/// benefit from "map transitions" in the underlying JavaScript
/// engine to speed up cache probing.
- var _getterCache;
+ var _getterCache = 4;
InstanceMirror getField(Symbol fieldName) {
// BUG(16400): This should be a labelled block, but that makes
@@ -956,7 +961,7 @@
// inferencing implementation.
do {
var cache = _getterCache;
- if (cache == null || isMissingProbe(fieldName)) break;
+ if (isMissingCache(cache) || isMissingProbe(fieldName)) break;
// If the [fieldName] has an associated probe function, we can use
// it to read from the getter cache specific to this [InstanceMirror].
var getter = JS('', '#.\$p(#)', fieldName, cache);
@@ -985,29 +990,29 @@
String name = n(fieldName);
var result = _invoke(fieldName, JSInvocationMirror.GETTER, name, const []);
var cacheEntry = JsCache.fetch(_classInvocationCache, name);
- if (cacheEntry.isNoSuchMethod || cacheEntry.isIntercepted) {
+ if (cacheEntry.isNoSuchMethod) {
return result;
}
// Make sure we have a getter cache in this [InstanceMirror].
var cache = _getterCache;
- if (cache == null) {
- cache = _getterCache = JS('=Object', 'Object.create(null)');
+ if (isMissingCache(cache)) {
+ if ((_getterCache = --cache) != 0) return result;
+ cache = _getterCache = JS('=Object', '({})');
}
// Make sure that symbol [fieldName] has a cache probing function ($p).
+ bool useEval = isEvalAllowed();
if (isMissingProbe(fieldName)) {
- var probe = isNewFunctionAllowed()
- ? JS('', 'new Function("c", "return c." + # + ";")', name)
- : JS('', 'function (c) { return c[#]; }', name);
+ var probe = _newProbeFn(name, useEval);
JS('void', '#.\$p = #', fieldName, probe);
}
// Create a new getter function and install it in the cache.
var mangledName = cacheEntry.mangledName;
- var getter = isNewFunctionAllowed()
- ? JS('', 'new Function("o", "return o." + # + "();")', mangledName)
- : JS('', 'function(o) { return o[#](); }', mangledName);
+ var getter = (cacheEntry.isIntercepted)
+ ? _newInterceptedGetterFn(mangledName, useEval)
+ : _newGetterFn(mangledName, useEval);
JS('void', '#[#] = #', cache, name, getter);
// Initialize the last value (v) and last mirror (m) on the
@@ -1019,6 +1024,53 @@
return result;
}
+ _newProbeFn(String id, bool useEval) {
+ if (useEval) {
+ // We give the probe function a name to make it appear nicely in
+ // profiles and when debugging. The name also makes the source code
+ // for the function more "unique" so the underlying JavaScript
+ // engine is less likely to re-use an existing piece of generated
+ // code as the result of calling eval. In return, this leads to
+ // less polymorphic access in the probe function.
+ var body = "(function probe\$$id(c){return c.$id})";
+ return JS('', '(function(b){return eval(b)})(#)', body);
+ } else {
+ return JS('', '(function(n){return(function(c){return c[n]})})(#)', id);
+ }
+ }
+
+ _newGetterFn(String name, bool useEval) {
+ if (!useEval) return _newGetterNoEvalFn(name);
+ // We give the getter function a name that associates it with the
+ // class of the reflectee. This makes it easier to spot in profiles
+ // and when debugging, but it also means that the underlying JavaScript
+ // engine will only share the generated code for accessors on the
+ // same class (through caching of eval'ed code). This makes the
+ // generated call to the getter - e.g. o.get$foo() - much more likely
+ // to be monomorphic and inlineable.
+ String className = JS('String', '#.constructor.name', reflectee);
+ var body = "(function $className\$$name(o){return o.$name()})";
+ return JS('', '(function(b){return eval(b)})(#)', body);
+ }
+
+ _newGetterNoEvalFn(n) => JS('',
+ '(function(n){return(function(o){return o[n]()})})(#)', n);
+
+ _newInterceptedGetterFn(String name, bool useEval) {
+ var object = reflectee;
+ // It is possible that the interceptor for a given object is the object
+ // itself, so it is important not to share the code that captures the
+ // interceptor between multiple different instances of [InstanceMirror].
+ var interceptor = getInterceptor(object);
+ if (!useEval) return _newInterceptGetterNoEvalFn(name, interceptor);
+ String className = JS('String', '#.constructor.name', object);
+ var body = "(function $className\$$name(o){return i.$name(o)})";
+ return JS('', '(function(b,i){return eval(b)})(#,#)', body, interceptor);
+ }
+
+ _newInterceptGetterNoEvalFn(n, i) => JS('',
+ '(function(n,i){return(function(o){return i[n](o)})})(#,#)', n, i);
+
delegate(Invocation invocation) {
return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
}
diff --git a/sdk/lib/_internal/lib/math_patch.dart b/sdk/lib/_internal/lib/math_patch.dart
index e3aabe3..2ba47aa 100644
--- a/sdk/lib/_internal/lib/math_patch.dart
+++ b/sdk/lib/_internal/lib/math_patch.dart
@@ -80,23 +80,81 @@
static const int _MASK32 = 0xFFFFFFFF;
// State comprised of two unsigned 32 bit integers.
- int _lo;
- int _hi;
+ int _lo = 0;
+ int _hi = 0;
// Implements:
+ // uint64_t hash = 0;
// do {
- // seed = (seed + 0x5A17) & _Random._MASK_64;
- // } while (seed == 0);
- // _lo = seed & _MASK_32;
- // _hi = seed >> 32;
+ // hash = hash * 1037 ^ mix64((uint64_t)seed);
+ // seed >>= 64;
+ // } while (seed != 0 && seed != -1); // Limits for pos/neg seed.
+ // if (hash == 0) {
+ // hash = 0x5A17;
+ // }
+ // _lo = hash & _MASK_32;
+ // _hi = hash >> 32;
// and then does four _nextState calls to shuffle bits around.
_Random(int seed) {
- // Works the same as the VM version for positive integers up to 2^53.
- // For bigints, the VM always uses zero as seed. That is really a bug, and
- // we don't simulate that.
- seed += 0x5A17;
- _lo = seed & _MASK32;
- _hi = (seed - _lo) ~/ _POW2_32;
+ int empty_seed = 0;
+ if (seed < 0) {
+ empty_seed = -1;
+ }
+ do {
+ int low = seed & _MASK32;
+ seed = (seed - low) ~/ _POW2_32;
+ int high = seed & _MASK32;
+ seed = (seed - high) ~/ _POW2_32;
+
+ // Thomas Wang's 64-bit mix function.
+ // http://www.concentric.net/~Ttwang/tech/inthash.htm
+ // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+
+ // key = ~key + (key << 21);
+ int tmplow = low << 21;
+ int tmphigh = (high << 21) | (low >> 11);
+ tmplow = (~low & _MASK32) + tmplow;
+ low = tmplow & _MASK32;
+ high = (~high + tmphigh + ((tmplow - low) ~/ 0x100000000)) & _MASK32;
+ // key = key ^ (key >> 24).
+ tmphigh = high >> 24;
+ tmplow = (low >> 24) | (high << 8);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key * 265
+ tmplow = low * 265;
+ low = tmplow & _MASK32;
+ high = (high * 265 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // key = key ^ (key >> 14);
+ tmphigh = high >> 14;
+ tmplow = (low >> 14) | (high << 18);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key * 21
+ tmplow = low * 21;
+ low = tmplow & _MASK32;
+ high = (high * 21 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // key = key ^ (key >> 28).
+ tmphigh = high >> 28;
+ tmplow = (low >> 28) | (high << 4);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key + (key << 31);
+ tmplow = low << 31;
+ tmphigh = (high << 31) | (low >> 1);
+ tmplow += low;
+ low = tmplow & _MASK32;
+ high = (high + tmphigh + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // Mix end.
+
+ // seed = seed * 1037 ^ key;
+ tmplow = _lo * 1037;
+ _lo = tmplow & _MASK32;
+ _hi = (_hi * 1037 + (tmplow - _lo) ~/ 0x100000000) & _MASK32;
+ _lo ^= low;
+ _hi ^= high;
+ } while (seed != empty_seed);
+
if (_hi == 0 && _lo == 0) {
_lo = 0x5A17;
}
diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart
index a589dcc..ecc8318 100644
--- a/sdk/lib/_internal/pub/bin/pub.dart
+++ b/sdk/lib/_internal/pub/bin/pub.dart
@@ -7,9 +7,11 @@
import 'package:args/args.dart';
import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
import '../lib/src/command.dart';
import '../lib/src/exit_codes.dart' as exit_codes;
+import '../lib/src/http.dart';
import '../lib/src/io.dart';
import '../lib/src/log.dart' as log;
import '../lib/src/sdk.dart' as sdk;
@@ -38,18 +40,6 @@
return;
}
- if (options.command == null) {
- if (options.rest.isEmpty) {
- // No command was chosen.
- PubCommand.printGlobalUsage();
- } else {
- log.error('Could not find a command named "${options.rest[0]}".');
- log.error('Run "pub help" to see available commands.');
- flushThenExit(exit_codes.USAGE);
- }
- return;
- }
-
if (options['trace']) {
log.recordTranscript();
}
@@ -81,8 +71,125 @@
cacheDir = '${Platform.environment['HOME']}/.pub-cache';
}
- validatePlatform().then((_) {
- PubCommand.commands[options.command.name].run(cacheDir, options, arguments);
+ validatePlatform().then((_) => runPub(cacheDir, options, arguments));
+}
+
+/// Runs the appropriate pub command whose [arguments] have been parsed to
+/// [options] using the system cache in [cacheDir].
+///
+/// Handles and correctly reports any errors that occur while running.
+void runPub(String cacheDir, ArgResults options, List<String> arguments) {
+ var captureStackChains =
+ options['trace'] ||
+ options['verbose'] ||
+ options['verbosity'] == 'all';
+
+ captureErrors(() => invokeCommand(cacheDir, options),
+ captureStackChains: captureStackChains).catchError((error, Chain chain) {
+ // This is basically the top-level exception handler so that we don't
+ // spew a stack trace on our users.
+ var message;
+
+ log.error(getErrorMessage(error));
+ log.fine("Exception type: ${error.runtimeType}");
+
+ if (options['trace'] || !isUserFacingException(error)) {
+ log.error(chain.terse);
+ } else {
+ log.fine(chain.terse);
+ }
+
+ if (error is ApplicationException && error.innerError != null) {
+ var message = "Wrapped exception: ${error.innerError}";
+ if (error.innerTrace != null) message = "$message\n${error.innerTrace}";
+ log.fine(message);
+ }
+
+ if (options['trace']) {
+ log.dumpTranscript();
+ } else if (!isUserFacingException(error)) {
+ log.error("""
+This is an unexpected error. Please run
+
+ pub --trace ${arguments.map((arg) => "'$arg'").join(' ')}
+
+and include the results in a bug report on http://dartbug.com/new.
+""");
+ }
+
+ return flushThenExit(chooseExitCode(error));
+ }).then((_) {
+ // Explicitly exit on success to ensure that any dangling dart:io handles
+ // don't cause the process to never terminate.
+ return flushThenExit(exit_codes.SUCCESS);
+ });
+}
+
+/// Returns the appropriate exit code for [exception], falling back on 1 if no
+/// appropriate exit code could be found.
+int chooseExitCode(exception) {
+ if (exception is HttpException || exception is HttpException ||
+ exception is SocketException || exception is PubHttpException) {
+ return exit_codes.UNAVAILABLE;
+ } else if (exception is FormatException) {
+ return exit_codes.DATA;
+ } else if (exception is UsageException) {
+ return exit_codes.USAGE;
+ } else {
+ return 1;
+ }
+}
+
+/// Walks the command tree and runs the selected pub command.
+Future invokeCommand(String cacheDir, ArgResults mainOptions) {
+ var commands = PubCommand.mainCommands;
+ var command;
+ var commandString = "pub";
+ var options = mainOptions;
+
+ while (commands.isNotEmpty) {
+ if (options.command == null) {
+ if (options.rest.isEmpty) {
+ if (command == null) {
+ // No top-level command was chosen.
+ PubCommand.printGlobalUsage();
+ return new Future.value();
+ }
+
+ command.usageError('Missing subcommand for "$commandString".');
+ } else {
+ if (command == null) {
+ PubCommand.usageErrorWithCommands(commands,
+ 'Could not find a command named "${options.rest[0]}".');
+ }
+
+ command.usageError('Could not find a subcommand named '
+ '"${options.rest[0]}" for "$commandString".');
+ }
+ }
+
+ // Step into the command.
+ options = options.command;
+ command = commands[options.name];
+ commands = command.subcommands;
+ commandString += " ${options.name}";
+
+ if (options['help']) {
+ command.printUsage();
+ return new Future.value();
+ }
+ }
+
+ // Make sure there aren't unexpected arguments.
+ if (!command.takesArguments && options.rest.isNotEmpty) {
+ command.usageError(
+ 'Command "${options.name}" does not take any arguments.');
+ }
+
+ return syncFuture(() {
+ return command.run(cacheDir, options);
+ }).whenComplete(() {
+ command.cache.deleteTempDir();
});
}
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index e3dcab5..3f6f35e 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -5,12 +5,10 @@
library pub.command;
import 'dart:async';
-import 'dart:io';
import 'dart:math' as math;
import 'package:args/args.dart';
import 'package:path/path.dart' as path;
-import 'package:stack_trace/stack_trace.dart';
import 'command/build.dart';
import 'command/cache.dart';
@@ -23,17 +21,18 @@
import 'command/uploader.dart';
import 'command/version.dart';
import 'entrypoint.dart';
-import 'exit_codes.dart' as exit_codes;
-import 'http.dart';
-import 'io.dart';
import 'log.dart' as log;
import 'system_cache.dart';
import 'utils.dart';
/// The base class for commands for the pub executable.
+///
+/// A command may either be a "leaf" command or it may be a parent for a set
+/// of subcommands. Only leaf commands are ever actually invoked. If a command
+/// has subcommands, then one of those must always be chosen.
abstract class PubCommand {
/// The commands that pub understands.
- static final Map<String, PubCommand> commands = _initCommands();
+ static final Map<String, PubCommand> mainCommands = _initCommands();
/// The top-level [ArgParser] used to parse the pub command line.
static final pubArgParser = _initArgParser();
@@ -44,35 +43,59 @@
var buffer = new StringBuffer();
buffer.writeln('Pub is a package manager for Dart.');
buffer.writeln();
- buffer.writeln('Usage: pub command [arguments]');
+ buffer.writeln('Usage: pub <command> [arguments]');
buffer.writeln();
buffer.writeln('Global options:');
buffer.writeln(pubArgParser.getUsage());
+ buffer.write(_listCommands(mainCommands));
buffer.writeln();
+ buffer.writeln(
+ 'Use "pub help [command]" for more information about a command.');
- // Show the public commands alphabetically.
- var names = ordered(commands.keys.where((name) =>
- !commands[name].aliases.contains(name) &&
- !commands[name].hidden));
+ log.message(buffer);
+ }
+ /// Fails with a usage error [message] when trying to select from one of
+ /// [commands].
+ static void usageErrorWithCommands(Map<String, PubCommand> commands,
+ String message) {
+ throw new UsageException("$message\n${_listCommands(commands)}");
+ }
+
+ /// Writes [commands] in a nicely formatted list to [buffer].
+ static String _listCommands(Map<String, PubCommand> commands) {
+ // If there are no subcommands, do nothing.
+ if (commands.isEmpty) return "";
+
+ // Don't include aliases.
+ var names = commands.keys
+ .where((name) => !commands[name].aliases.contains(name));
+
+ // Filter out hidden ones, unless they are all hidden.
+ var visible = names.where((name) => !commands[name].hidden);
+ if (visible.isNotEmpty) names = visible;
+
+ // Show the commands alphabetically.
+ names = ordered(names);
var length = names.map((name) => name.length).reduce(math.max);
+ var isSubcommand = commands != mainCommands;
- buffer.writeln('Available commands:');
+ var buffer = new StringBuffer();
+ buffer.writeln();
+ buffer.writeln('Available ${isSubcommand ? "sub" : ""}commands:');
for (var name in names) {
buffer.writeln(' ${padRight(name, length)} '
'${commands[name].description}');
}
- buffer.writeln();
- buffer.write(
- 'Use "pub help [command]" for more information about a command.');
- log.message(buffer.toString());
+ return buffer.toString();
}
SystemCache cache;
/// The parsed options for this command.
- ArgResults commandOptions;
+ ArgResults get commandOptions => _commandOptions;
+ ArgResults _commandOptions;
Entrypoint entrypoint;
@@ -81,18 +104,27 @@
/// If the command is undocumented and should not appear in command listings,
/// this will be `true`.
- bool get hidden => false;
+ bool get hidden {
+ // Leaf commands are visible by default.
+ if (subcommands.isEmpty) return false;
+
+ // Otherwise, a command is hidden if all of its subcommands are.
+ return subcommands.values.every((subcommand) => subcommand.hidden);
+ }
/// How to invoke this command (e.g. `"pub get [package]"`).
String get usage;
- /// Whether or not this command requires [entrypoint] to be defined. If false,
- /// pub won't look for a pubspec and [entrypoint] will be null when the
- /// command runs.
+ /// Whether or not this command requires [entrypoint] to be defined.
+ ///
+ /// If false, pub won't look for a pubspec and [entrypoint] will be null when
+ /// the command runs. This only needs to be set in leaf commands.
bool get requiresEntrypoint => true;
- /// Whether or not this command takes arguments in addition to options. If
- /// false, pub will exit with an error if arguments are provided.
+ /// Whether or not this command takes arguments in addition to options.
+ ///
+ /// If false, pub will exit with an error if arguments are provided. This
+ /// only needs to be set in leaf commands.
bool get takesArguments => false;
/// Alternate names for this command. These names won't be used in the
@@ -102,9 +134,17 @@
/// The [ArgParser] for this command.
final commandParser = new ArgParser();
+ /// Subcommands exposed by this command.
+ ///
+ /// If empty, then this command has no subcommands. Otherwise, a subcommand
+ /// must be specified by the user. In that case, this command's [onRun] will
+ /// not be called and the subcommand's will.
+ final subcommands = <String, PubCommand>{};
+
/// Override this to use offline-only sources instead of hitting the network.
+ ///
/// This will only be called before the [SystemCache] is created. After that,
- /// it has no effect.
+ /// it has no effect. This only needs to be set in leaf commands.
bool get isOffline => false;
PubCommand() {
@@ -113,94 +153,50 @@
help: 'Print usage information for this command.');
}
- void run(String cacheDir, ArgResults options, List<String> arguments) {
- commandOptions = options.command;
-
- if (commandOptions['help']) {
- this.printUsage();
- return;
- }
+ /// Runs this command using a system cache at [cacheDir] with [options].
+ Future run(String cacheDir, ArgResults options) {
+ _commandOptions = options;
cache = new SystemCache.withSources(cacheDir, isOffline: isOffline);
- handleError(error, Chain chain) {
- // This is basically the top-level exception handler so that we don't
- // spew a stack trace on our users.
- var message;
-
- log.error(getErrorMessage(error));
- log.fine("Exception type: ${error.runtimeType}");
-
- if (options['trace'] || !isUserFacingException(error)) {
- log.error(chain.terse);
- } else {
- log.fine(chain.terse);
- }
-
- if (error is ApplicationException && error.innerError != null) {
- var message = "Wrapped exception: ${error.innerError}";
- if (error.innerTrace != null) message = "$message\n${error.innerTrace}";
- log.fine(message);
- }
-
- if (options['trace']) {
- log.dumpTranscript();
- } else if (!isUserFacingException(error)) {
- log.error("""
-This is an unexpected error. Please run
-
- pub --trace ${arguments.map((arg) => "'$arg'").join(' ')}
-
-and include the results in a bug report on http://dartbug.com/new.
-""");
- }
-
- return flushThenExit(_chooseExitCode(error));
+ if (requiresEntrypoint) {
+ // TODO(rnystrom): Will eventually need better logic to walk up
+ // subdirectories until we hit one that looks package-like. For now,
+ // just assume the cwd is it.
+ entrypoint = new Entrypoint(path.current, cache);
}
- var captureStackChains =
- options['trace'] || options['verbose'] || options['verbosity'] == 'all';
- captureErrors(() {
- return syncFuture(() {
- // Make sure there aren't unexpected arguments.
- if (!takesArguments && commandOptions.rest.isNotEmpty) {
- log.error('Command "${commandOptions.name}" does not take any '
- 'arguments.');
- this.printUsage();
- return flushThenExit(exit_codes.USAGE);
- }
-
- if (requiresEntrypoint) {
- // TODO(rnystrom): Will eventually need better logic to walk up
- // subdirectories until we hit one that looks package-like. For now,
- // just assume the cwd is it.
- entrypoint = new Entrypoint(path.current, cache);
- }
-
- var commandFuture = onRun();
- if (commandFuture == null) return true;
-
- return commandFuture;
- }).whenComplete(() => cache.deleteTempDir());
- }, captureStackChains: captureStackChains).catchError(handleError)
- .then((_) {
- // Explicitly exit on success to ensure that any dangling dart:io handles
- // don't cause the process to never terminate.
- return flushThenExit(exit_codes.SUCCESS);
- });
+ return syncFuture(onRun);
}
- /// Override this to perform the specific command. Return a future that
- /// completes when the command is done or fails if the command fails. If the
- /// command is synchronous, it may return `null`.
- Future onRun();
+ /// Override this to perform the specific command.
+ ///
+ /// Return a future that completes when the command is done or fails if the
+ /// command fails. If the command is synchronous, it may return `null`. Only
+ /// leaf command should override this.
+ Future onRun() {
+ // Leaf commands should override this and non-leaf commands should never
+ // call it.
+ assert(false);
+ }
/// Displays usage information for this command.
void printUsage([String description]) {
if (description == null) description = this.description;
+ log.message('$description\n\n${_getUsage()}');
+ }
+ // TODO(rnystrom): Use this in other places handle usage failures.
+ /// Throw an [ApplicationException] for a usage error of this command with
+ /// [message].
+ void usageError(String message) {
+ throw new UsageException("$message\n\n${_getUsage()}");
+ }
+
+ /// Generates a string of usage information for this command.
+ String _getUsage() {
var buffer = new StringBuffer();
- buffer.write('$description\n\nUsage: $usage');
+ buffer.write('Usage: $usage');
var commandUsage = commandParser.getUsage();
if (!commandUsage.isEmpty) {
@@ -208,20 +204,12 @@
buffer.write(commandUsage);
}
- log.message(buffer.toString());
- }
-
- /// Returns the appropriate exit code for [exception], falling back on 1 if no
- /// appropriate exit code could be found.
- int _chooseExitCode(exception) {
- if (exception is HttpException || exception is HttpException ||
- exception is SocketException || exception is PubHttpException) {
- return exit_codes.UNAVAILABLE;
- } else if (exception is FormatException) {
- return exit_codes.DATA;
- } else {
- return 1;
+ if (subcommands.isNotEmpty) {
+ buffer.writeln();
+ buffer.write(_listCommands(subcommands));
}
+
+ return buffer.toString();
}
}
@@ -272,9 +260,19 @@
help: 'Shortcut for "--verbosity=all".');
// Register the commands.
- PubCommand.commands.forEach((name, command) {
- argParser.addCommand(name, command.commandParser);
+ PubCommand.mainCommands.forEach((name, command) {
+ _registerCommand(name, command, argParser);
});
return argParser;
}
+
+/// Registers a [command] with [name] on [parser].
+void _registerCommand(String name, PubCommand command, ArgParser parser) {
+ parser.addCommand(name, command.commandParser);
+
+ // Recursively wire up any subcommands.
+ command.subcommands.forEach((name, subcommand) {
+ _registerCommand(name, subcommand, command.commandParser);
+ });
+}
diff --git a/sdk/lib/_internal/pub/lib/src/command/build.dart b/sdk/lib/_internal/pub/lib/src/command/build.dart
index b470f1b..5131ea2 100644
--- a/sdk/lib/_internal/pub/lib/src/command/build.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/build.dart
@@ -27,8 +27,7 @@
/// Handles the `build` pub command.
class BuildCommand extends PubCommand {
- String get description =>
- "Copy and compile all Dart entrypoints in the 'web' directory.";
+ String get description => "Apply transformers to build a package.";
String get usage => "pub build [options]";
List<String> get aliases => const ["deploy", "settle-up"];
bool get takesArguments => true;
diff --git a/sdk/lib/_internal/pub/lib/src/command/cache.dart b/sdk/lib/_internal/pub/lib/src/command/cache.dart
index 97e5dbe..dbef315 100644
--- a/sdk/lib/_internal/pub/lib/src/command/cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/cache.dart
@@ -4,48 +4,15 @@
library pub.command.cache;
-import 'dart:async';
-import 'dart:convert';
-
import '../command.dart';
-import '../exit_codes.dart' as exit_codes;
-import '../io.dart';
-import '../log.dart' as log;
+import 'cache_list.dart';
/// Handles the `cache` pub command.
class CacheCommand extends PubCommand {
- String get description => "Inspect the system cache.";
- String get usage => "pub cache list";
- bool get hidden => true;
- bool get requiresEntrypoint => false;
- bool get takesArguments => true;
+ String get description => "Work with the system cache.";
+ String get usage => "pub cache <subcommand>";
- Future onRun() {
- // TODO(rnystrom): Use subcommand for "list".
- if (commandOptions.rest.length != 1) {
- log.error('The cache command expects one argument.');
- this.printUsage();
- return flushThenExit(exit_codes.USAGE);
- }
-
- if ((commandOptions.rest[0] != 'list')) {
- log.error('Unknown cache command "${commandOptions.rest[0]}".');
- this.printUsage();
- return flushThenExit(exit_codes.USAGE);
- }
-
- // TODO(keertip): Add flag to list packages from non default sources
- var packagesObj = <String, Map>{};
-
- for (var package in cache.sources.defaultSource.getCachedPackages()) {
-
- var packageInfo = packagesObj.putIfAbsent(package.name, () => {});
- packageInfo[package.version.toString()] = {'location': package.dir};
- }
-
- // TODO(keertip): Add support for non-JSON format
- // and check for --format flag
- log.message(JSON.encode({'packages': packagesObj}));
- }
+ final subcommands = {
+ "list": new CacheListCommand()
+ };
}
-
diff --git a/sdk/lib/_internal/pub/lib/src/command/cache_list.dart b/sdk/lib/_internal/pub/lib/src/command/cache_list.dart
new file mode 100644
index 0000000..d774a6b
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/command/cache_list.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2013, 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 pub.command.cache_list;
+
+import 'dart:async';
+import 'dart:convert';
+
+import '../command.dart';
+import '../log.dart' as log;
+
+/// Handles the `cache list` pub command.
+class CacheListCommand extends PubCommand {
+ String get description => "List packages in the system cache.";
+ String get usage => "pub cache list";
+ bool get hidden => true;
+ bool get requiresEntrypoint => false;
+
+ Future onRun() {
+ // TODO(keertip): Add flag to list packages from non default sources.
+ var packagesObj = <String, Map>{};
+
+ for (var package in cache.sources.defaultSource.getCachedPackages()) {
+ var packageInfo = packagesObj.putIfAbsent(package.name, () => {});
+ packageInfo[package.version.toString()] = {'location': package.dir};
+ }
+
+ // TODO(keertip): Add support for non-JSON format and check for --format
+ // flag.
+ log.message(JSON.encode({'packages': packagesObj}));
+ }
+}
diff --git a/sdk/lib/_internal/pub/lib/src/command/help.dart b/sdk/lib/_internal/pub/lib/src/command/help.dart
index 9118175..c1889ff 100644
--- a/sdk/lib/_internal/pub/lib/src/command/help.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/help.dart
@@ -7,9 +7,6 @@
import 'dart:async';
import '../command.dart';
-import '../exit_codes.dart' as exit_codes;
-import '../io.dart';
-import '../log.dart' as log;
/// Handles the `help` pub command.
class HelpCommand extends PubCommand {
@@ -19,18 +16,39 @@
bool get takesArguments => true;
Future onRun() {
+ // Show the default help if no command was specified.
if (commandOptions.rest.isEmpty) {
PubCommand.printGlobalUsage();
- } else {
- var name = commandOptions.rest[0];
- var command = PubCommand.commands[name];
- if (command == null) {
- log.error('Could not find a command named "$name".');
- log.error('Run "pub help" to see available commands.');
- return flushThenExit(exit_codes.USAGE);
+ return null;
+ }
+
+ // Walk the command tree to show help for the selected command or
+ // subcommand.
+ var commands = PubCommand.mainCommands;
+ var command = null;
+ var commandString = "pub";
+
+ for (var name in commandOptions.rest) {
+ if (commands.isEmpty) {
+ command.usageError(
+ 'Command "$commandString" does not expect a subcommand.');
}
- command.printUsage();
+ if (commands[name] == null) {
+ if (command == null) {
+ PubCommand.usageErrorWithCommands(commands,
+ 'Could not find a command named "$name".');
+ }
+
+ command.usageError(
+ 'Could not find a subcommand named "$name" for "$commandString".');
+ }
+
+ command = commands[name];
+ commands = command.subcommands;
+ commandString += " $name";
}
+
+ command.printUsage();
}
}
diff --git a/sdk/lib/_internal/pub/lib/src/command/lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
index bd9c445..d5e4676 100644
--- a/sdk/lib/_internal/pub/lib/src/command/lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -10,7 +10,6 @@
import '../command.dart';
import '../directory_tree.dart';
-import '../exit_codes.dart' as exit_codes;
import '../http.dart';
import '../io.dart';
import '../log.dart' as log;
@@ -94,9 +93,7 @@
Future onRun() {
if (force && dryRun) {
- log.error('Cannot use both --force and --dry-run.');
- this.printUsage();
- return flushThenExit(exit_codes.USAGE);
+ usageError('Cannot use both --force and --dry-run.');
}
var packageBytesFuture = entrypoint.packageFiles().then((files) {
@@ -144,15 +141,15 @@
if (dryRun) {
var s = warnings.length == 1 ? '' : 's';
- log.warning("Package has ${warnings.length} warning$s.");
+ log.warning("\nPackage has ${warnings.length} warning$s.");
return false;
}
- var message = 'Looks great! Are you ready to upload your package';
+ var message = '\nLooks great! Are you ready to upload your package';
if (!warnings.isEmpty) {
var s = warnings.length == 1 ? '' : 's';
- message = "Package has ${warnings.length} warning$s. Upload anyway";
+ message = "\nPackage has ${warnings.length} warning$s. Upload anyway";
}
return confirm(message).then((confirmed) {
diff --git a/sdk/lib/_internal/pub/lib/src/git.dart b/sdk/lib/_internal/pub/lib/src/git.dart
index e94e493..4e92a69 100644
--- a/sdk/lib/_internal/pub/lib/src/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/git.dart
@@ -6,9 +6,13 @@
library pub.git;
import 'dart:async';
+import 'dart:io';
+
import 'io.dart';
import 'log.dart' as log;
+import 'package:stack_trace/stack_trace.dart';
+
/// Tests whether or not the git command-line app is available for use.
Future<bool> get isInstalled {
if (_isGitInstalledCache != null) {
@@ -67,8 +71,13 @@
return runProcess(command, ["--version"]).then((results) {
var regexp = new RegExp("^git version");
return results.stdout.length == 1 && regexp.hasMatch(results.stdout[0]);
- }).catchError((err) {
+ }).catchError((err, stackTrace) {
// If the process failed, they probably don't have it.
- return false;
+ if (err is ProcessException) {
+ log.io('Git command is not "$command": $err\n$stackTrace');
+ return false;
+ }
+
+ throw err;
});
}
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 3f17a02..79c2931 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -391,21 +391,13 @@
/// symlink to the target. Otherwise, uses the [target] path unmodified.
void createPackageSymlink(String name, String target, String symlink,
{bool isSelfLink: false, bool relative: false}) {
- // See if the package has a "lib" directory.
+ // See if the package has a "lib" directory. If not, there's nothing to
+ // symlink to.
target = path.join(target, 'lib');
- log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'.");
- if (dirExists(target)) {
- createSymlink(target, symlink, relative: relative);
- return;
- }
+ if (!dirExists(target)) return;
- // It's OK for the self link (i.e. the root package) to not have a lib
- // directory since it may just be a leaf application that only has
- // code in bin or web.
- if (!isSelfLink) {
- log.warning('Warning: Package $name does not have a "lib" directory so '
- 'you will not be able to import any libraries from it.');
- }
+ log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'.");
+ createSymlink(target, symlink, relative: relative);
}
/// Whether pub is running from within the Dart SDK, as opposed to from the Dart
@@ -654,7 +646,7 @@
executable = "cmd";
}
- log.process(executable, args);
+ log.process(executable, args, workingDir == null ? '.' : workingDir);
return Chain.track(fn(executable,
args,
diff --git a/sdk/lib/_internal/pub/lib/src/log.dart b/sdk/lib/_internal/pub/lib/src/log.dart
index bbbcb3c..0dcf088 100644
--- a/sdk/lib/_internal/pub/lib/src/log.dart
+++ b/sdk/lib/_internal/pub/lib/src/log.dart
@@ -8,6 +8,8 @@
import 'dart:async';
import 'dart:io';
+import 'package:path/path.dart' as p;
+
import 'io.dart';
import 'transcript.dart';
import 'utils.dart';
@@ -117,6 +119,13 @@
if (_loggers.isEmpty) showNormal();
var lines = splitLines(message.toString());
+
+ // Discard a trailing newline. This is useful since StringBuffers often end
+ // up with an extra newline at the end from using [writeln].
+ if (lines.isNotEmpty && lines.last == "") {
+ lines.removeLast();
+ }
+
var entry = new Entry(level, lines);
var logFn = _loggers[level];
@@ -152,30 +161,32 @@
/// Logs the spawning of an [executable] process with [arguments] at [IO]
/// level.
-void process(String executable, List<String> arguments) {
- io("Spawning $executable ${arguments.join(' ')}");
+void process(String executable, List<String> arguments,
+ String workingDirectory) {
+ io("Spawning \"$executable ${arguments.join(' ')}\" in "
+ "${p.absolute(workingDirectory)}");
}
/// Logs the results of running [executable].
void processResult(String executable, PubProcessResult result) {
// Log it all as one message so that it shows up as a single unit in the logs.
var buffer = new StringBuffer();
- buffer.write("Finished $executable. Exit code ${result.exitCode}.");
+ buffer.writeln("Finished $executable. Exit code ${result.exitCode}.");
dumpOutput(String name, List<String> output) {
if (output.length == 0) {
- buffer.write("Nothing output on $name.");
+ buffer.writeln("Nothing output on $name.");
} else {
- buffer.write("$name:");
+ buffer.writeln("$name:");
var numLines = 0;
for (var line in output) {
if (++numLines > 1000) {
- buffer.write('[${output.length - 1000}] more lines of output '
+ buffer.writeln('[${output.length - 1000}] more lines of output '
'truncated...]');
break;
}
- buffer.write(line);
+ buffer.writeln("| $line");
}
}
}
@@ -183,7 +194,7 @@
dumpOutput("stdout", result.stdout);
dumpOutput("stderr", result.stderr);
- io(buffer.toString());
+ io(buffer.toString().trim());
}
/// Enables recording of log entries.
diff --git a/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
index 6856878..53507de 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
@@ -39,12 +39,6 @@
final _output = new StringBuffer();
- /// To avoid emitting trailing newlines, we track if any are needed and only
- /// emit then when text on the next line is about to be written.
- // TODO(rnystrom): Move this into a separate class that wraps any StringSink
- // with this logic.
- int _pendingLines = 0;
-
_SolveReport(this._sources, this._root, this._previousLockFile,
this._result) {
// Fill the map so we can use it later.
@@ -99,13 +93,13 @@
var removed = _previousLockFile.packages.keys.toSet();
removed.removeAll(names);
if (removed.isNotEmpty) {
- _writeln("These packages are no longer being depended on:");
+ _output.writeln("These packages are no longer being depended on:");
removed = removed.toList();
removed.sort();
removed.forEach(_reportPackage);
}
- log.message(_output.toString());
+ log.message(_output);
}
/// Displays a warning about the overrides currently in effect.
@@ -113,14 +107,14 @@
_output.clear();
if (_result.overrides.isNotEmpty) {
- _writeln("Warning: You are using these overridden dependencies:");
+ _output.writeln("Warning: You are using these overridden dependencies:");
var overrides = _result.overrides.map((dep) => dep.name).toList();
overrides.sort((a, b) => a.compareTo(b));
overrides.forEach(
(name) => _reportPackage(name, highlightOverride: false));
- log.warning(_output.toString());
+ log.warning(_output);
}
}
@@ -149,39 +143,39 @@
// < The package was downgraded from a higher version.
// * Any other change between the old and new package.
if (isOverridden) {
- _write(log.magenta("! "));
+ _output.write(log.magenta("! "));
} else if (newId == null) {
- _write(log.red("- "));
+ _output.write(log.red("- "));
} else if (oldId == null) {
- _write(log.green("+ "));
+ _output.write(log.green("+ "));
} else if (!_descriptionsEqual(oldId, newId)) {
- _write(log.cyan("* "));
+ _output.write(log.cyan("* "));
changed = true;
} else if (oldId.version < newId.version) {
- _write(log.green("> "));
+ _output.write(log.green("> "));
changed = true;
} else if (oldId.version > newId.version) {
- _write(log.cyan("< "));
+ _output.write(log.cyan("< "));
changed = true;
} else {
// Unchanged.
- _write(" ");
+ _output.write(" ");
}
- _write(log.bold(id.name));
- _write(" ");
+ _output.write(log.bold(id.name));
+ _output.write(" ");
_writeId(id);
// If the package was upgraded, show what it was upgraded from.
if (changed) {
- _write(" (was ");
+ _output.write(" (was ");
_writeId(oldId);
- _write(")");
+ _output.write(")");
}
// Highlight overridden packages.
if (isOverridden && highlightOverride) {
- _write(" ${log.magenta('(overridden)')}");
+ _output.write(" ${log.magenta('(overridden)')}");
}
// See if there are any newer versions of the package that we were
@@ -211,10 +205,10 @@
"${pluralize('version', newerUnstable)} available)";
}
- if (message != null) _write(" ${log.cyan(message)}");
+ if (message != null) _output.write(" ${log.cyan(message)}");
}
- _writeln();
+ _output.writeln();
}
/// Returns `true` if [a] and [b] are from the same source and have the same
@@ -233,7 +227,7 @@
/// Writes a terse description of [id] (not including its name) to the output.
void _writeId(PackageId id) {
- _write(id.version);
+ _output.write(id.version);
var source = null;
if (_sources.contains(id.source)) {
@@ -242,26 +236,7 @@
if (source != null && source != _sources.defaultSource) {
var description = source.formatDescription(_root.dir, id.description);
- _write(" from ${id.source} $description");
+ _output.write(" from ${id.source} $description");
}
}
-
- /// Writes [obj] to the output.
- void _write(Object obj) {
- while (_pendingLines > 0) {
- _output.writeln();
- _pendingLines--;
- }
- _output.write(obj);
- }
-
- /// Writes [obj] (if not null) followed by a newline to the output.
- ///
- /// Doesn't actually immediately write a newline. Instead, it waits until
- /// output is written on the next line. That way, trailing newlines aren't
- /// displayed.
- void _writeln([Object obj]) {
- if (obj != null) _write(obj);
- _pendingLines++;
- }
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/lib/src/source/git.dart b/sdk/lib/_internal/pub/lib/src/source/git.dart
index c50e719..2981ebe 100644
--- a/sdk/lib/_internal/pub/lib/src/source/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/git.dart
@@ -130,8 +130,9 @@
/// Returns a future that completes to the revision hash of [id].
Future<String> _revisionAt(PackageId id) {
- return git.run(["rev-parse", _getEffectiveRef(id)],
- workingDir: _repoCachePath(id)).then((result) => result[0]);
+ return _ensureRepoCache(id).then((_) =>
+ git.run(["rev-parse", _getEffectiveRef(id)],
+ workingDir: _repoCachePath(id)).then((result) => result[0]));
}
/// Clones the repo at the URI [from] to the path [to] on the local
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 6d77713..c5f81c2 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -144,7 +144,14 @@
var wrappedCallback = () {
new Future.sync(callback).then(completer.complete)
.catchError((e, stackTrace) {
- completer.completeError(e, new Chain.forTrace(stackTrace));
+ // [stackTrace] can be null if we're running without [captureStackChains],
+ // since dart:io will often throw errors without stack traces.
+ if (stackTrace != null) {
+ stackTrace = new Chain.forTrace(stackTrace);
+ } else {
+ stackTrace = new Chain([]);
+ }
+ completer.completeError(e, stackTrace);
});
};
@@ -152,7 +159,12 @@
Chain.capture(wrappedCallback, onError: completer.completeError);
} else {
runZoned(wrappedCallback, onError: (e, stackTrace) {
- completer.completeError(e, new Chain([new Trace.from(stackTrace)]));
+ if (stackTrace == null) {
+ stackTrace = new Chain([new Trace.from(stackTrace)]);
+ } else {
+ stackTrace = new Chain([]);
+ }
+ completer.completeError(e, stackTrace);
});
}
@@ -841,6 +853,12 @@
String toString() => message;
}
+/// A class for command usage exceptions.
+class UsageException extends ApplicationException {
+ UsageException(String message)
+ : super(message);
+}
+
/// An class for exceptions where a package could not be found in a [Source].
///
/// The source is responsible for wrapping its internal exceptions in this so
diff --git a/sdk/lib/_internal/pub/test/get/git/locked_revision_without_repo_test.dart b/sdk/lib/_internal/pub/test/get/git/locked_revision_without_repo_test.dart
new file mode 100644
index 0000000..137e384
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/get/git/locked_revision_without_repo_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2012, 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 pub_tests;
+
+import 'package:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../../../lib/src/io.dart';
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+// Regression test for issue 16470.
+
+main() {
+ initConfig();
+ integration('checks out the repository for a locked revision', () {
+ ensureGit();
+
+ d.git('foo.git', [
+ d.libDir('foo'),
+ d.libPubspec('foo', '1.0.0')
+ ]).create();
+
+ d.appDir({"foo": {"git": "../foo.git"}}).create();
+
+ // This get should lock the foo.git dependency to the current revision.
+ pubGet();
+
+ d.dir(packagesPath, [
+ d.dir('foo', [
+ d.file('foo.dart', 'main() => "foo";')
+ ])
+ ]).validate();
+
+ // Delete the packages path and the cache to simulate a brand new checkout
+ // of the application.
+ schedule(() => deleteEntry(path.join(sandboxDir, packagesPath)));
+ schedule(() => deleteEntry(path.join(sandboxDir, cachePath)));
+
+ d.git('foo.git', [
+ d.libDir('foo', 'foo 2'),
+ d.libPubspec('foo', '1.0.0')
+ ]).commit();
+
+ // This get shouldn't upgrade the foo.git dependency due to the lockfile.
+ pubGet();
+
+ d.dir(packagesPath, [
+ d.dir('foo', [
+ d.file('foo.dart', 'main() => "foo";')
+ ])
+ ]).validate();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart b/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
index 26231e3..c436ff2 100644
--- a/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
@@ -14,7 +14,16 @@
integration('--force cannot be combined with --dry-run', () {
schedulePub(args: ['lish', '--force', '--dry-run'],
- error: "Cannot use both --force and --dry-run.",
+ error: """
+ Cannot use both --force and --dry-run.
+
+ Usage: pub publish [options]
+ -h, --help Print usage information for this command.
+ -n, --dry-run Validate but do not publish the package.
+ -f, --force Publish without confirmation if there are no errors.
+ --server The package server to which to upload this package.
+ (defaults to "https://pub.dartlang.org")
+ """,
exitCode: exit_codes.USAGE);
});
}
diff --git a/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart b/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart
index d747b3b..a1c134d 100644
--- a/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart
@@ -7,7 +7,6 @@
import 'package:scheduled_test/scheduled_test.dart';
import 'package:scheduled_test/scheduled_server.dart';
-import '../../lib/src/exit_codes.dart' as exit_codes;
import '../descriptor.dart' as d;
import '../test_pub.dart';
import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/pub_cache_test.dart b/sdk/lib/_internal/pub/test/pub_cache_test.dart
index 91bc4a0..4483166 100644
--- a/sdk/lib/_internal/pub/test/pub_cache_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_cache_test.dart
@@ -17,30 +17,6 @@
"pub.dartlang.org", package);
}
- integration('running pub cache displays error message', () {
- schedulePub(args: ['cache'],
- output: '''
- Inspect the system cache.
-
- Usage: pub cache list
- -h, --help Print usage information for this command.
- ''',
- error: 'The cache command expects one argument.',
- exitCode: 64);
- });
-
- integration('running pub cache foo displays error message', () {
- schedulePub(args: ['cache' ,'foo'],
- output: '''
- Inspect the system cache.
-
- Usage: pub cache list
- -h, --help Print usage information for this command.
- ''',
- error: 'Unknown cache command "foo".',
- exitCode: 64);
- });
-
integration('running pub cache list when there is no cache', () {
schedulePub(args: ['cache', 'list'], output: '{"packages":{}}');
});
diff --git a/sdk/lib/_internal/pub/test/pub_test.dart b/sdk/lib/_internal/pub/test/pub_test.dart
index 336e125..8c9e652 100644
--- a/sdk/lib/_internal/pub/test/pub_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_test.dart
@@ -6,12 +6,13 @@
import 'package:scheduled_test/scheduled_test.dart';
+import '../lib/src/exit_codes.dart' as exit_codes;
import 'test_pub.dart';
final USAGE_STRING = """
Pub is a package manager for Dart.
- Usage: pub command [arguments]
+ Usage: pub <command> [arguments]
Global options:
-h, --help Print this usage information.
@@ -27,7 +28,7 @@
-v, --verbose Shortcut for "--verbosity=all".
Available commands:
- build Copy and compile all Dart entrypoints in the 'web' directory.
+ build Apply transformers to build a package.
get Get the current package's dependencies.
help Display help information for Pub.
publish Publish the current package to pub.dartlang.org.
@@ -80,6 +81,21 @@
''');
});
+ integration('running pub with --help after a command with subcommands shows '
+ 'command usage', () {
+ schedulePub(args: ['cache', '--help'],
+ output: '''
+ Work with the system cache.
+
+ Usage: pub cache <subcommand>
+ -h, --help Print usage information for this command.
+
+ Available subcommands:
+ list List packages in the system cache.
+ ''');
+ });
+
+
integration('running pub with just --version displays version', () {
schedulePub(args: ['--version'], output: VERSION_STRING);
});
@@ -88,9 +104,32 @@
schedulePub(args: ['quylthulg'],
error: '''
Could not find a command named "quylthulg".
- Run "pub help" to see available commands.
+
+ Available commands:
+ build Apply transformers to build a package.
+ get Get the current package's dependencies.
+ help Display help information for Pub.
+ publish Publish the current package to pub.dartlang.org.
+ serve Run a local web development server.
+ upgrade Upgrade the current package's dependencies to latest versions.
+ uploader Manage uploaders for a package on pub.dartlang.org.
+ version Print pub version.
''',
- exitCode: 64);
+ exitCode: exit_codes.USAGE);
+ });
+
+ integration('an unknown subcommand displays an error message', () {
+ schedulePub(args: ['cache', 'quylthulg'],
+ error: '''
+ Could not find a subcommand named "quylthulg" for "pub cache".
+
+ Usage: pub cache <subcommand>
+ -h, --help Print usage information for this command.
+
+ Available subcommands:
+ list List packages in the system cache.
+ ''',
+ exitCode: exit_codes.USAGE);
});
integration('an unknown option displays an error message', () {
@@ -99,7 +138,7 @@
Could not find an option named "blorf".
Run "pub help" to see available options.
''',
- exitCode: 64);
+ exitCode: exit_codes.USAGE);
});
integration('an unknown command option displays an error message', () {
@@ -110,21 +149,32 @@
Could not find an option named "blorf".
Run "pub help" to see available options.
''',
- exitCode: 64);
+ exitCode: exit_codes.USAGE);
});
integration('an unexpected argument displays an error message', () {
schedulePub(args: ['version', 'unexpected'],
- output: '''
- Print pub version.
+ error: '''
+ Command "version" does not take any arguments.
Usage: pub version
-h, --help Print usage information for this command.
''',
+ exitCode: exit_codes.USAGE);
+ });
+
+ integration('a missing subcommand displays an error message', () {
+ schedulePub(args: ['cache'],
error: '''
- Command "version" does not take any arguments.
+ Missing subcommand for "pub cache".
+
+ Usage: pub cache <subcommand>
+ -h, --help Print usage information for this command.
+
+ Available subcommands:
+ list List packages in the system cache.
''',
- exitCode: 64);
+ exitCode: exit_codes.USAGE);
});
group('help', () {
@@ -157,15 +207,58 @@
''');
});
+ integration('shows help for a subcommand', () {
+ schedulePub(args: ['help', 'cache', 'list'],
+ output: '''
+ List packages in the system cache.
+
+ Usage: pub cache list
+ -h, --help Print usage information for this command.
+ ''');
+ });
+
integration('an unknown help command displays an error message', () {
schedulePub(args: ['help', 'quylthulg'],
error: '''
Could not find a command named "quylthulg".
- Run "pub help" to see available commands.
+
+ Available commands:
+ build Apply transformers to build a package.
+ get Get the current package's dependencies.
+ help Display help information for Pub.
+ publish Publish the current package to pub.dartlang.org.
+ serve Run a local web development server.
+ upgrade Upgrade the current package's dependencies to latest versions.
+ uploader Manage uploaders for a package on pub.dartlang.org.
+ version Print pub version.
''',
- exitCode: 64);
+ exitCode: exit_codes.USAGE);
});
+ integration('an unknown help subcommand displays an error message', () {
+ schedulePub(args: ['help', 'cache', 'quylthulg'],
+ error: '''
+ Could not find a subcommand named "quylthulg" for "pub cache".
+
+ Usage: pub cache <subcommand>
+ -h, --help Print usage information for this command.
+
+ Available subcommands:
+ list List packages in the system cache.
+ ''',
+ exitCode: exit_codes.USAGE);
+ });
+
+ integration('an unexpected help subcommand displays an error message', () {
+ schedulePub(args: ['help', 'version', 'badsubcommand'],
+ error: '''
+ Command "pub version" does not expect a subcommand.
+
+ Usage: pub version
+ -h, --help Print usage information for this command.
+ ''',
+ exitCode: exit_codes.USAGE);
+ });
});
group('version', () {
diff --git a/sdk/lib/async/schedule_microtask.dart b/sdk/lib/async/schedule_microtask.dart
index 94a68c5..bd5312a 100644
--- a/sdk/lib/async/schedule_microtask.dart
+++ b/sdk/lib/async/schedule_microtask.dart
@@ -6,32 +6,45 @@
typedef void _AsyncCallback();
-bool _callbacksAreEnqueued = false;
-Queue<_AsyncCallback> _asyncCallbacks = new Queue<_AsyncCallback>();
+class _AsyncCallbackEntry {
+ final _AsyncCallback callback;
+ _AsyncCallbackEntry next;
+ _AsyncCallbackEntry(this.callback);
+}
-void _asyncRunCallback() {
+_AsyncCallbackEntry _nextCallback;
+_AsyncCallbackEntry _lastCallback;
+
+void _asyncRunCallbackLoop() {
+ _AsyncCallbackEntry entry = _nextCallback;
// As long as we are iterating over the registered callbacks we don't
- // unset the [_callbacksAreEnqueued] boolean.
- while (!_asyncCallbacks.isEmpty) {
- Function callback = _asyncCallbacks.removeFirst();
- try {
- callback();
- } catch (e) {
- _AsyncRun._scheduleImmediate(_asyncRunCallback);
- rethrow;
- }
+ // set the [_lastCallback] entry.
+ while (entry != null) {
+ entry.callback();
+ entry = _nextCallback = entry.next;
}
// Any new callback must register a callback function now.
- _callbacksAreEnqueued = false;
+ _lastCallback = null;
+}
+
+void _asyncRunCallback() {
+ try {
+ _asyncRunCallbackLoop();
+ } catch (e) {
+ _AsyncRun._scheduleImmediate(_asyncRunCallback);
+ _nextCallback = _nextCallback.next;
+ rethrow;
+ }
}
void _scheduleAsyncCallback(callback) {
// Optimizing a group of Timer.run callbacks to be executed in the
// same Timer callback.
- _asyncCallbacks.add(callback);
- if (!_callbacksAreEnqueued) {
+ if (_lastCallback == null) {
+ _nextCallback = _lastCallback = new _AsyncCallbackEntry(callback);
_AsyncRun._scheduleImmediate(_asyncRunCallback);
- _callbacksAreEnqueued = true;
+ } else {
+ _lastCallback = _lastCallback.next = new _AsyncCallbackEntry(callback);
}
}
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 8e480f8..2f513b0 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -133,8 +133,13 @@
_Utf8Encoder() : this.withBufferSize(_DEFAULT_BYTE_BUFFER_SIZE);
_Utf8Encoder.withBufferSize(int bufferSize)
- // TODO(11971, floitsch): use Uint8List instead of normal lists.
- : _buffer = new List<int>(bufferSize);
+ : _buffer = _createBuffer(bufferSize);
+
+ // TODO(11971): Always use Uint8List.
+ /**
+ * Allow an implementation to pick the most efficient way of storing bytes.
+ */
+ external static List<int> _createBuffer(int size);
/**
* Tries to combine the given [leadingSurrogate] with the [nextCodeUnit] and
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 8c2c61d..905250c 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -9,6 +9,7 @@
*
* An `Error` object represents a program failure that the programmer
* should have avoided.
+ *
* Examples include calling a function with invalid arguments,
* or even with the wrong number of arguments,
* or calling it at a time when it is not allowed.
@@ -50,7 +51,7 @@
* the stack trace at the throw point is recorded
* and stored in the error object.
* It can be retrieved using the [stackTrace] getter.
- * Errors that merely implement `Error`, and doesn't extend it,
+ * An error object that merely implements `Error`, and doesn't extend it,
* will not store the stack trace automatically.
*
* Error objects are also used for system wide failures
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index f966796..43fc262 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -32418,13 +32418,14 @@
_tryResume();
}
- void cancel() {
- if (_canceled) return;
+ Future cancel() {
+ if (_canceled) return null;
_unlisten();
// Clear out the target to indicate this is complete.
_target = null;
_onData = null;
+ return null;
}
bool get _canceled => _target == null;
@@ -34051,7 +34052,7 @@
* KeyboardEvent controller.
*/
_KeyboardEventHandler(this._type): super(_EVENT_TYPE),
- _stream = new _CustomKeyEventStreamImpl('event');
+ _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
/**
* Hook up all event listeners under the covers so we can estimate keycodes
@@ -35114,6 +35115,10 @@
return (receiver) {
setNativeSubclassDispatchRecord(receiver, interceptor);
+ // Mirrors uses the constructor property to cache lookups, so we need it to
+ // be set correctly, including on IE where it is not automatically picked
+ // up from the __proto__.
+ JS('', '#.constructor = #.__proto__.constructor', receiver, receiver);
return JS('', '#(#)', constructor, receiver);
};
}
@@ -35656,14 +35661,16 @@
// BSD-style license that can be found in the LICENSE file.
-_wrapZone(callback) {
+_wrapZone(callback(arg)) {
// For performance reasons avoid wrapping if we are in the root zone.
if (Zone.current == Zone.ROOT) return callback;
+ if (callback == null) return null;
return Zone.current.bindUnaryCallback(callback, runGuarded: true);
}
-_wrapBinaryZone(callback) {
+_wrapBinaryZone(callback(arg1, arg2)) {
if (Zone.current == Zone.ROOT) return callback;
+ if (callback == null) return null;
return Zone.current.bindBinaryCallback(callback, runGuarded: true);
}
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 62f36b9..52544f0 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -35098,13 +35098,14 @@
_tryResume();
}
- void cancel() {
- if (_canceled) return;
+ Future cancel() {
+ if (_canceled) return null;
_unlisten();
// Clear out the target to indicate this is complete.
_target = null;
_onData = null;
+ return null;
}
bool get _canceled => _target == null;
@@ -36731,7 +36732,7 @@
* KeyboardEvent controller.
*/
_KeyboardEventHandler(this._type): super(_EVENT_TYPE),
- _stream = new _CustomKeyEventStreamImpl('event');
+ _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
/**
* Hook up all event listeners under the covers so we can estimate keycodes
@@ -38053,14 +38054,16 @@
// BSD-style license that can be found in the LICENSE file.
-_wrapZone(callback) {
+_wrapZone(callback(arg)) {
// For performance reasons avoid wrapping if we are in the root zone.
if (Zone.current == Zone.ROOT) return callback;
+ if (callback == null) return null;
return Zone.current.bindUnaryCallback(callback, runGuarded: true);
}
-_wrapBinaryZone(callback) {
+_wrapBinaryZone(callback(arg1, arg2)) {
if (Zone.current == Zone.ROOT) return callback;
+ if (callback == null) return null;
return Zone.current.bindBinaryCallback(callback, runGuarded: true);
}
@@ -38522,7 +38525,7 @@
// TODO(vsm): Move these checks into native code.
ClassMirror cls = reflectClass(type);
if (_isBuiltinType(cls)) {
- throw new UnsupportedError("Invalid custom element from $libName.");
+ throw new UnsupportedError("Invalid custom element from ${cls.owner.uri}.");
}
var className = MirrorSystem.getName(cls.simpleName);
var createdConstructor = cls.declarations[new Symbol('$className.created')];
@@ -38629,6 +38632,9 @@
int get length => Maps.length(this);
bool get isEmpty => Maps.isEmpty(this);
bool get isNotEmpty => Maps.isNotEmpty(this);
+ void addAll(Map<String, String> other) {
+ other.forEach((key, value) => this[key] = value);
+ }
}
final _printClosure = window.console.log;
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 1912d61..9a657a1 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -35,6 +35,8 @@
static const _MODE = 4;
static const _SIZE = 5;
+ static const _notFound = const FileStat._internalNotFound();
+
/**
* The time of the last change to the data or metadata of the file system
* object. On Windows platforms, this is instead the file creation time.
@@ -73,7 +75,11 @@
this.mode,
this.size);
- external static List<int> _statSync(String path);
+ const FileStat._internalNotFound() :
+ changed = null, modified = null, accessed = null,
+ type = FileSystemEntityType.NOT_FOUND, mode = 0, size = -1;
+
+ external static _statSync(String path);
/**
@@ -88,7 +94,7 @@
path = FileSystemEntity._trimTrailingPathSeparators(path);
}
var data = _statSync(path);
- if (data is OSError) throw data;
+ if (data is OSError) return FileStat._notFound;
return new FileStat._internal(
new DateTime.fromMillisecondsSinceEpoch(data[_CHANGED_TIME] * 1000),
new DateTime.fromMillisecondsSinceEpoch(data[_MODIFIED_TIME] * 1000),
@@ -112,9 +118,7 @@
}
return _IOService.dispatch(_FILE_STAT, [path]).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "Error getting stat",
- path);
+ return FileStat._notFound;
}
// Unwrap the real list from the "I'm not an error" wrapper.
List data = response[1];
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index 1d7e9b5..0be5c08 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -444,7 +444,7 @@
void parseCookieString(String s) {
int index = 0;
- bool done() => index == s.length;
+ bool done() => index == -1 || index == s.length;
void skipWS() {
while (!done()) {
@@ -471,14 +471,11 @@
return s.substring(start, index);
}
- void expect(String expected) {
- if (done()) {
- throw new HttpException("Failed to parse header value [$s]");
- }
- if (s[index] != expected) {
- throw new HttpException("Failed to parse header value [$s]");
- }
+ bool expect(String expected) {
+ if (done()) return false;
+ if (s[index] != expected) return false;
index++;
+ return true;
}
while (!done()) {
@@ -486,13 +483,19 @@
if (done()) return;
String name = parseName();
skipWS();
- expect("=");
+ if (!expect("=")) {
+ index = s.indexOf(';', index);
+ continue;
+ }
skipWS();
String value = parseValue();
cookies.add(new _Cookie(name, value));
skipWS();
if (done()) return;
- expect(";");
+ if (!expect(";")) {
+ index = s.indexOf(';', index);
+ continue;
+ }
}
}
List<String> values = _headers[HttpHeaders.COOKIE];
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index 8856c10..5c3263f 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -96,68 +96,119 @@
static const int RESPONSE = 0;
}
-class _HttpDetachedIncoming extends Stream<List<int>> {
- StreamController<List<int>> controller;
- final StreamSubscription subscription;
- List<int> bufferedData;
- bool paused;
+/**
+ * The _HttpDetachedStreamSubscription takes a subscription and some extra data,
+ * and makes it possible to "inject" the data in from of other data events
+ * from the subscription.
+ *
+ * It does so by overriding pause/resume, so that once the
+ * _HttpDetachedStreamSubscription is resumed, it'll deliver the data before
+ * resuming the underlaying subscription.
+ */
+class _HttpDetachedStreamSubscription implements StreamSubscription<List<int>> {
+ StreamSubscription<List<int>> _subscription;
+ List<int> _injectData;
+ bool _isCanceled = false;
+ int _pauseCount = 1;
+ Function _userOnData;
+ bool _scheduled = false;
- Completer resumeCompleter;
+ _HttpDetachedStreamSubscription(this._subscription,
+ this._injectData,
+ this._userOnData);
- _HttpDetachedIncoming(this.subscription, this.bufferedData) {
- controller = new StreamController<List<int>>(
- sync: true,
- onListen: resume,
- onPause: pause,
- onResume: resume,
- onCancel: () => subscription.cancel());
- if (subscription == null) {
- // Socket was already closed.
- if (bufferedData != null) controller.add(bufferedData);
- controller.close();
+ bool get isPaused => _subscription.isPaused;
+
+ Future asFuture([futureValue]) => _subscription.asFuture(futureValue);
+
+ Future cancel() {
+ _isCanceled = true;
+ _injectData = null;
+ return _subscription.cancel();
+ }
+
+ void onData(void handleData(List<int> data)) {
+ _userOnData = handleData;
+ _subscription.onData(handleData);
+ }
+
+ void onDone(void handleDone()) {
+ _subscription.onDone(handleDone);
+ }
+
+ void onError(Function handleError) {
+ _subscription.onError(handleError);
+ }
+
+ void pause([Future resumeSignal]) {
+ if (_injectData == null) {
+ _subscription.pause(resumeSignal);
} else {
- pause();
- subscription
- ..resume()
- ..onData(controller.add)
- ..onDone(controller.close)
- ..onError(controller.addError);
+ _pauseCount++;
+ if (resumeSignal != null) {
+ resumeSignal.whenComplete(resume);
+ }
}
}
+ void resume() {
+ if (_injectData == null) {
+ _subscription.resume();
+ } else {
+ _pauseCount--;
+ _maybeScheduleData();
+ }
+ }
+
+ void _maybeScheduleData() {
+ if (_scheduled) return;
+ if (_pauseCount != 0) return;
+ _scheduled = true;
+ scheduleMicrotask(() {
+ _scheduled = false;
+ if (_pauseCount > 0 || _isCanceled) return;
+ var data = _injectData;
+ _injectData = null;
+ // To ensure that 'subscription.isPaused' is false, we resume the
+ // subscription here. This is fine as potential events are delayed.
+ _subscription.resume();
+ if (_userOnData != null) {
+ _userOnData(data);
+ }
+ });
+ }
+}
+
+
+class _HttpDetachedIncoming extends Stream<List<int>> {
+ final StreamSubscription subscription;
+ final List<int> bufferedData;
+
+ _HttpDetachedIncoming(this.subscription, this.bufferedData);
+
StreamSubscription<List<int>> listen(void onData(List<int> event),
{Function onError,
void onDone(),
bool cancelOnError}) {
- return controller.stream.listen(
- onData,
- onError: onError,
- onDone: onDone,
- cancelOnError: cancelOnError);
- }
-
- void resume() {
- paused = false;
- if (bufferedData != null) {
- var data = bufferedData;
- bufferedData = null;
- controller.add(data);
- // If the consumer pauses again after the carry-over data, we'll not
- // continue our subscriber until the next resume.
- if (paused) return;
- }
- if (resumeCompleter != null) {
- resumeCompleter.complete();
- resumeCompleter = null;
- }
- }
-
- void pause() {
- paused = true;
- if (resumeCompleter == null) {
- resumeCompleter = new Completer();
- subscription.pause(resumeCompleter.future);
+ if (subscription != null) {
+ subscription
+ ..onData(onData)
+ ..onError(onError)
+ ..onDone(onDone);
+ if (bufferedData == null) {
+ return subscription..resume();
+ }
+ return new _HttpDetachedStreamSubscription(subscription,
+ bufferedData,
+ onData)
+ ..resume();
+ } else {
+ return new Stream.fromIterable(bufferedData)
+ .listen(onData,
+ onError: onError,
+ onDone: onDone,
+ cancelOnError: cancelOnError);
}
}
}
@@ -833,6 +884,8 @@
void set responseToMethod(String method) { _responseToMethod = method; }
_HttpDetachedIncoming detachIncoming() {
+ // Simulate detached by marking as upgraded.
+ _state = _State.UPGRADED;
return new _HttpDetachedIncoming(_socketSubscription,
readUnparsedData());
}
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 75bd893..0cf7126 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -346,6 +346,20 @@
String toString() => _name;
+ /**
+ * Watch for process signals.
+ *
+ * The following [ProcessSignal]s can be listened to:
+ *
+ * * [ProcessSignal.SIGHUP].
+ * * [ProcessSignal.SIGINT].
+ * * [ProcessSignal.SIGTERM]. Not available on Windows.
+ * * [ProcessSignal.SIGUSR1]. Not available on Windows.
+ * * [ProcessSignal.SIGUSR2]. Not available on Windows.
+ * * [ProcessSignal.SIGWINCH]. Not available on Windows.
+ *
+ * Other signals are disallowed, as they may be used by the VM.
+ */
Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this);
}
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 5396a6a..495c70e 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -128,6 +128,7 @@
static int _idCount = 0;
static RawReceivePort _receivePort;
+ static SendPort _sendPort;
static bool _handlingCallbacks = false;
Function _callback;
@@ -241,10 +242,13 @@
// events.
_createTimerHandler();
}
- _EventHandler._sendData(null,
- _receivePort,
- _firstZeroTimer != null ?
- 0 : _heap.first._wakeupTime);
+ if (_firstZeroTimer != null) {
+ _sendPort.send(null);
+ } else {
+ _EventHandler._sendData(null,
+ _receivePort,
+ _heap.first._wakeupTime);
+ }
}
}
@@ -300,6 +304,7 @@
static void _createTimerHandler() {
if(_receivePort == null) {
_receivePort = new RawReceivePort(_handleTimeout);
+ _sendPort = _receivePort.sendPort;
}
}
diff --git a/sdk/lib/isolate/capability.dart b/sdk/lib/isolate/capability.dart
new file mode 100644
index 0000000..a51eec2
--- /dev/null
+++ b/sdk/lib/isolate/capability.dart
@@ -0,0 +1,34 @@
+// 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.
+
+part of dart.isolate;
+
+/**
+ * An unforgeable object that comes back as equal when passed through other
+ * isolates.
+ *
+ * Sending a capability object to another isolate, and getting it back,
+ * will produce an object that is equal to the original.
+ * There is no other way to create objects equal to a capability object.
+ *
+ * Capabilities can be used as access guards: A remote isolate can send
+ * a request for an operation, but it is only allowed if the request contains
+ * the correct capability object.
+ *
+ * This allows exposing the same interface to multiple clients,
+ * but restricting some operations to only those clients
+ * that have also been given the corresponding capability.
+ *
+ * Capabilities can be used inside a single isolate,
+ * but they have no advantage over
+ * just using `new Object` to create a unique object,
+ * and it offers no real security against other code
+ * running in the same isolate.
+ */
+class Capability {
+ /**
+ * Create a new unforgeable capability object.
+ */
+ external factory Capability();
+}
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index efc6ca2..4a5b50a 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -16,6 +16,8 @@
import "dart:async";
+part "capability.dart";
+
/**
* Thrown when an isolate cannot be created.
*/
@@ -27,11 +29,16 @@
}
class Isolate {
+ /**
+ * Control port used to send control messages to the isolate.
+ *
+ * This class provides helper functions that sends control messages
+ * to the control port.
+ */
+ final SendPort controlPort;
+ final Capability pauseCapability;
- final SendPort _controlPort;
-
- Isolate._fromControlPort(SendPort controlPort)
- : this._controlPort = controlPort;
+ Isolate._fromControlPort(this.controlPort, [this.pauseCapability]);
/**
* Creates and spawns an isolate that shares the same code as the current
@@ -74,6 +81,57 @@
*/
external static Future<Isolate> spawnUri(
Uri uri, List<String> args, var message);
+
+
+ /**
+ * Requests the isolate to pause.
+ *
+ * The isolate should stop handling events by pausing its event queue.
+ * The request will eventually make the isolate stop doing anything.
+ * It will be handled before any other messages sent to the isolate from
+ * the current isolate, but no other guarantees are provided.
+ *
+ * If [resumeCapability] is provided, it is used to identity the pause,
+ * and must be used again to end the pause using [resume].
+ * Otherwise a new capability is created and returned.
+ *
+ * If an isolate is paused more than once using the same capabilty,
+ * only one resume with that capability is needed to end the pause.
+ *
+ * If an isolate is paused using more than one capability,
+ * they must all be individully ended before the isolate resumes.
+ *
+ * Returns the capability that must be used to resume end the pause.
+ *
+ * WARNING: This method is not handled on any platform yet.
+ */
+ Capability pause([Capability resumeCapability]) {
+ if (resumeCapability == null) resumeCapability = new Capability();
+ var message = new List(3)
+ ..[0] = "pause"
+ ..[1] = pauseCapability
+ ..[2] = resumeCapability;
+ controlPort.send(message);
+ return resumeCapability;
+ }
+
+ /**
+ * Resumes a paused isolate.
+ *
+ * Sends a message to an isolate requesting that it ends a pause
+ * that was requested using the [resumeCapability].
+ *
+ * The capability must be one returned by a call to [pause] on this
+ * isolate, otherwise the resume call does nothing.
+ *
+ * WARNING: This method is not handled on any platform yet.
+ */
+ void resume(Capability resumeCapability) {
+ var message = new List(2)
+ ..[0] = "resume"
+ ..[1] = resumeCapability;
+ controlPort.send(message);
+ }
}
/**
diff --git a/sdk/lib/isolate/isolate_sources.gypi b/sdk/lib/isolate/isolate_sources.gypi
index e1c4825..8d3ff84 100644
--- a/sdk/lib/isolate/isolate_sources.gypi
+++ b/sdk/lib/isolate/isolate_sources.gypi
@@ -6,5 +6,6 @@
'sources': [
'isolate.dart',
# The above file needs to be first as it lists the parts below.
+ 'capability.dart',
],
}
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
index b1003d9..576cb234 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -471,6 +471,13 @@
return false;
}
+Object _getOwnProperty(o, String name) {
+ if (JS('bool', 'Object.prototype.hasOwnProperty.call(#, #)', o, name)) {
+ return JS('', '#[#]', o, name);
+ }
+ return null;
+}
+
bool _isLocalObject(o) => JS('bool', '# instanceof Object', o);
dynamic _convertToJS(dynamic o) {
@@ -498,7 +505,7 @@
}
Object _getJsProxy(o, String propertyName, createProxy(o)) {
- var jsProxy = JS('', '#[#]', o, propertyName);
+ var jsProxy = _getOwnProperty(o, propertyName);
if (jsProxy == null) {
jsProxy = createProxy(o);
_defineProperty(o, propertyName, jsProxy);
@@ -543,7 +550,7 @@
}
Object _getDartProxy(o, String propertyName, createProxy(o)) {
- var dartProxy = JS('', '#[#]', o, propertyName);
+ var dartProxy = _getOwnProperty(o, propertyName);
// Temporary fix for dartbug.com/15193
// In some cases it's possible to see a JavaScript object that
// came from a different context and was previously proxied to
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index 7e0b50b..a2764d7 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -814,7 +814,7 @@
int get offsetInBytes => _storage.offsetInBytes;
- final int elementSizeInBytes = 16;
+ int get elementSizeInBytes => BYTES_PER_ELEMENT;
void _invalidIndex(int index, int length) {
if (index < 0 || index >= length) {
@@ -892,7 +892,8 @@
*/
Float32x4List.view(ByteBuffer buffer,
[int byteOffset = 0, int length])
- : _storage = new Float32List.view(buffer, byteOffset, length);
+ : _storage = new Float32List.view(buffer, byteOffset,
+ length != null ? length * 4 : null);
static const int BYTES_PER_ELEMENT = 16;
@@ -940,7 +941,7 @@
int get offsetInBytes => _storage.offsetInBytes;
- final int elementSizeInBytes = 16;
+ int get elementSizeInBytes => BYTES_PER_ELEMENT;
void _invalidIndex(int index, int length) {
if (index < 0 || index >= length) {
@@ -1019,7 +1020,8 @@
*/
Int32x4List.view(ByteBuffer buffer,
[int byteOffset = 0, int length])
- : _storage = new Uint32List.view(buffer, byteOffset, length);
+ : _storage = new Uint32List.view(buffer, byteOffset,
+ length != null ? length * 4 : null);
static const int BYTES_PER_ELEMENT = 16;
@@ -1050,6 +1052,127 @@
/**
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class Float64x2List
+ extends Object with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
+ implements List<Float64x2>, TypedData {
+
+ final Float64List _storage;
+
+ ByteBuffer get buffer => _storage.buffer;
+
+ int get lengthInBytes => _storage.lengthInBytes;
+
+ int get offsetInBytes => _storage.offsetInBytes;
+
+ int get elementSizeInBytes => BYTES_PER_ELEMENT;
+
+ void _invalidIndex(int index, int length) {
+ if (index < 0 || index >= length) {
+ throw new RangeError.range(index, 0, length);
+ } else {
+ throw new ArgumentError('Invalid list index $index');
+ }
+ }
+
+ void _checkIndex(int index, int length) {
+ if (JS('bool', '(# >>> 0 != #)', index, index) || index >= length) {
+ _invalidIndex(index, length);
+ }
+ }
+
+ int _checkSublistArguments(int start, int end, int length) {
+ // For `sublist` the [start] and [end] indices are allowed to be equal to
+ // [length]. However, [_checkIndex] only allows indices in the range
+ // 0 .. length - 1. We therefore increment the [length] argument by one
+ // for the [_checkIndex] checks.
+ _checkIndex(start, length + 1);
+ if (end == null) return length;
+ _checkIndex(end, length + 1);
+ if (start > end) throw new RangeError.range(start, 0, end);
+ return end;
+ }
+
+ /**
+ * Creates a [Float64x2List] of the specified length (in elements),
+ * all of whose elements are initially zero.
+ */
+ Float64x2List(int length) : _storage = new Float64List(length * 2);
+
+ Float64x2List._externalStorage(Float64List storage) : _storage = storage;
+
+ Float64x2List._slowFromList(List<Float64x2> list)
+ : _storage = new Float64List(list.length * 2) {
+ for (int i = 0; i < list.length; i++) {
+ var e = list[i];
+ _storage[(i * 2) + 0] = e.x;
+ _storage[(i * 2) + 1] = e.y;
+ }
+ }
+
+ /**
+ * Creates a [Float64x2List] with the same size as the [elements] list
+ * and copies over the elements.
+ */
+ factory Float64x2List.fromList(List<Float64x2> list) {
+ if (list is Float64x2List) {
+ Float64x2List nativeList = list as Float64x2List;
+ return new Float64x2List._externalStorage(
+ new Float64List.fromList(nativeList._storage));
+ } else {
+ return new Float64x2List._slowFromList(list);
+ }
+ }
+
+ /**
+ * Creates a [Float64x2List] _view_ of the specified region in the specified
+ * byte buffer. Changes in the [Float64x2List] will be visible in the byte
+ * buffer and vice versa. If the [offsetInBytes] index of the region is not
+ * specified, it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to null, which indicates
+ * that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * BYTES_PER_ELEMENT.
+ */
+ Float64x2List.view(ByteBuffer buffer,
+ [int byteOffset = 0, int length])
+ : _storage = new Float64List.view(buffer, byteOffset,
+ length != null ? length * 2 : null);
+
+ static const int BYTES_PER_ELEMENT = 16;
+
+ int get length => _storage.length ~/ 2;
+
+ Float64x2 operator[](int index) {
+ _checkIndex(index, length);
+ double _x = _storage[(index * 2) + 0];
+ double _y = _storage[(index * 2) + 1];
+ return new Float64x2(_x, _y);
+ }
+
+ void operator[]=(int index, Float64x2 value) {
+ _checkIndex(index, length);
+ _storage[(index * 2) + 0] = value._storage[0];
+ _storage[(index * 2) + 1] = value._storage[1];
+ }
+
+ List<Float64x2> sublist(int start, [int end]) {
+ end = _checkSublistArguments(start, end, length);
+ return new Float64x2List._externalStorage(
+ _storage.sublist(start * 2, end * 2));
+ }
+}
+
+
+/**
* Interface of Dart Float32x4 immutable value type and operations.
* Float32x4 stores 4 32-bit floating point values in "lanes".
* The lanes are "x", "y", "z", and "w" respectively.
@@ -1078,6 +1201,14 @@
_storage[2] = view[2];
_storage[3] = view[3];
}
+ Float32x4.fromFloat64x2(Float64x2 v) {
+ _storage[0] = v._storage[0];
+ _storage[1] = v._storage[1];
+ }
+
+ String toString() {
+ return '[${_storage[0]}, ${_storage[1]}, ${_storage[2]}, ${_storage[3]}]';
+ }
/// Addition operator.
Float32x4 operator+(Float32x4 other) {
@@ -1665,6 +1796,10 @@
_storage[3] = view[3];
}
+ String toString() {
+ return '[${_storage[0]}, ${_storage[1]}, ${_storage[2]}, ${_storage[3]}]';
+ }
+
/// The bit-wise or operator.
Int32x4 operator|(Int32x4 other) {
int _x = _storage[0] | other._storage[0];
@@ -2124,3 +2259,126 @@
return r;
}
}
+
+class Float64x2 {
+ final _storage = new Float64List(2);
+
+ Float64x2(double x, double y) {
+ _storage[0] = x;
+ _storage[1] = y;
+ }
+
+ Float64x2.splat(double v) {
+ _storage[0] = v;
+ _storage[1] = v;
+ }
+
+ Float64x2.zero();
+
+ Float64x2.fromFloat32x4(Float32x4 v) {
+ _storage[0] = v._storage[0];
+ _storage[1] = v._storage[1];
+ }
+
+ String toString() {
+ return '[${_storage[0]}, ${_storage[1]}]';
+ }
+
+ /// Addition operator.
+ Float64x2 operator+(Float64x2 other) {
+ return new Float64x2(_storage[0] + other._storage[0],
+ _storage[1] + other._storage[1]);
+ }
+
+ /// Negate operator.
+ Float64x2 operator-() {
+ return new Float64x2(-_storage[0], -_storage[1]);
+ }
+
+ /// Subtraction operator.
+ Float64x2 operator-(Float64x2 other) {
+ return new Float64x2(_storage[0] - other._storage[0],
+ _storage[1] - other._storage[1]);
+ }
+ /// Multiplication operator.
+ Float64x2 operator*(Float64x2 other) {
+ return new Float64x2(_storage[0] * other._storage[0],
+ _storage[1] * other._storage[1]);
+ }
+ /// Division operator.
+ Float64x2 operator/(Float64x2 other) {
+ return new Float64x2(_storage[0] / other._storage[0],
+ _storage[1] / other._storage[1]);
+ }
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ Float64x2 scale(double s) {
+ return new Float64x2(_storage[0] * s, _storage[1] * s);
+ }
+
+ /// Returns the absolute value of this [Float64x2].
+ Float64x2 abs() {
+ return new Float64x2(_storage[0].abs(), _storage[1].abs());
+ }
+
+ /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+ Float64x2 clamp(Float64x2 lowerLimit,
+ Float64x2 upperLimit) {
+ double _lx = lowerLimit._storage[0];
+ double _ly = lowerLimit._storage[1];
+ double _ux = upperLimit._storage[0];
+ double _uy = upperLimit._storage[1];
+ double _x = _storage[0];
+ double _y = _storage[1];
+ // MAX(MIN(self, upper), lower).
+ _x = _x > _ux ? _ux : _x;
+ _y = _y > _uy ? _uy : _y;
+ _x = _x < _lx ? _lx : _x;
+ _y = _y < _ly ? _ly : _y;
+ return new Float64x2(_x, _y);
+ }
+
+ /// Extracted x value.
+ double get x => _storage[0];
+ /// Extracted y value.
+ double get y => _storage[1];
+
+ /// Extract the sign bits from each lane return them in the first 2 bits.
+ int get signMask {
+ var view = new Uint32List.view(_storage.buffer);
+ var mx = (view[1] & 0x80000000) >> 31;
+ var my = (view[3] & 0x80000000) >> 31;
+ return mx | my << 1;
+ }
+
+ /// Returns a new [Float64x2] copied from [this] with a new x value.
+ Float64x2 withX(double x) {
+ return new Float64x2(x, _storage[1]);
+ }
+
+ /// Returns a new [Float64x2] copied from [this] with a new y value.
+ Float64x2 withY(double y) {
+ return new Float64x2(_storage[0], y);
+ }
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float64x2 min(Float64x2 other) {
+ return new Float64x2(
+ _storage[0] < other._storage[0] ? _storage[0] : other._storage[0],
+ _storage[1] < other._storage[1] ? _storage[1] : other._storage[1]);
+
+ }
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float64x2 max(Float64x2 other) {
+ return new Float64x2(
+ _storage[0] > other._storage[0] ? _storage[0] : other._storage[0],
+ _storage[1] > other._storage[1] ? _storage[1] : other._storage[1]);
+ }
+
+ /// Returns the lane-wise square root of [this].
+ Float64x2 sqrt() {
+ return new Float64x2(Math.sqrt(_storage[0]), Math.sqrt(_storage[1]));
+ }
+}
+
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 413eff3..66a86bc 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -364,7 +364,7 @@
external factory Int8List(int length);
/**
- * Creates a [Int8List] with the same size as the [elements] list
+ * Creates a [Int8List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Int8List.fromList(List<int> elements);
@@ -401,7 +401,7 @@
external factory Uint8List(int length);
/**
- * Creates a [Uint8List] with the same size as the [elements] list
+ * Creates a [Uint8List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Uint8List.fromList(List<int> elements);
@@ -476,7 +476,7 @@
external factory Int16List(int length);
/**
- * Creates a [Int16List] with the same size as the [elements] list
+ * Creates a [Int16List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Int16List.fromList(List<int> elements);
@@ -494,7 +494,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Int16List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -516,7 +516,7 @@
external factory Uint16List(int length);
/**
- * Creates a [Uint16List] with the same size as the [elements] list
+ * Creates a [Uint16List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Uint16List.fromList(List<int> elements);
@@ -534,7 +534,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Uint16List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -556,7 +556,7 @@
external factory Int32List(int length);
/**
- * Creates a [Int32List] with the same size as the [elements] list
+ * Creates a [Int32List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Int32List.fromList(List<int> elements);
@@ -574,7 +574,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Int32List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -596,7 +596,7 @@
external factory Uint32List(int length);
/**
- * Creates a [Uint32List] with the same size as the [elements] list
+ * Creates a [Uint32List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Uint32List.fromList(List<int> elements);
@@ -614,7 +614,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Uint32List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -636,7 +636,7 @@
external factory Int64List(int length);
/**
- * Creates a [Int64List] with the same size as the [elements] list
+ * Creates a [Int64List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Int64List.fromList(List<int> elements);
@@ -654,7 +654,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Int64List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -676,7 +676,7 @@
external factory Uint64List(int length);
/**
- * Creates a [Uint64List] with the same size as the [elements] list
+ * Creates a [Uint64List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Uint64List.fromList(List<int> elements);
@@ -695,7 +695,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Uint64List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -718,7 +718,7 @@
external factory Float32List(int length);
/**
- * Creates a [Float32List] with the same size as the [elements] list
+ * Creates a [Float32List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Float32List.fromList(List<double> elements);
@@ -736,7 +736,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Float32List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -759,7 +759,7 @@
external factory Float64List(int length);
/**
- * Creates a [Float64List] with the same size as the [elements] list
+ * Creates a [Float64List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Float64List.fromList(List<double> elements);
@@ -777,7 +777,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Float64List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -799,7 +799,7 @@
external factory Float32x4List(int length);
/**
- * Creates a [Float32x4List] with the same size as the [elements] list
+ * Creates a [Float32x4List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Float32x4List.fromList(List<Float32x4> elements);
@@ -817,7 +817,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Float32x4List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -839,7 +839,7 @@
external factory Int32x4List(int length);
/**
- * Creates a [Int32x4List] with the same size as the [elements] list
+ * Creates a [Int32x4List] with the same length as the [elements] list
* and copies over the elements.
*/
external factory Int32x4List.fromList(List<Int32x4> elements);
@@ -857,7 +857,7 @@
* the length of [buffer].
*
* Throws [ArgumentError] if [offsetInBytes] is not a multiple of
- * BYTES_PER_ELEMENT.
+ * [BYTES_PER_ELEMENT].
*/
external factory Int32x4List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]);
@@ -867,7 +867,47 @@
/**
- * Interface of Dart Float32x4 immutable value type and operations.
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Float64x2List implements List<Float64x2>, TypedData {
+ /**
+ * Creates a [Float64x2List] of the specified length (in elements),
+ * all of whose elements have all lanes set to zero.
+ */
+ external factory Float64x2List(int length);
+
+ /**
+ * Creates a [Float64x2List] with the same length as the [elements] list
+ * and copies over the elements.
+ */
+ external factory Float64x2List.fromList(List<Float64x2> elements);
+
+ /**
+ * Creates a [Float64x2List] _view_ of the specified region in the specified
+ * byte buffer. Changes in the [Float64x2List] will be visible in the byte
+ * buffer and vice versa. If the [offsetInBytes] index of the region is not
+ * specified, it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to null, which indicates
+ * that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [BYTES_PER_ELEMENT].
+ */
+ external factory Float64x2List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]);
+
+ static const int BYTES_PER_ELEMENT = 16;
+}
+
+
+/**
+ * Float32x4 immutable value type and operations.
* Float32x4 stores 4 32-bit floating point values in "lanes".
* The lanes are "x", "y", "z", and "w" respectively.
*/
@@ -876,6 +916,9 @@
external factory Float32x4.splat(double v);
external factory Float32x4.zero();
external factory Float32x4.fromInt32x4Bits(Int32x4 x);
+ /// Sets the x and y lanes to their respective values in [v] and sets the z
+ /// and w lanes to 0.0.
+ external factory Float32x4.fromFloat64x2(Float64x2 v);
/// Addition operator.
Float32x4 operator+(Float32x4 other);
@@ -902,12 +945,12 @@
Int32x4 notEqual(Float32x4 other);
/// Returns a copy of [this] each lane being scaled by [s].
+ /// Equivalent to this * new Float32x4.splat(s)
Float32x4 scale(double s);
- /// Returns the absolute value of this [Float32x4].
+ /// Returns the lane-wise absolute value of this [Float32x4].
Float32x4 abs();
- /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
- Float32x4 clamp(Float32x4 lowerLimit,
- Float32x4 upperLimit);
+ /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+ Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit);
/// Extracted x value.
double get x;
@@ -919,6 +962,10 @@
double get w;
/// Extract the sign bits from each lane return them in the first 4 bits.
+ /// "x" lane is bit 0.
+ /// "y" lane is bit 1.
+ /// "z" lane is bit 2.
+ /// "w" lane is bit 3.
int get signMask;
/// Mask passed to [shuffle] or [shuffleMix].
@@ -1214,7 +1261,7 @@
/**
- * Interface of Dart Int32x4 and operations.
+ * Int32x4 and operations.
* Int32x4 stores 4 32-bit bit-masks in "lanes".
* The lanes are "x", "y", "z", and "w" respectively.
*/
@@ -1244,6 +1291,10 @@
int get w;
/// Extract the top bit from each lane return them in the first 4 bits.
+ /// "x" lane is bit 0.
+ /// "y" lane is bit 1.
+ /// "z" lane is bit 2.
+ /// "w" lane is bit 3.
int get signMask;
/// Mask passed to [shuffle] or [shuffleMix].
@@ -1544,3 +1595,61 @@
/// Select bit from [falseValue] when bit in [this] is off.
Float32x4 select(Float32x4 trueValue, Float32x4 falseValue);
}
+
+/**
+ * Float64x2 immutable value type and operations.
+ * Float64x2 stores 2 64-bit floating point values in "lanes".
+ * The lanes are "x" and "y" respectively.
+ */
+abstract class Float64x2 {
+ external factory Float64x2(double x, double y);
+ external factory Float64x2.splat(double v);
+ external factory Float64x2.zero();
+ /// Uses the "x" and "y" lanes from [v].
+ external factory Float64x2.fromFloat32x4(Float32x4 v);
+
+ /// Addition operator.
+ Float64x2 operator+(Float64x2 other);
+ /// Negate operator.
+ Float64x2 operator-();
+ /// Subtraction operator.
+ Float64x2 operator-(Float64x2 other);
+ /// Multiplication operator.
+ Float64x2 operator*(Float64x2 other);
+ /// Division operator.
+ Float64x2 operator/(Float64x2 other);
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ /// Equivalent to this * new Float64x2.splat(s)
+ Float64x2 scale(double s);
+ /// Returns the lane-wise absolute value of this [Float64x2].
+ Float64x2 abs();
+
+ /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+ Float64x2 clamp(Float64x2 lowerLimit,
+ Float64x2 upperLimit);
+
+ /// Extracted x value.
+ double get x;
+ /// Extracted y value.
+ double get y;
+
+ /// Extract the sign bits from each lane return them in the first 2 bits.
+ /// "x" lane is bit 0.
+ /// "y" lane is bit 1.
+ int get signMask;
+
+ /// Returns a new [Float64x2] copied from [this] with a new x value.
+ Float64x2 withX(double x);
+ /// Returns a new [Float64x2] copied from [this] with a new y value.
+ Float64x2 withY(double y);
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float64x2 min(Float64x2 other);
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float64x2 max(Float64x2 other);
+
+ /// Returns the lane-wise square root of [this].
+ Float64x2 sqrt();
+}
diff --git a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
index 185ac73..561e1f0 100644
--- a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
+++ b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -3158,14 +3158,14 @@
*/
@JSName('texSubImage2D')
void texSubImage2DUntyped(int targetTexture, int levelOfDetail,
- int internalFormat, int format, int type, data) native;
+ int xOffset, int yOffset, int format, int type, data) native;
/**
* Updates a sub-rectangle of the currently bound texture to [data].
*/
@JSName('texSubImage2D')
void texSubImage2DTyped(int targetTexture, int levelOfDetail,
- int internalFormat, int width, int height, int border, int format,
+ int xOffset, int yOffset, int width, int height, int border, int format,
int type, TypedData data) native;
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
diff --git a/sdk/lib/web_gl/dartium/web_gl_dartium.dart b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
index e19200f..867aa67 100644
--- a/sdk/lib/web_gl/dartium/web_gl_dartium.dart
+++ b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
@@ -2990,8 +2990,8 @@
*
*/
void texSubImage2DUntyped(int targetTexture, int levelOfDetail,
- int internalFormat, int format, int type, data) {
- texSubImage2D(targetTexture, levelOfDetail, internalFormat,
+ int xOffset, int yOffset, int format, int type, data) {
+ texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
format, type, data);
}
@@ -2999,10 +2999,10 @@
* Updates a sub-rectangle of the currently bound texture to [data].
*/
void texSubImage2DTyped(int targetTexture, int levelOfDetail,
- int internalFormat, int width, int height, int border, int format,
+ int xOffset, int yOffset, int width, int height, int format,
int type, TypedData data) {
- texSubImage2D(targetTexture, levelOfDetail, internalFormat,
- width, height, border, format, type, data);
+ texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
+ width, height, format, type, data);
}
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
diff --git a/site/try/build_try.gyp b/site/try/build_try.gyp
index 1122ba0..193cc13 100644
--- a/site/try/build_try.gyp
+++ b/site/try/build_try.gyp
@@ -26,7 +26,7 @@
'../../third_party/font-awesome/font-awesome-4.0.3/'
'fonts/fontawesome-webfont.woff',
- '../../sdk/lib/_internal/dartdoc/static/favicon.ico',
+ 'favicon.ico',
'<(SHARED_INTERMEDIATE_DIR)/leap.dart.js',
'<(SHARED_INTERMEDIATE_DIR)/sdk.json',
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 597905e..beab79d 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -490,7 +490,6 @@
LibTest/typed_data/Float32List/fold_A01_t01: fail # co19-roll r559: Please triage this failure
LibTest/typed_data/Float32List/join_A01_t01: fail # co19-roll r559: Please triage this failure
LibTest/typed_data/Float32List/join_A01_t02: fail # co19-roll r559: Please triage this failure
-LibTest/typed_data/Float32x4List/Float32x4List.view_A02_t01: RuntimeError # co19-roll r559: Please triage this failure
LibTest/typed_data/Float32x4List/Float32x4List.view_A05_t01: RuntimeError # co19-roll r559: Please triage this failure
LibTest/typed_data/Float32x4List/Float32x4List.view_A05_t02: RuntimeError # co19-roll r559: Please triage this failure
LibTest/typed_data/Float32x4List/Float32x4List.view_A05_t03: RuntimeError # co19-roll r559: Please triage this failure
@@ -574,7 +573,6 @@
LibTest/async/Stream/Stream.periodic_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/async/Timer/cancel_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/async/Timer/Timer_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/typed_data/Float32x4List/Float32x4List.view_A01_t02: fail # co19-roll r587: Please triage this failure
LibTest/typed_data/Float32x4List/Float32x4List.view_A06_t01: fail # co19-roll r587: Please triage this failure
Language/12_Expressions/00_Object_Identity/1_Object_Identity_A05_t02: RuntimeError # co19-roll r607: Please triage this failure
Language/12_Expressions/17_Getter_Invocation_A07_t02: RuntimeError # co19-roll r607: Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index a1f2845..ad284aa 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -5,7 +5,7 @@
[ $compiler == none && $runtime == drt ]
*: Skip # running co19 tests on content_shell would make our dartium cycle-times very long
-[ $compiler == none && $runtime == dartium && $mode == debug && $system == windows ]
+[ $compiler == none && $runtime == dartium && $mode == debug ]
Language/15_Types/4_Interface_Types_A11_t01: Skip # Issue 16343
Language/15_Types/4_Interface_Types_A11_t02: Skip # Issue 16343
@@ -39,5 +39,7 @@
LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError # co19-roll r667: Please triage this failure
LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # co19-roll r667: Please triage this failure
+LibTest/async/Timer/Timer_A01_t01: RuntimeError, Pass # Issue 16475
+
[ $compiler == none && $runtime == dartium && $checked ]
LibTest/core/List/removeAt_A02_t01: Fail # co19-roll r641: Please triage this failure
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index d601c2c..763bf35 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -83,16 +83,21 @@
return backend.assembleCode(element);
}
+// TODO(herhut): Disallow warnings and errors during compilation by default.
MockCompiler compilerFor(String code, Uri uri,
{bool analyzeAll: false,
bool analyzeOnly: false,
String coreSource: DEFAULT_CORELIB,
- bool disableInlining: true}) {
+ bool disableInlining: true,
+ bool allowErrors: true,
+ bool allowWarnings: true}) {
MockCompiler compiler = new MockCompiler(
analyzeAll: analyzeAll,
analyzeOnly: analyzeOnly,
coreSource: coreSource,
- disableInlining: disableInlining);
+ disableInlining: disableInlining,
+ allowErrors: allowErrors,
+ allowWarnings: allowWarnings);
compiler.sourceFiles[uri.toString()] =
new StringSourceFile(uri.toString(), code);
return compiler;
@@ -100,10 +105,13 @@
Future<String> compileAll(String code,
{String coreSource: DEFAULT_CORELIB,
- bool disableInlining: true}) {
+ bool disableInlining: true,
+ bool allowErrors: true,
+ bool allowWarnings: true}) {
Uri uri = new Uri(scheme: 'source');
MockCompiler compiler = compilerFor(
- code, uri, coreSource: coreSource, disableInlining: disableInlining);
+ code, uri, coreSource: coreSource, disableInlining: disableInlining,
+ allowErrors: allowErrors, allowWarnings: allowWarnings);
return compiler.runCompiler(uri).then((_) {
Expect.isFalse(compiler.compilationFailed,
'Unexpected compilation error');
@@ -113,9 +121,12 @@
Future compileAndCheck(String code,
String name,
- check(MockCompiler compiler, lego.Element element)) {
+ check(MockCompiler compiler, lego.Element element),
+ {bool allowErrors: true, bool allowWarnings: true}) {
Uri uri = new Uri(scheme: 'source');
- MockCompiler compiler = compilerFor(code, uri);
+ MockCompiler compiler = compilerFor(code, uri,
+ allowErrors: allowErrors,
+ allowWarnings: allowWarnings);
return compiler.runCompiler(uri).then((_) {
lego.Element element = findElement(compiler, name);
return check(compiler, element);
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 7bbae64..90ce342 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -6,17 +6,31 @@
constant_folding_string_test: Fail
boolified_operator_test: Fail # Issue 8001
-# Don't mark these tests as failing. Instead, fix the errors/warnings that they
-# report or update the whitelist in the test-files to temporarily allow
-# digression.
-analyze_api_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
-analyze_dart2js_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
-
# simple_function_subtype_test is temporarily(?) disabled due to new method for
# building function type tests.
simple_function_subtype_test: Fail
mirror_final_field_inferrer2_test: Crash, Pass # dartbug.com/15581
+simple_inferrer_const_closure_test: Fail # Issue 16507
+simple_inferrer_const_closure2_test: Fail # Issue 16507
+simple_inferrer_global_field_closure_test: Fail # Issue 16507
+
+[ $mode == debug ]
+mirror_final_field_inferrer2_test: Crash, Pass, Slow # dartbug.com/15581
+
+deferred_mirrors_test: Pass, Slow
+in_user_code_test: Pass, Slow
+analyze_unused_dart2js_test: Pass, Slow
+exit_code_test: Pass, Slow
+deferred_load_graph_segmentation_test: Pass, Slow
+check_members_test: Pass, Slow
+
+# Don't mark these tests as failing. Instead, fix the errors/warnings that they
+# report or update the whitelist in the test-files to temporarily allow
+# digression.
+analyze_api_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
+analyze_dart2js_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
+
[ $jscl || $runtime == drt || $runtime == dartium || $runtime == ff || $runtime == firefox || $runtime == chrome || $runtime == safari || $runtime == ie9 || $runtime == opera ]
*: Skip # dart2js uses #import('dart:io'); and it is not self-hosted (yet).
diff --git a/tests/compiler/dart2js/deferred_emit_type_checks_test.dart b/tests/compiler/dart2js/deferred_emit_type_checks_test.dart
new file mode 100644
index 0000000..890397a
--- /dev/null
+++ b/tests/compiler/dart2js/deferred_emit_type_checks_test.dart
@@ -0,0 +1,83 @@
+// 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.
+
+// Test that the additional runtime type support is output to the right
+// Files when using deferred loading.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'memory_source_file_helper.dart';
+import "dart:async";
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+ as dart2js;
+
+class MemoryOutputSink<T> extends EventSink<T> {
+ List<T> mem = new List<T>();
+ void add(T event) {
+ mem.add(event);
+ }
+ void addError(T event, [StackTrace stackTrace]) {}
+ void close() {}
+}
+
+void main() {
+ Uri script = currentDirectory.resolveUri(Platform.script);
+ Uri libraryRoot = script.resolve('../../../sdk/');
+ Uri packageRoot = script.resolve('./packages/');
+
+ var provider = new MemorySourceFileProvider(MEMORY_SOURCE_FILES);
+ var handler = new FormattingDiagnosticHandler(provider);
+
+ Map<String, MemoryOutputSink> outputs = new Map<String, MemoryOutputSink>();
+
+ MemoryOutputSink outputSaver(name, extension) {
+ if (name == '') {
+ name = 'main';
+ extension ='js';
+ }
+ return outputs.putIfAbsent("$name.$extension", () {
+ return new MemoryOutputSink();
+ });
+ }
+
+ Compiler compiler = new Compiler(provider.readStringFromUri,
+ outputSaver,
+ handler.diagnosticHandler,
+ libraryRoot,
+ packageRoot,
+ [],
+ {});
+ asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ String mainOutput = outputs['main.js'].mem[0];
+ String deferredOutput = outputs['deferred.js'].mem[0];
+ RegExp re = new RegExp(r"\n.\.A\.\$isA = true;");
+ print(deferredOutput);
+ Expect.isTrue(re.hasMatch(deferredOutput));
+ Expect.isFalse(re.hasMatch(mainOutput));
+ }));
+}
+
+// We force additional runtime type support to be output for A by instantiating
+// it with a type argument, and testing for the type. The extra support should
+// go to the deferred hunk.
+const Map MEMORY_SOURCE_FILES = const {"main.dart": """
+import "dart:async";
+
+@def import 'lib.dart' show f, A;
+
+const def = const DeferredLibrary("deferred");
+
+void main() {
+ def.load().then((_) {
+ print(f(new A<A>()));
+ });
+}
+""", "lib.dart": """
+class A<T> {}
+
+bool f (Object o) {
+ return o is A<A>;
+}
+""",};
diff --git a/tests/compiler/dart2js/list_tracer_test.dart b/tests/compiler/dart2js/list_tracer_test.dart
index 738c48c..e2e8d82 100644
--- a/tests/compiler/dart2js/list_tracer_test.dart
+++ b/tests/compiler/dart2js/list_tracer_test.dart
@@ -117,7 +117,7 @@
((a) => a[0] = aDouble)(listPassedToClosure);
listReturnedFromClosure[0] = anInt;
- (() => listReturnedFromClosure)[0] = aDouble;
+ (() => listReturnedFromClosure)()[0] = aDouble;
listInField[0] = anInt;
new A(listInField).useField();
@@ -198,7 +198,8 @@
void doTest(String allocation, {bool nullify}) {
Uri uri = new Uri(scheme: 'source');
- var compiler = compilerFor(generateTest(allocation), uri);
+ var compiler = compilerFor(generateTest(allocation), uri,
+ allowErrors: false, allowWarnings: false);
asyncTest(() => compiler.runCompiler(uri).then((_) {
var typesTask = compiler.typesTask;
var typesInferrer = typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/map_tracer_test.dart b/tests/compiler/dart2js/map_tracer_test.dart
new file mode 100644
index 0000000..8dc4fcd
--- /dev/null
+++ b/tests/compiler/dart2js/map_tracer_test.dart
@@ -0,0 +1,283 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import
+ '../../../sdk/lib/_internal/compiler/implementation/types/types.dart'
+ show MapTypeMask, TypeMask;
+
+import 'compiler_helper.dart';
+import 'parser_helper.dart';
+
+
+String generateTest(String mapAllocation) {
+ return """
+int anInt = 42;
+double aDouble = 42.5;
+String aKey = 'aKey';
+String anotherKey = 'anotherKey';
+String presetKey = 'presetKey';
+
+class A {
+ var field;
+ var nonFinalField;
+
+ A(this.field);
+
+ A.bar(map) {
+ nonFinalField = map;
+ }
+
+ receiveIt(map) {
+ map[aKey] = aDouble;
+ }
+
+ returnIt() {
+ return mapReturnedFromSelector;
+ }
+
+ useField() {
+ field[aKey] = aDouble;
+ }
+
+ set callSetter(map) {
+ map[aKey] = aDouble;
+ }
+
+ operator[](key) {
+ key[aKey] = aDouble;
+ }
+
+ operator[]=(index, value) {
+ index[aKey] = anInt;
+ if (value == mapEscapingTwiceInIndexSet) {
+ value[aKey] = aDouble;
+ }
+ }
+}
+
+class B extends A {
+ B(map) : super.bar(map);
+
+ set nonFinalField(value) {
+ value[aKey] = aDouble;
+ }
+}
+
+class C {
+ C();
+
+ operator[]=(index, value) {
+ index[aKey] = anInt;
+ value[aKey] = aDouble;
+ }
+}
+
+var mapInField = $mapAllocation;
+var mapPassedToClosure = $mapAllocation;
+var mapReturnedFromClosure = $mapAllocation;
+var mapPassedToMethod = $mapAllocation;
+var mapReturnedFromMethod = $mapAllocation;
+var mapUsedWithCascade = $mapAllocation;
+var mapUsedInClosure = $mapAllocation;
+var mapPassedToSelector = $mapAllocation;
+var mapReturnedFromSelector = $mapAllocation;
+var mapUsedWithNonOkSelector = $mapAllocation;
+var mapUsedWithConstraint = $mapAllocation;
+var mapEscapingFromSetter = $mapAllocation;
+var mapUsedInLocal = $mapAllocation;
+var mapUnset = $mapAllocation;
+var mapOnlySetWithConstraint = $mapAllocation;
+var mapEscapingInSetterValue = $mapAllocation;
+var mapEscapingInIndex = $mapAllocation;
+var mapEscapingInIndexSet = $mapAllocation;
+var mapEscapingTwiceInIndexSet = $mapAllocation;
+var mapPassedAsOptionalParameter = $mapAllocation;
+var mapPassedAsNamedParameter = $mapAllocation;
+var mapSetInNonFinalField = $mapAllocation;
+var mapStoredInList = $mapAllocation;
+var mapStoredInListButEscapes = $mapAllocation;
+var mapStoredInMap = $mapAllocation;
+var mapStoredInMapButEscapes = $mapAllocation;
+
+foo(map) {
+ map[aKey] = aDouble;
+}
+
+bar() {
+ return mapReturnedFromMethod;
+}
+
+takeOptional([map]) {
+ map[aKey] = aDouble;
+}
+
+takeNamed({map}) {
+ map[aKey] = aDouble;
+}
+
+main() {
+ mapReturnedFromMethod[aKey] = anInt;
+ bar()[aKey] = aDouble;
+
+ mapPassedToMethod[aKey] = anInt;
+ foo(mapPassedToMethod);
+
+ mapPassedToClosure[aKey] = anInt;
+ ((a) => a[aKey] = aDouble)(mapPassedToClosure);
+
+ mapReturnedFromClosure[aKey] = anInt;
+ (() => mapReturnedFromClosure)()[aKey] = aDouble;
+
+ mapInField[aKey] = anInt;
+ new A(mapInField).useField();
+
+ mapUsedWithCascade[aKey] = anInt;
+ mapUsedWithCascade..[aKey] = aDouble;
+
+ mapUsedInClosure[aKey] = anInt;
+ (() => mapUsedInClosure[aKey] = aDouble)();
+
+ mapPassedToSelector[aKey] = anInt;
+ new A(null).receiveIt(mapPassedToSelector);
+
+ mapReturnedFromSelector[aKey] = anInt;
+ new A(null).returnIt()[aKey] = aDouble;
+
+ mapUsedWithNonOkSelector[aKey] = anInt;
+ mapUsedWithNonOkSelector.map((k,v) => v);
+
+ mapUsedWithConstraint[aKey] = anInt;
+ mapUsedWithConstraint[aKey]++;
+ mapUsedWithConstraint[aKey] += anInt;
+
+ mapEscapingFromSetter[aKey] = anInt;
+ foo(new A(null).field = mapEscapingFromSetter);
+
+ mapUsedInLocal[aKey] = anInt;
+ var a = mapUsedInLocal;
+ mapUsedInLocal[anotherKey] = aDouble;
+
+ // At least use [mapUnset] in a local to pretend it's used.
+ var b = mapUnset;
+
+ mapOnlySetWithConstraint[aKey]++;
+
+ mapEscapingInSetterValue[aKey] = anInt;
+ new A(null).callSetter = mapEscapingInSetterValue;
+
+ mapEscapingInIndex[aKey] = anInt;
+ new A(null)[mapEscapingInIndex];
+
+ new A(null)[mapEscapingInIndexSet] = 42;
+
+ new C()[mapEscapingTwiceInIndexSet] = mapEscapingTwiceInIndexSet;
+
+ mapPassedAsOptionalParameter[aKey] = anInt;
+ takeOptional(mapPassedAsOptionalParameter);
+
+ mapPassedAsNamedParameter[aKey] = anInt;
+ takeNamed(map: mapPassedAsNamedParameter);
+
+ mapSetInNonFinalField[aKey] = anInt;
+ new B(mapSetInNonFinalField);
+
+ a = [mapStoredInList];
+ a[0][aKey] = 42;
+
+ a = [mapStoredInListButEscapes];
+ a[0][aKey] = 42;
+ a.forEach((e) => print(e));
+
+ a = {aKey: mapStoredInMap};
+ a[aKey][aKey] = 42;
+
+ a = {aKey: mapStoredInMapButEscapes};
+ a[aKey][aKey] = 42;
+ a.forEach((k,v) => print(v));
+}
+""";
+}
+
+void main() {
+ // Test empty literal map
+ doTest('{}');
+ // Test preset map of <String,uint32>
+ doTest('{presetKey : anInt}', "presetKey", "anInt");
+ // Test preset map of <Double,uint32>
+ doTest('{aDouble : anInt}', "aDouble", "anInt");
+}
+
+void doTest(String allocation, [String keyElement,
+ String valueElement]) {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(generateTest(allocation), uri,
+ allowErrors: false, allowWarnings: false);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var keyType, valueType;
+ var typesTask = compiler.typesTask;
+ var typesInferrer = typesTask.typesInferrer;
+ var emptyType = new TypeMask.nonNullEmpty();
+ var aKeyType
+ = typesInferrer.getTypeOfElement(findElement(compiler, 'aKey'));
+ if (keyElement != null) {
+ keyType
+ = typesInferrer.getTypeOfElement(findElement(compiler, keyElement));
+ }
+ if (valueElement != null) {
+ valueType
+ = typesInferrer.getTypeOfElement(findElement(compiler, valueElement));
+ }
+ if (keyType == null) keyType = emptyType;
+ if (valueType == null) valueType = emptyType;
+
+ checkType(String name, keyType, valueType) {
+ var element = findElement(compiler, name);
+ MapTypeMask mask = typesInferrer.getTypeOfElement(element);
+ Expect.equals(keyType, mask.keyType.simplify(compiler), name);
+ Expect.equals(valueType, mask.valueType.simplify(compiler), name);
+ }
+
+ K(TypeMask other) => keyType.union(other, compiler).simplify(compiler);
+ V(TypeMask other) => valueType.union(other, compiler).simplify(compiler);
+
+ checkType('mapInField', K(aKeyType), V(typesTask.numType));
+ checkType('mapPassedToMethod', K(aKeyType), V(typesTask.numType));
+ checkType('mapReturnedFromMethod', K(aKeyType), V(typesTask.numType));
+ checkType('mapUsedWithCascade', K(aKeyType), V(typesTask.numType));
+ checkType('mapUsedInClosure', K(aKeyType), V(typesTask.numType));
+ checkType('mapPassedToSelector', K(aKeyType), V(typesTask.numType));
+ checkType('mapReturnedFromSelector', K(aKeyType), V(typesTask.numType));
+ checkType('mapUsedWithConstraint', K(aKeyType), V(typesTask.uint31Type));
+ checkType('mapEscapingFromSetter', K(aKeyType), V(typesTask.numType));
+ checkType('mapUsedInLocal', K(aKeyType), V(typesTask.numType));
+ checkType('mapEscapingInSetterValue', K(aKeyType), V(typesTask.numType));
+ checkType('mapEscapingInIndex', K(aKeyType), V(typesTask.numType));
+ checkType('mapEscapingInIndexSet', K(aKeyType), V(typesTask.uint31Type));
+ checkType('mapEscapingTwiceInIndexSet', K(aKeyType), V(typesTask.numType));
+ checkType('mapSetInNonFinalField', K(aKeyType), V(typesTask.numType));
+
+ checkType('mapPassedToClosure', K(typesTask.dynamicType),
+ V(typesTask.dynamicType));
+ checkType('mapReturnedFromClosure', K(typesTask.dynamicType),
+ V(typesTask.dynamicType));
+ checkType('mapUsedWithNonOkSelector', K(typesTask.dynamicType),
+ V(typesTask.dynamicType));
+ checkType('mapPassedAsOptionalParameter', K(aKeyType),
+ V(typesTask.numType));
+ checkType('mapPassedAsNamedParameter', K(aKeyType),
+ V(typesTask.numType));
+ checkType('mapStoredInList', K(aKeyType),
+ V(typesTask.uint31Type));
+ checkType('mapStoredInListButEscapes', K(typesTask.dynamicType),
+ V(typesTask.dynamicType));
+ checkType('mapStoredInMap', K(aKeyType), V(typesTask.uint31Type));
+ checkType('mapStoredInMapButEscapes', K(typesTask.dynamicType),
+ V(typesTask.dynamicType));
+
+ checkType('mapUnset', K(emptyType), V(emptyType));
+ checkType('mapOnlySetWithConstraint', K(aKeyType), V(emptyType));
+ }));
+}
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index f39e046..269cc1c 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -15,8 +15,8 @@
import 'dart:async';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
class DiagnosticMessage {
final Uri uri;
@@ -83,11 +83,10 @@
Compiler cachedCompiler,
bool showDiagnostics: true,
Uri packageRoot}) {
- Uri script = currentDirectory.resolveUri(Platform.script);
- Uri libraryRoot = script.resolve('../../../sdk/');
+ Uri libraryRoot = Uri.base.resolve('sdk/');
+ Uri script = Uri.base.resolveUri(Platform.script);
if (packageRoot == null) {
- packageRoot = currentDirectory.resolve(
- appendSlash(nativeToUriPath(Platform.packageRoot)));
+ packageRoot = Uri.base.resolve('${Platform.packageRoot}/');
}
MemorySourceFileProvider provider;
@@ -158,9 +157,9 @@
{DiagnosticHandler diagnosticHandler,
List<String> options: const [],
bool showDiagnostics: true}) {
- Uri script = currentDirectory.resolveUri(Platform.script);
- Uri libraryRoot = script.resolve('../../../sdk/');
- Uri packageRoot = script.resolve('./packages/');
+ Uri libraryRoot = Uri.base.resolve('sdk/');
+ Uri packageRoot = Uri.base.resolve('${Platform.packageRoot}/');
+ Uri script = Uri.base.resolveUri(Platform.script);
var provider = new MemorySourceFileProvider(memorySourceFiles);
var handler =
diff --git a/tests/compiler/dart2js/mirror_system_helper.dart b/tests/compiler/dart2js/mirror_system_helper.dart
index 2776de6..3faf23d 100644
--- a/tests/compiler/dart2js/mirror_system_helper.dart
+++ b/tests/compiler/dart2js/mirror_system_helper.dart
@@ -5,11 +5,11 @@
library mirror_system_helper;
import 'dart:async';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart';
import 'mock_compiler.dart';
-export '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+export '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
export '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
const String SOURCE = 'source';
diff --git a/tests/compiler/dart2js/mirrors/class_mirror_type_variables_test.dart b/tests/compiler/dart2js/mirrors/class_mirror_type_variables_test.dart
new file mode 100644
index 0000000..a3f6871
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/class_mirror_type_variables_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, 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:mirrors";
+
+import "package:async_helper/async_helper.dart";
+
+import "mirrors_test_helper.dart";
+import "../../../lib/mirrors/class_mirror_type_variables_expect.dart";
+
+class CompileTimeEnv implements Env {
+ final MirrorSystem mirrors;
+
+ CompileTimeEnv(this.mirrors);
+
+ LibraryMirror get core => mirrors.libraries[Uri.parse('dart:core')];
+
+ LibraryMirror get test =>
+ mirrors.findLibrary(#class_mirror_type_variables_data);
+
+
+ ClassMirror getA() => test.declarations[#A];
+ ClassMirror getB() => test.declarations[#B];
+ ClassMirror getC() => test.declarations[#C];
+ ClassMirror getD() => test.declarations[#D];
+ ClassMirror getE() => test.declarations[#E];
+ ClassMirror getF() => test.declarations[#F];
+ ClassMirror getNoTypeParams() => test.declarations[#NoTypeParams];
+ ClassMirror getObject() => core.declarations[#Object];
+ ClassMirror getString() => core.declarations[#String];
+ ClassMirror getHelperOfString() =>
+ createInstantiation(test.declarations[#Helper], [getString()]);
+}
+
+main() {
+ asyncTest(() => analyze("class_mirror_type_variables_data.dart").
+ then((MirrorSystem mirrors) {
+ test(new CompileTimeEnv(mirrors));
+ }));
+
+}
diff --git a/tests/compiler/dart2js/mirrors/default_value_test.dart b/tests/compiler/dart2js/mirrors/default_value_test.dart
new file mode 100644
index 0000000..53b8721
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/default_value_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2013, 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:mirrors";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import "../memory_compiler.dart";
+
+const SOURCE = const {
+ 'main.dart': """
+library main;
+
+class Class {
+ var a, b, c, d, e, f, g, h;
+ Class.optional(this.a, int b, void this.c(),
+ [this.d, int this.e, void this.f(),
+ this.g = 0, int this.h = 0]);
+ Class.named(this.a, int b, void this.c(),
+ {this.d, int this.e, void this.f(),
+ this.g: 0, int this.h: 0});
+ methodOptional(a, int b, void c(),
+ [d, int e, void f(),
+ g = 0, int h = 0]) {}
+ methodNamed(a, int b, void c(),
+ {d, int e, void f(),
+ g: 0, int h: 0}) {}
+}
+""",
+};
+
+main() {
+ asyncTest(() => mirrorSystemFor(SOURCE).then((MirrorSystem mirrors) {
+ LibraryMirror dartCore = mirrors.libraries[Uri.parse('memory:main.dart')];
+ ClassMirror classMirror = dartCore.declarations[#Class];
+ testMethod(classMirror.declarations[#optional]);
+ testMethod(classMirror.declarations[#named]);
+ testMethod(classMirror.declarations[#methodOptional]);
+ testMethod(classMirror.declarations[#methodNamed]);
+ }));
+}
+
+testMethod(MethodMirror mirror) {
+ Expect.equals(8, mirror.parameters.length);
+ for (int i = 0 ; i < 6 ; i++) {
+ testParameter(mirror.parameters[i], false);
+ }
+ for (int i = 6 ; i < 8 ; i++) {
+ testParameter(mirror.parameters[i], true);
+ }
+}
+
+testParameter(ParameterMirror mirror, bool expectDefaultValue) {
+ if (expectDefaultValue) {
+ Expect.isTrue(mirror.hasDefaultValue);
+ Expect.isNotNull(mirror.defaultValue);
+ } else {
+ Expect.isFalse(mirror.hasDefaultValue);
+ Expect.isNull(mirror.defaultValue);
+ }
+}
diff --git a/tests/compiler/dart2js/mirrors/mirrors_reader_test.dart b/tests/compiler/dart2js/mirrors/mirrors_reader_test.dart
new file mode 100644
index 0000000..53c9ceb
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/mirrors_reader_test.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2013, 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.
+
+// Test that everything reachable from a [MirrorSystem] can be accessed.
+
+library test.mirrors.reader;
+
+import "dart:mirrors" hide SourceLocation;
+
+import "package:async_helper/async_helper.dart";
+
+import "mirrors_test_helper.dart";
+import "../../../lib/mirrors/mirrors_reader.dart";
+import "../../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
+import "../../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart";
+import "../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart";
+
+class SourceMirrorsReader extends MirrorsReader {
+ final Dart2JsMirrorSystem mirrorSystem;
+
+ SourceMirrorsReader(this.mirrorSystem,
+ {bool verbose: false, bool includeStackTrace: false})
+ : super(verbose: verbose, includeStackTrace: includeStackTrace);
+
+ evaluate(f()) {
+ try {
+ return f();
+ } on SpannableAssertionFailure catch (e) {
+ mirrorSystem.compiler.reportAssertionFailure(e);
+ rethrow;
+ }
+ }
+
+ visitMirror(Mirror mirror) {
+ if (mirror is CombinatorMirror) {
+ visitCombinatorMirror(mirror);
+ } else if (mirror is LibraryDependencyMirror) {
+ visitLibraryDependencyMirror(mirror);
+ } else if (mirror is CommentInstanceMirror) {
+ visitCommentInstanceMirror(mirror);
+ } else if (mirror is ListInstanceMirror) {
+ visitListInstanceMirror(mirror);
+ } else if (mirror is MapInstanceMirror) {
+ visitMapInstanceMirror(mirror);
+ } else if (mirror is TypeInstanceMirror) {
+ visitTypeInstanceMirror(mirror);
+ } else {
+ super.visitMirror(mirror);
+ }
+ }
+
+ visitDeclarationMirror(DeclarationSourceMirror mirror) {
+ super.visitDeclarationMirror(mirror);
+ visit(mirror, 'isNameSynthetic', () => mirror.isNameSynthetic);
+ }
+
+ visitClassMirror(ClassSourceMirror mirror) {
+ super.visitClassMirror(mirror);
+ visit(mirror, 'isAbstract', () => mirror.isAbstract);
+ }
+
+ visitLibraryMirror(LibrarySourceMirror mirror) {
+ super.visitLibraryMirror(mirror);
+ visit(mirror, 'libraryDependencies', () => mirror.libraryDependencies);
+ }
+
+ visitParameterMirror(ParameterMirror mirror) {
+ super.visitParameterMirror(mirror);
+ if (mirror is ParameterSourceMirror) {
+ visit(mirror, 'isInitializingFormal', () => mirror.isInitializingFormal);
+ visit(mirror, 'initializedField', () => mirror.initializedField);
+ }
+ }
+
+ visitTypeMirror(TypeSourceMirror mirror) {
+ super.visitTypeMirror(mirror);
+ visit(mirror, 'isVoid', () => mirror.isVoid);
+ visit(mirror, 'isDynamic', () => mirror.isDynamic);
+ }
+
+ visitSourceLocation(SourceLocation location) {
+ super.visitSourceLocation(location);
+ visit(location, 'line', () => location.line);
+ visit(location, 'column', () => location.column);
+ visit(location, 'offset', () => location.offset);
+ visit(location, 'length', () => location.length);
+ visit(location, 'text', () => location.text);
+ visit(location, 'sourceUri', () => location.sourceUri);
+ visit(location, 'sourceText', () => location.sourceText);
+ }
+
+ visitCombinatorMirror(CombinatorMirror mirror) {
+ visit(mirror, 'identifiers', () => mirror.identifiers);
+ visit(mirror, 'isShow', () => mirror.isShow);
+ visit(mirror, 'isHide', () => mirror.isHide);
+ }
+
+ visitLibraryDependencyMirror(LibraryDependencyMirror mirror) {
+ visit(mirror, 'isImport', () => mirror.isImport);
+ visit(mirror, 'isExport', () => mirror.isExport);
+ visit(mirror, 'sourceLibrary', () => mirror.sourceLibrary);
+ visit(mirror, 'targetLibrary', () => mirror.targetLibrary);
+ visit(mirror, 'prefix', () => mirror.prefix);
+ visit(mirror, 'combinators', () => mirror.combinators);
+ visit(mirror, 'location', () => mirror.location);
+ }
+
+ visitCommentInstanceMirror(CommentInstanceMirror mirror) {
+ visitInstanceMirror(mirror);
+ visit(mirror, 'text', () => mirror.text);
+ visit(mirror, 'trimmedText', () => mirror.trimmedText);
+ visit(mirror, 'isDocComment', () => mirror.isDocComment);
+ }
+
+ visitListInstanceMirror(ListInstanceMirror mirror) {
+ visitInstanceMirror(mirror);
+ visit(mirror, 'length', () => mirror.length);
+ }
+
+ visitMapInstanceMirror(MapInstanceMirror mirror) {
+ visitInstanceMirror(mirror);
+ visit(mirror, 'keys', () => mirror.keys);
+ visit(mirror, 'length', () => mirror.length);
+ }
+
+ visitTypeInstanceMirror(TypeInstanceMirror mirror) {
+ visitInstanceMirror(mirror);
+ visit(mirror, 'representedType', () => mirror.representedType);
+ }
+}
+
+main(List<String> arguments) {
+ asyncTest(() => analyzeUri(Uri.parse('dart:core')).
+ then((MirrorSystem mirrors) {
+ MirrorsReader reader = new SourceMirrorsReader(mirrors,
+ verbose: arguments.contains('-v'),
+ includeStackTrace: arguments.contains('-s'));
+ reader.checkMirrorSystem(mirrors);
+ }));
+}
diff --git a/tests/compiler/dart2js/mirrors/mirrors_test_helper.dart b/tests/compiler/dart2js/mirrors/mirrors_test_helper.dart
new file mode 100644
index 0000000..b6a954a
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/mirrors_test_helper.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+import 'dart:async';
+
+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart' as source_mirrors;
+import '../../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
+
+TypeMirror createInstantiation(TypeSourceMirror type,
+ List<TypeMirror> typeArguments) {
+ return type.createInstantiation(typeArguments);
+}
+
+Future<MirrorSystem> analyze(String test) {
+ Uri repository = Platform.script.resolve('../../../../');
+ Uri testUri = repository.resolve('tests/lib/mirrors/$test');
+ return analyzeUri(testUri);
+}
+
+
+Future<MirrorSystem> analyzeUri(Uri testUri) {
+ Uri repository = Platform.script.resolve('../../../../');
+ Uri libraryRoot = repository.resolve('sdk/');
+ Uri packageRoot = Uri.base.resolve('${Platform.packageRoot}/');
+ var provider = new CompilerSourceFileProvider();
+ var handler = new FormattingDiagnosticHandler(provider);
+ return source_mirrors.analyze(
+ [testUri],
+ libraryRoot,
+ packageRoot,
+ provider,
+ handler);
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/mirrors_exports_test.dart b/tests/compiler/dart2js/mirrors_exports_test.dart
index 412014c..51da7c1 100644
--- a/tests/compiler/dart2js/mirrors_exports_test.dart
+++ b/tests/compiler/dart2js/mirrors_exports_test.dart
@@ -6,7 +6,7 @@
import 'package:async_helper/async_helper.dart';
import 'dart:async';
import 'memory_compiler.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
const SOURCE_FILES = const {
'main.dart': '''
@@ -32,19 +32,19 @@
void main() {
asyncTest(() => mirrorSystemFor(SOURCE_FILES).then((MirrorSystem mirrors) {
- LibraryMirror mainLibrary =
+ LibrarySourceMirror mainLibrary =
mirrors.libraries[Uri.parse('memory:main.dart')];
Expect.isNotNull(mainLibrary);
- LibraryMirror aLibrary =
+ LibrarySourceMirror aLibrary =
mirrors.libraries[Uri.parse('memory:a.dart')];
Expect.isNotNull(aLibrary);
- LibraryMirror bLibrary =
+ LibrarySourceMirror bLibrary =
mirrors.libraries[Uri.parse('memory:b.dart')];
Expect.isNotNull(bLibrary);
- LibraryMirror coreLibrary =
+ LibrarySourceMirror coreLibrary =
mirrors.libraries[Uri.parse('dart:core')];
Expect.isNotNull(coreLibrary);
diff --git a/tests/compiler/dart2js/mirrors_helper.dart b/tests/compiler/dart2js/mirrors_helper.dart
index 1fb7ab3..8bba108 100644
--- a/tests/compiler/dart2js/mirrors_helper.dart
+++ b/tests/compiler/dart2js/mirrors_helper.dart
@@ -29,7 +29,7 @@
@metadata
/** Multiline doc comment. */
/* Multiline comment. */ class Foo {
-
+ m(@metadata a) {}
}
diff --git a/tests/compiler/dart2js/mirrors_lookup_test.dart b/tests/compiler/dart2js/mirrors_lookup_test.dart
index d5ebab5..4ef9b70 100644
--- a/tests/compiler/dart2js/mirrors_lookup_test.dart
+++ b/tests/compiler/dart2js/mirrors_lookup_test.dart
@@ -7,7 +7,7 @@
import 'package:expect/expect.dart';
import "package:async_helper/async_helper.dart";
import 'memory_compiler.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
const Map MEMORY_SOURCE_FILES = const {
@@ -40,67 +40,67 @@
}
void test(MirrorSystem mirrors) {
- LibraryMirror dartCore = mirrors.libraries[Uri.parse('dart:core')];
+ LibrarySourceMirror dartCore = mirrors.libraries[Uri.parse('dart:core')];
Expect.isNotNull(dartCore);
- LibraryMirror dartAsync = mirrors.libraries[Uri.parse('dart:async')];
+ LibrarySourceMirror dartAsync = mirrors.libraries[Uri.parse('dart:async')];
Expect.isNotNull(dartAsync);
- LibraryMirror library = mirrors.libraries[Uri.parse('memory:main.dart')];
+ LibrarySourceMirror library = mirrors.libraries[Uri.parse('memory:main.dart')];
Expect.isNotNull(library);
// Check top-level scope.
- DeclarationMirror String_ = library.lookupInScope('String');
+ DeclarationSourceMirror String_ = library.lookupInScope('String');
Expect.isTrue(String_ is ClassMirror);
- Expect.equals('String', String_.simpleName);
+ Expect.equals(#String, String_.simpleName);
Expect.equals(dartCore, String_.owner);
Expect.isNull(library.lookupInScope('async'));
Expect.isNull(library.lookupInScope('Future'));
- DeclarationMirror Future_ = library.lookupInScope('async.Future');
+ DeclarationSourceMirror Future_ = library.lookupInScope('async.Future');
Expect.isTrue(Future_ is ClassMirror);
- Expect.equals('Future', Future_.simpleName);
+ Expect.equals(#Future, Future_.simpleName);
Expect.equals(dartAsync, Future_.owner);
// Timer is not in scope.
Expect.isNull(library.lookupInScope('Timer'));
// async.Timer is hidden.
Expect.isNull(library.lookupInScope('async.Timer'));
- DeclarationMirror variable = library.lookupInScope('variable');
+ DeclarationSourceMirror variable = library.lookupInScope('variable');
Expect.isTrue(variable is VariableMirror);
- Expect.equals('variable', variable.simpleName);
- Expect.equals('main.variable', variable.qualifiedName);
+ Expect.equals(#variable, variable.simpleName);
+ Expect.equals(#main.variable, variable.qualifiedName);
Expect.equals(library, variable.owner);
// Parameter `a` is not in scope.
Expect.isNull(library.lookupInScope('a'));
// Parameter `b` is not in scope.
Expect.isNull(library.lookupInScope('b'));
- DeclarationMirror method = library.lookupInScope('method');
+ DeclarationSourceMirror method = library.lookupInScope('method');
Expect.isTrue(method is MethodMirror);
- Expect.equals('method', method.simpleName);
- Expect.equals('main.method', method.qualifiedName);
+ Expect.equals(#method, method.simpleName);
+ Expect.equals(#main.method, method.qualifiedName);
Expect.equals(library, method.owner);
- DeclarationMirror Class = library.lookupInScope('Class');
+ DeclarationSourceMirror Class = library.lookupInScope('Class');
Expect.isTrue(Class is ClassMirror);
- Expect.equals('Class', Class.simpleName);
- Expect.equals('main.Class', Class.qualifiedName);
+ Expect.equals(#Class, Class.simpleName);
+ Expect.equals(#main.Class, Class.qualifiedName);
Expect.equals(library, Class.owner);
// Type variable `A` is not in scope.
Expect.isNull(library.lookupInScope('A'));
- DeclarationMirror Subclass = library.lookupInScope('Subclass');
+ DeclarationSourceMirror Subclass = library.lookupInScope('Subclass');
Expect.isTrue(Subclass is ClassMirror);
- Expect.equals('Subclass', Subclass.simpleName);
- Expect.equals('main.Subclass', Subclass.qualifiedName);
+ Expect.equals(#Subclass, Subclass.simpleName);
+ Expect.equals(#main.Subclass, Subclass.qualifiedName);
Expect.equals(library, Subclass.owner);
// Type variable `B` is not in scope.
Expect.isNull(library.lookupInScope('B'));
// Check top-level declaration scope.
- checkTopScope(DeclarationMirror declaration) {
+ checkTopScope(DeclarationSourceMirror declaration) {
Expect.equals(String_, declaration.lookupInScope('String'));
Expect.equals(Future_, declaration.lookupInScope('async.Future'));
Expect.isNull(method.lookupInScope('Timer'));
@@ -127,27 +127,28 @@
checkTopScope(method);
// Parameter `a` is in scope of `method`.
+ print(method.lookupInScope('a'));
Expect.isTrue(method.lookupInScope('a') is ParameterMirror);
// Parameter `b` is in scope of `method`.
Expect.isTrue(method.lookupInScope('b') is ParameterMirror);
// Check class scope.
- DeclarationMirror Class_field = Class.lookupInScope('field');
+ DeclarationSourceMirror Class_field = Class.lookupInScope('field');
Expect.isTrue(Class_field is VariableMirror);
Expect.notEquals(variable, Class_field);
Expect.equals(Class, Class_field.owner);
- DeclarationMirror Class_variable = Class.lookupInScope('variable');
+ DeclarationSourceMirror Class_variable = Class.lookupInScope('variable');
Expect.isTrue(Class_variable is VariableMirror);
Expect.notEquals(variable, Class_variable);
Expect.equals(Class, Class_variable.owner);
- DeclarationMirror Class_method = Class.lookupInScope('method');
+ DeclarationSourceMirror Class_method = Class.lookupInScope('method');
Expect.isTrue(Class_method is MethodMirror);
Expect.notEquals(method, Class_method);
Expect.equals(Class, Class_method.owner);
- checkClassScope(DeclarationMirror declaration, {bool parametersInScope}) {
+ checkClassScope(DeclarationSourceMirror declaration, {bool parametersInScope}) {
Expect.equals(String_, declaration.lookupInScope('String'));
Expect.equals(Future_, declaration.lookupInScope('async.Future'));
Expect.isNull(declaration.lookupInScope('Timer'));
@@ -189,12 +190,12 @@
checkClassScope(Class_method, parametersInScope: true);
// Check class scope.
- DeclarationMirror Subclass_subfield = Subclass.lookupInScope('subfield');
+ DeclarationSourceMirror Subclass_subfield = Subclass.lookupInScope('subfield');
Expect.isTrue(Subclass_subfield is VariableMirror);
Expect.notEquals(variable, Subclass_subfield);
Expect.equals(Subclass, Subclass_subfield.owner);
- checkSubclassScope(DeclarationMirror declaration) {
+ checkSubclassScope(DeclarationSourceMirror declaration) {
Expect.equals(String_, declaration.lookupInScope('String'));
Expect.equals(Future_, declaration.lookupInScope('async.Future'));
Expect.isNull(declaration.lookupInScope('Timer'));
diff --git a/tests/compiler/dart2js/mirrors_metadata_test.dart b/tests/compiler/dart2js/mirrors_metadata_test.dart
index 66c2e41..c430997 100644
--- a/tests/compiler/dart2js/mirrors_metadata_test.dart
+++ b/tests/compiler/dart2js/mirrors_metadata_test.dart
@@ -11,12 +11,12 @@
String text,
String trimmedText,
bool isDocComment,
- List<String> declarationNames) {
+ List<Symbol> declarationNames) {
asyncTest(() => createMirrorSystem(code).then((mirrors) {
LibraryMirror library = mirrors.libraries[SOURCE_URI];
Expect.isNotNull(library);
- for (String declarationName in declarationNames) {
- DeclarationMirror declaration = library.members[declarationName];
+ for (Symbol declarationName in declarationNames) {
+ DeclarationMirror declaration = library.declarations[declarationName];
Expect.isNotNull(declaration);
List<InstanceMirror> metadata = declaration.metadata;
Expect.isNotNull(metadata);
@@ -30,7 +30,7 @@
}));
}
-void testDeclarationComment(String declaration, List<String> declarationNames) {
+void testDeclarationComment(String declaration, List<Symbol> declarationNames) {
String text = 'Single line comment';
String comment = '// $text';
String code = '$comment\n$declaration';
@@ -51,18 +51,18 @@
}
void main() {
- testDeclarationComment('var field;', ['field']);
- testDeclarationComment('int field;', ['field']);
- testDeclarationComment('int field = 0;', ['field']);
- testDeclarationComment('int field1, field2;', ['field1', 'field2']);
- testDeclarationComment('final field = 0;', ['field']);
- testDeclarationComment('final int field = 0;', ['field']);
- testDeclarationComment('final field1 = 0, field2 = 0;', ['field1', 'field2']);
+ testDeclarationComment('var field;', [#field]);
+ testDeclarationComment('int field;', [#field]);
+ testDeclarationComment('int field = 0;', [#field]);
+ testDeclarationComment('int field1, field2;', [#field1, #field2]);
+ testDeclarationComment('final field = 0;', [#field]);
+ testDeclarationComment('final int field = 0;', [#field]);
+ testDeclarationComment('final field1 = 0, field2 = 0;', [#field1, #field2]);
testDeclarationComment('final int field1 = 0, field2 = 0;',
- ['field1', 'field2']);
- testDeclarationComment('const field = 0;', ['field']);
- testDeclarationComment('const int field = 0;', ['field']);
- testDeclarationComment('const field1 = 0, field2 = 0;', ['field1', 'field2']);
+ [#field1, #field2]);
+ testDeclarationComment('const field = 0;', [#field]);
+ testDeclarationComment('const int field = 0;', [#field]);
+ testDeclarationComment('const field1 = 0, field2 = 0;', [#field1, #field2]);
testDeclarationComment('const int field1 = 0, field2 = 0;',
- ['field1', 'field2']);
+ [#field1, #field2]);
}
diff --git a/tests/compiler/dart2js/mirrors_mixin_test.dart b/tests/compiler/dart2js/mirrors_mixin_test.dart
index 1486851..0a94a06 100644
--- a/tests/compiler/dart2js/mirrors_mixin_test.dart
+++ b/tests/compiler/dart2js/mirrors_mixin_test.dart
@@ -35,37 +35,37 @@
Expect.isTrue(cls is ClassMirror);
Expect.isFalse(isMixinApplication(cls));
Expect.isFalse(cls.isNameSynthetic);
- Expect.isFalse(cls.isObject);
- Expect.isTrue(cls.superclass.isObject);
+ Expect.isFalse(isObject(cls));
+ Expect.isTrue(isObject(cls.superclass));
Expect.equals(0, cls.superinterfaces.length);
- Expect.isTrue(getSuperclass(cls).isObject);
+ Expect.isTrue(isObject(getSuperclass(cls)));
Expect.isTrue(getAppliedMixins(cls).isEmpty);
Expect.isTrue(getExplicitInterfaces(cls).isEmpty);
}
// class A {}
- var A = library.classes['A'];
+ var A = library.declarations[#A];
checkSimpleClass(A);
// class S {}
- var S = library.classes['S'];
+ var S = library.declarations[#S];
checkSimpleClass(S);
// class M1 {}
- var M1 = library.classes['M1'];
+ var M1 = library.declarations[#M1];
checkSimpleClass(M1);
// class M2 {}
- var M2 = library.classes['M2'];
+ var M2 = library.declarations[#M2];
checkSimpleClass(M2);
// class C extends S with M1<A> {}
- var C = library.classes['C'];
+ var C = library.declarations[#C];
Expect.isNotNull(C);
Expect.isTrue(C is ClassMirror);
Expect.isFalse(isMixinApplication(C));
- Expect.isFalse(C.isObject);
+ Expect.isFalse(isObject(C));
Expect.equals(0, C.superinterfaces.length);
var C_super = C.superclass;
Expect.isNotNull(C_super);
@@ -75,7 +75,7 @@
Expect.equals(1, C_super.superinterfaces.length);
Expect.isTrue(containsType(M1, [A], C_super.superinterfaces));
Expect.isTrue(isInstance(M1, [A], C_super.mixin));
- Expect.isFalse(C_super.isObject);
+ Expect.isFalse(isObject(C_super));
Expect.isTrue(isSameDeclaration(S, C_super.superclass));
Expect.isTrue(isSameDeclaration(S, getSuperclass(C)));
@@ -83,11 +83,11 @@
Expect.isTrue(getExplicitInterfaces(C).isEmpty);
// D extends S with M1, M2 {}
- var D = library.classes['D'];
+ var D = library.declarations[#D];
Expect.isNotNull(D);
Expect.isTrue(D is ClassMirror);
Expect.isFalse(isMixinApplication(D));
- Expect.isFalse(D.isObject);
+ Expect.isFalse(isObject(D));
Expect.equals(0, D.superinterfaces.length);
var D_super = D.superclass;
Expect.isNotNull(D_super);
@@ -97,7 +97,7 @@
Expect.equals(1, D_super.superinterfaces.length);
Expect.isTrue(containsDeclaration(M2, D_super.superinterfaces));
Expect.isTrue(isSameDeclaration(M2, D_super.mixin));
- Expect.isFalse(D_super.isObject);
+ Expect.isFalse(isObject(D_super));
Expect.isFalse(isSameDeclaration(S, D_super.superclass));
var D_super_super = D_super.superclass;
Expect.isNotNull(D_super_super);
@@ -107,7 +107,7 @@
Expect.equals(1, D_super_super.superinterfaces.length);
Expect.isTrue(containsDeclaration(M1, D_super_super.superinterfaces));
Expect.isTrue(isSameDeclaration(M1, D_super_super.mixin));
- Expect.isFalse(D_super_super.isObject);
+ Expect.isFalse(isObject(D_super_super));
Expect.isTrue(isSameDeclaration(S, D_super_super.superclass));
Expect.isTrue(isSameDeclaration(S, getSuperclass(D)));
@@ -115,11 +115,11 @@
Expect.isTrue(getExplicitInterfaces(D).isEmpty);
// class E extends S with M2, M1 implements A, M1 {}
- var E = library.classes['E'];
+ var E = library.declarations[#E];
Expect.isNotNull(E);
Expect.isTrue(E is ClassMirror);
Expect.isFalse(isMixinApplication(E));
- Expect.isFalse(E.isObject);
+ Expect.isFalse(isObject(E));
Expect.equals(2, E.superinterfaces.length);
Expect.isTrue(containsDeclaration(A, E.superinterfaces));
Expect.isTrue(containsDeclaration(M1, E.superinterfaces));
@@ -131,7 +131,7 @@
Expect.equals(1, E_super.superinterfaces.length);
Expect.isTrue(containsDeclaration(M1, E_super.superinterfaces));
Expect.isTrue(isSameDeclaration(M1, E_super.mixin));
- Expect.isFalse(E_super.isObject);
+ Expect.isFalse(isObject(E_super));
Expect.isFalse(isSameDeclaration(S, E_super.superclass));
var E_super_super = E_super.superclass;
Expect.isNotNull(E_super_super);
@@ -141,7 +141,7 @@
Expect.equals(1, E_super_super.superinterfaces.length);
Expect.isTrue(containsDeclaration(M2, E_super_super.superinterfaces));
Expect.isTrue(isSameDeclaration(M2, E_super_super.mixin));
- Expect.isFalse(E_super_super.isObject);
+ Expect.isFalse(isObject(E_super_super));
Expect.isTrue(isSameDeclaration(S, E_super_super.superclass));
Expect.isTrue(isSameDeclaration(S, getSuperclass(E)));
@@ -149,20 +149,20 @@
Expect.isTrue(isSameDeclarationSet([A, M1], getExplicitInterfaces(E)));
// class E2 extends E {}
- var E2 = library.classes['E2'];
+ var E2 = library.declarations[#E2];
Expect.isTrue(isSameDeclaration(E, getSuperclass(E2)));
Expect.isTrue(getAppliedMixins(E2).isEmpty);
Expect.isTrue(getExplicitInterfaces(E2).isEmpty);
// class F = S with M1<A>;
- var F = library.classes['F'];
+ var F = library.declarations[#F];
Expect.isNotNull(F);
Expect.isTrue(F is ClassMirror);
Expect.isFalse(F.isAbstract);
Expect.isTrue(isMixinApplication(F));
Expect.isFalse(F.isNameSynthetic);
- Expect.equals('F', F.simpleName);
- Expect.isFalse(F.isObject);
+ Expect.equals(#F, F.simpleName);
+ Expect.isFalse(isObject(F));
Expect.equals(1, F.superinterfaces.length);
Expect.isTrue(containsDeclaration(M1, F.superinterfaces));
Expect.isTrue(isInstance(M1, [A], F.mixin));
@@ -170,7 +170,7 @@
Expect.isNotNull(F_super);
Expect.isTrue(F_super is ClassMirror);
Expect.isFalse(isMixinApplication(F_super));
- Expect.isFalse(F_super.isObject);
+ Expect.isFalse(isObject(F_super));
Expect.isTrue(isSameDeclaration(S, F_super));
Expect.isTrue(isSameDeclaration(S, getSuperclass(F)));
@@ -178,14 +178,14 @@
Expect.isTrue(getExplicitInterfaces(F).isEmpty);
// typedef G = abstract S with M1, M2;
- var G = library.classes['G'];
+ var G = library.declarations[#G];
Expect.isNotNull(G);
Expect.isTrue(G is ClassMirror);
Expect.isTrue(G.isAbstract);
Expect.isTrue(isMixinApplication(G));
Expect.isFalse(G.isNameSynthetic);
- Expect.equals('G', G.simpleName);
- Expect.isFalse(G.isObject);
+ Expect.equals(#G, G.simpleName);
+ Expect.isFalse(isObject(G));
Expect.equals(1, G.superinterfaces.length);
Expect.isTrue(containsDeclaration(M2, G.superinterfaces));
Expect.isTrue(isSameDeclaration(M2, G.mixin));
@@ -196,7 +196,7 @@
Expect.equals(1, G_super.superinterfaces.length);
Expect.isTrue(containsDeclaration(M1, G_super.superinterfaces));
Expect.isTrue(isSameDeclaration(M1, G_super.mixin));
- Expect.isFalse(G_super.isObject);
+ Expect.isFalse(isObject(G_super));
Expect.isTrue(isSameDeclaration(S, G_super.superclass));
Expect.isTrue(isSameDeclaration(S, getSuperclass(G)));
@@ -204,14 +204,14 @@
Expect.isTrue(getExplicitInterfaces(G).isEmpty);
// typedef H = S with M2, M1 implements A, M1;
- var H = library.classes['H'];
+ var H = library.declarations[#H];
Expect.isNotNull(H);
Expect.isTrue(H is ClassMirror);
Expect.isFalse(H.isAbstract);
Expect.isTrue(isMixinApplication(H));
Expect.isFalse(H.isNameSynthetic);
- Expect.equals('H', H.simpleName);
- Expect.isFalse(H.isObject);
+ Expect.equals(#H, H.simpleName);
+ Expect.isFalse(isObject(H));
Expect.equals(3, H.superinterfaces.length);
Expect.isTrue(containsDeclaration(A, H.superinterfaces));
Expect.isTrue(containsDeclaration(M1, H.superinterfaces));
@@ -224,7 +224,7 @@
Expect.equals(1, H_super.superinterfaces.length);
Expect.isTrue(containsDeclaration(M2, H_super.superinterfaces));
Expect.isTrue(isSameDeclaration(M2, H_super.mixin));
- Expect.isFalse(H_super.isObject);
+ Expect.isFalse(isObject(H_super));
Expect.isTrue(isSameDeclaration(S, H_super.superclass));
Expect.isTrue(isSameDeclaration(S, getSuperclass(H)));
@@ -232,7 +232,7 @@
Expect.isTrue(isSameDeclarationSet([A, M1], getExplicitInterfaces(H)));
// class H2 extends H {}
- var H2 = library.classes['H2'];
+ var H2 = library.declarations[#H2];
Expect.isTrue(isSameDeclaration(H, getSuperclass(H2)));
Expect.isTrue(getAppliedMixins(H2).isEmpty);
Expect.isTrue(getExplicitInterfaces(H2).isEmpty);
diff --git a/tests/compiler/dart2js/mirrors_test.dart b/tests/compiler/dart2js/mirrors_test.dart
index 3536683..13cffcc1 100644
--- a/tests/compiler/dart2js/mirrors_test.dart
+++ b/tests/compiler/dart2js/mirrors_test.dart
@@ -4,9 +4,9 @@
import "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart'
show currentDirectory;
import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
@@ -32,7 +32,7 @@
return false;
}
-DeclarationMirror findMirror(Iterable<DeclarationMirror> list, String name) {
+DeclarationMirror findMirror(Iterable<DeclarationMirror> list, Symbol name) {
for (DeclarationMirror mirror in list) {
if (mirror.simpleName == name) {
return mirror;
@@ -64,13 +64,13 @@
Expect.isNotNull(libraries, "No libraries map returned");
Expect.isFalse(libraries.isEmpty, "Empty libraries map returned");
- var helperLibrary = findMirror(libraries.values, "mirrors_helper");
+ var helperLibrary = findMirror(libraries.values, #mirrors_helper);
Expect.isNotNull(helperLibrary, "Library 'mirrors_helper' not found");
- Expect.stringEquals("mirrors_helper", helperLibrary.simpleName,
+ Expect.equals(#mirrors_helper, helperLibrary.simpleName,
"Unexpected library simple name");
- Expect.stringEquals("mirrors_helper", helperLibrary.qualifiedName,
+ Expect.equals(#mirrors_helper, helperLibrary.qualifiedName,
"Unexpected library qualified name");
- Expect.equals(helperLibrary, mirrors.findLibrary('mirrors_helper'));
+ Expect.equals(helperLibrary, mirrors.findLibrary(#mirrors_helper));
var helperLibraryLocation = helperLibrary.location;
Expect.isNotNull(helperLibraryLocation);
@@ -80,26 +80,18 @@
Expect.equals(1, helperLibraryLocation.column, "Unexpected column");
- var classes = helperLibrary.classes;
- Expect.isNotNull(classes, "No classes map returned");
- Expect.isFalse(classes.isEmpty, "Empty classes map returned");
+ var declarations = helperLibrary.declarations;
+ Expect.isNotNull(declarations, "No declarations map returned");
+ Expect.isFalse(declarations.isEmpty, "Empty declarations map returned");
- testFoo(mirrors, helperLibrary, classes);
- testBar(mirrors, helperLibrary, classes);
- testBaz(mirrors, helperLibrary, classes);
+ testFoo(mirrors, helperLibrary, declarations);
+ testBar(mirrors, helperLibrary, declarations);
+ testBaz(mirrors, helperLibrary, declarations);
// TODO(johnniwinther): Add test of class [Boz] and typedef [Func].
// TODO(johnniwinther): Add tests of type argument substitution, which
// is not currently implemented in dart2js.
// TODO(johnniwinther): Add tests of Location and Source.
- testPrivate(mirrors, helperLibrary, classes);
- // TODO(johnniwinther): Add thorough tests of [LibraryMirror.functions],
- // [LibraryMirror.getters], [LibraryMirror.setters], [LibraryMirror.members],
- // and [LibraryMirror.variable].
- Expect.isNotNull(helperLibrary.functions);
- Expect.isNotNull(helperLibrary.members);
- Expect.isNotNull(helperLibrary.getters);
- Expect.isNotNull(helperLibrary.setters);
- Expect.isNotNull(helperLibrary.variables);
+ testPrivate(mirrors, helperLibrary, declarations);
}
// Testing class Foo:
@@ -108,76 +100,68 @@
//
// }
void testFoo(MirrorSystem system, LibraryMirror helperLibrary,
- Map<String,TypeMirror> classes) {
- var fooClass = classes["Foo"];
+ Map<Symbol, DeclarationMirror> declarations) {
+ var fooClass = declarations[#Foo];
Expect.isNotNull(fooClass, "Type 'Foo' not found");
Expect.isTrue(fooClass is ClassMirror,
"Unexpected mirror type returned");
- Expect.stringEquals("Foo", fooClass.simpleName,
+ Expect.equals(#Foo, fooClass.simpleName,
"Unexpected type simple name");
- Expect.stringEquals("mirrors_helper.Foo", fooClass.qualifiedName,
+ Expect.equals(#mirrors_helper.Foo, fooClass.qualifiedName,
"Unexpected type qualified name");
- Expect.equals(helperLibrary, fooClass.library,
+ Expect.equals(helperLibrary, getLibrary(fooClass),
"Unexpected library returned from type");
- Expect.isFalse(fooClass.isObject, "Class is Object");
+ Expect.isFalse(isObject(fooClass), "Class is Object");
Expect.isFalse(fooClass.isDynamic, "Class is dynamic");
Expect.isFalse(fooClass.isVoid, "Class is void");
- Expect.isFalse(fooClass.isTypeVariable, "Class is a type variable");
- Expect.isFalse(fooClass.isTypedef, "Class is a typedef");
- Expect.isFalse(fooClass.isFunction, "Class is a function");
+ Expect.isFalse(fooClass is TypeVariableMirror, "Class is a type variable");
+ Expect.isFalse(fooClass is TypedefMirror, "Class is a typedef");
+ Expect.isFalse(fooClass is FunctionTypeMirror, "Class is a function");
Expect.isTrue(fooClass.isOriginalDeclaration);
Expect.equals(fooClass, fooClass.originalDeclaration);
- Expect.isTrue(fooClass.isClass, "Class is not class");
+ Expect.isTrue(fooClass is ClassMirror, "Class is not class");
Expect.isFalse(fooClass.isAbstract);
Expect.isFalse(fooClass.isPrivate, "Class is private");
var objectType = fooClass.superclass;
Expect.isNotNull(objectType, "Superclass is null");
- Expect.isTrue(objectType.isObject, "Object is not Object");
- Expect.isFalse(objectType.isOriginalDeclaration);
+ Expect.isTrue(isObject(objectType), "Object is not Object");
+ Expect.isTrue(objectType.isOriginalDeclaration);
Expect.isTrue(containsType(fooClass,
- computeSubdeclarations(objectType)),
+ computeSubdeclarations(system, objectType)),
"Class is not subclass of superclass");
var fooInterfaces = fooClass.superinterfaces;
Expect.isNotNull(fooInterfaces, "Interfaces map is null");
Expect.isTrue(fooInterfaces.isEmpty, "Interfaces map is not empty");
- var fooSubdeclarations = computeSubdeclarations(fooClass);
+ var fooSubdeclarations = computeSubdeclarations(system, fooClass);
Expect.equals(1, count(fooSubdeclarations), "Unexpected subtype count");
for (var fooSubdeclaration in fooSubdeclarations) {
Expect.equals(fooClass, fooSubdeclaration.superclass.originalDeclaration);
}
- Expect.throws(() => fooClass.typeArguments,
- (exception) => true,
- "Class has type arguments");
+ Expect.isTrue(fooClass.typeArguments.isEmpty);
var fooClassTypeVariables = fooClass.typeVariables;
Expect.isNotNull(fooClassTypeVariables, "Type variable list is null");
Expect.isTrue(fooClassTypeVariables.isEmpty,
"Type variable list is not empty");
- var fooClassMembers = fooClass.members;
+ var fooClassMembers = fooClass.declarations;
Expect.isNotNull(fooClassMembers, "Declared members map is null");
- Expect.isTrue(fooClassMembers.isEmpty, "Declared members map is unempty");
+ Expect.equals(1, fooClassMembers.length);
- var fooClassConstructors = fooClass.constructors;
- Expect.isNotNull(fooClassConstructors, "Constructors map is null");
- Expect.isTrue(fooClassConstructors.isEmpty,
- "Constructors map is unempty");
-
- // TODO(johnniwinther): Add thorough tests of [ClassMirror.functions],
- // [ClassMirror.getters], [ClassMirror.setters], [ClassMirror.members],
- // and [ClassMirror.variable].
- Expect.isNotNull(fooClass.functions);
- Expect.isNotNull(fooClass.members);
- Expect.isNotNull(fooClass.getters);
- Expect.isNotNull(fooClass.setters);
- Expect.isNotNull(fooClass.variables);
+ var fooM = fooClassMembers[#m];
+ Expect.isNotNull(fooM);
+ Expect.isTrue(fooM is MethodMirror);
+ Expect.equals(1, fooM.parameters.length);
+ var fooMa = fooM.parameters[0];
+ Expect.isNotNull(fooMa);
+ Expect.isTrue(fooMa is ParameterMirror);
//////////////////////////////////////////////////////////////////////////////
// Metadata tests
@@ -191,7 +175,7 @@
var dartMirrorsLibrary = system.libraries[DART_MIRRORS_URI];
Expect.isNotNull(dartMirrorsLibrary);
- var commentType = dartMirrorsLibrary.classes['Comment'];
+ var commentType = dartMirrorsLibrary.declarations[#Comment];
Expect.isNotNull(commentType);
// /// Singleline doc comment.
@@ -215,7 +199,7 @@
Expect.isTrue(metadata is TypeInstanceMirror);
var metadataType = metadata.representedType;
Expect.isNotNull(metadataType);
- Expect.stringEquals('Metadata', metadataType.simpleName);
+ Expect.equals(#Metadata, metadataType.simpleName);
// // This is intentionally the type literal.
metadata = metadataList[metadataListIndex++];
@@ -262,7 +246,7 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- InstanceMirror data = metadata.getField('data');
+ InstanceMirror data = metadata.getField(#data);
Expect.isNotNull(data);
Expect.isTrue(data.hasReflectee);
Expect.isNull(data.reflectee);
@@ -273,7 +257,7 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isNotNull(data);
Expect.isTrue(data.hasReflectee);
Expect.isTrue(data.reflectee);
@@ -284,7 +268,7 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isNotNull(data);
Expect.isTrue(data.hasReflectee);
Expect.isFalse(data.reflectee);
@@ -295,7 +279,7 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isNotNull(data);
Expect.isTrue(data.hasReflectee);
Expect.equals(0, data.reflectee);
@@ -306,7 +290,7 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isNotNull(data);
Expect.isTrue(data.hasReflectee);
Expect.equals(1.5, data.reflectee);
@@ -317,7 +301,7 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isNotNull(data);
Expect.isTrue(data.hasReflectee);
Expect.stringEquals("Foo", data.reflectee);
@@ -328,13 +312,13 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isTrue(data is ListInstanceMirror);
Expect.isFalse(data.hasReflectee);
Expect.throws(() => data.reflectee, (_) => true);
ListInstanceMirror listData = data;
Expect.equals(1, listData.length);
- InstanceMirror element = listData[0];
+ InstanceMirror element = listData.getElement(0);
Expect.isNotNull(element);
Expect.isTrue(element.hasReflectee);
Expect.stringEquals("Foo", element.reflectee);
@@ -345,7 +329,7 @@
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isTrue(data is MapInstanceMirror);
Expect.isFalse(data.hasReflectee);
Expect.throws(() => data.reflectee, (_) => true);
@@ -354,19 +338,19 @@
var it = mapData.keys.iterator;
Expect.isTrue(it.moveNext());
Expect.stringEquals('foo', it.current);
- element = mapData['foo'];
+ element = mapData.getValue('foo');
Expect.isNotNull(element);
Expect.isTrue(element.hasReflectee);
Expect.stringEquals("Foo", element.reflectee);
- Expect.isNull(mapData['bar']);
+ Expect.isNull(mapData.getValue('bar'));
// @metadata
- metadata = metadataList[metadataListIndex++];
+ var metadataRef = metadata = metadataList[metadataListIndex++];
Expect.isTrue(metadata is InstanceMirror);
Expect.isFalse(metadata.hasReflectee);
Expect.throws(() => metadata.reflectee, (_) => true);
Expect.equals(metadataType.originalDeclaration, metadata.type);
- data = metadata.getField('data');
+ data = metadata.getField(#data);
Expect.isNotNull(data);
Expect.isTrue(data.hasReflectee);
Expect.isNull(data.reflectee);
@@ -399,6 +383,10 @@
Expect.equals(metadataList.length, metadataListIndex);
+ Expect.isNotNull(fooMa.metadata);
+ Expect.equals(1, fooMa.metadata.length);
+ Expect.equals(metadataRef, fooMa.metadata[0]);
+
//////////////////////////////////////////////////////////////////////////////
// Location test
//////////////////////////////////////////////////////////////////////////////
@@ -409,7 +397,7 @@
// leading comment.
Expect.equals(376, fooClassLocation.offset, "Unexpected offset");
// Expect the location to end with the class body.
- Expect.equals(332, fooClassLocation.length, "Unexpected length");
+ Expect.equals(351, fooClassLocation.length, "Unexpected length");
Expect.equals(18, fooClassLocation.line, "Unexpected line");
Expect.equals(1, fooClassLocation.column, "Unexpected column");
@@ -421,46 +409,46 @@
//
// }
void testBar(MirrorSystem system, LibraryMirror helperLibrary,
- Map<String,TypeMirror> classes) {
- var barClass = classes["Bar"];
+ Map<Symbol, DeclarationMirror> classes) {
+ var barClass = classes[#Bar];
Expect.isNotNull(barClass, "Type 'Bar' not found");
Expect.isTrue(barClass is ClassMirror,
"Unexpected mirror type returned");
- Expect.stringEquals("Bar", barClass.simpleName,
+ Expect.equals(#Bar, barClass.simpleName,
"Unexpected type simple name");
- Expect.stringEquals("mirrors_helper.Bar", barClass.qualifiedName,
- "Unexpected type qualified name");
+ Expect.equals(#mirrors_helper.Bar, barClass.qualifiedName,
+ "Unexpected type qualified name");
- Expect.equals(helperLibrary, barClass.library,
+ Expect.equals(helperLibrary, getLibrary(barClass),
"Unexpected library returned from type");
- Expect.isFalse(barClass.isObject, "Interface is Object");
+ Expect.isFalse(isObject(barClass), "Interface is Object");
Expect.isFalse(barClass.isDynamic, "Interface is dynamic");
Expect.isFalse(barClass.isVoid, "Interface is void");
- Expect.isFalse(barClass.isTypeVariable, "Interface is a type variable");
- Expect.isFalse(barClass.isTypedef, "Interface is a typedef");
- Expect.isFalse(barClass.isFunction, "Interface is a function");
+ Expect.isFalse(barClass is TypeVariableMirror, "Interface is a type variable");
+ Expect.isFalse(barClass is TypedefMirror, "Interface is a typedef");
+ Expect.isFalse(barClass is FunctionTypeMirror, "Interface is a function");
Expect.isTrue(barClass.isOriginalDeclaration);
Expect.equals(barClass, barClass.originalDeclaration);
- Expect.isTrue(barClass.isClass);
+ Expect.isTrue(barClass is ClassMirror);
Expect.isTrue(barClass.isAbstract);
Expect.isFalse(barClass.isPrivate, "Interface is private");
var objectType = barClass.superclass;
Expect.isNotNull(objectType, "Superclass is null");
- Expect.isTrue(objectType.isObject, "Object is not Object");
- Expect.isFalse(objectType.isOriginalDeclaration);
+ Expect.isTrue(isObject(objectType), "Object is not Object");
+ Expect.isTrue(objectType.isOriginalDeclaration);
Expect.isTrue(containsType(barClass,
- computeSubdeclarations(objectType)),
+ computeSubdeclarations(system, objectType)),
"Class is not subclass of superclass");
var barInterfaces = barClass.superinterfaces;
Expect.isNotNull(barInterfaces, "Interfaces map is null");
Expect.isTrue(barInterfaces.isEmpty, "Interfaces map is not empty");
- var barSubdeclarations = computeSubdeclarations(barClass);
+ var barSubdeclarations = computeSubdeclarations(system, barClass);
Expect.equals(1, count(barSubdeclarations), "Unexpected subtype count");
for (var barSubdeclaration in barSubdeclarations) {
Expect.isTrue(containsType(barClass,
@@ -468,9 +456,7 @@
"Interface is not superinterface of subclass");
}
- Expect.throws(() => barClass.typeArguments,
- (exception) => true,
- "Interface has type arguments");
+ Expect.isTrue(barClass.typeArguments.isEmpty);
var barInterfaceTypeVariables = barClass.typeVariables;
Expect.isNotNull(barInterfaceTypeVariables, "Type variable list is null");
Expect.isFalse(barInterfaceTypeVariables.isEmpty,
@@ -480,17 +466,12 @@
var barE = barInterfaceTypeVariables[0];
Expect.isNotNull(barE, "Type variable is null");
- Expect.isTrue(barE.isTypeVariable, "Type variable is not type variable");
+ Expect.isTrue(barE is TypeVariableMirror);
- var barInterfaceMembers = barClass.members;
+ var barInterfaceMembers = barClass.declarations;
Expect.isNotNull(barInterfaceMembers, "Declared members map is null");
Expect.isTrue(barInterfaceMembers.isEmpty,
- "Declared members map is unempty");
-
- var barInterfaceConstructors = barClass.constructors;
- Expect.isNotNull(barInterfaceConstructors, "Constructors map is null");
- Expect.isTrue(barInterfaceConstructors.isEmpty,
- "Constructors map is unempty");
+ "Declarations map is unempty");
var metadata = barClass.metadata;
Expect.isNotNull(metadata);
@@ -512,39 +493,39 @@
// int operator -() => 0;
// }
void testBaz(MirrorSystem system, LibraryMirror helperLibrary,
- Map<String,TypeMirror> classes) {
- var bazClass = classes["Baz"];
+ Map<Symbol, DeclarationMirror> declarations) {
+ var bazClass = declarations[#Baz];
Expect.isNotNull(bazClass, "Type 'Baz' not found");
Expect.isTrue(bazClass is ClassMirror,
"Unexpected mirror type returned");
- Expect.stringEquals("Baz", bazClass.simpleName,
- "Unexpected type simple name");
- Expect.stringEquals("mirrors_helper.Baz", bazClass.qualifiedName,
- "Unexpected type qualified name");
+ Expect.equals(#Baz, bazClass.simpleName,
+ "Unexpected type simple name");
+ Expect.equals(#mirrors_helper.Baz, bazClass.qualifiedName,
+ "Unexpected type qualified name");
- Expect.equals(helperLibrary, bazClass.library,
+ Expect.equals(helperLibrary, getLibrary(bazClass),
"Unexpected library returned from type");
- Expect.isFalse(bazClass.isObject, "Class is Object");
+ Expect.isFalse(isObject(bazClass), "Class is Object");
Expect.isFalse(bazClass.isDynamic, "Class is dynamic");
Expect.isFalse(bazClass.isVoid, "Class is void");
- Expect.isFalse(bazClass.isTypeVariable, "Class is a type variable");
- Expect.isFalse(bazClass.isTypedef, "Class is a typedef");
- Expect.isFalse(bazClass.isFunction, "Class is a function");
+ Expect.isFalse(bazClass is TypeVariableMirror, "Class is a type variable");
+ Expect.isFalse(bazClass is TypedefMirror, "Class is a typedef");
+ Expect.isFalse(bazClass is FunctionTypeMirror, "Class is a function");
Expect.isTrue(bazClass.isOriginalDeclaration);
Expect.equals(bazClass, bazClass.originalDeclaration);
- Expect.isTrue(bazClass.isClass, "Class is not class");
+ Expect.isTrue(bazClass is ClassMirror, "Class is not class");
Expect.isFalse(bazClass.isAbstract);
Expect.isFalse(bazClass.isPrivate, "Class is private");
var objectType = bazClass.superclass;
Expect.isNotNull(objectType, "Superclass is null");
- Expect.isTrue(objectType.isObject, "Object is not Object");
- Expect.isFalse(objectType.isOriginalDeclaration);
+ Expect.isTrue(isObject(objectType), "Object is not Object");
+ Expect.isTrue(objectType.isOriginalDeclaration);
Expect.isTrue(containsType(bazClass,
- computeSubdeclarations(objectType)),
+ computeSubdeclarations(system, objectType)),
"Class is not subclass of superclass");
var bazInterfaces = bazClass.superinterfaces;
@@ -552,14 +533,14 @@
Expect.isTrue(!bazInterfaces.isEmpty, "Interfaces map is empty");
for (var bazInterface in bazInterfaces) {
Expect.isTrue(containsType(bazClass,
- computeSubdeclarations(objectType)),
+ computeSubdeclarations(system, objectType)),
"Class is not subclass of superinterface");
}
- var bazSubdeclarations = computeSubdeclarations(bazClass);
+ var bazSubdeclarations = computeSubdeclarations(system, bazClass);
Expect.equals(0, count(bazSubdeclarations), "Unexpected subtype count");
- var barInterface = findMirror(bazInterfaces, "Bar");
+ var barInterface = findMirror(bazInterfaces, #Bar);
Expect.isNotNull(barInterface, "Interface bar is missing");
Expect.isFalse(barInterface.isOriginalDeclaration);
var barInterfaceTypeArguments = barInterface.typeArguments;
@@ -567,9 +548,7 @@
Expect.equals(1, barInterfaceTypeArguments.length,
"Type arguments is empty");
- Expect.throws(() => bazClass.typeArguments,
- (exception) => true,
- "Class has type arguments");
+ Expect.isTrue(bazClass.typeArguments.isEmpty, "Class has type arguments");
var bazClassTypeVariables = bazClass.typeVariables;
Expect.isNotNull(bazClassTypeVariables, "Type variable list is null");
Expect.equals(2, bazClassTypeVariables.length,
@@ -577,29 +556,29 @@
var bazE = bazClassTypeVariables[0];
Expect.isNotNull(bazE, "Type variable is null");
- Expect.stringEquals('E', bazE.simpleName, "Unexpected simpleName");
- Expect.stringEquals('mirrors_helper.Baz.E', bazE.qualifiedName,
- "Unexpected qualifiedName");
- Expect.equals(bazClass, bazE.declarer,
+ Expect.equals(#E, bazE.simpleName, "Unexpected simpleName");
+ Expect.equals(#mirrors_helper.Baz.E, bazE.qualifiedName,
+ "Unexpected qualifiedName");
+ Expect.equals(bazClass, bazE.owner,
"Unexpected type variable declarer");
var bazEbound = bazE.upperBound;
Expect.isNotNull(bazEbound);
- Expect.isFalse(bazEbound.isOriginalDeclaration);
- Expect.isTrue(bazEbound.isObject, "Bound is not object");
+ Expect.isTrue(bazEbound.isOriginalDeclaration);
+ Expect.isTrue(isObject(bazEbound), "Bound is not object");
var bazF = bazClassTypeVariables[1];
Expect.isNotNull(bazF, "Type variable is null");
- Expect.stringEquals('F', bazF.simpleName, "Unexpected simpleName");
- Expect.stringEquals('mirrors_helper.Baz.F', bazF.qualifiedName,
- "Unexpected qualifiedName");
- Expect.equals(bazClass, bazF.declarer);
+ Expect.equals(#F, bazF.simpleName, "Unexpected simpleName");
+ Expect.equals(#mirrors_helper.Baz.F, bazF.qualifiedName,
+ "Unexpected qualifiedName");
+ Expect.equals(bazClass, bazF.owner);
var bazFbound = bazF.upperBound;
Expect.isNotNull(bazFbound);
- Expect.isFalse(bazFbound.isOriginalDeclaration);
- Expect.stringEquals("mirrors_helper.Foo", bazFbound.qualifiedName,
- "Bound is not Foo");
+ Expect.isTrue(bazFbound.isOriginalDeclaration);
+ Expect.equals(#mirrors_helper.Foo, bazFbound.qualifiedName,
+ "Bound is not Foo");
- var bazClassMembers = bazClass.members;
+ var bazClassMembers = bazClass.declarations;
Expect.isNotNull(bazClassMembers, "Declared members map is null");
Expect.equals(8, bazClassMembers.length,
"Unexpected number of declared members");
@@ -607,20 +586,16 @@
////////////////////////////////////////////////////////////////////////////
// static method1(e) {}
////////////////////////////////////////////////////////////////////////////
- var method1 = bazClassMembers["method1"];
+ var method1 = bazClassMembers[#method1];
Expect.isNotNull(method1, "method1 not found");
- Expect.stringEquals('method1', method1.simpleName,
- "Unexpected method simpleName");
- Expect.stringEquals('mirrors_helper.Baz.method1', method1.qualifiedName,
- "Unexpected method qualifiedName");
+ Expect.equals(#method1, method1.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method1, method1.qualifiedName);
Expect.equals(method1.owner, bazClass);
Expect.isFalse(method1.isTopLevel);
+ Expect.isTrue(method1 is MethodMirror);
Expect.isFalse(method1.isConstructor);
- Expect.isFalse(method1.isVariable);
- Expect.isTrue(method1.isMethod);
Expect.isFalse(method1.isPrivate);
Expect.isTrue(method1.isStatic);
- Expect.isTrue(method1 is MethodMirror);
Expect.isTrue(method1.isRegularMethod);
Expect.isFalse(method1.isConstConstructor);
Expect.isFalse(method1.isGenerativeConstructor);
@@ -632,12 +607,12 @@
var dynamicType = method1.returnType;
Expect.isNotNull(dynamicType, "Return type was null");
- Expect.isFalse(dynamicType.isObject, "dynamic is Object");
+ Expect.isFalse(isObject(dynamicType), "dynamic is Object");
Expect.isTrue(dynamicType.isDynamic, "dynamic is not dynamic");
Expect.isFalse(dynamicType.isVoid, "dynamic is void");
- Expect.isFalse(dynamicType.isTypeVariable, "dynamic is a type variable");
- Expect.isFalse(dynamicType.isTypedef, "dynamic is a typedef");
- Expect.isFalse(dynamicType.isFunction, "dynamic is a function");
+ Expect.isFalse(dynamicType is TypeVariableMirror, "dynamic is a type variable");
+ Expect.isFalse(dynamicType is TypedefMirror, "dynamic is a typedef");
+ Expect.isFalse(dynamicType is FunctionTypeMirror, "dynamic is a function");
var method1Parameters = method1.parameters;
Expect.isNotNull(method1Parameters, "Method parameters is null");
@@ -645,11 +620,8 @@
var method1Parameter1 = method1Parameters[0];
Expect.isNotNull(method1Parameter1, "Parameter is null");
Expect.equals(dynamicType, method1Parameter1.type);
- Expect.stringEquals("e", method1Parameter1.simpleName,
- "Unexpected parameter simpleName");
- Expect.stringEquals("mirrors_helper.Baz.method1#e",
- method1Parameter1.qualifiedName,
- "Unexpected parameter qualifiedName");
+ Expect.equals(#e, method1Parameter1.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method1.e, method1Parameter1.qualifiedName);
Expect.isFalse(method1Parameter1.hasDefaultValue,
"Parameter has default value");
Expect.isNull(method1Parameter1.defaultValue,
@@ -659,20 +631,16 @@
////////////////////////////////////////////////////////////////////////////
// static void method2(E e, [F f = null]) {}
////////////////////////////////////////////////////////////////////////////
- var method2 = bazClassMembers["method2"];
+ var method2 = bazClassMembers[#method2];
Expect.isNotNull(method2, "method2 not found");
- Expect.stringEquals('method2', method2.simpleName,
- "Unexpected method simpleName");
- Expect.stringEquals('mirrors_helper.Baz.method2', method2.qualifiedName,
- "Unexpected method qualifiedName");
+ Expect.equals(#method2, method2.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method2, method2.qualifiedName);
Expect.equals(method2.owner, bazClass);
Expect.isFalse(method2.isTopLevel);
+ Expect.isTrue(method2 is MethodMirror);
Expect.isFalse(method2.isConstructor);
- Expect.isFalse(method2.isVariable);
- Expect.isTrue(method2.isMethod);
Expect.isFalse(method2.isPrivate);
Expect.isFalse(method2.isStatic);
- Expect.isTrue(method2 is MethodMirror);
Expect.isTrue(method2.isRegularMethod);
Expect.isFalse(method2.isConstConstructor);
Expect.isFalse(method2.isGenerativeConstructor);
@@ -684,12 +652,12 @@
var voidType = method2.returnType;
Expect.isNotNull(voidType, "Return type was null");
- Expect.isFalse(voidType.isObject, "void is Object");
+ Expect.isFalse(isObject(voidType), "void is Object");
Expect.isFalse(voidType.isDynamic, "void is dynamic");
Expect.isTrue(voidType.isVoid, "void is not void");
- Expect.isFalse(voidType.isTypeVariable, "void is a type variable");
- Expect.isFalse(voidType.isTypedef, "void is a typedef");
- Expect.isFalse(voidType.isFunction, "void is a function");
+ Expect.isFalse(voidType is TypeVariableMirror, "void is a type variable");
+ Expect.isFalse(voidType is TypedefMirror, "void is a typedef");
+ Expect.isFalse(voidType is FunctionTypeMirror, "void is a function");
var method2Parameters = method2.parameters;
Expect.isNotNull(method2Parameters, "Method parameters is null");
@@ -697,11 +665,8 @@
var method2Parameter1 = method2Parameters[0];
Expect.isNotNull(method2Parameter1, "Parameter is null");
Expect.equals(bazE, method2Parameter1.type);
- Expect.stringEquals("e", method2Parameter1.simpleName,
- "Unexpected parameter simpleName");
- Expect.stringEquals("mirrors_helper.Baz.method2#e",
- method2Parameter1.qualifiedName,
- "Unexpected parameter qualifiedName");
+ Expect.equals(#e, method2Parameter1.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method2.e, method2Parameter1.qualifiedName);
Expect.isFalse(method2Parameter1.hasDefaultValue,
"Parameter has default value");
Expect.isNull(method2Parameter1.defaultValue,
@@ -710,34 +675,28 @@
var method2Parameter2 = method2Parameters[1];
Expect.isNotNull(method2Parameter2, "Parameter is null");
Expect.equals(bazF, method2Parameter2.type);
- Expect.stringEquals("f", method2Parameter2.simpleName,
- "Unexpected parameter simpleName");
- Expect.stringEquals("mirrors_helper.Baz.method2#f",
- method2Parameter2.qualifiedName,
- "Unexpected parameter qualifiedName");
+ Expect.equals(#f, method2Parameter2.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method2.f,
+ method2Parameter2.qualifiedName);
Expect.isTrue(method2Parameter2.hasDefaultValue,
"Parameter has default value");
- Expect.stringEquals("null", method2Parameter2.defaultValue,
- "Parameter default value is non-null");
+ Expect.isNotNull(method2Parameter2.defaultValue,
+ "Parameter default value is null");
Expect.isTrue(method2Parameter2.isOptional, "Parameter is not optional");
////////////////////////////////////////////////////////////////////////////
// Baz<E,F> method3(E func1(F f), Func<E,F> func2) => null;
////////////////////////////////////////////////////////////////////////////
- var method3 = bazClassMembers["method3"];
+ var method3 = bazClassMembers[#method3];
Expect.isNotNull(method3, "method3 not found");
- Expect.stringEquals('method3', method3.simpleName,
- "Unexpected method simpleName");
- Expect.stringEquals('mirrors_helper.Baz.method3', method3.qualifiedName,
- "Unexpected method qualifiedName");
+ Expect.equals(#method3, method3.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method3, method3.qualifiedName);
Expect.equals(method3.owner, bazClass);
Expect.isFalse(method3.isTopLevel);
+ Expect.isTrue(method3 is MethodMirror);
Expect.isFalse(method3.isConstructor);
- Expect.isFalse(method3.isVariable);
- Expect.isTrue(method3.isMethod);
Expect.isFalse(method3.isPrivate);
Expect.isFalse(method3.isStatic);
- Expect.isTrue(method3 is MethodMirror);
Expect.isTrue(method3.isRegularMethod);
Expect.isFalse(method3.isConstConstructor);
Expect.isFalse(method3.isGenerativeConstructor);
@@ -773,15 +732,12 @@
"Return type of 'func1' is not a E");
Expect.isNotNull(method3Parameter1type.parameters[0],
"Parameter 1 of 'func1' is null");
- Expect.stringEquals('f', method3Parameter1type.parameters[0].simpleName,
- "Unexpected name parameter 1 of 'func1'");
+ Expect.equals(#f, method3Parameter1type.parameters[0].simpleName);
Expect.equals(bazF, method3Parameter1type.parameters[0].type,
"Argument type of 'func1' is not a F");
- Expect.stringEquals("func1", method3Parameter1.simpleName,
- "Unexpected parameter simpleName");
- Expect.stringEquals("mirrors_helper.Baz.method3#func1",
- method3Parameter1.qualifiedName,
- "Unexpected parameter qualifiedName");
+ Expect.equals(#func1, method3Parameter1.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method3.func1,
+ method3Parameter1.qualifiedName);
Expect.isFalse(method3Parameter1.hasDefaultValue,
"Parameter has default value");
Expect.isNull(method3Parameter1.defaultValue,
@@ -792,48 +748,33 @@
Expect.isNotNull(method3Parameter2, "Parameter is null");
var funcTypedef = method3Parameter2.type;
Expect.isNotNull(funcTypedef, "Parameter type is null");
- Expect.stringEquals("Func", funcTypedef.simpleName,
- "Unexpected simpleName");
- Expect.stringEquals("mirrors_helper.Func", funcTypedef.qualifiedName,
- "Unexpected simpleName");
- Expect.isFalse(funcTypedef.isObject, "Typedef is Object");
+ Expect.equals(#Func, funcTypedef.simpleName);
+ Expect.equals(#mirrors_helper.Func, funcTypedef.qualifiedName);
+ Expect.isFalse(isObject(funcTypedef), "Typedef is Object");
Expect.isFalse(funcTypedef.isDynamic, "Typedef is dynamic");
Expect.isFalse(funcTypedef.isVoid, "Typedef is void");
- Expect.isFalse(funcTypedef.isTypeVariable, "Typedef is a type variable");
- Expect.isTrue(funcTypedef.isTypedef, "Typedef is not a typedef");
- Expect.isFalse(funcTypedef.isFunction, "Typedef is a function");
+ Expect.isFalse(funcTypedef is TypeVariableMirror, "Typedef is a type variable");
+ Expect.isTrue(funcTypedef is TypedefMirror, "Typedef is not a typedef");
+ Expect.isFalse(funcTypedef is FunctionTypeMirror, "Typedef is a function");
- Expect.equals(helperLibrary, funcTypedef.library,
+ Expect.equals(helperLibrary, getLibrary(funcTypedef),
"Unexpected typedef library");
- Expect.isNull(funcTypedef.superclass, "Non-null superclass on typedef");
- Expect.isNotNull(funcTypedef.superinterfaces);
- Expect.isTrue(funcTypedef.superinterfaces.isEmpty);
- Expect.isNotNull(funcTypedef.members);
- Expect.isTrue(funcTypedef.members.isEmpty);
- // TODO(johnniwinther): Returned typedef should not be the original
- // declaration:
- Expect.isTrue(funcTypedef.isOriginalDeclaration);
- Expect.isFalse(funcTypedef.isClass, "Typedef is class");
+ Expect.isFalse(funcTypedef.isOriginalDeclaration);
+ Expect.isFalse(funcTypedef is ClassMirror, "Typedef is class");
Expect.isFalse(funcTypedef.isPrivate, "Typedef is private");
- // TODO(johnniwinther): Should not throw an exception since the type should
- // not be the original declaration.
- Expect.throws(() => funcTypedef.typeArguments,
- (exception) => true,
- "Typedef has type arguments");
+ Expect.equals(2, funcTypedef.typeArguments.length);
var funcTypedefTypeVariables = funcTypedef.typeVariables;
Expect.isNotNull(funcTypedefTypeVariables);
Expect.equals(2, funcTypedefTypeVariables.length);
- var funcTypedefDefinition = funcTypedef.value;
+ var funcTypedefDefinition = funcTypedef.referent;
Expect.isNotNull(funcTypedefDefinition);
Expect.isTrue(funcTypedefDefinition is FunctionTypeMirror);
- Expect.stringEquals("func2", method3Parameter2.simpleName,
- "Unexpected parameter simpleName");
- Expect.stringEquals("mirrors_helper.Baz.method3#func2",
- method3Parameter2.qualifiedName,
- "Unexpected parameter qualifiedName");
+ Expect.equals(#func2, method3Parameter2.simpleName);
+ Expect.equals(#mirrors_helper.Baz.method3.func2,
+ method3Parameter2.qualifiedName);
Expect.isFalse(method3Parameter2.hasDefaultValue,
"Parameter 'func2' has default value: "
"${method3Parameter2.defaultValue}");
@@ -844,22 +785,20 @@
////////////////////////////////////////////////////////////////////////////
// bool operator==(Object other) => false;
////////////////////////////////////////////////////////////////////////////
- var operator_eq = bazClassMembers['=='];
+ var operator_eq = bazClassMembers[const Symbol('==')];
Expect.isNotNull(operator_eq, "operator == not found");
- Expect.stringEquals('==', operator_eq.simpleName,
- "Unexpected method simpleName");
+ Expect.equals(const Symbol('=='), operator_eq.simpleName,
+ "Unexpected method simpleName");
Expect.stringEquals('operator ==', displayName(operator_eq));
- Expect.stringEquals('mirrors_helper.Baz.==',
- operator_eq.qualifiedName,
- "Unexpected method qualifiedName");
+ Expect.equals(const Symbol('mirrors_helper.Baz.=='),
+ operator_eq.qualifiedName,
+ "Unexpected method qualifiedName");
Expect.equals(operator_eq.owner, bazClass);
Expect.isFalse(operator_eq.isTopLevel);
+ Expect.isTrue(operator_eq is MethodMirror);
Expect.isFalse(operator_eq.isConstructor);
- Expect.isFalse(operator_eq.isVariable);
- Expect.isTrue(operator_eq.isMethod);
Expect.isFalse(operator_eq.isPrivate);
Expect.isFalse(operator_eq.isStatic);
- Expect.isTrue(operator_eq is MethodMirror);
Expect.isTrue(operator_eq.isRegularMethod);
Expect.isFalse(operator_eq.isConstConstructor);
Expect.isFalse(operator_eq.isGenerativeConstructor);
@@ -873,22 +812,20 @@
////////////////////////////////////////////////////////////////////////////
// int operator -() => 0;
////////////////////////////////////////////////////////////////////////////
- var operator_negate = bazClassMembers[Mirror.UNARY_MINUS];
+ var operator_negate = bazClassMembers[const Symbol('unary-')];
Expect.isNotNull(operator_negate, "operator < not found");
- Expect.stringEquals(Mirror.UNARY_MINUS, operator_negate.simpleName,
+ Expect.equals(const Symbol('unary-'), operator_negate.simpleName,
"Unexpected method simpleName");
Expect.stringEquals('operator -', displayName(operator_negate));
- Expect.stringEquals('mirrors_helper.Baz.${Mirror.UNARY_MINUS}',
+ Expect.equals(const Symbol('mirrors_helper.Baz.unary-'),
operator_negate.qualifiedName,
"Unexpected method qualifiedName");
Expect.equals(operator_negate.owner, bazClass);
Expect.isFalse(operator_negate.isTopLevel);
+ Expect.isTrue(operator_negate is MethodMirror);
Expect.isFalse(operator_negate.isConstructor);
- Expect.isFalse(operator_negate.isVariable);
- Expect.isTrue(operator_negate.isMethod);
Expect.isFalse(operator_negate.isPrivate);
Expect.isFalse(operator_negate.isStatic);
- Expect.isTrue(operator_negate is MethodMirror);
Expect.isTrue(operator_negate.isRegularMethod);
Expect.isFalse(operator_negate.isConstConstructor);
Expect.isFalse(operator_negate.isGenerativeConstructor);
@@ -899,16 +836,10 @@
Expect.isTrue(operator_negate.isOperator);
Expect.stringEquals('-', operatorName(operator_negate));
-
- var bazClassConstructors = bazClass.constructors;
- Expect.isNotNull(bazClassConstructors, "Constructors map is null");
- Expect.equals(3, bazClassConstructors.length,
- "Unexpected number of constructors");
-
////////////////////////////////////////////////////////////////////////////
// Baz();
////////////////////////////////////////////////////////////////////////////
- var bazClassNonameConstructor = bazClassConstructors[''];
+ var bazClassNonameConstructor = bazClassMembers[const Symbol('')];
Expect.isNotNull(bazClassNonameConstructor);
Expect.isTrue(bazClassNonameConstructor is MethodMirror);
Expect.isTrue(bazClassNonameConstructor.isConstructor);
@@ -917,15 +848,15 @@
Expect.isTrue(bazClassNonameConstructor.isGenerativeConstructor);
Expect.isFalse(bazClassNonameConstructor.isRedirectingConstructor);
Expect.isFalse(bazClassNonameConstructor.isFactoryConstructor);
- Expect.stringEquals('', bazClassNonameConstructor.simpleName);
+ Expect.equals(const Symbol(''), bazClassNonameConstructor.simpleName);
Expect.stringEquals('Baz', displayName(bazClassNonameConstructor));
- Expect.stringEquals('mirrors_helper.Baz.',
+ Expect.equals(const Symbol('mirrors_helper.Baz.'),
bazClassNonameConstructor.qualifiedName);
////////////////////////////////////////////////////////////////////////////
// const Baz.named();
////////////////////////////////////////////////////////////////////////////
- var bazClassNamedConstructor = bazClassConstructors['named'];
+ var bazClassNamedConstructor = bazClassMembers[#named];
Expect.isNotNull(bazClassNamedConstructor);
Expect.isTrue(bazClassNamedConstructor is MethodMirror);
Expect.isTrue(bazClassNamedConstructor.isConstructor);
@@ -934,15 +865,15 @@
Expect.isFalse(bazClassNamedConstructor.isGenerativeConstructor);
Expect.isFalse(bazClassNamedConstructor.isRedirectingConstructor);
Expect.isFalse(bazClassNamedConstructor.isFactoryConstructor);
- Expect.stringEquals('named', bazClassNamedConstructor.simpleName);
+ Expect.equals(#named, bazClassNamedConstructor.simpleName);
Expect.stringEquals('Baz.named', displayName(bazClassNamedConstructor));
- Expect.stringEquals('mirrors_helper.Baz.named',
+ Expect.equals(#mirrors_helper.Baz.named,
bazClassNamedConstructor.qualifiedName);
////////////////////////////////////////////////////////////////////////////
// factory Baz.factory() => new Baz<E,F>();
////////////////////////////////////////////////////////////////////////////
- var bazClassFactoryConstructor = bazClassConstructors['factory'];
+ var bazClassFactoryConstructor = bazClassMembers[#factory];
Expect.isNotNull(bazClassFactoryConstructor);
Expect.isTrue(bazClassFactoryConstructor is MethodMirror);
Expect.isTrue(bazClassFactoryConstructor.isConstructor);
@@ -951,9 +882,9 @@
Expect.isFalse(bazClassFactoryConstructor.isGenerativeConstructor);
Expect.isFalse(bazClassFactoryConstructor.isRedirectingConstructor);
Expect.isTrue(bazClassFactoryConstructor.isFactoryConstructor);
- Expect.stringEquals('factory', bazClassFactoryConstructor.simpleName);
+ Expect.equals(#factory, bazClassFactoryConstructor.simpleName);
Expect.stringEquals('Baz.factory', displayName(bazClassFactoryConstructor));
- Expect.stringEquals('mirrors_helper.Baz.factory',
+ Expect.equals(#mirrors_helper.Baz.factory,
bazClassFactoryConstructor.qualifiedName);
// TODO(johnniwinther): Add more tests of constructors.
@@ -973,41 +904,41 @@
// factory _PrivateClass._privateFactoryConstructor() => new _PrivateClass();
// }
void testPrivate(MirrorSystem system, LibraryMirror helperLibrary,
- Map<String,TypeMirror> classes) {
- var privateClass = classes['_PrivateClass'];
+ Map<Symbol, DeclarationMirror> declarations) {
+ var privateClass = declarations[const Symbol('_PrivateClass')];
Expect.isNotNull(privateClass);
Expect.isTrue(privateClass is ClassMirror);
- Expect.isTrue(privateClass.isClass);
Expect.isFalse(privateClass.isAbstract);
Expect.isTrue(privateClass.isPrivate);
- var privateField = privateClass.members['_privateField'];
+ var privateField = privateClass.declarations[const Symbol('_privateField')];
Expect.isNotNull(privateField);
Expect.isTrue(privateField is VariableMirror);
Expect.isTrue(privateField.isPrivate);
- var privateGetter = privateClass.members['_privateGetter'];
+ var privateGetter = privateClass.declarations[const Symbol('_privateGetter')];
Expect.isNotNull(privateGetter);
Expect.isTrue(privateGetter is MethodMirror);
Expect.isTrue(privateGetter.isGetter);
Expect.isTrue(privateGetter.isPrivate);
Expect.isFalse(privateGetter.isRegularMethod);
- var privateSetter = privateClass.members['_privateSetter='];
+ var privateSetter =
+ privateClass.declarations[const Symbol('_privateSetter=')];
Expect.isNotNull(privateSetter);
Expect.isTrue(privateSetter is MethodMirror);
Expect.isTrue(privateSetter.isSetter);
Expect.isTrue(privateSetter.isPrivate);
Expect.isFalse(privateSetter.isRegularMethod);
- var privateMethod = privateClass.members['_privateMethod'];
+ var privateMethod = privateClass.declarations[const Symbol('_privateMethod')];
Expect.isNotNull(privateMethod);
Expect.isTrue(privateMethod is MethodMirror);
Expect.isTrue(privateMethod.isPrivate);
Expect.isTrue(privateMethod.isRegularMethod);
var privateConstructor =
- privateClass.members['_privateConstructor'];
+ privateClass.declarations[const Symbol('_privateConstructor')];
Expect.isNotNull(privateConstructor);
Expect.isTrue(privateConstructor is MethodMirror);
Expect.isTrue(privateConstructor.isConstructor);
@@ -1018,7 +949,7 @@
Expect.isFalse(privateConstructor.isFactoryConstructor);
var privateFactoryConstructor =
- privateClass.members['_privateFactoryConstructor'];
+ privateClass.declarations[const Symbol('_privateFactoryConstructor')];
Expect.isNotNull(privateFactoryConstructor);
Expect.isTrue(privateFactoryConstructor is MethodMirror);
Expect.isTrue(privateFactoryConstructor.isConstructor);
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index b63df94..eca7e6f 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -237,6 +237,8 @@
List<WarningMessage> errors;
List<WarningMessage> hints;
List<WarningMessage> infos;
+ final bool allowWarnings;
+ final bool allowErrors;
final Map<String, SourceFile> sourceFiles;
Node parsedTree;
@@ -255,7 +257,9 @@
bool preserveComments: false,
// Our unit tests check code generation output that is
// affected by inlining support.
- bool disableInlining: true})
+ bool disableInlining: true,
+ bool this.allowWarnings: true,
+ bool this.allowErrors: true})
: warnings = [], errors = [], hints = [], infos = [],
sourceFiles = new Map<String, SourceFile>(),
super(enableTypeAssertions: enableTypeAssertions,
@@ -299,6 +303,18 @@
deferredLoadTask = new MockDeferredLoadTask(this);
}
+ Future runCompiler(Uri uri) {
+ return super.runCompiler(uri).then((result) {
+ if (!allowErrors && !errors.isEmpty) {
+ throw "unexpected error during compilation ${errors}";
+ } else if (!allowWarnings && !warnings.isEmpty) {
+ throw "unexpected warnings during compilation ${warnings}";
+ } else {
+ return result;
+ }
+ });
+ }
+
/**
* Registers the [source] with [uri] making it possible load [source] as a
* library.
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart
new file mode 100644
index 0000000..d8bdeb3
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) { // Called via [foo] with integer then double.
+ return a;
+}
+
+const foo = method;
+
+returnNum(x) {
+ return foo(x);
+}
+
+main() {
+ returnNum(10);
+ returnNum(10.5);
+}
+""";
+
+
+void main() {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(TEST, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var typesInferrer = compiler.typesTask.typesInferrer;
+
+ checkReturn(String name, type) {
+ var element = findElement(compiler, name);
+ Expect.equals(type,
+ typesInferrer.getReturnTypeOfElement(element).simplify(compiler),
+ name);
+ }
+
+ checkReturn('method', compiler.typesTask.numType);
+ checkReturn('returnNum', compiler.typesTask.numType);
+ }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart
new file mode 100644
index 0000000..184229a
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) { // Called only via [foo2] with a small integer.
+ return a;
+}
+
+const foo = method;
+
+returnInt() {
+ return foo(54);
+}
+
+main() {
+ returnInt();
+}
+""";
+
+
+void main() {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(TEST, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var typesInferrer = compiler.typesTask.typesInferrer;
+
+ checkArgument(String functionName, type) {
+ var functionElement = findElement(compiler, functionName);
+ var signature = functionElement.functionSignature;
+ var element = signature.requiredParameters.first;
+ Expect.equals(type,
+ typesInferrer.getTypeOfElement(element).simplify(compiler),
+ functionName);
+ }
+
+ checkArgument('method', compiler.typesTask.uint31Type);
+ }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart
new file mode 100644
index 0000000..36c988d
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart
@@ -0,0 +1,46 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) { // Called via [foo] with integer then double.
+ return a;
+}
+
+const foo = method;
+
+returnNum(x) {
+ return foo(x);
+}
+
+main() {
+ returnNum(10);
+ returnNum(10.5);
+}
+""";
+
+
+void main() {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(TEST, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var typesInferrer = compiler.typesTask.typesInferrer;
+
+ checkArgument(String functionName, type) {
+ var functionElement = findElement(compiler, functionName);
+ var signature = functionElement.functionSignature;
+ var element = signature.requiredParameters.first;
+ Expect.equals(type,
+ typesInferrer.getTypeOfElement(element).simplify(compiler),
+ functionName);
+ }
+
+ checkArgument('method', compiler.typesTask.numType);
+ checkArgument('returnNum', compiler.typesTask.numType);
+ }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart
new file mode 100644
index 0000000..46b4e83
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart
@@ -0,0 +1,45 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) { // Called only via [foo2] with a small integer.
+ return a;
+}
+
+const foo = method;
+
+returnInt() {
+ return foo(54);
+}
+
+main() {
+ returnInt();
+ method(55.2);
+}
+""";
+
+
+void main() {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(TEST, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var typesInferrer = compiler.typesTask.typesInferrer;
+
+ checkArgument(String functionName, type) {
+ var functionElement = findElement(compiler, functionName);
+ var signature = functionElement.functionSignature;
+ var element = signature.requiredParameters.first;
+ Expect.equals(type,
+ typesInferrer.getTypeOfElement(element).simplify(compiler),
+ functionName);
+ }
+
+ checkArgument('method', compiler.typesTask.numType);
+ }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart
new file mode 100644
index 0000000..7b7be1a
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart
@@ -0,0 +1,56 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method1() {
+ return 42;
+}
+
+method2(a) { // Called only via [foo2] with a small integer.
+ return a;
+}
+
+const foo1 = method1;
+const foo2 = method2;
+
+returnInt1() {
+ return foo1();
+}
+
+returnInt2() {
+ return foo2(54);
+}
+
+main() {
+ returnInt1();
+ returnInt2();
+}
+""";
+
+
+void main() {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(TEST, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var typesInferrer = compiler.typesTask.typesInferrer;
+
+ checkReturn(String name, type) {
+ var element = findElement(compiler, name);
+ Expect.equals(type,
+ typesInferrer.getReturnTypeOfElement(element).simplify(compiler),
+ name);
+ }
+
+ checkReturn('method1', compiler.typesTask.uint31Type);
+ checkReturn('returnInt1', compiler.typesTask.uint31Type);
+
+ checkReturn('method2', compiler.typesTask.uint31Type);
+ checkReturn('returnInt2', compiler.typesTask.uint31Type);
+ }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart b/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart
new file mode 100644
index 0000000..0b9510e
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) { // Called only via [foo] with a small integer.
+ return a;
+}
+
+var foo = method;
+
+returnInt() {
+ return foo(54);
+}
+
+main() {
+ returnInt();
+}
+""";
+
+
+void main() {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(TEST, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var typesInferrer = compiler.typesTask.typesInferrer;
+
+ checkArgument(String functionName, type) {
+ var functionElement = findElement(compiler, functionName);
+ var signature = functionElement.functionSignature;
+ var element = signature.requiredParameters.first;
+ Expect.equals(type,
+ typesInferrer.getTypeOfElement(element).simplify(compiler),
+ functionName);
+ }
+
+ checkArgument('method', compiler.typesTask.uint31Type);
+ }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart
new file mode 100644
index 0000000..fcfa00c9
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart
@@ -0,0 +1,56 @@
+// 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method1() {
+ return 42;
+}
+
+method2(a) { // Called only via [foo2] with a small integer.
+ return a;
+}
+
+var foo1 = method1;
+var foo2 = method2;
+
+returnInt1() {
+ return foo1();
+}
+
+returnInt2() {
+ return foo2(54);
+}
+
+main() {
+ returnInt1();
+ returnInt2();
+}
+""";
+
+
+void main() {
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(TEST, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ var typesInferrer = compiler.typesTask.typesInferrer;
+
+ checkReturn(String name, type) {
+ var element = findElement(compiler, name);
+ Expect.equals(type,
+ typesInferrer.getReturnTypeOfElement(element).simplify(compiler),
+ name);
+ }
+
+ checkReturn('method1', compiler.typesTask.uint31Type);
+ checkReturn('returnInt1', compiler.typesTask.uint31Type);
+
+ checkReturn('method2', compiler.typesTask.uint31Type);
+ checkReturn('returnInt2', compiler.typesTask.uint31Type);
+ }));
+}
diff --git a/tests/compiler/dart2js/unparser_test.dart b/tests/compiler/dart2js/unparser_test.dart
index e978f80..5409768 100644
--- a/tests/compiler/dart2js/unparser_test.dart
+++ b/tests/compiler/dart2js/unparser_test.dart
@@ -337,6 +337,8 @@
//"int this.baz(a)", // Commented out due to Issue 7852
//"int this.boz(int a,int b)=null" // Commented out due to Issue 7852
]);
+ testUnparseParameters(
+ ["@a foo", "@b @c bar=0", "@D(0) int baz", "@E([f],{g:h}) int boz=0"]);
}
testSymbolLiterals() {
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 55294d8..504e89f 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -11,6 +11,9 @@
deferred/deferred_constant_test: Fail # http://dartbug.com/11138
constant_javascript_semantics4_test: Fail, OK
+[ $compiler == dart2js && $runtime == jsshell ]
+mirror_printer_test: Pass, Slow # Issue 16473
+
[ $compiler == dart2js && $checked ]
variable_type_test/03: Fail, OK
variable_type_test/01: Fail, OK
diff --git a/tests/html/events_test.dart b/tests/html/events_test.dart
index ebb9181..3b87540 100644
--- a/tests/html/events_test.dart
+++ b/tests/html/events_test.dart
@@ -71,7 +71,16 @@
provider.forTarget(element).listen(handler);
invocationCounter = 0;
element.dispatchEvent(event);
- expect(invocationCounter, 1);
+
+ // NOTE: when run in a custom zone, the handler is wrapped
+ // The logic for html events which ensures identical handlers are added only
+ // once is therefor muted by the wrapped handlers.
+ // Hence, we get different behavior depending on the current zone.
+ if(Zone.current == Zone.ROOT) {
+ expect(invocationCounter, 1);
+ } else {
+ expect(invocationCounter, 2);
+ }
});
test('InitMouseEvent', () {
diff --git a/tests/html/html.status b/tests/html/html.status
index 0e256b0..26672d0 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -67,7 +67,6 @@
async_test: Pass, Fail # timers test fails on ie10.
indexeddb_5_test: Fail # Issue 12893
js_test: Fail # Issue 14246
-custom/constructor_calls_created_synchronously_test: Fail, Pass # Issue 16453
[ $compiler == dart2js && ( $runtime == ie9 || $runtime == ie10 ) ]
worker_api_test: Fail # IE does not support URL.createObjectURL in web workers.
@@ -174,9 +173,6 @@
xhr_cross_origin_test: Skip # Issue 12920
xhr_test/json: Fail # IE9 returns null because of unsupported type
js_test: RuntimeError # Issue 14645
-custom/mirrors_test: pass, fail # Issue 16441
-custom/constructor_calls_created_synchronously_test: pass, fail # Issue 16441
-custom/document_register_basic_test: pass, fail # Issue 16455
# IE9 Feature support statuses-
# All changes should be accompanied by platform support annotation changes.
diff --git a/tests/html/js_test.dart b/tests/html/js_test.dart
index 3d58e2d..ba5d007 100644
--- a/tests/html/js_test.dart
+++ b/tests/html/js_test.dart
@@ -186,6 +186,10 @@
return o1 === o2;
}
+var someProto = { role: "proto" };
+var someObject = Object.create(someProto);
+someObject.role = "object";
+
""";
document.body.append(script);
}
@@ -286,6 +290,17 @@
context.deleteProperty('obj');
});
+ group('caching', () {
+ test('JS->Dart', () {
+ // Test that we are not pulling cached proxy from the prototype
+ // when asking for a proxy for the object.
+ final proto = context['someProto'];
+ expect(proto['role'], equals('proto'));
+ final obj = context['someObject'];
+ expect(obj['role'], equals('object'));
+ });
+ });
+
});
group('context', () {
@@ -995,4 +1010,5 @@
});
});
+
}
diff --git a/tests/html/utils.dart b/tests/html/utils.dart
index 6e5010e..9b469b1 100644
--- a/tests/html/utils.dart
+++ b/tests/html/utils.dart
@@ -163,11 +163,6 @@
Future loadCustomElementPolyfill() {
if (!document.supportsRegister) {
- if (!MutationObserver.supported) {
- var script = new ScriptElement()
- ..src = '/packages/mutation_observer/mutation_observer.js';
- document.head.append(script);
- }
var script = new ScriptElement()
..src = '/packages/custom_element/custom-elements.debug.js';
document.head.append(script);
diff --git a/tests/isolate/capability_test.dart b/tests/isolate/capability_test.dart
new file mode 100644
index 0000000..a9d3ae6
--- /dev/null
+++ b/tests/isolate/capability_test.dart
@@ -0,0 +1,22 @@
+// 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.
+
+import "dart:isolate";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+void main() {
+ asyncStart();
+ var c1 = new Capability();
+ var c2 = new Capability();
+ Expect.notEquals(c1, c2);
+
+ var receive = new RawReceivePort();
+ receive.sendPort.send(c1);
+ receive.handler = (c3) {
+ Expect.equals(c3, c1);
+ Expect.notEquals(c3, c2);
+ asyncEnd();
+ };
+}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 0df05ed2..a753ec2 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -6,10 +6,12 @@
browser/*: SkipByDesign # Browser specific tests
isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests.
-[ $compiler == none ]
+[ $compiler == none || $compiler == dart2dart ]
serialization_test: SkipByDesign # Tests dart2js-specific serialization code
isolate_throws_test/01: Skip # Issue 12587
compile_time_error_test/01: Skip # Issue 12587
+capability_test: Fail # Not implemented yet
+pause_test: Fail
[ $compiler == dart2js && $jscl ]
browser/*: SkipByDesign # Browser specific tests
@@ -19,6 +21,7 @@
[ $compiler == dart2js ]
serialization_test: RuntimeError # Issue 1882, tries to access class TestingOnly declared in isolate_patch.dart
+pause_test: Fail
[ $compiler == dart2js && $runtime == ie9 ]
browser/typed_data_message_test: Fail # Issue 12624
@@ -39,8 +42,6 @@
[ $compiler == dart2js && $runtime == none ]
serialization_test: Pass # Issue 12628
-illegal_msg_function_test: Pass # Issue 12628
-illegal_msg_mirror_test: Pass # Issue 12628
[ $compiler == dart2js && $runtime == chromeOnAndroid ]
isolate_stress_test: Pass, Slow # TODO(kasperl): Please triage.
@@ -48,7 +49,11 @@
mandel_isolate_test: Pass, Timeout # TODO(kasperl): Please triage.
[ $compiler == dart2dart ]
-*: Skip # Issue 12629
+illegal_msg_mirror_test: RuntimeError # Issue 16548
+spawn_uri_multi_test/none: RuntimeError # Issue 16549
+spawn_uri_nested_vm_test: RuntimeError # Issue 16549
+spawn_uri_test: RuntimeError # Issue 16549
+spawn_uri_vm_test: RuntimeError # Issue 16549
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari || $runtime == drt || $runtime == chrome || $runtime == chromeOnAndroid) ]
isolate_stress_test: Pass, Slow # Issue 10697
diff --git a/tests/isolate/pause_test.dart b/tests/isolate/pause_test.dart
new file mode 100644
index 0000000..71691ad
--- /dev/null
+++ b/tests/isolate/pause_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+import "dart:isolate";
+import "dart:async";
+import "package:async_helper/async_helper.dart";
+
+isomain1(replyPort) {
+ RawReceivePort port = new RawReceivePort();
+ port.handler = (v) {
+ replyPort.send(v);
+ port.close();
+ };
+ replyPort.send(port.sendPort);
+}
+
+main(){
+ asyncStart();
+ RawReceivePort reply = new RawReceivePort();
+ Isolate isolate;
+ Capability resume;
+ var completer = new Completer(); // Completed by first reply from isolate.
+ reply.handler = completer.complete;
+ Isolate.spawn(isomain1, reply.sendPort).then((Isolate iso) {
+ isolate = iso;
+ resume = isolate.pause();
+ return completer.future;
+ }).then((echoPort) {
+ // Isolate has been created, and first response has been returned.
+ echoPort.send(24);
+ reply.handler = (v) {
+ throw "RESPONSE WHILE PAUSED?!?";
+ };
+ return new Future.delayed(const Duration(milliseconds: 250));
+ }).then((_) {
+ reply.handler = (v) {
+ if (v != 24) throw "WRONG ANSWER!";
+ reply.close();
+ asyncEnd();
+ };
+ isolate.resume(resume);
+ });
+}
diff --git a/tests/language/arithmetic_test.dart b/tests/language/arithmetic_test.dart
index 64ab133..b660960 100644
--- a/tests/language/arithmetic_test.dart
+++ b/tests/language/arithmetic_test.dart
@@ -449,6 +449,14 @@
Expect.approxEquals(1.0, sinCosSub(3.14159265 / 2.0));
}
+ // Test fix for issue 16592.
+ static void testSinCosNoUse() {
+ for (var i = 0; i < 20; i++) {
+ sin(i);
+ cos(i);
+ }
+ }
+
static mySqrt(var x) => sqrt(x);
static testSqrtDeopt() {
@@ -477,6 +485,7 @@
testSqrtDeopt();
testDoubleEquality();
testSinCos();
+ testSinCosNoUse();
}
}
}
diff --git a/tests/language/function_propagation_test.dart b/tests/language/function_propagation_test.dart
new file mode 100644
index 0000000..afb4a1c
--- /dev/null
+++ b/tests/language/function_propagation_test.dart
@@ -0,0 +1,35 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+class A {
+ int call(String str) => 499;
+}
+
+typedef int F(String str);
+
+main() {
+ var a = new A();
+ if (a is Function) {
+ Expect.isTrue(a is A);
+ } else {
+ Expect.fail("a should be a Function");
+ }
+
+ var a2 = new A();
+ if (a2 is F) {
+ Expect.isTrue(a2 is A);
+ } else {
+ Expect.fail("a2 should be an F");
+ }
+
+ Function a3 = new A();
+ // Dart2Js mistakenly assumed that Function and A couldn't be related and
+ // returned false for a is A.
+ Expect.isTrue(a3 is A);
+
+ F a4 = new A();
+ Expect.isTrue(a4 is A);
+}
diff --git a/tests/language/function_type_call_getter2_test.dart b/tests/language/function_type_call_getter2_test.dart
new file mode 100644
index 0000000..2d27ea8
--- /dev/null
+++ b/tests/language/function_type_call_getter2_test.dart
@@ -0,0 +1,49 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+class A {
+ final call = null;
+}
+
+class B {
+ get call => null;
+}
+
+class C {
+ set call(x) {}
+}
+
+typedef int F(String str);
+
+main() {
+ A a = new A();
+ B b = new B();
+ C c = new C();
+
+ final
+ Function /// 00: static type warning, dynamic type error
+ a2 = a;
+
+ final
+ F /// 01: static type warning, dynamic type error
+ a3 = a;
+
+ final
+ Function /// 02: static type warning, dynamic type error
+ b2 = b;
+
+ final
+ F /// 03: static type warning, dynamic type error
+ b3 = b;
+
+ final
+ Function /// 04: static type warning, dynamic type error
+ c2 = c;
+
+ final
+ F /// 05: static type warning, dynamic type error
+ c3 = c;
+}
diff --git a/tests/language/function_type_call_getter_test.dart b/tests/language/function_type_call_getter_test.dart
new file mode 100644
index 0000000..52ecbaa
--- /dev/null
+++ b/tests/language/function_type_call_getter_test.dart
@@ -0,0 +1,28 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+class A {
+ final call = null;
+}
+
+class B {
+ get call => null;
+}
+
+class C {
+ set call(x) {}
+}
+
+typedef int F(String str);
+
+main() {
+ Expect.isFalse(new A() is Function);
+ Expect.isFalse(new B() is Function);
+ Expect.isFalse(new C() is Function);
+ Expect.isFalse(new A() is F);
+ Expect.isFalse(new B() is F);
+ Expect.isFalse(new C() is F);
+}
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index e86eaa7..c48c244 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -24,7 +24,7 @@
assignable_expression_test/32: Fail # Issue 15471
assignable_expression_test/42: Fail # Issue 15471
-#unicode_bom_test: Fail # Issue 16314
+unicode_bom_test: Fail # Issue 16314
# Please add new failing tests before this line.
# Section below is for invalid tests.
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index 2f847f5..e2ec9f3 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -6,35 +6,31 @@
lib/_internal: Skip # Slow like a hell - timeouts.
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
-lib/_chrome/dart2js/chrome_dart2js: CompileTimeError
-lib/html/dart2js/html_dart2js: CompileTimeError
-lib/html/dartium/html_dartium: CompileTimeError
-lib/html/html_common/html_common: CompileTimeError
-lib/html/html_common/html_common_dart2js: CompileTimeError
-lib/indexed_db/dart2js/indexed_db_dart2js: CompileTimeError
-lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError
-lib/_internal/compiler/samples/compile_loop/compile_loop: CompileTimeError
-lib/_internal/compiler/samples/darttags/darttags: CompileTimeError
-lib/_internal/compiler/samples/leap/leap: CompileTimeError
-lib/_internal/compiler/samples/leap/leap_leg: CompileTimeError
-lib/_internal/compiler/samples/leap/request_cache: CompileTimeError
-lib/_internal/dartdoc/bin/dartdoc: CompileTimeError
-lib/_internal/dartdoc/lib/dartdoc: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/client-live-nav: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/client-shared: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/dropdown: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/search: CompileTimeError
-lib/_internal/dartdoc/lib/universe_serializer: CompileTimeError
-lib/_internal/pub/lib/src/command: Pass, CompileTimeError # Pass necessary, since CompileTimeError is valid for everything in that directory (not only for src/command.dart)
-lib/js/dart2js/js_dart2js: CompileTimeError
-lib/js/dartium/js_dartium: CompileTimeError
-lib/svg/dart2js/svg_dart2js: CompileTimeError
-lib/svg/dartium/svg_dartium: CompileTimeError
-lib/typed_data/dart2js/native_typed_data_dart2js: CompileTimeError
-lib/typed_data/dart2js/typed_data_dart2js: CompileTimeError
-lib/web_audio/dart2js/web_audio_dart2js: CompileTimeError
-lib/web_audio/dartium/web_audio_dartium: CompileTimeError
-lib/web_gl/dart2js/web_gl_dart2js: CompileTimeError
-lib/web_gl/dartium/web_gl_dartium: CompileTimeError
-lib/web_sql/dart2js/web_sql_dart2js: CompileTimeError
-lib/web_sql/dartium/web_sql_dartium: CompileTimeError
+lib/_chrome/dart2js/chrome_dart2js: CompileTimeError # Issue 16522
+lib/html/dart2js/html_dart2js: CompileTimeError # Issue 16522
+lib/html/dartium/html_dartium: CompileTimeError # Issue 16522
+lib/html/html_common/html_common: CompileTimeError # Issue 16522
+lib/html/html_common/html_common_dart2js: CompileTimeError # Issue 16522
+lib/indexed_db/dart2js/indexed_db_dart2js: CompileTimeError # Issue 16524
+lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError # Issue 16524
+lib/_internal/compiler/samples/compile_loop/compile_loop: CompileTimeError # Issue 16524
+lib/_internal/compiler/samples/darttags/darttags: CompileTimeError # Issue 16524
+lib/js/dart2js/js_dart2js: CompileTimeError # Issue 16524
+lib/js/dartium/js_dartium: CompileTimeError # Issue 16524
+lib/svg/dart2js/svg_dart2js: CompileTimeError # Issue 16524
+lib/svg/dartium/svg_dartium: CompileTimeError # Issue 16524
+lib/typed_data/dart2js/native_typed_data_dart2js: CompileTimeError # Issue 16524
+lib/typed_data/dart2js/typed_data_dart2js: CompileTimeError # Issue 16524
+lib/web_audio/dart2js/web_audio_dart2js: CompileTimeError # Issue 16524
+lib/web_audio/dartium/web_audio_dartium: CompileTimeError # Issue 16524
+lib/web_gl/dart2js/web_gl_dart2js: CompileTimeError # Issue 16524
+lib/web_gl/dartium/web_gl_dartium: CompileTimeError # Issue 16524
+lib/web_sql/dart2js/web_sql_dart2js: CompileTimeError # Issue 16524
+lib/web_sql/dartium/web_sql_dartium: CompileTimeError # Issue 16524
+lib/_internal/compiler/samples/jsonify/jsonify: CompileTimeError # issue 16466
+lib/_internal/compiler/implementation/mirrors/analyze: CompileTimeError # issue 16466
+lib/_internal/compiler/implementation/mirrors/dart2js_mirrors: CompileTimeError # issue 16466
+
+# Pass necessary, since CompileTimeError is valid for everything in that
+# directory (not only for src/command.dart)
+lib/_internal/pub/lib/src/command: Pass, CompileTimeError
diff --git a/tests/lib/async/future_timeout_test.dart b/tests/lib/async/future_timeout_test.dart
index cd30645..d81c87f 100644
--- a/tests/lib/async/future_timeout_test.dart
+++ b/tests/lib/async/future_timeout_test.dart
@@ -142,6 +142,7 @@
});
test("timeoutZone", () {
+ var initialZone = Zone.current;
Zone forked;
int registerCallDelta = 0;
bool callbackCalled = false;
@@ -169,7 +170,7 @@
timedOut.then(expectAsync1((v) {
expect(callbackCalled, true);
expect(registerCallDelta, 0);
- expect(Zone.current, Zone.ROOT);
+ expect(Zone.current, initialZone);
expect(v, 42);
}));
});
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index cf8e1f6..986be7e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -68,12 +68,13 @@
mirrors/method_mirror_name_test: RuntimeError # Issue 6335
mirrors/method_mirror_properties_test: RuntimeError # Issue 11861
mirrors/method_mirror_source_test : RuntimeError # Issue 6490
+mirrors/method_mirror_source_line_ending_test : RuntimeError # Issue 6490
mirrors/mirrors_test: RuntimeError # TODO(ahe): I'm working on fixing this.
mirrors/mixin_test: RuntimeError # Issue 12464
mirrors/mixin_application_test/none: RuntimeError # Issue 12464
mirrors/null_test : RuntimeError # Issue 12129
mirrors/parameter_test/none: RuntimeError # Issue 6490
-mirrors/parameter_metadata_test: CompileTimeError # Issue 10905
+mirrors/parameter_metadata_test: RuntimeError # Issue 10905
mirrors/private_symbol_test: CompileTimeError # Issue 13597
mirrors/proxy_type_test: RuntimeError # Issue 13842
mirrors/redirecting_factory_test/none: RuntimeError # Issue 6490
@@ -91,6 +92,7 @@
mirrors/variable_is_const_test/01: MissingCompileTimeError # Issue 5519
mirrors/list_constructor_test/01: RuntimeError # Issue 13523
mirrors/raw_type_test/01: RuntimeError # http://dartbug.com/6490
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16589
[ $runtime == safari ]
typed_data/setRange_2_test: Fail # Safari doesn't fully implement spec for TypedArray.set
@@ -197,6 +199,7 @@
convert/utf85_test: Skip # Issue 12029.
async/timer_isolate_test: Pass, Fail # Issue 14734
convert/json_util_test: Fail # Issue 16109
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16589
[ $compiler == dart2js ]
typed_data/typed_data_hierarchy_int64_test: RuntimeError # Issue 10275
@@ -226,6 +229,15 @@
async/timer_not_available_test: SkipByDesign # only meant to test when there is no way to implement timer (currently only in d8)
+[ $compiler == none ]
+mirrors/mirrors_reader_test: Slow, Pass
+
+[ $compiler == none && $checked ]
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16588
+
+[ $compiler == none && $runtime == dartium ]
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16626
+
[ $compiler == none && ( $runtime == drt || $runtime == dartium ) ]
async/schedule_microtask6_test: Fail # Issue 10910
mirrors/immutable_collections_test: Pass, Slow # Dartium debug uses -O0
diff --git a/tests/lib/math/random_test.dart b/tests/lib/math/random_test.dart
index 28cf084..f769efb 100644
--- a/tests/lib/math/random_test.dart
+++ b/tests/lib/math/random_test.dart
@@ -11,50 +11,91 @@
import 'dart:math';
main() {
+ checkSequence();
+ checkSeed();
+}
+
+void checkSequence() {
+ // Check the sequence of numbers generated by the random generator for a seed
+ // doesn't change unintendedly, and it agrees between implementations.
var rnd = new Random(20130307);
// Make sure we do not break the random number generation.
// If the random algorithm changes, make sure both the VM and dart2js
// generate the same new sequence.
var i = 1;
- Expect.equals( 1, rnd.nextInt(i *= 2));
- Expect.equals( 1, rnd.nextInt(i *= 2));
+ Expect.equals( 0, rnd.nextInt(i *= 2));
+ Expect.equals( 3, rnd.nextInt(i *= 2));
Expect.equals( 7, rnd.nextInt(i *= 2));
- Expect.equals( 6, rnd.nextInt(i *= 2));
- Expect.equals( 6, rnd.nextInt(i *= 2));
- Expect.equals( 59, rnd.nextInt(i *= 2));
- Expect.equals( 11, rnd.nextInt(i *= 2));
- Expect.equals( 212, rnd.nextInt(i *= 2));
+ Expect.equals( 5, rnd.nextInt(i *= 2));
+ Expect.equals( 29, rnd.nextInt(i *= 2));
Expect.equals( 17, rnd.nextInt(i *= 2));
- Expect.equals( 507, rnd.nextInt(i *= 2));
- Expect.equals( 1060, rnd.nextInt(i *= 2));
- Expect.equals( 891, rnd.nextInt(i *= 2));
- Expect.equals( 1534, rnd.nextInt(i *= 2));
- Expect.equals( 8404, rnd.nextInt(i *= 2));
- Expect.equals( 13839, rnd.nextInt(i *= 2));
- Expect.equals( 23298, rnd.nextInt(i *= 2));
- Expect.equals( 53622, rnd.nextInt(i *= 2));
- Expect.equals( 205997, rnd.nextInt(i *= 2));
- Expect.equals( 393823, rnd.nextInt(i *= 2));
- Expect.equals( 514614, rnd.nextInt(i *= 2));
- Expect.equals( 233715, rnd.nextInt(i *= 2));
- Expect.equals( 895357, rnd.nextInt(i *= 2));
- Expect.equals( 4726185, rnd.nextInt(i *= 2));
- Expect.equals( 7976427, rnd.nextInt(i *= 2));
- Expect.equals( 31792146, rnd.nextInt(i *= 2));
- Expect.equals( 35563210, rnd.nextInt(i *= 2));
- Expect.equals( 113261265, rnd.nextInt(i *= 2));
- Expect.equals( 205117298, rnd.nextInt(i *= 2));
- Expect.equals( 447729735, rnd.nextInt(i *= 2));
- Expect.equals(1072507596, rnd.nextInt(i *= 2));
- Expect.equals(2134030067, rnd.nextInt(i *= 2));
- Expect.equals( 721180690, rnd.nextInt(i *= 2));
+ Expect.equals( 104, rnd.nextInt(i *= 2));
+ Expect.equals( 199, rnd.nextInt(i *= 2));
+ Expect.equals( 408, rnd.nextInt(i *= 2));
+ Expect.equals( 362, rnd.nextInt(i *= 2));
+ Expect.equals( 995, rnd.nextInt(i *= 2));
+ Expect.equals( 2561, rnd.nextInt(i *= 2));
+ Expect.equals( 2548, rnd.nextInt(i *= 2));
+ Expect.equals( 9553, rnd.nextInt(i *= 2));
+ Expect.equals( 2628, rnd.nextInt(i *= 2));
+ Expect.equals( 42376, rnd.nextInt(i *= 2));
+ Expect.equals( 101848, rnd.nextInt(i *= 2));
+ Expect.equals( 85153, rnd.nextInt(i *= 2));
+ Expect.equals( 495595, rnd.nextInt(i *= 2));
+ Expect.equals( 647122, rnd.nextInt(i *= 2));
+ Expect.equals( 793546, rnd.nextInt(i *= 2));
+ Expect.equals( 1073343, rnd.nextInt(i *= 2));
+ Expect.equals( 4479969, rnd.nextInt(i *= 2));
+ Expect.equals( 9680425, rnd.nextInt(i *= 2));
+ Expect.equals( 28460171, rnd.nextInt(i *= 2));
+ Expect.equals( 49481738, rnd.nextInt(i *= 2));
+ Expect.equals( 9878974, rnd.nextInt(i *= 2));
+ Expect.equals( 132552472, rnd.nextInt(i *= 2));
+ Expect.equals( 210267283, rnd.nextInt(i *= 2));
+ Expect.equals( 125422442, rnd.nextInt(i *= 2));
+ Expect.equals( 226275094, rnd.nextInt(i *= 2));
+ Expect.equals(1639629168, rnd.nextInt(i *= 2));
Expect.equals(0x100000000, i);
// If max is too large expect an ArgumentError.
Expect.throws(() => rnd.nextInt(i + 1), (e) => e is ArgumentError);
rnd = new Random(6790);
- Expect.approxEquals(0.7360144236, rnd.nextDouble());
- Expect.approxEquals(0.3292339731, rnd.nextDouble());
- Expect.approxEquals(0.3489622548, rnd.nextDouble());
- Expect.approxEquals(0.9815975892, rnd.nextDouble());
+ Expect.approxEquals(0.1202733131, rnd.nextDouble());
+ Expect.approxEquals(0.5554054805, rnd.nextDouble());
+ Expect.approxEquals(0.0385160727, rnd.nextDouble());
+ Expect.approxEquals(0.2836345217, rnd.nextDouble());
+}
+
+void checkSeed() {
+ // Check that various seeds generate the expected first values.
+ // 53 significant bits, so the number is representable in JS.
+ var rawSeed = 0x19a32c640e1d71;
+ var expectations = [
+ 26007, 43006, 46458, 18610, 16413, 50455, 2164, 47399, 8859, 9732,
+ 20367, 33935, 54549, 54913, 4819, 24198, 49353, 22277, 51852, 35959,
+ 45347, 12100, 10136, 22372, 15293, 20066, 1351, 49030, 64845, 12793,
+ 50916, 55784, 43170, 27653, 34696, 1492, 50255, 9597, 45929, 2874,
+ 27629, 53084, 36064, 42140, 32016, 41751, 13967, 20516, 578, 16773,
+ 53064, 14814, 22737, 48846, 45147, 10205, 56584, 63711, 44128, 21099,
+ 47966, 35471, 39576, 1141, 45716, 54940, 57406, 15437, 31721, 35044,
+ 28136, 39797, 50801, 22184, 58686
+ ];
+ var negative_seed_expectations = [
+ 12170, 42844, 39228, 64032, 29046, 57572, 8453, 52224, 27060, 28454,
+ 20510, 28804, 59221, 53422, 11047, 50864, 33997, 19611, 1250, 65088,
+ 19690, 11396, 20, 48867, 44862, 47129, 58724, 13325, 50005, 33320,
+ 16523, 4740, 63721, 63272, 30545, 51403, 35845, 3943, 31850, 23148,
+ 26307, 1724, 29281, 39988, 43653, 48012, 43810, 16755, 13105, 25325,
+ 32648, 19958, 38838, 8322, 3421, 28624, 17269, 45385, 50680, 1696,
+ 26088, 2787, 48566, 34357, 27731, 51764, 8455, 16498, 59721, 59568,
+ 46333, 7935, 51459, 36766, 50711
+ ];
+ for (var i = 0, m = 1; i < 75; i++) {
+ Expect.equals(expectations[i], new Random(rawSeed * m).nextInt(65536));
+ Expect.equals(negative_seed_expectations[i],
+ new Random(rawSeed * -m).nextInt(65536));
+ m *= 2;
+ }
+ // And test zero seed too.
+ Expect.equals(21391, new Random(0).nextInt(65536));
}
diff --git a/tests/lib/mirrors/class_mirror_type_variables_data.dart b/tests/lib/mirrors/class_mirror_type_variables_data.dart
new file mode 100644
index 0000000..e47b96a
--- /dev/null
+++ b/tests/lib/mirrors/class_mirror_type_variables_data.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, 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 class_mirror_type_variables_data;
+
+class NoTypeParams {}
+class A<T, S extends String> {}
+class B<Z extends B<Z>> {}
+class C<Z extends B<Z>> {}
+class D<R,S,T> {
+ R foo(R r) => r;
+ S bar(S s) => s;
+ T baz(T t) => t;
+}
+class Helper<S> {}
+class E<R extends Map<R, Helper<String>>> {}
+class F<Z extends Helper<F<Z>>> {}
+
diff --git a/tests/lib/mirrors/class_mirror_type_variables_expect.dart b/tests/lib/mirrors/class_mirror_type_variables_expect.dart
new file mode 100644
index 0000000..00c5124
--- /dev/null
+++ b/tests/lib/mirrors/class_mirror_type_variables_expect.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2013, 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.
+
+// Test expectations for 'class_mirror_type_variables_data.dart'.
+
+library class_mirror_type_variables_expect;
+
+import "dart:mirrors";
+
+import "package:expect/expect.dart";
+
+
+/// The interface of [Env] is shared between the runtime and the source mirrors
+/// test.
+abstract class Env {
+ ClassMirror getA();
+ ClassMirror getB();
+ ClassMirror getC();
+ ClassMirror getD();
+ ClassMirror getE();
+ ClassMirror getF();
+ ClassMirror getNoTypeParams();
+ ClassMirror getObject();
+ ClassMirror getString();
+ ClassMirror getHelperOfString();
+}
+
+void test(Env env) {
+ testNoTypeParams(env);
+ testA(env);
+ testBAndC(env);
+ testD(env);
+ testE(env);
+ testF(env);
+}
+
+testNoTypeParams(Env env) {
+ ClassMirror cm = env.getNoTypeParams();
+ Expect.equals(cm.typeVariables.length, 0);
+}
+
+void testA(Env env) {
+ ClassMirror a = env.getA();
+ Expect.equals(2, a.typeVariables.length);
+
+ TypeVariableMirror aT = a.typeVariables[0];
+ TypeVariableMirror aS = a.typeVariables[1];
+ ClassMirror aTBound = aT.upperBound;
+ ClassMirror aSBound = aS.upperBound;
+
+ Expect.isTrue(aTBound.isOriginalDeclaration);
+ Expect.isTrue(aSBound.isOriginalDeclaration);
+
+ Expect.equals(env.getObject(), aTBound);
+ Expect.equals(env.getString(), aSBound);
+}
+
+void testBAndC(Env env) {
+ ClassMirror b = env.getB();
+ ClassMirror c = env.getC();
+
+ Expect.equals(1, b.typeVariables.length);
+ Expect.equals(1, c.typeVariables.length);
+
+ TypeVariableMirror bZ = b.typeVariables[0];
+ TypeVariableMirror cZ = c.typeVariables[0];
+ ClassMirror bZBound = bZ.upperBound;
+ ClassMirror cZBound = cZ.upperBound;
+
+ Expect.isFalse(bZBound.isOriginalDeclaration);
+ Expect.isFalse(cZBound.isOriginalDeclaration);
+
+ Expect.notEquals(bZBound, cZBound);
+ Expect.equals(b, bZBound.originalDeclaration);
+ Expect.equals(b, cZBound.originalDeclaration);
+
+ TypeMirror bZBoundTypeArgument = bZBound.typeArguments.single;
+ TypeMirror cZBoundTypeArgument = cZBound.typeArguments.single;
+ TypeVariableMirror bZBoundTypeVariable = bZBound.typeVariables.single;
+ TypeVariableMirror cZBoundTypeVariable = cZBound.typeVariables.single;
+
+ Expect.equals(b, bZ.owner);
+ Expect.equals(c, cZ.owner);
+ Expect.equals(b, bZBoundTypeVariable.owner);
+ Expect.equals(b, cZBoundTypeVariable.owner);
+ Expect.equals(b, bZBoundTypeArgument.owner);
+ Expect.equals(c, cZBoundTypeArgument.owner);
+
+ Expect.notEquals(bZ, cZ);
+ Expect.equals(bZ, bZBoundTypeArgument);
+ Expect.equals(cZ, cZBoundTypeArgument);
+ Expect.equals(bZ, bZBoundTypeVariable);
+ Expect.equals(bZ, cZBoundTypeVariable);
+}
+
+testD(Env env) {
+ ClassMirror cm = env.getD();
+ Expect.equals(3, cm.typeVariables.length);
+ var values = cm.typeVariables;
+ values.forEach((e) {
+ Expect.equals(true, e is TypeVariableMirror);
+ });
+ Expect.equals(#R, values.elementAt(0).simpleName);
+ Expect.equals(#S, values.elementAt(1).simpleName);
+ Expect.equals(#T, values.elementAt(2).simpleName);
+}
+
+void testE(Env env) {
+ ClassMirror e = env.getE();
+ TypeVariableMirror eR = e.typeVariables.single;
+ ClassMirror mapRAndHelperOfString = eR.upperBound;
+
+ Expect.isFalse(mapRAndHelperOfString.isOriginalDeclaration);
+ Expect.equals(eR, mapRAndHelperOfString.typeArguments.first);
+ Expect.equals(env.getHelperOfString(),
+ mapRAndHelperOfString.typeArguments.last);
+}
+
+void testF(Env env) {
+ ClassMirror f = env.getF();
+ TypeVariableMirror fZ = f.typeVariables[0];
+ ClassMirror fZBound = fZ.upperBound;
+ ClassMirror fZBoundTypeArgument = fZBound.typeArguments.single;
+
+ Expect.equals(1, f.typeVariables.length);
+ Expect.isFalse(fZBound.isOriginalDeclaration);
+ Expect.isFalse(fZBoundTypeArgument.isOriginalDeclaration);
+ Expect.equals(f, fZBoundTypeArgument.originalDeclaration);
+ Expect.equals(fZ, fZBoundTypeArgument.typeArguments.single);
+}
diff --git a/tests/lib/mirrors/class_mirror_type_variables_test.dart b/tests/lib/mirrors/class_mirror_type_variables_test.dart
index 51da82e..8918de7 100644
--- a/tests/lib/mirrors/class_mirror_type_variables_test.dart
+++ b/tests/lib/mirrors/class_mirror_type_variables_test.dart
@@ -6,120 +6,22 @@
import "package:expect/expect.dart";
-class NoTypeParams {}
-class A<T, S extends String> {}
-class B<Z extends B<Z>> {}
-class C<Z extends B<Z>> {}
-class D<R,S,T> {
- R foo(R r) => r;
- S bar(S s) => s;
- T baz(T t) => t;
-}
-class Helper<S> {}
-class E<R extends Map<R, Helper<String>>> {}
-class F<Z extends Helper<F<Z>>> {}
+import "class_mirror_type_variables_data.dart";
+import "class_mirror_type_variables_expect.dart";
-testNoTypeParams() {
- ClassMirror cm = reflectClass(NoTypeParams);
- Expect.equals(cm.typeVariables.length, 0);
-}
-
-void testA() {
- ClassMirror a = reflectClass(A);
- Expect.equals(2, a.typeVariables.length);
-
- TypeVariableMirror aT = a.typeVariables[0];
- TypeVariableMirror aS = a.typeVariables[1];
- ClassMirror aTBound = aT.upperBound;
- ClassMirror aSBound = aS.upperBound;
-
- Expect.isTrue(aTBound.isOriginalDeclaration);
- Expect.isTrue(aSBound.isOriginalDeclaration);
-
- Expect.equals(reflectClass(Object), aTBound);
- Expect.equals(reflectClass(String), aSBound);
-}
-
-void testBAndC() {
- ClassMirror b = reflectClass(B);
- ClassMirror c = reflectClass(C);
-
- Expect.equals(1, b.typeVariables.length);
- Expect.equals(1, c.typeVariables.length);
-
- TypeVariableMirror bZ = b.typeVariables[0];
- TypeVariableMirror cZ = c.typeVariables[0];
- ClassMirror bZBound = bZ.upperBound;
- ClassMirror cZBound = cZ.upperBound;
-
- Expect.isFalse(bZBound.isOriginalDeclaration);
- Expect.isFalse(cZBound.isOriginalDeclaration);
-
- Expect.notEquals(bZBound, cZBound);
- Expect.equals(b, bZBound.originalDeclaration);
- Expect.equals(b, cZBound.originalDeclaration);
-
- TypeMirror bZBoundTypeArgument = bZBound.typeArguments.single;
- TypeMirror cZBoundTypeArgument = cZBound.typeArguments.single;
- TypeVariableMirror bZBoundTypeVariable = bZBound.typeVariables.single;
- TypeVariableMirror cZBoundTypeVariable = cZBound.typeVariables.single;
-
- Expect.equals(b, bZ.owner);
- Expect.equals(c, cZ.owner);
- Expect.equals(b, bZBoundTypeVariable.owner);
- Expect.equals(b, cZBoundTypeVariable.owner);
- Expect.equals(b, bZBoundTypeArgument.owner);
- Expect.equals(c, cZBoundTypeArgument.owner);
-
- Expect.notEquals(bZ, cZ);
- Expect.equals(bZ, bZBoundTypeArgument);
- Expect.equals(cZ, cZBoundTypeArgument);
- Expect.equals(bZ, bZBoundTypeVariable);
- Expect.equals(bZ, cZBoundTypeVariable);
-}
-
-testD() {
- ClassMirror cm;
- cm = reflectClass(D);
- Expect.equals(3, cm.typeVariables.length);
- var values = cm.typeVariables;
- values.forEach((e) {
- Expect.equals(true, e is TypeVariableMirror);
- });
- Expect.equals(#R, values.elementAt(0).simpleName);
- Expect.equals(#S, values.elementAt(1).simpleName);
- Expect.equals(#T, values.elementAt(2).simpleName);
-}
-
-void testE() {
- ClassMirror e = reflectClass(E);
- TypeVariableMirror eR = e.typeVariables.single;
- ClassMirror mapRAndHelperOfString = eR.upperBound;
-
- Expect.isFalse(mapRAndHelperOfString.isOriginalDeclaration);
- Expect.equals(eR, mapRAndHelperOfString.typeArguments.first);
- Expect.equals(reflect(new Helper<String>()).type,
- mapRAndHelperOfString.typeArguments.last);
-}
-
-void testF() {
- ClassMirror f = reflectClass(F);
- TypeVariableMirror fZ = f.typeVariables[0];
- ClassMirror fZBound = fZ.upperBound;
- ClassMirror fZBoundTypeArgument = fZBound.typeArguments.single;
-
- Expect.equals(1, f.typeVariables.length);
- Expect.isFalse(fZBound.isOriginalDeclaration);
- Expect.isFalse(fZBoundTypeArgument.isOriginalDeclaration);
- Expect.equals(f, fZBoundTypeArgument.originalDeclaration);
- Expect.equals(fZ, fZBoundTypeArgument.typeArguments.single);
+class RuntimeEnv implements Env {
+ ClassMirror getA() => reflectClass(A);
+ ClassMirror getB() => reflectClass(B);
+ ClassMirror getC() => reflectClass(C);
+ ClassMirror getD() => reflectClass(D);
+ ClassMirror getE() => reflectClass(E);
+ ClassMirror getF() => reflectClass(F);
+ ClassMirror getNoTypeParams() => reflectClass(NoTypeParams);
+ ClassMirror getObject() => reflectClass(Object);
+ ClassMirror getString() => reflectClass(String);
+ ClassMirror getHelperOfString() => reflect(new Helper<String>()).type;
}
main() {
- testNoTypeParams();
- testA();
- testBAndC();
- testD();
- testE();
- testF();
+ test(new RuntimeEnv());
}
diff --git a/tests/lib/mirrors/declarations_type_test.dart b/tests/lib/mirrors/declarations_type_test.dart
new file mode 100644
index 0000000..7cdd20e
--- /dev/null
+++ b/tests/lib/mirrors/declarations_type_test.dart
@@ -0,0 +1,30 @@
+// 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.
+
+// Regression test for Issue 14972.
+
+library test.declarations_type;
+
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class C {}
+
+main() {
+ var classDeclarations = reflectClass(C).declarations;
+ Expect.isTrue(classDeclarations is Map<Symbol, DeclarationMirror>);
+ Expect.isTrue(classDeclarations.values is Iterable<DeclarationMirror>);
+ Expect.isTrue(classDeclarations.values.where((x) => true) is Iterable<DeclarationMirror>);
+ Expect.isFalse(classDeclarations is Map<Symbol, MethodMirror>);
+ Expect.isFalse(classDeclarations.values is Iterable<MethodMirror>);
+ Expect.isFalse(classDeclarations.values.where((x) => true) is Iterable<MethodMirror>);
+
+ var libraryDeclarations = (reflectClass(C).owner as LibraryMirror).declarations;
+ Expect.isTrue(libraryDeclarations is Map<Symbol, DeclarationMirror>);
+ Expect.isTrue(libraryDeclarations.values is Iterable<DeclarationMirror>);
+ Expect.isTrue(libraryDeclarations.values.where((x) => true) is Iterable<DeclarationMirror>);
+ Expect.isFalse(libraryDeclarations is Map<Symbol, ClassMirror>);
+ Expect.isFalse(libraryDeclarations.values is Iterable<ClassMirror>);
+ Expect.isFalse(libraryDeclarations.values.where((x) => true) is Iterable<ClassMirror>);
+}
diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_cr.dart b/tests/lib/mirrors/method_mirror_source_line_ending_cr.dart
new file mode 100755
index 0000000..851c04c
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_cr.dart
Binary files differ
diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_crlf.dart b/tests/lib/mirrors/method_mirror_source_line_ending_crlf.dart
new file mode 100755
index 0000000..bcf3e64
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_crlf.dart
@@ -0,0 +1,16 @@
+// 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.
+
+// This file is marked executable so source control will preserve the type of
+// line ending.
+
+library line_endings.crlf;
+
+oneLineCRLF(x) => x;
+multiLineCRLF(y) {
+ return y + 1;
+}
+c
+(){
+}
diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_lf.dart b/tests/lib/mirrors/method_mirror_source_line_ending_lf.dart
new file mode 100755
index 0000000..71a34c8
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_lf.dart
@@ -0,0 +1,16 @@
+// 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.
+
+// This file is marked executable so source control will preserve the type of
+// line ending.
+
+library line_endings.lf;
+
+oneLineLF(x) => x;
+multiLineLF(y) {
+ return y + 1;
+}
+a
+(){
+}
diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_test.dart b/tests/lib/mirrors/method_mirror_source_line_ending_test.dart
new file mode 100644
index 0000000..e052cc1
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_test.dart
@@ -0,0 +1,32 @@
+// 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.
+
+import "dart:mirrors";
+import "package:expect/expect.dart";
+
+import "method_mirror_source_line_ending_lf.dart";
+import "method_mirror_source_line_ending_cr.dart";
+import "method_mirror_source_line_ending_crlf.dart";
+
+main() {
+ String sourceOf(Function f) => (reflect(f) as ClosureMirror).function.source;
+
+ // Source does not cross line breaks.
+ Expect.stringEquals('oneLineLF(x) => x;', sourceOf(oneLineLF));
+ Expect.stringEquals('oneLineCR(x) => x;', sourceOf(oneLineCR));
+ Expect.stringEquals('oneLineCRLF(x) => x;', sourceOf(oneLineCRLF));
+
+ // Source includes line breaks.
+ Expect.stringEquals('multiLineLF(y) {\n return y + 1;\n}',
+ sourceOf(multiLineLF));
+ Expect.stringEquals('multiLineCR(y) {\r return y + 1;\r}',
+ sourceOf(multiLineCR));
+ Expect.stringEquals('multiLineCRLF(y) {\r\n return y + 1;\r\n}',
+ sourceOf(multiLineCRLF));
+
+ // First and last characters separated from middle by line breaks.
+ Expect.stringEquals('a\n(){\n}', sourceOf(a));
+ Expect.stringEquals('b\r(){\r}', sourceOf(b));
+ Expect.stringEquals('c\r\n(){\r\n}', sourceOf(c));
+}
diff --git a/tests/lib/mirrors/mirrors_reader.dart b/tests/lib/mirrors/mirrors_reader.dart
new file mode 100644
index 0000000..9b16f81
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_reader.dart
@@ -0,0 +1,263 @@
+// 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 LICESNE file.
+
+library mirrors.reader;
+
+import 'dart:mirrors';
+import 'mirrors_visitor.dart';
+
+class ReadError {
+ final String tag;
+ final exception;
+ final StackTrace stackTrace;
+
+ ReadError(this.tag, this.exception, this.stackTrace);
+}
+
+class MirrorsReader extends MirrorsVisitor {
+ /// Produce verbose output.
+ final bool verbose;
+ /// Include stack trace in the error report.
+ final bool includeStackTrace;
+
+ bool fatalError = false;
+ Set<Mirror> visited = new Set<Mirror>();
+ Set<TypeMirror> declarations = new Set<TypeMirror>();
+ Set<TypeMirror> instantiations = new Set<TypeMirror>();
+ List<ReadError> errors = <ReadError>[];
+ List<Mirror> queue = <Mirror>[];
+
+ MirrorsReader({this.verbose: false, this.includeStackTrace: false});
+
+ void checkMirrorSystem(MirrorSystem mirrorSystem) {
+ visitMirrorSystem(mirrorSystem);
+ if (!errors.isEmpty) {
+ Set<String> errorMessages = new Set<String>();
+ for (ReadError error in errors) {
+ String text = 'Mirrors read error: ${error.tag}=${error.exception}';
+ if (includeStackTrace) {
+ text = '$text\n${error.stackTrace}';
+ }
+ if (errorMessages.add(text)) {
+ print(text);
+ }
+ }
+ throw 'Unexpected errors occurred reading mirrors.';
+ }
+ }
+
+ // Skip mirrors so that each mirror is only visited once.
+ bool skipMirror(Mirror mirror) {
+ if (fatalError) return true;
+ if (mirror is TypeMirror) {
+ if (mirror.isOriginalDeclaration) {
+ // Visit the declation once.
+ return !declarations.add(mirror);
+ } else {
+ // Visit only one instantiation.
+ return !instantiations.add(mirror.originalDeclaration);
+ }
+ }
+ return !visited.add(mirror);
+ }
+
+ reportError(var receiver, String tag, var exception, StackTrace stackTrace) {
+ String errorTag = '${receiver.runtimeType}.$tag';
+ errors.add(new ReadError(errorTag, exception, stackTrace));
+ }
+
+ visitUnsupported(var receiver, String tag,
+ UnsupportedError exception,
+ StackTrace stackTrace) {
+ if (verbose) print('visitUnsupported:$receiver.$tag:$exception');
+ if (!expectUnsupported(receiver, tag, exception) &&
+ !allowUnsupported(receiver, tag, exception)) {
+ reportError(receiver, tag, exception, stackTrace);
+ }
+ }
+
+ /// Override to specify that access is expected to be unsupported.
+ bool expectUnsupported(var receiver, String tag,
+ UnsupportedError exception) => false;
+
+ /// Override to allow unsupported access.
+ bool allowUnsupported(var receiver, String tag,
+ UnsupportedError exception) => false;
+
+ /// Evaluates the function [f]. Subclasses can override this to handle
+ /// specific exceptions.
+ evaluate(f()) => f();
+
+ visit(var receiver, String tag, var value) {
+ if (value is Function) {
+ try {
+ var result = evaluate(value);
+ if (expectUnsupported(receiver, tag, null)) {
+ reportError(receiver, tag, 'Expected UnsupportedError.', null);
+ }
+ return visit(receiver, tag, result);
+ } on UnsupportedError catch (e, s) {
+ visitUnsupported(receiver, tag, e, s);
+ } on OutOfMemoryError catch (e, s) {
+ reportError(receiver, tag, e, s);
+ fatalError = true;
+ } on StackOverflowError catch (e, s) {
+ reportError(receiver, tag, e, s);
+ fatalError = true;
+ } catch (e, s) {
+ reportError(receiver, tag, e, s);
+ }
+ } else {
+ if (value is Mirror) {
+ if (!skipMirror(value)) {
+ if (verbose) print('visit:$receiver.$tag=$value');
+ bool drain = queue.isEmpty;
+ queue.add(value);
+ if (drain) {
+ while (!queue.isEmpty) {
+ visitMirror(queue.removeLast());
+ }
+ }
+ }
+ } else if (value is MirrorSystem) {
+ visitMirrorSystem(value);
+ } else if (value is SourceLocation) {
+ visitSourceLocation(value);
+ } else if (value is Iterable) {
+ // TODO(johnniwinther): Merge with `immutable_collections_test.dart`.
+ value.forEach((e) {
+ visit(receiver, tag, e);
+ });
+ } else if (value is Map) {
+ value.forEach((k, v) {
+ visit(receiver, tag, k);
+ visit(receiver, tag, v);
+ });
+ }
+ }
+ return value;
+ }
+
+ visitMirrorSystem(MirrorSystem mirrorSystem) {
+ visit(mirrorSystem, 'dynamicType', () => mirrorSystem.dynamicType);
+ visit(mirrorSystem, 'voidType', () => mirrorSystem.voidType);
+ visit(mirrorSystem, 'libraries', () => mirrorSystem.libraries);
+ }
+
+ visitClassMirror(ClassMirror mirror) {
+ super.visitClassMirror(mirror);
+ visit(mirror, 'declarations', () => mirror.declarations);
+ bool hasReflectedType =
+ visit(mirror, 'hasReflectedType', () => mirror.hasReflectedType);
+ visit(mirror, 'instanceMembers', () => mirror.instanceMembers);
+ visit(mirror, 'mixin', () => mirror.mixin);
+ if (hasReflectedType) {
+ visit(mirror, 'reflectedType', () => mirror.reflectedType);
+ }
+ visit(mirror, 'staticMembers', () => mirror.staticMembers);
+ visit(mirror, 'superclass', () => mirror.superclass);
+ visit(mirror, 'superinterfaces', () => mirror.superinterfaces);
+ }
+
+ visitDeclarationMirror(DeclarationMirror mirror) {
+ super.visitDeclarationMirror(mirror);
+ visit(mirror, 'isPrivate', () => mirror.isPrivate);
+ visit(mirror, 'isTopLevel', () => mirror.isTopLevel);
+ visit(mirror, 'location', () => mirror.location);
+ visit(mirror, 'metadata', () => mirror.metadata);
+ visit(mirror, 'owner', () => mirror.owner);
+ visit(mirror, 'qualifiedName', () => mirror.qualifiedName);
+ visit(mirror, 'simpleName', () => mirror.simpleName);
+ }
+
+ visitFunctionTypeMirror(FunctionTypeMirror mirror) {
+ super.visitFunctionTypeMirror(mirror);
+ visit(mirror, 'callMethod', () => mirror.callMethod);
+ visit(mirror, 'parameters', () => mirror.parameters);
+ visit(mirror, 'returnType', () => mirror.returnType);
+ }
+
+ visitInstanceMirror(InstanceMirror mirror) {
+ super.visitInstanceMirror(mirror);
+ bool hasReflectee =
+ visit(mirror, 'hasReflectee', () => mirror.hasReflectee);
+ if (hasReflectee) {
+ visit(mirror, 'reflectee', () => mirror.reflectee);
+ }
+ visit(mirror, 'type', () => mirror.type);
+ }
+
+ visitLibraryMirror(LibraryMirror mirror) {
+ super.visitLibraryMirror(mirror);
+ visit(mirror, 'declarations', () => mirror.declarations);
+ visit(mirror, 'topLevelMembers', () => mirror.topLevelMembers);
+ visit(mirror, 'uri', () => mirror.uri);
+ }
+
+ visitMethodMirror(MethodMirror mirror) {
+ super.visitMethodMirror(mirror);
+ visit(mirror, 'constructorName', () => mirror.constructorName);
+ visit(mirror, 'isAbstract', () => mirror.isAbstract);
+ visit(mirror, 'isConstConstructor', () => mirror.isConstConstructor);
+ visit(mirror, 'isConstructor', () => mirror.isConstructor);
+ visit(mirror, 'isFactoryConstructor',
+ () => mirror.isFactoryConstructor);
+ visit(mirror, 'isGenerativeConstructor',
+ () => mirror.isGenerativeConstructor);
+ visit(mirror, 'isGetter', () => mirror.isGetter);
+ visit(mirror, 'isOperator', () => mirror.isOperator);
+ visit(mirror, 'isRedirectingConstructor',
+ () => mirror.isRedirectingConstructor);
+ visit(mirror, 'isRegularMethod', () => mirror.isRegularMethod);
+ visit(mirror, 'isSetter', () => mirror.isSetter);
+ visit(mirror, 'isStatic', () => mirror.isStatic);
+ visit(mirror, 'isSynthetic', () => mirror.isSynthetic);
+ visit(mirror, 'parameters', () => mirror.parameters);
+ visit(mirror, 'returnType', () => mirror.returnType);
+ visit(mirror, 'source', () => mirror.source);
+ }
+
+ visitParameterMirror(ParameterMirror mirror) {
+ super.visitParameterMirror(mirror);
+ bool hasDefaultValue =
+ visit(mirror, 'hasDefaultValue', () => mirror.hasDefaultValue);
+ if (hasDefaultValue) {
+ visit(mirror, 'defaultValue', () => mirror.defaultValue);
+ }
+ visit(mirror, 'isNamed', () => mirror.isNamed);
+ visit(mirror, 'isOptional', () => mirror.isOptional);
+ visit(mirror, 'type', () => mirror.type);
+ }
+
+ visitSourceLocation(SourceLocation location) {
+
+ }
+
+ visitTypedefMirror(TypedefMirror mirror) {
+ super.visitTypedefMirror(mirror);
+ visit(mirror, 'referent', () => mirror.referent);
+ }
+
+ visitTypeMirror(TypeMirror mirror) {
+ super.visitTypeMirror(mirror);
+ visit(mirror, 'isOriginalDeclaration',
+ () => mirror.isOriginalDeclaration);
+ visit(mirror, 'originalDeclaration', () => mirror.originalDeclaration);
+ visit(mirror, 'typeArguments', () => mirror.typeArguments);
+ visit(mirror, 'typeVariables', () => mirror.typeVariables);
+ }
+
+ visitTypeVariableMirror(TypeVariableMirror mirror) {
+ super.visitTypeVariableMirror(mirror);
+ visit(mirror, 'upperBound', () => mirror.upperBound);
+ }
+
+ visitVariableMirror(VariableMirror mirror) {
+ super.visitVariableMirror(mirror);
+ visit(mirror, 'isConst', () => mirror.isConst);
+ visit(mirror, 'isFinal', () => mirror.isFinal);
+ visit(mirror, 'isStatic', () => mirror.isStatic);
+ visit(mirror, 'type', () => mirror.type);
+ }
+}
\ No newline at end of file
diff --git a/tests/lib/mirrors/mirrors_reader_test.dart b/tests/lib/mirrors/mirrors_reader_test.dart
new file mode 100644
index 0000000..4cd7b8c
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_reader_test.dart
@@ -0,0 +1,53 @@
+// 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.
+
+// Test that everything reachable from a [MirrorSystem] can be accessed.
+
+library test.mirrors.reader;
+
+import 'dart:mirrors';
+import 'mirrors_reader.dart';
+
+class RuntimeMirrorsReader extends MirrorsReader {
+ final String mirrorSystemType;
+
+ RuntimeMirrorsReader(MirrorSystem mirrorSystem,
+ {bool verbose: false, bool includeStackTrace: false})
+ : this.mirrorSystemType = '${mirrorSystem.runtimeType}',
+ super(verbose: verbose, includeStackTrace: includeStackTrace);
+
+ bool allowUnsupported(var receiver, String tag, UnsupportedError exception) {
+ if (mirrorSystemType == '_LocalMirrorSystem') {
+ // VM mirror system.
+ } else if (mirrorSystemType == 'JsMirrorSystem') {
+ // Dart2js runtime mirror system.
+ if (tag.endsWith('.metadata')) {
+ return true;// Issue 10905.
+ }
+ }
+ return false;
+ }
+
+ bool expectUnsupported(var receiver, String tag, UnsupportedError exception) {
+ // [DeclarationMirror.location] is intentionally not supported in runtime
+ // mirrors.
+ if (receiver is DeclarationMirror && tag == 'location') {
+ return true;
+ }
+ if (mirrorSystemType == '_LocalMirrorSystem') {
+ // VM mirror system.
+ } else if (mirrorSystemType == 'JsMirrorSystem') {
+ // Dart2js runtime mirror system.
+ }
+ return false;
+ }
+}
+
+void main([List<String> arguments = const <String>[]]) {
+ MirrorSystem mirrors = currentMirrorSystem();
+ MirrorsReader reader = new RuntimeMirrorsReader(mirrors,
+ verbose: arguments.contains('-v'),
+ includeStackTrace: arguments.contains('-s'));
+ reader.checkMirrorSystem(mirrors);
+}
diff --git a/tests/lib/mirrors/mirrors_visitor.dart b/tests/lib/mirrors/mirrors_visitor.dart
new file mode 100644
index 0000000..3eef8ee
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_visitor.dart
@@ -0,0 +1,92 @@
+// 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 mirrors.visitor;
+
+import 'dart:mirrors';
+
+abstract class MirrorsVisitor {
+ visitMirror(Mirror mirror) {
+ if (mirror == null) return;
+
+ if (mirror is FunctionTypeMirror) {
+ visitFunctionTypeMirror(mirror);
+ } else if (mirror is ClassMirror) {
+ visitClassMirror(mirror);
+ } else if (mirror is TypedefMirror) {
+ visitTypedefMirror(mirror);
+ } else if (mirror is TypeVariableMirror) {
+ visitTypeVariableMirror(mirror);
+ } else if (mirror is TypeMirror) {
+ visitTypeMirror(mirror);
+ } else if (mirror is ParameterMirror) {
+ visitParameterMirror(mirror);
+ } else if (mirror is VariableMirror) {
+ visitVariableMirror(mirror);
+ } else if (mirror is MethodMirror) {
+ visitMethodMirror(mirror);
+ } else if (mirror is LibraryMirror) {
+ visitLibraryMirror(mirror);
+ } else if (mirror is InstanceMirror) {
+ visitInstanceMirror(mirror);
+ } else if (mirror is ObjectMirror) {
+ visitObjectMirror(mirror);
+ } else if (mirror is DeclarationMirror) {
+ visitDeclarationMirror(mirror);
+ } else {
+ throw new StateError(
+ 'Unexpected mirror kind ${mirror.runtimeType}: $mirror');
+ }
+ }
+
+ visitClassMirror(ClassMirror mirror) {
+ visitObjectMirror(mirror);
+ visitTypeMirror(mirror);
+ }
+
+ visitDeclarationMirror(DeclarationMirror mirror) {
+
+ }
+
+ visitFunctionTypeMirror(FunctionTypeMirror mirror) {
+ visitClassMirror(mirror);
+ }
+
+ visitInstanceMirror(InstanceMirror mirror) {
+ visitObjectMirror(mirror);
+ }
+
+ visitLibraryMirror(LibraryMirror mirror) {
+ visitObjectMirror(mirror);
+ visitDeclarationMirror(mirror);
+ }
+
+ visitMethodMirror(MethodMirror mirror) {
+ visitDeclarationMirror(mirror);
+ }
+
+ visitObjectMirror(ObjectMirror mirror) {
+
+ }
+
+ visitParameterMirror(ParameterMirror mirror) {
+ visitVariableMirror(mirror);
+ }
+
+ visitTypedefMirror(TypedefMirror mirror) {
+ visitTypeMirror(mirror);
+ }
+
+ visitTypeMirror(TypeMirror mirror) {
+ visitDeclarationMirror(mirror);
+ }
+
+ visitTypeVariableMirror(TypeVariableMirror mirror) {
+ visitTypeMirror(mirror);
+ }
+
+ visitVariableMirror(VariableMirror mirror) {
+ visitDeclarationMirror(mirror);
+ }
+}
\ No newline at end of file
diff --git a/tests/lib/typed_data/float64x2_functional_test.dart b/tests/lib/typed_data/float64x2_functional_test.dart
new file mode 100644
index 0000000..642b42b
--- /dev/null
+++ b/tests/lib/typed_data/float64x2_functional_test.dart
@@ -0,0 +1,295 @@
+// Copyright (c) 2013, 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.
+// VMOptions=--deoptimization_counter_threshold=1000 --optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library float32x4_test;
+
+import "package:expect/expect.dart";
+import 'dart:typed_data';
+
+testConstructor() {
+ var a = new Float64x2(1.0, 2.0);
+ Expect.equals(1.0, a.x);
+ Expect.equals(2.0, a.y);
+ var b = new Float64x2.splat(1.0);
+ Expect.equals(1.0, b.x);
+ Expect.equals(1.0, b.y);
+ var c = new Float64x2.zero();
+ Expect.equals(0.0, c.x);
+ Expect.equals(0.0, c.y);
+}
+
+testCastConstructor() {
+ var a = new Float32x4(9.0, 8.0, 7.0, 6.0);
+ var b = new Float64x2.fromFloat32x4(a);
+ Expect.equals(9.0, b.x);
+ Expect.equals(8.0, b.y);
+ var c = new Float32x4.fromFloat64x2(b);
+ Expect.equals(9.0, c.x);
+ Expect.equals(8.0, c.y);
+ Expect.equals(0.0, c.z);
+ Expect.equals(0.0, c.w);
+}
+
+testLaneSetter() {
+ var a = new Float64x2.zero();
+ Expect.equals(0.0, a.x);
+ Expect.equals(0.0, a.y);
+ var b = a.withX(99.0);
+ Expect.equals(0.0, a.x);
+ Expect.equals(0.0, a.y);
+ Expect.equals(99.0, b.x);
+ Expect.equals(0.0, b.y);
+ var c = a.withY(88.0);
+ Expect.equals(0.0, a.x);
+ Expect.equals(0.0, a.y);
+ Expect.equals(0.0, c.x);
+ Expect.equals(88.0, c.y);
+ var d = c.withX(11.0);
+ Expect.equals(0.0, c.x);
+ Expect.equals(88.0, c.y);
+ Expect.equals(11.0, d.x);
+ Expect.equals(88.0, d.y);
+}
+
+testNegate() {
+ var m = new Float64x2(1.0, -2.0);
+ var o = -m;
+ Expect.equals(-1.0, o.x);
+ Expect.equals(2.0, o.y);
+}
+
+testAdd() {
+ var m = new Float64x2(1.0, -2.0);
+ var n = new Float64x2(1.0, 2.0);
+ var o = m + n;
+ Expect.equals(2.0, o.x);
+ Expect.equals(0.0, o.y);
+}
+
+testSub() {
+ var m = new Float64x2(1.0, -2.0);
+ var n = new Float64x2(1.0, 2.0);
+ var o = m - n;
+ Expect.equals(0.0, o.x);
+ Expect.equals(-4.0, o.y);
+}
+
+testMul() {
+ var m = new Float64x2(1.0, -2.0);
+ var n = new Float64x2(2.0, 2.0);
+ var o = m * n;
+ Expect.equals(2.0, o.x);
+ Expect.equals(-4.0, o.y);
+}
+
+testDiv() {
+ var m = new Float64x2(1.0, -2.0);
+ var n = new Float64x2(2.0, 2.0);
+ var o = m / n;
+ Expect.equals(0.5, o.x);
+ Expect.equals(-1.0, o.y);
+}
+
+testScale() {
+ var m = new Float64x2(1.0, 0.5);
+ var n = m.scale(2.0);
+ Expect.equals(2.0, n.x);
+ Expect.equals(1.0, n.y);
+}
+
+testAbs() {
+ var m = new Float64x2(1.0, -0.5).abs();
+ var n = new Float64x2(-2.0, 1.0).abs();
+ Expect.equals(1.0, m.x);
+ Expect.equals(0.5, m.y);
+ Expect.equals(2.0, n.x);
+ Expect.equals(1.0, n.y);
+}
+
+testClamp() {
+ var m = new Float64x2(1.0, -2.0);
+ var lo = new Float64x2(0.0, 0.0);
+ var hi = new Float64x2(2.0, 2.0);
+ m = m.clamp(lo, hi);
+ Expect.equals(1.0, m.x);
+ Expect.equals(0.0, m.y);
+}
+
+testSignMask() {
+ var m = new Float64x2(-1.0, -0.0);
+ Expect.equals(3, m.signMask);
+ m = new Float64x2(0.0, 0.0);
+ Expect.equals(0, m.signMask);
+ m = new Float64x2(-1.0, 0.0);
+ Expect.equals(1, m.signMask);
+ m = new Float64x2(1.0, -0.0);
+ Expect.equals(2, m.signMask);
+}
+
+testMin() {
+ var m = new Float64x2(0.0, -99.0);
+ var n = new Float64x2(-1.0, -1.0);
+ var o = m.min(n);
+ Expect.equals(-1.0, o.x);
+ Expect.equals(-99.0, o.y);
+}
+
+testMax() {
+ var m = new Float64x2(0.0, -99.0);
+ var n = new Float64x2(-1.0, -1.0);
+ var o = m.max(n);
+ Expect.equals(0.0, o.x);
+ Expect.equals(-1.0, o.y);
+}
+
+testSqrt() {
+ var m = new Float64x2(9.0, 16.0);
+ var o = m.sqrt();
+ Expect.equals(3.0, o.x);
+ Expect.equals(4.0, o.y);
+}
+
+testTypedList() {
+ var m = new Float64x2List(2);
+ var n = m[0];
+ Expect.equals(0.0, n.x);
+ Expect.equals(0.0, n.y);
+ n = n.withX(1.0);
+ n = n.withY(2.0);
+ m[0] = n;
+ n = n.withX(99.0);
+ Expect.equals(99.0, n.x);
+ Expect.equals(1.0, m[0].x);
+ Expect.equals(2.0, m[0].y);
+}
+
+testTypedListFromList() {
+ var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+ var m = new Float64x2List.fromList(l);
+ Expect.equals(2, m.length);
+ Expect.equals(16, m.elementSizeInBytes);
+ Expect.equals(32, m.lengthInBytes);
+ Expect.equals(1.0, m[0].x);
+ Expect.equals(2.0, m[0].y);
+ Expect.equals(3.0, m[1].x);
+ Expect.equals(4.0, m[1].y);
+}
+
+testTypedListFromTypedList() {
+ var l = new Float64x2List(2);
+ l[0] = new Float64x2(1.0, 2.0);
+ l[1] = new Float64x2(3.0, 4.0);
+ Expect.equals(2, l.length);
+ Expect.equals(16, l.elementSizeInBytes);
+ Expect.equals(32, l.lengthInBytes);
+ Expect.equals(1.0, l[0].x);
+ Expect.equals(2.0, l[0].y);
+ Expect.equals(3.0, l[1].x);
+ Expect.equals(4.0, l[1].y);
+ var m = new Float64x2List.fromList(l);
+ Expect.equals(2, m.length);
+ Expect.equals(16, m.elementSizeInBytes);
+ Expect.equals(32, m.lengthInBytes);
+ Expect.equals(2, m.length);
+ Expect.equals(1.0, m[0].x);
+ Expect.equals(2.0, m[0].y);
+ Expect.equals(3.0, m[1].x);
+ Expect.equals(4.0, m[1].y);
+}
+
+testTypedListView() {
+ var l = [1.0, 2.0, 3.0, 4.0];
+ Expect.equals(4, l.length);
+ l = new Float64List.fromList(l);
+ Expect.equals(4, l.length);
+ var m = new Float64x2List.view(l.buffer);
+ Expect.equals(2, m.length);
+ Expect.equals(1.0, m[0].x);
+ Expect.equals(2.0, m[0].y);
+ Expect.equals(3.0, m[1].x);
+ Expect.equals(4.0, m[1].y);
+}
+
+testTypedListFullView() {
+ var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+ var m = new Float64x2List.fromList(l);
+ Expect.equals(2, m.length);
+ Expect.equals(1.0, m[0].x);
+ Expect.equals(2.0, m[0].y);
+ Expect.equals(3.0, m[1].x);
+ Expect.equals(4.0, m[1].y);
+ // Create a view which spans the entire buffer.
+ var n = new Float64x2List.view(m.buffer);
+ Expect.equals(2, n.length);
+ Expect.equals(1.0, n[0].x);
+ Expect.equals(2.0, n[0].y);
+ Expect.equals(3.0, n[1].x);
+ Expect.equals(4.0, n[1].y);
+ // Create a view which spans the entire buffer by specifying length.
+ var o = new Float64x2List.view(m.buffer, 0, 2);
+ Expect.equals(2, o.length);
+ Expect.equals(1.0, o[0].x);
+ Expect.equals(2.0, o[0].y);
+ Expect.equals(3.0, o[1].x);
+ Expect.equals(4.0, o[1].y);
+}
+
+testSubList() {
+ var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+ var m = new Float64x2List.fromList(l);
+ var n = m.sublist(0, 1);
+ Expect.equals(1, n.length);
+ Expect.equals(1.0, n[0].x);
+ Expect.equals(2.0, n[0].y);
+ var o = m.sublist(1, 2);
+ Expect.equals(1, o.length);
+ Expect.equals(3.0, o[0].x);
+ Expect.equals(4.0, o[0].y);
+}
+
+testSubView() {
+ var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+ var m = new Float64x2List.fromList(l);
+ var n = new Float64x2List.view(m.buffer, 16, 1);
+ Expect.equals(1, n.length);
+ Expect.equals(16, n.offsetInBytes);
+ Expect.equals(16, n.lengthInBytes);
+ Expect.equals(3.0, n[0].x);
+ Expect.equals(4.0, n[0].y);
+ var o = new Float64x2List.view(m.buffer, 0, 1);
+ Expect.equals(1, o.length);
+ Expect.equals(0, o.offsetInBytes);
+ Expect.equals(16, o.lengthInBytes);
+ Expect.equals(1.0, o[0].x);
+ Expect.equals(2.0, o[0].y);
+}
+
+main() {
+ for (int i = 0; i < 20; i++) {
+ testConstructor();
+ testCastConstructor();
+ testLaneSetter();
+ testNegate();
+ testAdd();
+ testSub();
+ testMul();
+ testDiv();
+ testScale();
+ testAbs();
+ testClamp();
+ testSignMask();
+ testMin();
+ testMax();
+ testSqrt();
+ testTypedList();
+ testTypedListFromList();
+ testTypedListFromTypedList();
+ testTypedListView();
+ testTypedListFullView();
+ testSubList();
+ testSubView();
+ }
+}
diff --git a/tests/lib/typed_data/typed_data_load2_test.dart b/tests/lib/typed_data/typed_data_load2_test.dart
new file mode 100644
index 0000000..3775615
--- /dev/null
+++ b/tests/lib/typed_data/typed_data_load2_test.dart
@@ -0,0 +1,107 @@
+// 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.
+
+// Test that the compiler's load elimination phase sees interfering writes to
+// the array's buffer.
+
+import "dart:typed_data";
+import 'package:expect/expect.dart';
+
+aliasWithByteData1() {
+ var aa = new Int8List(10);
+ var b = new ByteData.view(aa.buffer);
+ for (int i = 0; i < aa.length; i++) aa[i] = 9;
+
+ var x1 = aa[3];
+ b.setInt8(3, 1);
+ var x2 = aa[3];
+
+ Expect.equals(9, x1);
+ Expect.equals(1, x2);
+}
+
+aliasWithByteData2() {
+ var b = new ByteData(10);
+ var aa = new Int8List.view(b.buffer);
+ for (int i = 0; i < aa.length; i++) aa[i] = 9;
+
+ var x1 = aa[3];
+ b.setInt8(3, 1);
+ var x2 = aa[3];
+
+ Expect.equals(9, x1);
+ Expect.equals(1, x2);
+}
+
+alias8x8() {
+ var buffer = new Int8List(10).buffer;
+ var a1 = new Int8List.view(buffer);
+ var a2 = new Int8List.view(buffer, 1);
+
+ for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+ // Different indexes that alias.
+ var x1 = a1[1];
+ a2[0] = 0;
+ var x2 = a1[1];
+ Expect.equals(9, x1);
+ Expect.equals(0, x2);
+
+ for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+ // Same indexes that don't alias.
+ x1 = a1[1];
+ a2[1] = 5;
+ x2 = a1[1];
+ Expect.equals(9, x1);
+ Expect.equals(9, x2);
+}
+
+alias8x16() {
+ var a1 = new Int8List(10);
+ var a2 = new Int16List.view(a1.buffer);
+
+ for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+ // Same indexes that alias.
+ var x1 = a1[0];
+ a2[0] = 0x101;
+ var x2 = a1[0];
+ Expect.equals(9, x1);
+ Expect.equals(1, x2);
+
+ for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+ // Different indexes that alias.
+ x1 = a1[4];
+ a2[2] = 0x505;
+ x2 = a1[4];
+ Expect.equals(9, x1);
+ Expect.equals(5, x2);
+
+ for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+ // Same indexes that don't alias.
+ x1 = a1[3];
+ a2[3] = 0x505;
+ x2 = a1[3];
+ Expect.equals(9, x1);
+ Expect.equals(9, x2);
+
+ for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+ // Different indexes don't alias.
+ x1 = a1[2];
+ a2[0] = 0x505;
+ x2 = a1[2];
+ Expect.equals(9, x1);
+ Expect.equals(9, x2);
+}
+
+main() {
+ aliasWithByteData1();
+ aliasWithByteData2();
+ alias8x8();
+ alias8x16();
+}
diff --git a/tests/standalone/io/file_stat_test.dart b/tests/standalone/io/file_stat_test.dart
index 28fbcc3..429d337 100644
--- a/tests/standalone/io/file_stat_test.dart
+++ b/tests/standalone/io/file_stat_test.dart
@@ -14,8 +14,10 @@
void testStat() {
Directory directory = Directory.systemTemp.createTempSync('dart_file_stat');
File file = new File(join(directory.path, "file"));
- Expect.throws(file.statSync);
- Expect.throws(() => FileStat.statSync(file.path));
+ FileStat fileStat = FileStat.statSync(file.path);
+ FileStat fileStatDirect = file.statSync();
+ Expect.equals(FileSystemEntityType.NOT_FOUND, fileStat.type);
+ Expect.equals(FileSystemEntityType.NOT_FOUND, fileStatDirect.type);
file.writeAsStringSync("Dart IO library test of FileStat");
new Timer(const Duration(seconds: 2), () {
file.readAsStringSync();
@@ -52,11 +54,11 @@
.then((directory) {
File file = new File(join(directory.path, "file"));
return FileStat.stat(file.path)
- .then((_) => Expect.fail("FileStat.stat should throw an exception."))
- .catchError((e) => null)
+ .then((fileStat) => Expect.equals(FileSystemEntityType.NOT_FOUND,
+ fileStat.type))
.then((_) => file.stat())
- .then((_) => Expect.fail("File.stat should throw an exception."))
- .catchError((e) => null)
+ .then((fileStat) => Expect.equals(FileSystemEntityType.NOT_FOUND,
+ fileStat.type))
.then((_) => file.writeAsString("Dart IO library test of FileStat"))
.then((_) => new Future.delayed(const Duration(seconds: 2)))
.then((_) => file.readAsString())
diff --git a/tests/standalone/io/file_windows_test.dart b/tests/standalone/io/file_windows_test.dart
new file mode 100644
index 0000000..f27f49f
--- /dev/null
+++ b/tests/standalone/io/file_windows_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import "package:expect/expect.dart";
+
+void testDeleteLongPathPrefix() {
+ var dir = Directory.systemTemp.createTempSync('dart_file_win');
+ var dirPath = "\\\\?\\${dir.path}";
+ var subPath = dirPath;
+ for (int i = 0; i < 16; i++) {
+ subPath += "\\a-long-path-segment";
+ dir = new Directory(subPath)..createSync();
+ }
+ Expect.isTrue(dir.path.length > 256);
+ var prefixDir = new Directory(dirPath);
+ Expect.isTrue(prefixDir.existsSync());
+ prefixDir.deleteSync(recursive: true);
+ Expect.isFalse(dir.existsSync());
+ Expect.isFalse(prefixDir.existsSync());
+}
+
+
+void main() {
+ if (!Platform.isWindows) return;
+ testDeleteLongPathPrefix();
+}
diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart
index d1d261f..7417d56 100644
--- a/tests/standalone/io/http_headers_test.dart
+++ b/tests/standalone/io/http_headers_test.dart
@@ -436,6 +436,13 @@
Expect.throws(() => new _Cookie.fromSetCookieValue("xxx"));
Expect.throws(() => new _Cookie.fromSetCookieValue(
"xxx=yyy; expires=12 jan 2013"));
+
+ _HttpHeaders headers = new _HttpHeaders("1.1");
+ headers.set('Cookie',
+ 'DARTSESSID=d3d6fdd78d51aaaf2924c32e991f4349; undefined');
+ Expect.equals('DARTSESSID', headers._parseCookies().single.name);
+ Expect.equals('d3d6fdd78d51aaaf2924c32e991f4349',
+ headers._parseCookies().single.value);
}
void testHeaderLists() {
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 6cc81d2..fc3c77b 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -9,7 +9,7 @@
package/invalid_uri_test: Fail, OK # CompileTimeErrors intentionally
-issue14236_test: Crash # Issue 14516.
+issue14236_test: Crash, RuntimeError # Issue 14516.
[ $runtime == vm ]
package/package_isolate_test: Fail # Issue 12474
diff --git a/tests/utils/source_mirrors_test.dart b/tests/utils/source_mirrors_test.dart
new file mode 100644
index 0000000..f587560
--- /dev/null
+++ b/tests/utils/source_mirrors_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2012, 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.
+// VMOptions=
+// VMOptions=--print-object-histogram
+
+// Smoke test of the dart2js compiler API.
+library source_mirrors_test;
+
+import 'dart:async';
+import "package:async_helper/async_helper.dart";
+
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
+import 'dummy_compiler_test.dart';
+
+main() {
+ asyncStart();
+ Future result =
+ analyze([new Uri(scheme: 'main')],
+ new Uri(scheme: 'lib', path: '/'),
+ new Uri(scheme: 'package', path: '/'),
+ provider, handler);
+ result.then((mirrorSystem) {
+ if (mirrorSystem == null) {
+ throw 'Analysis failed';
+ }
+ mirrorSystem.libraries.forEach((uri, library) {
+ print(library);
+ library.declarations.forEach((name, declaration) {
+ print(' $name:$declaration');
+ });
+ });
+ }, onError: (e) {
+ throw 'Analysis failed';
+ }).then(asyncSuccess);
+}
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index be55dba..1d71869 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -16,3 +16,8 @@
[ $compiler == none && $runtime == dartium ]
dart2js_test: Skip # Uses dart:io.
+[ $compiler == dartanalyzer ]
+source_mirrors_test: StaticWarning # issue 16466
+
+[ $compiler == dart2analyzer ]
+source_mirrors_test: StaticWarning # issue 16466
diff --git a/tools/VERSION b/tools/VERSION
index 6f3dbda..624a175 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 2
PATCH 0
-PRERELEASE 3
-PRERELEASE_PATCH 2
+PRERELEASE 4
+PRERELEASE_PATCH 0
diff --git a/tools/bots/bot.py b/tools/bots/bot.py
index ad0ad00..bf99227 100644
--- a/tools/bots/bot.py
+++ b/tools/bots/bot.py
@@ -151,7 +151,8 @@
try:
Clobber()
- build_step(build_info)
+ if build_step:
+ build_step(build_info)
custom_steps(build_info)
except OSError as e:
diff --git a/tools/bots/pub.py b/tools/bots/pub.py
index 73db559..dddb655 100755
--- a/tools/bots/pub.py
+++ b/tools/bots/pub.py
@@ -48,7 +48,7 @@
common_args.append('--builder-tag=%s' % build_info.builder_tag)
bot.RunTest('pub', build_info,
- common_args + ['pub', 'pkg', 'dartdoc', 'docs'])
+ common_args + ['pub', 'pkg', 'docs'])
pkgbuild_build_info = bot.BuildInfo('none', 'vm', 'release',
build_info.system, checked=False)
diff --git a/tools/bots/src-tarball.py b/tools/bots/src-tarball.py
new file mode 100644
index 0000000..3441e93
--- /dev/null
+++ b/tools/bots/src-tarball.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+
+# 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.
+
+"""
+Buildbot steps for src tarball generation and debian package generation
+
+Package up the src of the dart repo and create a debian package.
+Archive tarball and debian package to google cloud storage.
+"""
+
+import re
+import sys
+
+import bot
+
+SRC_BUILDER = r'src-tarball-linux'
+
+def SrcConfig(name, is_buildbot):
+ """Returns info for the current buildbot based on the name of the builder.
+
+ Currently, since we only run this on linux, this is just:
+ - mode: always "release"
+ - system: always "linux"
+ """
+ src_pattern = re.match(SRC_BUILDER, name)
+ if not src_pattern:
+ return None
+
+ return bot.BuildInfo('none', 'none', 'release', 'linux')
+
+def SrcSteps(build_info):
+ with bot.BuildStep('Create src tarball'):
+ args = [sys.executable, './tools/create_tarball.py']
+ print 'Building src tarball'
+ bot.RunProcess(args)
+
+if __name__ == '__main__':
+ # We pass in None for build_step to avoid building the sdk.
+ bot.RunBot(SrcConfig, SrcSteps, build_step=None)
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 2fe0851..4d12ae8 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -105,7 +105,7 @@
def CopyDartScripts(home, sdk_root):
- for executable in ['dart2js', 'dartanalyzer', 'dartdoc', 'docgen', 'pub']:
+ for executable in ['dart2js', 'dartanalyzer', 'docgen', 'pub']:
CopyShellScript(os.path.join(home, 'sdk', 'bin', executable),
os.path.join(sdk_root, 'bin'))
@@ -194,7 +194,6 @@
for library in [join('_chrome', 'dart2js'), join('_chrome', 'dartium'),
join('_internal', 'compiler'),
- join('_internal', 'dartdoc'),
join('_internal', 'lib'),
'async', 'collection', 'convert', 'core',
'crypto', 'internal', 'io', 'isolate',
@@ -236,7 +235,7 @@
join(RESOURCE, '7zip'),
ignore=ignore_patterns('.svn'))
- # Copy dart2js/dartdoc/pub.
+ # Copy dart2js/pub.
CopyDartScripts(HOME, SDK_tmp)
CopySnapshots(SNAPSHOT, SDK_tmp)
diff --git a/tools/create_tarball.py b/tools/create_tarball.py
new file mode 100755
index 0000000..71ed4a8
--- /dev/null
+++ b/tools/create_tarball.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+# Script to build a tarball of the Dart source.
+#
+# The tarball includes all the source needed to build Dart. This
+# includes source in third_party. As part of creating the tarball the
+# files used to build Debian packages are copied to a top-level debian
+# directory. This makes it easy to build Debian packages from the
+# tarball.
+#
+# For building a Debian package one need to the tarball to follow the
+# Debian naming rules upstream tar files.
+#
+# $ mv dart-XXX.tar.gz dart_XXX.orig.tar.gz
+# $ tar xf dart_XXX.orig.tar.gz
+# $ cd dart_XXX
+# $ debuild -us -uc
+
+import datetime
+import optparse
+import sys
+import tarfile
+import utils
+
+from os import listdir, makedirs
+from os.path import join, exists, split, dirname, abspath
+
+HOST_OS = utils.GuessOS()
+DART_DIR = abspath(join(__file__, '..', '..'))
+
+# TODO (16582): Remove this when the LICENSE file becomes part of
+# all checkouts.
+license = [
+ 'This license applies to all parts of Dart that are not externally',
+ 'maintained libraries. The external maintained libraries used by',
+ 'Dart are:',
+ '',
+ '7-Zip - in third_party/7zip',
+ 'JSCRE - in runtime/third_party/jscre',
+ 'Ant - in third_party/apache_ant',
+ 'args4j - in third_party/args4j',
+ 'bzip2 - in third_party/bzip2',
+ 'Commons IO - in third_party/commons-io',
+ 'Commons Lang in third_party/commons-lang',
+ 'dromaeo - in samples/third_party/dromaeo',
+ 'Eclipse - in third_party/eclipse',
+ 'gsutil - in third_party/gsutil',
+ 'Guava - in third_party/guava',
+ 'hamcrest - in third_party/hamcrest',
+ 'Httplib2 - in samples/third_party/httplib2',
+ 'JSON - in third_party/json',
+ 'JUnit - in third_party/junit',
+ 'Oauth - in samples/third_party/oauth2client',
+ 'weberknecht - in third_party/weberknecht',
+ 'fest - in third_party/fest',
+ 'mockito - in third_party/mockito',
+ '',
+ 'The libraries may have their own licenses; we recommend you read them,',
+ 'as their terms may differ from the terms below.',
+ '',
+ 'Copyright 2012, the Dart project authors. All rights reserved.',
+ 'Redistribution and use in source and binary forms, with or without',
+ 'modification, are permitted provided that the following conditions are',
+ 'met:',
+ ' * Redistributions of source code must retain the above copyright',
+ ' notice, this list of conditions and the following disclaimer.',
+ ' * Redistributions in binary form must reproduce the above',
+ ' copyright notice, this list of conditions and the following',
+ ' disclaimer in the documentation and/or other materials provided',
+ ' with the distribution.',
+ ' * Neither the name of Google Inc. nor the names of its',
+ ' contributors may be used to endorse or promote products derived',
+ ' from this software without specific prior written permission.',
+ 'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS',
+ '"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT',
+ 'LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR',
+ 'A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT',
+ 'OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,',
+ 'SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT',
+ 'LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,',
+ 'DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY',
+ 'THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT',
+ '(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE',
+ 'OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'
+]
+
+# Flags.
+verbose = False
+
+# Name of the dart directory when unpacking the tarball.
+versiondir = ''
+
+# Ignore Git/SVN files, checked-in binaries, backup files, etc..
+ignoredPaths = ['tools/testing/bin'
+ 'third_party/7zip', 'third_party/android_tools',
+ 'third_party/clang', 'third_party/d8',
+ 'third_party/firefox_jsshell']
+ignoredDirs = ['.svn', '.git']
+ignoredEndings = ['.mk', '.pyc', 'Makefile', '~']
+
+def BuildOptions():
+ result = optparse.OptionParser()
+ result.add_option("-v", "--verbose",
+ help='Verbose output.',
+ default=False, action="store_true")
+ return result
+
+def Filter(tar_info):
+ # Get the name of the file relative to the dart directory. Note the
+ # name from the TarInfo does not include a leading slash.
+ assert tar_info.name.startswith(DART_DIR[1:])
+ original_name = tar_info.name[len(DART_DIR):]
+ _, tail = split(original_name)
+ if tail in ignoredDirs:
+ return None
+ for path in ignoredPaths:
+ if original_name.startswith(path):
+ return None
+ for ending in ignoredEndings:
+ if original_name.endswith(ending):
+ return None
+ # Add the dart directory name with version. Place the debian
+ # directory one level over the rest which are placed in the
+ # directory 'dart'. This enables building the Debian packages
+ # out-of-the-box.
+ tar_info.name = join(versiondir, 'dart', original_name)
+ if verbose:
+ print 'Adding %s as %s' % (original_name, tar_info.name)
+ return tar_info
+
+def GenerateCopyright(filename):
+ license_lines = license
+ try:
+ # TODO (16582): The LICENSE file is currently not in a normal the
+ # dart checkout.
+ with open(join(DART_DIR, 'LICENSE')) as lf:
+ license_lines = lf.read().splitlines()
+ except:
+ pass
+
+ with open(filename, 'w') as f:
+ f.write('Name: dart\n')
+ f.write('Maintainer: Dart Team <misc@dartlang.org>\n')
+ f.write('Source: https://code.google.com/p/dart/\n')
+ f.write('License:\n')
+ for line in license_lines:
+ f.write(' %s\n' % line)
+
+def GenerateChangeLog(filename, version):
+ with open(filename, 'w') as f:
+ f.write('dart (%s-1) UNRELEASED; urgency=low\n' % version)
+ f.write('\n')
+ f.write(' * Generated file.\n')
+ f.write('\n')
+ f.write(' -- Dart Team <misc@dartlang.org> %s\n' %
+ datetime.datetime.utcnow().strftime('%a, %d %b %Y %X +0000'))
+
+def GenerateSvnRevision(filename, svn_revision):
+ with open(filename, 'w') as f:
+ f.write(svn_revision)
+
+
+def CreateTarball():
+ global ignoredPaths # Used for adding the output directory.
+ # Generate the name of the tarfile
+ version = utils.GetVersion()
+ global versiondir
+ versiondir = 'dart-%s' % version
+ tarname = '%s.tar.gz' % versiondir
+ debian_dir = 'tools/linux_dist_support/debian'
+ # Create the tar file in the build directory.
+ tardir = join(DART_DIR, utils.GetBuildDir(HOST_OS, HOST_OS))
+ # Don't include the build directory in the tarball.
+ ignoredPaths.append(tardir)
+ if not exists(tardir):
+ makedirs(tardir)
+ tarfilename = join(tardir, tarname)
+ print 'Creating tarball: %s' % tarfilename
+ with tarfile.open(tarfilename, mode='w:gz') as tar:
+ for f in listdir(DART_DIR):
+ tar.add(join(DART_DIR, f), filter=Filter)
+ for f in listdir(join(DART_DIR, debian_dir)):
+ tar.add(join(DART_DIR, debian_dir, f),
+ arcname='%s/debian/%s' % (versiondir, f))
+
+ with utils.TempDir() as temp_dir:
+ # Generate and add debian/copyright
+ copyright = join(temp_dir, 'copyright')
+ GenerateCopyright(copyright)
+ tar.add(copyright, arcname='%s/debian/copyright' % versiondir)
+
+ # Generate and add debian/changelog
+ change_log = join(temp_dir, 'changelog')
+ GenerateChangeLog(change_log, version)
+ tar.add(change_log, arcname='%s/debian/changelog' % versiondir)
+
+ # For bleeding_edge add the SVN_REVISION file.
+ if utils.GetChannel() == 'be':
+ svn_revision = join(temp_dir, 'SVN_REVISION')
+ GenerateSvnRevision(svn_revision, utils.GetSVNRevision())
+ tar.add(svn_revision, arcname='%s/dart/tools/SVN_REVISION' % versiondir)
+
+def Main():
+ if HOST_OS != 'linux':
+ print 'Tarball can only be created on linux'
+ return -1
+
+ # Parse the options.
+ parser = BuildOptions()
+ (options, args) = parser.parse_args()
+ if options.verbose:
+ global verbose
+ verbose = True
+
+ CreateTarball()
+
+if __name__ == '__main__':
+ sys.exit(Main())
diff --git a/tools/dom/docs/lib/docs.dart b/tools/dom/docs/lib/docs.dart
index e7c4abf..62ca836 100644
--- a/tools/dom/docs/lib/docs.dart
+++ b/tools/dom/docs/lib/docs.dart
@@ -11,7 +11,7 @@
library docs;
import '../../../../sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart';
-import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
import '../../../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
import '../../../../sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart';
@@ -93,15 +93,17 @@
var libraryJson = {};
var sortedClasses = _sortAndFilterMirrors(
- libMirror.classes.values.toList(), ignoreDocsEditable: true);
+ classesOf(libMirror.declarations).toList(), ignoreDocsEditable: true);
for (ClassMirror classMirror in sortedClasses) {
+ print(' class: $classMirror');
var classJson = {};
var sortedMembers = _sortAndFilterMirrors(
- classMirror.members.values.toList());
+ membersOf(classMirror.declarations).toList());
var membersJson = {};
for (var memberMirror in sortedMembers) {
+ print(' member: $memberMirror');
var memberDomName = domNames(memberMirror)[0];
var memberComment = _splitCommentsByNewline(
computeUntrimmedCommentAsList(memberMirror));
@@ -136,7 +138,7 @@
}
if (!libraryJson.isEmpty) {
- convertedJson.putIfAbsent(libMirror.simpleName, () =>
+ convertedJson.putIfAbsent(nameOf(libMirror), () =>
libraryJson);
}
}
@@ -182,7 +184,7 @@
if (domNameMetadata != null) {
var domNames = <String>[];
- var tags = domNameMetadata.getField('name');
+ var tags = domNameMetadata.getField(#name);
for (var s in tags.reflectee.split(',')) {
domNames.add(s.trim());
}
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index c234928..d1c9c3f 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -971,7 +971,6 @@
if requires_stack_info:
self._cpp_impl_includes.add('"ScriptArguments.h"')
- self._cpp_impl_includes.add('"ScriptCallStack.h"')
body_emitter.Emit(
'\n'
' ScriptState* currentState = DartUtilities::currentScriptState();\n'
@@ -984,10 +983,7 @@
' Dart_Handle customArgument = Dart_GetNativeArgument(args, $INDEX);\n'
' RefPtr<ScriptArguments> scriptArguments(DartUtilities::createScriptArguments(customArgument, exception));\n'
' if (!scriptArguments)\n'
- ' goto fail;\n'
- ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::createScriptCallStack());\n'
- ' if (!scriptCallStack->size())\n'
- ' return;\n',
+ ' goto fail;\n',
INDEX=len(arguments) + 1)
if requires_script_arguments:
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 2e787bd..85b4d78 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -223,13 +223,14 @@
_tryResume();
}
- void cancel() {
- if (_canceled) return;
+ Future cancel() {
+ if (_canceled) return null;
_unlisten();
// Clear out the target to indicate this is complete.
_target = null;
_onData = null;
+ return null;
}
bool get _canceled => _target == null;
diff --git a/tools/dom/src/KeyboardEventStream.dart b/tools/dom/src/KeyboardEventStream.dart
index b7e1607..520ac87 100644
--- a/tools/dom/src/KeyboardEventStream.dart
+++ b/tools/dom/src/KeyboardEventStream.dart
@@ -76,7 +76,7 @@
* KeyboardEvent controller.
*/
_KeyboardEventHandler(this._type): super(_EVENT_TYPE),
- _stream = new _CustomKeyEventStreamImpl('event');
+ _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
/**
* Hook up all event listeners under the covers so we can estimate keycodes
diff --git a/tools/dom/src/dart2js_CustomElementSupport.dart b/tools/dom/src/dart2js_CustomElementSupport.dart
index b622190..aa1c037 100644
--- a/tools/dom/src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/src/dart2js_CustomElementSupport.dart
@@ -8,6 +8,10 @@
return (receiver) {
setNativeSubclassDispatchRecord(receiver, interceptor);
+ // Mirrors uses the constructor property to cache lookups, so we need it to
+ // be set correctly, including on IE where it is not automatically picked
+ // up from the __proto__.
+ JS('', '#.constructor = #.__proto__.constructor', receiver, receiver);
return JS('', '#(#)', constructor, receiver);
};
}
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index 23d9931..d7a3fe6 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -406,7 +406,7 @@
// TODO(vsm): Move these checks into native code.
ClassMirror cls = reflectClass(type);
if (_isBuiltinType(cls)) {
- throw new UnsupportedError("Invalid custom element from $libName.");
+ throw new UnsupportedError("Invalid custom element from ${cls.owner.uri}.");
}
var className = MirrorSystem.getName(cls.simpleName);
var createdConstructor = cls.declarations[new Symbol('$className.created')];
@@ -513,6 +513,9 @@
int get length => Maps.length(this);
bool get isEmpty => Maps.isEmpty(this);
bool get isNotEmpty => Maps.isNotEmpty(this);
+ void addAll(Map<String, String> other) {
+ other.forEach((key, value) => this[key] = value);
+ }
}
final _printClosure = window.console.log;
diff --git a/tools/dom/src/shared_html.dart b/tools/dom/src/shared_html.dart
index c44effc..7c4f696 100644
--- a/tools/dom/src/shared_html.dart
+++ b/tools/dom/src/shared_html.dart
@@ -4,14 +4,16 @@
part of dart.dom.html;
-_wrapZone(callback) {
+_wrapZone(callback(arg)) {
// For performance reasons avoid wrapping if we are in the root zone.
if (Zone.current == Zone.ROOT) return callback;
+ if (callback == null) return null;
return Zone.current.bindUnaryCallback(callback, runGuarded: true);
}
-_wrapBinaryZone(callback) {
+_wrapBinaryZone(callback(arg1, arg2)) {
if (Zone.current == Zone.ROOT) return callback;
+ if (callback == null) return null;
return Zone.current.bindBinaryCallback(callback, runGuarded: true);
}
diff --git a/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate b/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate
index d04c3bb..bec16f9 100644
--- a/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate
+++ b/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate
@@ -67,11 +67,11 @@
$if DART2JS
@JSName('texSubImage2D')
void texSubImage2DUntyped(int targetTexture, int levelOfDetail,
- int internalFormat, int format, int type, data) native;
+ int xOffset, int yOffset, int format, int type, data) native;
$else
void texSubImage2DUntyped(int targetTexture, int levelOfDetail,
- int internalFormat, int format, int type, data) {
- texSubImage2D(targetTexture, levelOfDetail, internalFormat,
+ int xOffset, int yOffset, int format, int type, data) {
+ texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
format, type, data);
}
$endif
@@ -82,14 +82,14 @@
$if DART2JS
@JSName('texSubImage2D')
void texSubImage2DTyped(int targetTexture, int levelOfDetail,
- int internalFormat, int width, int height, int border, int format,
+ int xOffset, int yOffset, int width, int height, int border, int format,
int type, TypedData data) native;
$else
void texSubImage2DTyped(int targetTexture, int levelOfDetail,
- int internalFormat, int width, int height, int border, int format,
+ int xOffset, int yOffset, int width, int height, int format,
int type, TypedData data) {
- texSubImage2D(targetTexture, levelOfDetail, internalFormat,
- width, height, border, format, type, data);
+ texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
+ width, height, format, type, data);
}
$endif
}
diff --git a/tools/full-coverage.dart b/tools/full-coverage.dart
index b16f944..bafc0d1 100644
--- a/tools/full-coverage.dart
+++ b/tools/full-coverage.dart
@@ -6,7 +6,6 @@
import "dart:convert";
import "dart:io";
import "dart:isolate";
-import "dart:mirrors";
import "package:args/args.dart";
import "package:path/path.dart";
@@ -189,7 +188,7 @@
hitMap[source][line] += count;
}
- JSON.decode(rawJson).forEach((Map e) {
+ JSON.decode(rawJson)['coverage'].forEach((Map e) {
String source = resolver.resolve(e["source"]);
if (source == null) {
// Couldnt resolve import, so skip this entry.
@@ -255,58 +254,78 @@
return [new File(absPath)];
}
-worker() {
+worker(WorkMessage msg) {
final start = new DateTime.now().millisecondsSinceEpoch;
- String me = currentMirrorSystem().isolate.debugName;
- port.receive((Message message, reply) {
- if (message.type == Message.SHUTDOWN) {
- port.close();
+ var env = msg.environment;
+ List files = msg.files;
+ Resolver resolver = new Resolver(env);
+ var workerHitmap = {};
+ files.forEach((File fileEntry) {
+ // Read file sync, as it only contains 1 object.
+ String contents = fileEntry.readAsStringSync();
+ if (contents.length > 0) {
+ mergeHitmaps(createHitmap(contents, resolver), workerHitmap);
}
-
- if (message.type == Message.WORK) {
- var env = message.payload[0];
- List files = message.payload[1];
- Resolver resolver = new Resolver(env);
- var workerHitmap = {};
- files.forEach((File fileEntry) {
- // Read file sync, as it only contains 1 object.
- String contents = fileEntry.readAsStringSync();
- if (contents.length > 0) {
- mergeHitmaps(createHitmap(contents, resolver), workerHitmap);
- }
- });
- if (env["verbose"]) {
- final end = new DateTime.now().millisecondsSinceEpoch;
- print("worker[${me}]: Finished processing files. "
- "Took ${end - start} ms.");
- }
- reply.send(new Message(Message.RESULT, [workerHitmap, resolver.failed]));
- }
-
});
+
+ if (env["verbose"]) {
+ final end = new DateTime.now().millisecondsSinceEpoch;
+ print("${msg.workerName}: Finished processing ${files.length} files. "
+ "Took ${end - start} ms.");
+ }
+
+ msg.replyPort.send(new ResultMessage(workerHitmap, resolver.failed));
}
-class Message {
- static const int SHUTDOWN = 1;
- static const int RESULT = 2;
- static const int WORK = 3;
+class WorkMessage {
+ final String workerName;
+ final Map environment;
+ final List files;
+ final SendPort replyPort;
+ WorkMessage(this.workerName, this.environment, this.files, this.replyPort);
+}
- final int type;
- final payload;
-
- Message(this.type, this.payload);
+class ResultMessage {
+ final hitmap;
+ final failedResolves;
+ ResultMessage(this.hitmap, this.failedResolves);
}
final env = new Environment();
+List<List> split(List list, int nBuckets) {
+ var buckets = new List(nBuckets);
+ var bucketSize = list.length ~/ nBuckets;
+ var leftover = list.length % nBuckets;
+ var taken = 0;
+ var start = 0;
+ for (int i = 0; i < nBuckets; i++) {
+ var end = (i < leftover) ? (start + bucketSize + 1) : (start + bucketSize);
+ buckets[i] = list.sublist(start, end);
+ taken += buckets[i].length;
+ start = end;
+ }
+ if (taken != list.length) throw "Error splitting";
+ return buckets;
+}
+
+Future<ResultMessage> spawnWorker(name, environment, files) {
+ RawReceivePort port = new RawReceivePort();
+ var completer = new Completer();
+ port.handler = ((ResultMessage msg) {
+ completer.complete(msg);
+ port.close();
+ });
+ var msg = new WorkMessage(name, environment, files, port.sendPort);
+ Isolate.spawn(worker, msg);
+ return completer.future;
+}
+
main(List<String> arguments) {
parseArgs(arguments);
List files = filesToProcess(env.input);
- int filesPerWorker = files.length ~/ env.workers;
- List workerPorts = [];
- int doneCnt = 0;
List failedResolves = [];
List failedLoads = [];
@@ -321,57 +340,6 @@
print(" package-root: ${env.pkgRoot}");
}
- port.receive((Message message, reply) {
- if (message.type == Message.RESULT) {
- mergeHitmaps(message.payload[0], globalHitmap);
- failedResolves.addAll(message.payload[1]);
- doneCnt++;
- }
-
- // All workers are done. Process the data.
- if (doneCnt == env.workers) {
- workerPorts.forEach((p) => p.send(new Message(Message.SHUTDOWN, null)));
- if (env.verbose) {
- final end = new DateTime.now().millisecondsSinceEpoch;
- print("Done creating a global hitmap. Took ${end - start} ms.");
- }
-
- Future out;
- if (env.prettyPrint) {
- out = prettyPrint(globalHitmap, failedLoads);
- }
- if (env.lcov) {
- out = lcov(globalHitmap);
- }
-
- out.then((_) {
- env.output.close().then((_) {
- if (env.verbose) {
- final end = new DateTime.now().millisecondsSinceEpoch;
- print("Done flushing output. Took ${end - start} ms.");
- }
- });
- port.close();
-
- if (env.verbose) {
- if (failedResolves.length > 0) {
- print("Failed to resolve:");
- failedResolves.toSet().forEach((e) {
- print(" ${e}");
- });
- }
- if (failedLoads.length > 0) {
- print("Failed to load:");
- failedLoads.toSet().forEach((e) {
- print(" ${e}");
- });
- }
- }
-
- });
- }
- });
-
Map sharedEnv = {
"sdkRoot": env.sdkRoot,
"pkgRoot": env.pkgRoot,
@@ -379,22 +347,54 @@
};
// Create workers.
- for (var i = 1; i < env.workers; i++) {
- var p = spawnFunction(worker);
- workerPorts.add(p);
- var start = files.length - filesPerWorker;
- var end = files.length;
- var workerFiles = files.getRange(start, end).toList();
- files.removeRange(start, end);
- p.send(new Message(Message.WORK, [sharedEnv, workerFiles]), port);
- }
- // Let the last worker deal with the rest of the files (which should be only
- // off by at max (#workers - 1).
- var p = spawnFunction(worker);
- workerPorts.add(p);
- p.send(new Message(Message.WORK, [sharedEnv, files]), port.toSendPort());
+ int workerId = 0;
+ var results = split(files, env.workers).map((workerFiles) {
+ var result = spawnWorker("Worker ${workerId++}", sharedEnv, workerFiles);
+ return result.then((ResultMessage message) {
+ mergeHitmaps(message.hitmap, globalHitmap);
+ failedResolves.addAll(message.failedResolves);
+ });
+ });
- return 0;
+ Future.wait(results).then((ignore) {
+ // All workers are done. Process the data.
+ if (env.verbose) {
+ final end = new DateTime.now().millisecondsSinceEpoch;
+ print("Done creating a global hitmap. Took ${end - start} ms.");
+ }
+
+ Future out;
+ if (env.prettyPrint) {
+ out = prettyPrint(globalHitmap, failedLoads);
+ }
+ if (env.lcov) {
+ out = lcov(globalHitmap);
+ }
+
+ out.then((_) {
+ env.output.close().then((_) {
+ if (env.verbose) {
+ final end = new DateTime.now().millisecondsSinceEpoch;
+ print("Done flushing output. Took ${end - start} ms.");
+ }
+ });
+
+ if (env.verbose) {
+ if (failedResolves.length > 0) {
+ print("Failed to resolve:");
+ failedResolves.toSet().forEach((e) {
+ print(" ${e}");
+ });
+ }
+ if (failedLoads.length > 0) {
+ print("Failed to load:");
+ failedLoads.toSet().forEach((e) {
+ print(" ${e}");
+ });
+ }
+ }
+ });
+ });
}
/// Checks the validity of the provided arguments. Does not initialize actual
diff --git a/tools/line_doc_comments.dart b/tools/line_doc_comments.dart
index 855648a..5f3448c 100755
--- a/tools/line_doc_comments.dart
+++ b/tools/line_doc_comments.dart
@@ -21,10 +21,10 @@
}
var dir = new Directory(args[0]);
- dir.list(recursive: true).listen(
+ dir.list(recursive: true, followLinks: false).listen(
(entity) {
if (entity is File) {
- var file = entity.name;
+ var file = entity.path;
if (path.extension(file) != '.dart') return;
fixFile(file);
}
@@ -33,10 +33,10 @@
void fixFile(String path) {
var file = new File(path);
- file.readAsLines().transform(fixContents).chain((fixed) {
+ file.readAsLines().then(fixContents).then((fixed) {
return new File(path).writeAsString(fixed);
}).then((file) {
- print(file.name);
+ print(file.path);
});
}
@@ -54,14 +54,24 @@
line = null;
} else {
var match = blockLine.firstMatch(line);
- line = '$indent/// ${match[1]}';
+ var comment = match[1];
+ if (comment != '') {
+ line = '$indent/// $comment';
+ } else {
+ line = '$indent///';
+ }
}
} else {
// See if it's a one-line block comment like: /** Blah. */
var match = oneLineBlock.firstMatch(line);
if (match != null) {
- if (match[2] != '') {
- line = '${match[1]}/// ${match[2]}';
+ var comment = match[2];
+ if (comment != '') {
+ // Remove the extra space before the `*/`
+ if (comment.endsWith(' ')) {
+ comment = comment.substring(0, comment.length - 1);
+ }
+ line = '${match[1]}/// $comment';
} else {
line = '${match[1]}///';
}
diff --git a/tools/linux_dist_support/debian/compat b/tools/linux_dist_support/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/tools/linux_dist_support/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/tools/linux_dist_support/debian/control b/tools/linux_dist_support/debian/control
new file mode 100644
index 0000000..bc8c570
--- /dev/null
+++ b/tools/linux_dist_support/debian/control
@@ -0,0 +1,16 @@
+Source: dart
+Maintainer: Soren Gjesse <sgjesse@google.com>
+Section: misc
+Priority: optional
+Standards-Version: 3.9.2
+Build-Depends: debhelper (>= 9),
+ subversion,
+ python,
+ g++-4.6,
+ openjdk-6-jdk
+
+Package: dart
+Architecture: amd64 i386
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Dart SDK
+
diff --git a/tools/linux_dist_support/debian/dart.install b/tools/linux_dist_support/debian/dart.install
new file mode 100644
index 0000000..0ea869a
--- /dev/null
+++ b/tools/linux_dist_support/debian/dart.install
@@ -0,0 +1,2 @@
+debian/tmp/out/dart usr/lib
+
diff --git a/tools/linux_dist_support/debian/dart.links b/tools/linux_dist_support/debian/dart.links
new file mode 100644
index 0000000..30c3b93
--- /dev/null
+++ b/tools/linux_dist_support/debian/dart.links
@@ -0,0 +1,2 @@
+usr/lib/dart/bin/dart usr/bin/dart
+
diff --git a/tools/linux_dist_support/debian/rules b/tools/linux_dist_support/debian/rules
new file mode 100755
index 0000000..e733811
--- /dev/null
+++ b/tools/linux_dist_support/debian/rules
@@ -0,0 +1,51 @@
+#!/usr/bin/make -f
+export DH_VERBOSE = 1
+
+# Use DEB_BUILD_OPTIONS's parallel=n option (see Policy 4.9.1)
+ifneq (,$(findstring parallel,$(DEB_BUILD_OPTIONS)))
+PARALLEL_JOBS := $(shell echo $(DEB_BUILD_OPTIONS) | \
+ sed -e 's/.*parallel=\([0-9]\+\).*/\1/')
+else
+PARALLEL_JOBS := 1
+endif
+
+DEB_HOST_ARCH_CPU := $(shell dpkg-architecture -qDEB_HOST_ARCH_CPU)
+ifeq (amd64,$(DEB_HOST_ARCH_CPU))
+BUILD_TYPE += ReleaseX64
+else
+ifeq (i386,$(DEB_HOST_ARCH_CPU))
+BUILD_TYPE += ReleaseIA32
+else
+$(warning unsupported target arch $(DEB_HOST_ARCH_CPU) - continuing anyway)
+endif
+endif
+
+# Verbose?
+ifeq (1,$(DH_VERBOSE))
+BUILD_ARGS += V=1
+endif
+
+%:
+ dh $@
+
+override_dh_auto_clean:
+ echo $(DEB_BUILD_OPTIONS)
+ rm -fr dart/out dart/Makefile
+ find . -name *.tmp -execdir rm -f {} \;
+ find . -name *.pyc -execdir rm -f {} \;
+ find . -name *.mk -execdir rm -f {} \;
+ find . -name *.Makefile -execdir rm -f {} \;
+
+override_dh_auto_configure:
+ GYP_GENERATORS=make python dart/tools/gyp_dart.py all
+
+override_dh_auto_build:
+ make -C dart -j$(PARALLEL_JOBS) \
+ BUILDTYPE=$(BUILD_TYPE) $(BUILD_ARGS) create_sdk
+
+override_dh_auto_install:
+ mkdir -p debian/tmp/out
+ cp -R dart/out/$(BUILD_TYPE)/dart-sdk debian/tmp/out
+ mv debian/tmp/out/dart-sdk debian/tmp/out/dart
+ dh_install
+ dh_link
diff --git a/tools/linux_dist_support/debian/source/format b/tools/linux_dist_support/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/tools/linux_dist_support/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/tools/test.dart b/tools/test.dart
index 27d0370..a0f5525 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -65,10 +65,6 @@
new Path('utils/tests/css'),
new Path('utils/tests/peg'),
new Path('sdk/lib/_internal/pub'),
- // TODO(amouravski): move these to tests/ once they no longer rely on weird
- // dependencies.
- new Path('sdk/lib/_internal/dartdoc'),
- new Path('tools/dom/docs'),
];
void testConfigurations(List<Map> configurations) {
diff --git a/tools/utils.py b/tools/utils.py
index 1c460fc..49ff0b1 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -339,6 +339,14 @@
if revision:
return revision
+ # When building from tarball use tools/SVN_REVISION
+ svn_revision_file = os.path.join(DART_DIR, 'tools', 'SVN_REVISION')
+ try:
+ with open(svn_revision_file) as fd:
+ return fd.read()
+ except:
+ pass
+
# Only fail on the buildbot in case of a SVN client version mismatch.
user = GetUserName()
if user != 'chrome-bot':
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index 326cce2..a9604f5 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -21,7 +21,7 @@
import 'html_diff.dart';
// TODO(rnystrom): Use "package:" URL (#4968).
-import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
import '../../sdk/lib/_internal/compiler/implementation/filenames.dart';
import '../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
@@ -305,7 +305,7 @@
includeMdnTypeComment(type), super.getTypeComment(type));
}
- DocComment getMemberComment(MemberMirror member) {
+ DocComment getMemberComment(DeclarationMirror member) {
return _mergeDocs(
includeMdnMemberComment(member), super.getMemberComment(member));
}
@@ -360,7 +360,7 @@
MdnComment lookupMdnComment(Mirror mirror) {
if (mirror is TypeMirror) {
return includeMdnTypeComment(mirror);
- } else if (mirror is MemberMirror) {
+ } else if (mirror is MethodMirror || mirror is VariableMirror) {
return includeMdnMemberComment(mirror);
} else {
return null;
@@ -377,7 +377,7 @@
}
var typeString = '';
- if (HTML_LIBRARY_URIS.contains(type.library.uri)) {
+ if (HTML_LIBRARY_URIS.contains(getLibrary(type).uri)) {
// If it's an HTML type, try to map it to a base DOM type so we can find
// the MDN docs.
final domTypes = _diff.htmlTypesToDom[type.qualifiedName];
@@ -411,8 +411,8 @@
* Gets the MDN-scraped docs for [member], or `null` if this type isn't
* scraped from MDN.
*/
- MdnComment includeMdnMemberComment(MemberMirror member) {
- var library = findLibrary(member);
+ MdnComment includeMdnMemberComment(DeclarationMirror member) {
+ var library = getLibrary(member);
var memberString = '';
if (HTML_LIBRARY_URIS.contains(library.uri)) {
// If it's an HTML type, try to map it to a DOM type name so we can find
@@ -464,7 +464,7 @@
* Returns a link to [member], relative to a type page that may be in a
* different library than [member].
*/
- String _linkMember(MemberMirror member) {
+ String _linkMember(DeclarationMirror member) {
final typeName = member.owner.simpleName;
var memberName = '$typeName.${member.simpleName}';
if (member is MethodMirror && member.isConstructor) {
diff --git a/utils/apidoc/apidoc.gyp b/utils/apidoc/apidoc.gyp
deleted file mode 100644
index 3c41afe..0000000
--- a/utils/apidoc/apidoc.gyp
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright (c) 2012, 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.
-
-{
- 'variables' : {
- 'script_suffix%': '',
- },
- 'conditions' : [
- ['OS=="win"', {
- 'variables' : {
- 'script_suffix': '.bat',
- },
- }],
- ],
- 'targets': [
- {
- 'target_name': 'api_docs',
- 'type': 'none',
- 'dependencies': [
- '../../utils/compiler/compiler.gyp:dart2js',
- '../../runtime/dart-runtime.gyp:dart',
- '../../pkg/pkg.gyp:pkg_packages',
- ],
- 'includes': [
- '../../sdk/lib/core/corelib_sources.gypi',
- ],
- 'actions': [
- {
- 'action_name': 'run_apidoc',
- # The 'inputs' list records the files whose timestamps are
- # compared to the files listed in 'outputs'. If a file
- # 'outputs' doesn't exist or if a file in 'inputs' is newer
- # than a file in 'outputs', this action is executed. Notice
- # that the dependencies listed above has nothing to do with
- # when this action is executed. You must list a file in
- # 'inputs' to make sure that it exists before the action is
- # executed, or to make sure this action is re-run.
- #
- # We want to build the platform documentation whenever
- # dartdoc, apidoc, or its dependency changes. This prevents
- # people from accidentally breaking apidoc when making
- # changes to the platform libraries and or when modifying
- # dart2js or the VM.
- #
- # In addition, we want to make sure that the platform
- # documentation is regenerated when the platform sources
- # changes.
- #
- # So we want this action to be re-run when a dart file
- # changes in this directory, or in the SDK library (we may
- # no longer need to list the files in ../../runtime/lib and
- # ../../runtime/bin, as most of them has moved to
- # ../../sdk/lib).
- #
- # In addition, we want to make sure the documentation is
- # regenerated when a resource file (CSS, PNG, etc) is
- # updated. This is because these files are also copied to
- # the output directory.
- 'inputs': [
- '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
- '<(SHARED_INTERMEDIATE_DIR)/utils_wrapper.dart.snapshot',
- '<!@(["python", "../../tools/list_files.py", "\\.(css|ico|js|json|png|sh|txt|yaml|py)$", ".", "../../sdk/lib/_internal/dartdoc"])',
- '<!@(["python", "../../tools/list_files.py", "\\.dart$", ".", "../../sdk/lib", "../../runtime/lib", "../../runtime/bin"])',
- '../../sdk/bin/dart',
- '../../sdk/bin/dart.bat',
- '../../sdk/bin/dart2js',
- '../../sdk/bin/dart2js.bat',
- '../../tools/only_in_release_mode.py',
- ],
- 'outputs': [
- '<(PRODUCT_DIR)/api_docs/index.html',
- '<(PRODUCT_DIR)/api_docs/client-static.js',
- ],
- 'action': [
- 'python',
- '../../tools/only_in_release_mode.py',
- '<@(_outputs)',
- '--',
- '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
- '--package-root=<(PRODUCT_DIR)/packages/',
- 'apidoc.dart',
- '--out=<(PRODUCT_DIR)/api_docs',
- '--version=<!@(["python", "../../tools/print_version.py"])',
- '--package-root=<(PRODUCT_DIR)/packages',
- '--mode=static',
- '--exclude-lib=analyzer',
- '--exclude-lib=async_helper',
- '--exclude-lib=barback',
- '--exclude-lib=browser',
- '--exclude-lib=dartdoc',
- '--exclude-lib=docgen',
- '--exclude-lib=expect',
- '--exclude-lib=oauth2',
- '--exclude-lib=scheduled_test',
- '--exclude-lib=stack_trace',
- '--exclude-lib=watcher',
- '--exclude-lib=webdriver',
- '--exclude-lib=yaml',
- '--include-lib=matcher',
- '--extra-lib=pkg/unittest/lib/mock.dart',
- ],
- 'message': 'Running apidoc: <(_action)',
- },
- ],
- }
- ],
-}
diff --git a/utils/apidoc/docgen.gyp b/utils/apidoc/docgen.gyp
index 51889c0..d57e9c3 100644
--- a/utils/apidoc/docgen.gyp
+++ b/utils/apidoc/docgen.gyp
@@ -21,7 +21,6 @@
'../../utils/compiler/compiler.gyp:dart2js',
'../../runtime/dart-runtime.gyp:dart',
'../../pkg/pkg.gyp:pkg_packages',
- 'apidoc.gyp:api_docs',
],
'includes': [
'../../sdk/lib/core/corelib_sources.gypi',
@@ -66,9 +65,6 @@
'../../sdk/bin/docgen',
'../../sdk/bin/docgen.bat',
'../../tools/only_in_release_mode.py',
- # We sit inside the api_docs directory, so make sure it has run
- # before we do. Otherwise it might run later and delete us.
- '<(PRODUCT_DIR)/api_docs/index.html',
],
'outputs': [
'<(PRODUCT_DIR)/api_docs/docgen/index.json',
@@ -78,7 +74,9 @@
'../../tools/only_in_release_mode.py',
'<@(_outputs)',
'--',
- '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart-sdk/bin/docgen<(script_suffix)',
+ '../../sdk/bin/dart',
+ '--package-root=<(PRODUCT_DIR)/packages',
+ '../../pkg/docgen/bin/docgen.dart',
'--out=<(PRODUCT_DIR)/api_docs/docgen',
'--json',
'--include-sdk',
diff --git a/utils/apidoc/html_diff.dart b/utils/apidoc/html_diff.dart
index 45ae9dd..85c49c9 100644
--- a/utils/apidoc/html_diff.dart
+++ b/utils/apidoc/html_diff.dart
@@ -9,17 +9,14 @@
library html_diff;
import 'dart:async';
-import 'dart:io';
import 'lib/metadata.dart';
// TODO(rnystrom): Use "package:" URL (#4968).
-import '../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
-import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
import '../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
-import '../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
-import '../../sdk/lib/html/html_common/metadata.dart';
// TODO(amouravski): There is currently magic that looks at dart:* libraries
// rather than the declared library names. This changed due to recent syntax
@@ -103,15 +100,15 @@
warn('Could not find $libraryUri');
result.complete(false);
}
- for (ClassMirror type in library.classes.values) {
+ for (ClassMirror type in classesOf(library.declarations)) {
final domTypes = htmlToDomTypes(type);
if (domTypes.isEmpty) continue;
- htmlTypesToDom.putIfAbsent(type.qualifiedName,
+ htmlTypesToDom.putIfAbsent(qualifiedNameOf(type),
() => new Set()).addAll(domTypes);
- type.members.forEach(
- (_, m) => _addMemberDiff(m, domTypes, library.simpleName));
+ membersOf(type.declarations).forEach(
+ (m) => _addMemberDiff(m, domTypes, nameOf(library)));
}
}
result.complete(true);
@@ -125,7 +122,7 @@
* `@DomName` type values that correspond to [htmlMember]'s
* defining type.
*/
- void _addMemberDiff(MemberMirror htmlMember, List<String> domTypes,
+ void _addMemberDiff(DeclarationMirror htmlMember, List<String> domTypes,
String libraryName) {
var domMembers = htmlToDomMembers(htmlMember, domTypes);
if (htmlMember == null && !domMembers.isEmpty) {
@@ -137,7 +134,7 @@
if (htmlMember == null) return;
if (!domMembers.isEmpty) {
- htmlToDom[htmlMember.qualifiedName] = domMembers;
+ htmlToDom[qualifiedNameOf(htmlMember)] = domMembers;
}
}
@@ -152,7 +149,7 @@
final domNameMetadata = findMetadata(htmlType.metadata, 'DomName');
if (domNameMetadata != null) {
var domNames = <String>[];
- var names = domNameMetadata.getField('name');
+ var names = domNameMetadata.getField(symbolOf('name'));
for (var s in names.reflectee.split(',')) {
domNames.add(s.trim());
}
@@ -170,13 +167,14 @@
* `@DomName` type values that correspond to [htmlMember]'s
* defining type.
*/
- Set<String> htmlToDomMembers(MemberMirror htmlMember, List<String> domTypes) {
+ Set<String> htmlToDomMembers(DeclarationMirror htmlMember,
+ List<String> domTypes) {
if (htmlMember.isPrivate) return new Set();
final domNameMetadata = findMetadata(htmlMember.metadata, 'DomName');
if (domNameMetadata != null) {
var domNames = <String>[];
- var names = domNameMetadata.getField('name');
+ var names = domNameMetadata.getField(symbolOf('name'));
for (var s in names.reflectee.split(',')) {
domNames.add(s.trim());
}
diff --git a/utils/apidoc/lib/metadata.dart b/utils/apidoc/lib/metadata.dart
index c0a848c..2881bc1 100644
--- a/utils/apidoc/lib/metadata.dart
+++ b/utils/apidoc/lib/metadata.dart
@@ -1,14 +1,15 @@
library metadata;
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
/// Returns the metadata for the given string or null if not found.
InstanceMirror findMetadata(List<InstanceMirror> metadataList, String find) {
return metadataList.firstWhere(
(metadata) {
if (metadata is TypeInstanceMirror) {
- return metadata.representedType.simpleName == find;
+ return nameOf(metadata.representedType) == find;
}
- return metadata.type.simpleName == find;
+ return nameOf(metadata.type) == find;
}, orElse: () => null);
}
diff --git a/utils/compiler/compiler.gyp b/utils/compiler/compiler.gyp
index 4f4ae14..fc4b1cf 100644
--- a/utils/compiler/compiler.gyp
+++ b/utils/compiler/compiler.gyp
@@ -34,7 +34,6 @@
'create_snapshot.dart',
'--output_dir=<(SHARED_INTERMEDIATE_DIR)',
'--dart2js_main=sdk/lib/_internal/compiler/implementation/dart2js.dart',
- '--dartdoc_main=sdk/lib/_internal/dartdoc/bin/dartdoc.dart',
'--docgen_main=pkg/docgen/bin/docgen.dart',
'--package_root=<(PRODUCT_DIR)/packages/',
],
diff --git a/utils/compiler/create_snapshot.dart b/utils/compiler/create_snapshot.dart
index f5f3b95..0123792 100644
--- a/utils/compiler/create_snapshot.dart
+++ b/utils/compiler/create_snapshot.dart
@@ -18,13 +18,11 @@
Future<String> getSnapshotGenerationFile(var args, var rootPath) {
var dart2js = rootPath.resolve(args["dart2js_main"]);
- var dartdoc = rootPath.resolve(args["dartdoc_main"]);
var docgen = rootPath.resolve(args["docgen_main"]);
return getVersion(rootPath).then((version) {
var snapshotGenerationText =
"""
import '${dart2js.toFilePath(windows: false)}' as dart2jsMain;
-import '${dartdoc.toFilePath(windows: false)}' as dartdocMain;
import '${docgen.toFilePath(windows: false)}' as docgenMain;
import 'dart:io';
@@ -34,8 +32,6 @@
if (tool == "dart2js") {
dart2jsMain.BUILD_ID = "$version";
dart2jsMain.main(arguments.skip(1).toList());
- } else if (tool == "dartdoc") {
- dartdocMain.main(arguments.skip(1).toList());
} else if (tool == "docgen") {
docgenMain.main(arguments.skip(1).toList());
}
@@ -88,12 +84,11 @@
* Takes the following arguments:
* --output_dir=val The full path to the output_dir.
* --dart2js_main=val The path to the dart2js main script relative to root.
- * --dartdoc_main=val The path to the dartdoc main script relative to root.
* --docgen_main=val The path to the docgen main script relative to root.
* --package-root=val The package-root used to find packages for the snapshot.
*/
void main(List<String> arguments) {
- var validArguments = ["--output_dir", "--dart2js_main", "--dartdoc_main",
+ var validArguments = ["--output_dir", "--dart2js_main",
"--docgen_main", "--package_root"];
var args = {};
for (var argument in arguments) {
@@ -105,7 +100,6 @@
args[argumentSplit[0].substring(2)] = argumentSplit[1];
}
if (!args.containsKey("dart2js_main")) throw "Please specify dart2js_main";
- if (!args.containsKey("dartdoc_main")) throw "Please specify dartdoc_main";
if (!args.containsKey("docgen_main")) throw "Please specify docgen_main";
if (!args.containsKey("output_dir")) throw "Please specify output_dir";
if (!args.containsKey("package_root")) throw "Please specify package_root";