Version 0.4.3.0 .
svn merge -r 20113:20419 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 20422 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@20424 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/.gitignore b/.gitignore
index 894d9fa..293bd10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,7 +42,6 @@
# Compiled python binaries
*.pyc
-third_party/gsutil/*/gsutilc
# From the Mac OS X Finder
.DS_Store
diff --git a/client/tools/buildbot_annotated_steps.py b/client/tools/buildbot_annotated_steps.py
index 4ed1ada..c424255 100755
--- a/client/tools/buildbot_annotated_steps.py
+++ b/client/tools/buildbot_annotated_steps.py
@@ -1,9 +1,8 @@
+#!/usr/bin/python
# 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.
-#!/usr/bin/python
-
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -100,12 +99,6 @@
# get the latest changed revision from the current repository sub-tree
version = GetLatestChangedRevision()
- #TODO: debug statements to be removed in the future.
- print "mode = " + mode
- print "name = " + name
- print "version = " + version
- print "toolsBuildScript = " + os.path.abspath(toolsBuildScript)
-
utils = GetUtils()
outdir = GetOutDir(utils, mode)
cmds = [sys.executable, toolsBuildScript,
@@ -140,9 +133,11 @@
if buildbot_javahome:
current_pwd = os.getenv('PWD')
java_home = os.path.join(current_pwd, buildbot_javahome)
+ java_bin = os.path.join(java_home, 'bin')
os.environ['JAVA_HOME'] = java_home
- print 'Setting java home to'
- print java_home
+ os.environ['PATH'] = '%s;%s' % (java_bin, os.environ['PATH'])
+
+ print 'Setting java home to ', java_home
sys.stdout.flush()
def ClobberBuilder():
@@ -184,8 +179,6 @@
return svnRev
def main():
- print 'main'
-
if len(sys.argv) == 0:
print 'Script pathname not known, giving up.'
return 1
@@ -208,7 +201,18 @@
# root directory, set JAVA_HOME based on that.
FixJavaHome()
if name.startswith('dart-editor'):
+ # TODO(kustermann,ricow): This is a temporary hack until we can safely
+ # enable it on main waterfall. We need to remove this eventually
+ is_fyi = False
+ if name.startswith('dart-editor-fyi'):
+ match = re.search('dart-editor-fyi(.*)', name)
+ name = 'dart-editor' + match.group(1)
+ is_fyi = True
+ # Run the old annotated steps script first.
status = ProcessTools('release', name, version)
+ # In case we're an FYI builder, run 'tools/bots/editor.py' as well
+ if is_fyi:
+ status = ProcessBot(name, 'editor') or status
elif name.startswith('pub-'):
status = ProcessBot(name, 'pub')
elif name.startswith('vm-android'):
diff --git a/dart.gyp b/dart.gyp
index 860d4464..7f5ec30 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -133,6 +133,44 @@
],
},
{
+ 'target_name': 'editor',
+ 'type': 'none',
+ 'dependencies': [
+ 'editor/build/generated/editor_deps.gyp:editor_deps',
+
+ # This dependency on create_sdk does not mean that the Editor
+ # is rebuilt if the SDK is. It only means that when you build
+ # the Editor, you should also build the SDK. If we wanted to
+ # make sure that the editor is rebuilt when the SDK is, we
+ # should list a *file* in PRODUCT_DIR which the action below
+ # uses as input.
+ # This is the desired behavior as we would otherwise have to
+ # rebuild the editor each time the VM, dart2js, or library
+ # code changes.
+ 'create_sdk',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'create_editor_py',
+ 'inputs': [
+ 'tools/create_editor.py',
+ '<(SHARED_INTERMEDIATE_DIR)/editor_deps/editor.stamp',
+ '<!@(["python", "tools/list_files.py", "", "editor/tools/features/com.google.dart.tools.deploy.feature_releng"])',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/editor/VERSION',
+ ],
+ 'action': [
+ 'python',
+ 'tools/create_editor.py',
+ '--out', '<(PRODUCT_DIR)/editor',
+ '--build', '<(INTERMEDIATE_DIR)',
+ ],
+ 'message': 'Creating editor.',
+ },
+ ],
+ },
+ {
'target_name': 'samples',
'type': 'none',
'dependencies': [
diff --git a/pkg/analyzer_experimental/example/resolver_driver.dart b/pkg/analyzer_experimental/example/resolver_driver.dart
new file mode 100644
index 0000000..e1bcd68
--- /dev/null
+++ b/pkg/analyzer_experimental/example/resolver_driver.dart
@@ -0,0 +1,60 @@
+#!/usr/bin/env dart
+
+// 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:analyzer_experimental/src/generated/java_io.dart';
+import 'package:analyzer_experimental/src/generated/source_io.dart';
+import 'package:analyzer_experimental/src/generated/ast.dart';
+import 'package:analyzer_experimental/src/generated/sdk.dart';
+import 'package:analyzer_experimental/src/generated/element.dart';
+import 'package:analyzer_experimental/src/generated/engine.dart';
+
+import 'dart:io';
+
+main() {
+ print('working dir ${new File('.').fullPathSync()}');
+
+ var args = new Options().arguments;
+ if (args.length != 2) {
+ print('Usage: resolve_driver [path_to_sdk] [file_to_resolve]');
+ exit(0);
+ }
+
+ JavaSystemIO.setProperty("com.google.dart.sdk", args[0]);
+ DartSdk sdk = DartSdk.defaultSdk;
+
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ context.sourceFactory = new SourceFactory.con2([new DartUriResolver(sdk), new FileUriResolver()]);
+ Source source = new FileBasedSource.con1(context.sourceFactory, new JavaFile(args[1]));
+ //
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.added(source);
+ context.applyChanges(changeSet);
+ LibraryElement libElement = context.getLibraryElement(source);
+ print("libElement: $libElement");
+
+ CompilationUnit resolvedUnit = context.resolve(source, libElement);
+ var visitor = new _ASTVisitor();
+ resolvedUnit.accept(visitor);
+}
+
+class _ASTVisitor extends GeneralizingASTVisitor {
+ visitNode(ASTNode node) {
+ String text = '${node.runtimeType} : <"${node.toString()}">';
+ if (node is SimpleIdentifier) {
+ Element element = node.element;
+ if (element != null) {
+ text += " element: ${element.runtimeType}";
+ LibraryElement library = element.library;
+ if (library != null) {
+ text += " from ${element.library.definingCompilationUnit.source.fullName}";
+ }
+ }
+ }
+ print(text);
+ return super.visitNode(node);
+ }
+}
+
diff --git a/pkg/analyzer_experimental/lib/src/generated/ast.dart b/pkg/analyzer_experimental/lib/src/generated/ast.dart
index b47c576..931fa95 100644
--- a/pkg/analyzer_experimental/lib/src/generated/ast.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/ast.dart
@@ -7415,7 +7415,7 @@
* Return {@code true} if this method is declared to be an abstract method.
* @return {@code true} if this method is declared to be an abstract method
*/
- bool isAbstract() => _modifierKeyword != null && identical(((_modifierKeyword as KeywordToken)).keyword, Keyword.ABSTRACT);
+ bool isAbstract() => _externalKeyword == null && (_body is EmptyFunctionBody);
/**
* Return {@code true} if this method declares a getter.
* @return {@code true} if this method declares a getter
diff --git a/pkg/analyzer_experimental/lib/src/generated/constant.dart b/pkg/analyzer_experimental/lib/src/generated/constant.dart
index 93ddccb..9e82ce9 100644
--- a/pkg/analyzer_experimental/lib/src/generated/constant.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/constant.dart
@@ -363,9 +363,9 @@
* @param errorCode the error code for the error to be generated
*/
ErrorResult.con1(ASTNode node, ErrorCode errorCode) {
- _jtd_constructor_156_impl(node, errorCode);
+ _jtd_constructor_158_impl(node, errorCode);
}
- _jtd_constructor_156_impl(ASTNode node, ErrorCode errorCode) {
+ _jtd_constructor_158_impl(ASTNode node, ErrorCode errorCode) {
_errors.add(new ErrorResult_ErrorData(node, errorCode));
}
/**
@@ -375,9 +375,9 @@
* @param secondResult the second set of results being merged
*/
ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) {
- _jtd_constructor_157_impl(firstResult, secondResult);
+ _jtd_constructor_159_impl(firstResult, secondResult);
}
- _jtd_constructor_157_impl(ErrorResult firstResult, ErrorResult secondResult) {
+ _jtd_constructor_159_impl(ErrorResult firstResult, ErrorResult secondResult) {
_errors.addAll(firstResult._errors);
_errors.addAll(secondResult._errors);
}
diff --git a/pkg/analyzer_experimental/lib/src/generated/element.dart b/pkg/analyzer_experimental/lib/src/generated/element.dart
index 601a3e1..79b1bc9 100644
--- a/pkg/analyzer_experimental/lib/src/generated/element.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/element.dart
@@ -761,6 +761,12 @@
* @return {@code true} if this method is abstract
*/
bool isAbstract();
+ /**
+ * Return {@code true} if this method is an operator. The test may be based on the name of the
+ * method, in which case the result will be correct when the name is legal.
+ * @return {@code true} if this method is an operator
+ */
+ bool isOperator();
}
/**
* The interface {@code MultiplyDefinedElement} defines the behavior of pseudo-elements that
@@ -1308,10 +1314,10 @@
ElementKind get kind => ElementKind.CLASS;
List<MethodElement> get methods => _methods;
List<InterfaceType> get mixins => _mixins;
- ConstructorElement getNamedConstructor(String name23) {
+ ConstructorElement getNamedConstructor(String name24) {
for (ConstructorElement element in constructors) {
String elementName = element.name;
- if (elementName != null && elementName == name23) {
+ if (elementName != null && elementName == name24) {
return element;
}
}
@@ -1700,8 +1706,8 @@
* Set the source that corresponds to this compilation unit to the given source.
* @param source the source that corresponds to this compilation unit
*/
- void set source(Source source5) {
- this._source = source5;
+ void set source(Source source7) {
+ this._source = source7;
}
/**
* Set the top-level variables contained in this compilation unit to the given variables.
@@ -1944,11 +1950,11 @@
* Initialize a newly created element to have the given name.
* @param name the name of this element
*/
- ElementImpl.con1(Identifier name24) {
- _jtd_constructor_172_impl(name24);
+ ElementImpl.con1(Identifier name25) {
+ _jtd_constructor_174_impl(name25);
}
- _jtd_constructor_172_impl(Identifier name24) {
- _jtd_constructor_173_impl(name24 == null ? "" : name24.name, name24 == null ? -1 : name24.offset);
+ _jtd_constructor_174_impl(Identifier name25) {
+ _jtd_constructor_175_impl(name25 == null ? "" : name25.name, name25 == null ? -1 : name25.offset);
}
/**
* Initialize a newly created element to have the given name.
@@ -1957,9 +1963,9 @@
* declaration of this element
*/
ElementImpl.con2(String name8, int nameOffset2) {
- _jtd_constructor_173_impl(name8, nameOffset2);
+ _jtd_constructor_175_impl(name8, nameOffset2);
}
- _jtd_constructor_173_impl(String name8, int nameOffset2) {
+ _jtd_constructor_175_impl(String name8, int nameOffset2) {
this._name = name8;
this._nameOffset = nameOffset2;
this._modifiers = new Set();
@@ -2012,6 +2018,15 @@
this._metadata = metadata2;
}
/**
+ * Set the offset of the name of this element in the file that contains the declaration of this
+ * element to the given value. This is normally done via the constructor, but this method is
+ * provided to support unnamed constructors.
+ * @param nameOffset the offset to the beginning of the name
+ */
+ void set nameOffset(int nameOffset3) {
+ this._nameOffset = nameOffset3;
+ }
+ /**
* Set whether this element is synthetic to correspond to the given value.
* @param isSynthetic {@code true} if the element is synthetic
*/
@@ -2111,9 +2126,9 @@
* @param element the element whose location is being represented
*/
ElementLocationImpl.con1(Element element) {
- _jtd_constructor_174_impl(element);
+ _jtd_constructor_176_impl(element);
}
- _jtd_constructor_174_impl(Element element) {
+ _jtd_constructor_176_impl(Element element) {
List<String> components = new List<String>();
Element ancestor = element;
while (ancestor != null) {
@@ -2127,9 +2142,9 @@
* @param encoding the encoded form of a location
*/
ElementLocationImpl.con2(String encoding) {
- _jtd_constructor_175_impl(encoding);
+ _jtd_constructor_177_impl(encoding);
}
- _jtd_constructor_175_impl(String encoding) {
+ _jtd_constructor_177_impl(String encoding) {
this._components = decode(encoding);
}
bool operator ==(Object object) {
@@ -2268,9 +2283,9 @@
* @param name the name of this element
*/
ExecutableElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_177_impl(name);
+ _jtd_constructor_179_impl(name);
}
- _jtd_constructor_177_impl(Identifier name) {
+ _jtd_constructor_179_impl(Identifier name) {
}
/**
* Initialize a newly created executable element to have the given name.
@@ -2279,9 +2294,9 @@
* declaration of this element
*/
ExecutableElementImpl.con2(String name, int nameOffset) : super.con2(name, nameOffset) {
- _jtd_constructor_178_impl(name, nameOffset);
+ _jtd_constructor_180_impl(name, nameOffset);
}
- _jtd_constructor_178_impl(String name, int nameOffset) {
+ _jtd_constructor_180_impl(String name, int nameOffset) {
}
ElementImpl getChild(String identifier27) {
for (ExecutableElement function in _functions) {
@@ -2465,18 +2480,18 @@
* @param name the name of this element
*/
FieldElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_181_impl(name);
+ _jtd_constructor_183_impl(name);
}
- _jtd_constructor_181_impl(Identifier name) {
+ _jtd_constructor_183_impl(Identifier name) {
}
/**
* Initialize a newly created synthetic field element to have the given name.
* @param name the name of this element
*/
FieldElementImpl.con2(String name) : super.con2(name) {
- _jtd_constructor_182_impl(name);
+ _jtd_constructor_184_impl(name);
}
- _jtd_constructor_182_impl(String name) {
+ _jtd_constructor_184_impl(String name) {
}
accept(ElementVisitor visitor) => visitor.visitFieldElement(this);
ClassElement get enclosingElement => super.enclosingElement as ClassElement;
@@ -2512,9 +2527,9 @@
* Initialize a newly created synthetic function element.
*/
FunctionElementImpl() : super.con2("", -1) {
- _jtd_constructor_183_impl();
+ _jtd_constructor_185_impl();
}
- _jtd_constructor_183_impl() {
+ _jtd_constructor_185_impl() {
synthetic = true;
}
/**
@@ -2522,9 +2537,9 @@
* @param name the name of this element
*/
FunctionElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_184_impl(name);
+ _jtd_constructor_186_impl(name);
}
- _jtd_constructor_184_impl(Identifier name) {
+ _jtd_constructor_186_impl(Identifier name) {
}
accept(ElementVisitor visitor) => visitor.visitFunctionElement(this);
String get identifier => name;
@@ -2751,8 +2766,8 @@
* Set the source that corresponds to this HTML file to the given source.
* @param source the source that corresponds to this HTML file
*/
- void set source(Source source6) {
- this._source = source6;
+ void set source(Source source8) {
+ this._source = source8;
}
void visitChildren(ElementVisitor<Object> visitor) {
super.visitChildren(visitor);
@@ -3075,8 +3090,8 @@
visited.add(this);
for (int index = 0; index < visited.length; index++) {
LibraryElement library = visited[index];
- Source source10 = library.definingCompilationUnit.source;
- if (source10 == htmlLibSource) {
+ Source source12 = library.definingCompilationUnit.source;
+ if (source12 == htmlLibSource) {
return true;
}
for (LibraryElement importedLibrary in library.importedLibraries) {
@@ -3156,9 +3171,9 @@
* @param name the name of this element
*/
MethodElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_193_impl(name);
+ _jtd_constructor_195_impl(name);
}
- _jtd_constructor_193_impl(Identifier name) {
+ _jtd_constructor_195_impl(Identifier name) {
}
/**
* Initialize a newly created method element to have the given name.
@@ -3167,14 +3182,22 @@
* declaration of this element
*/
MethodElementImpl.con2(String name, int nameOffset) : super.con2(name, nameOffset) {
- _jtd_constructor_194_impl(name, nameOffset);
+ _jtd_constructor_196_impl(name, nameOffset);
}
- _jtd_constructor_194_impl(String name, int nameOffset) {
+ _jtd_constructor_196_impl(String name, int nameOffset) {
}
accept(ElementVisitor visitor) => visitor.visitMethodElement(this);
ClassElement get enclosingElement => super.enclosingElement as ClassElement;
ElementKind get kind => ElementKind.METHOD;
bool isAbstract() => hasModifier(Modifier.ABSTRACT);
+ bool isOperator() {
+ String name14 = name;
+ if (name14.isEmpty) {
+ return false;
+ }
+ int first = name14.codeUnitAt(0);
+ return !((0x61 <= first && first <= 0x7A) || (0x41 <= first && first <= 0x5A) || first == 0x5F || first == 0x24);
+ }
bool isStatic() => hasModifier(Modifier.STATIC);
/**
* Set whether this method is abstract to correspond to the given value.
@@ -3444,9 +3467,9 @@
* @param name the name of this element
*/
PropertyAccessorElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_199_impl(name);
+ _jtd_constructor_201_impl(name);
}
- _jtd_constructor_199_impl(Identifier name) {
+ _jtd_constructor_201_impl(Identifier name) {
}
/**
* Initialize a newly created synthetic property accessor element to be associated with the given
@@ -3454,9 +3477,9 @@
* @param variable the variable with which this access is associated
*/
PropertyAccessorElementImpl.con2(PropertyInducingElementImpl variable2) : super.con2(variable2.name, -1) {
- _jtd_constructor_200_impl(variable2);
+ _jtd_constructor_202_impl(variable2);
}
- _jtd_constructor_200_impl(PropertyInducingElementImpl variable2) {
+ _jtd_constructor_202_impl(PropertyInducingElementImpl variable2) {
this._variable = variable2;
synthetic = true;
}
@@ -3521,18 +3544,18 @@
* @param name the name of this element
*/
PropertyInducingElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_201_impl(name);
+ _jtd_constructor_203_impl(name);
}
- _jtd_constructor_201_impl(Identifier name) {
+ _jtd_constructor_203_impl(Identifier name) {
}
/**
* Initialize a newly created synthetic element to have the given name.
* @param name the name of this element
*/
PropertyInducingElementImpl.con2(String name) : super.con2(name, -1) {
- _jtd_constructor_202_impl(name);
+ _jtd_constructor_204_impl(name);
}
- _jtd_constructor_202_impl(String name) {
+ _jtd_constructor_204_impl(String name) {
synthetic = true;
}
PropertyAccessorElement get getter => _getter;
@@ -3603,18 +3626,18 @@
* @param name the name of this element
*/
TopLevelVariableElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_204_impl(name);
+ _jtd_constructor_206_impl(name);
}
- _jtd_constructor_204_impl(Identifier name) {
+ _jtd_constructor_206_impl(Identifier name) {
}
/**
* Initialize a newly created synthetic top-level variable element to have the given name.
* @param name the name of this element
*/
TopLevelVariableElementImpl.con2(String name) : super.con2(name) {
- _jtd_constructor_205_impl(name);
+ _jtd_constructor_207_impl(name);
}
- _jtd_constructor_205_impl(String name) {
+ _jtd_constructor_207_impl(String name) {
}
accept(ElementVisitor visitor) => visitor.visitTopLevelVariableElement(this);
ElementKind get kind => ElementKind.TOP_LEVEL_VARIABLE;
@@ -3693,9 +3716,9 @@
* @param name the name of this element
*/
VariableElementImpl.con1(Identifier name) : super.con1(name) {
- _jtd_constructor_207_impl(name);
+ _jtd_constructor_209_impl(name);
}
- _jtd_constructor_207_impl(Identifier name) {
+ _jtd_constructor_209_impl(Identifier name) {
}
/**
* Initialize a newly created variable element to have the given name.
@@ -3704,9 +3727,9 @@
* declaration of this element
*/
VariableElementImpl.con2(String name, int nameOffset) : super.con2(name, nameOffset) {
- _jtd_constructor_208_impl(name, nameOffset);
+ _jtd_constructor_210_impl(name, nameOffset);
}
- _jtd_constructor_208_impl(String name, int nameOffset) {
+ _jtd_constructor_210_impl(String name, int nameOffset) {
}
/**
* Return the result of evaluating this variable's initializer as a compile-time constant
@@ -3899,9 +3922,9 @@
* @param element the element representing the declaration of the function type
*/
FunctionTypeImpl.con1(ExecutableElement element) : super(element, element == null ? null : element.name) {
- _jtd_constructor_259_impl(element);
+ _jtd_constructor_261_impl(element);
}
- _jtd_constructor_259_impl(ExecutableElement element) {
+ _jtd_constructor_261_impl(ExecutableElement element) {
}
/**
* Initialize a newly created function type to be declared by the given element and to have the
@@ -3909,9 +3932,9 @@
* @param element the element representing the declaration of the function type
*/
FunctionTypeImpl.con2(FunctionTypeAliasElement element) : super(element, element == null ? null : element.name) {
- _jtd_constructor_260_impl(element);
+ _jtd_constructor_262_impl(element);
}
- _jtd_constructor_260_impl(FunctionTypeAliasElement element) {
+ _jtd_constructor_262_impl(FunctionTypeAliasElement element) {
}
bool operator ==(Object object) {
if (object is! FunctionTypeImpl) {
@@ -4200,9 +4223,9 @@
* @param element the element representing the declaration of the type
*/
InterfaceTypeImpl.con1(ClassElement element) : super(element, element.name) {
- _jtd_constructor_261_impl(element);
+ _jtd_constructor_263_impl(element);
}
- _jtd_constructor_261_impl(ClassElement element) {
+ _jtd_constructor_263_impl(ClassElement element) {
}
/**
* Initialize a newly created type to have the given name. This constructor should only be used in
@@ -4210,9 +4233,9 @@
* @param name the name of the type
*/
InterfaceTypeImpl.con2(String name) : super(null, name) {
- _jtd_constructor_262_impl(name);
+ _jtd_constructor_264_impl(name);
}
- _jtd_constructor_262_impl(String name) {
+ _jtd_constructor_264_impl(String name) {
}
bool operator ==(Object object) {
if (object is! InterfaceTypeImpl) {
diff --git a/pkg/analyzer_experimental/lib/src/generated/engine.dart b/pkg/analyzer_experimental/lib/src/generated/engine.dart
index f782870..02832e5 100644
--- a/pkg/analyzer_experimental/lib/src/generated/engine.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/engine.dart
@@ -97,8 +97,14 @@
/**
* The interface {@code AnalysisContext} defines the behavior of objects that represent a context in
* which analysis can be performed. The context includes such information as the version of the SDK
- * being analyzed against as well as the package-root used to resolve 'package:' URI's. (The latter
- * is included indirectly through the {@link SourceFactory source factory}.)
+ * being analyzed against as well as the package-root used to resolve 'package:' URI's. (Both of
+ * which are known indirectly through the {@link SourceFactory source factory}.)
+ * <p>
+ * They also represent the state of a given analysis, which includes knowing which sources have been
+ * included in the analysis (either directly or indirectly) and the results of the analysis. Some
+ * analysis results are cached in order to allow the context to balance between memory usage and
+ * performance. TODO(brianwilkerson) Decide how this is reflected in the API: a getFoo() and
+ * getOrComputeFoo() pair of methods, or a single getFoo(boolean).
* <p>
* Analysis engine allows for having more than one context. This can be used, for example, to
* perform one analysis based on the state of files on disk and a separate analysis based on the
@@ -107,34 +113,19 @@
*/
abstract class AnalysisContext {
/**
- * Respond to the given set of changes by removing any cached information that might now be
- * out-of-date. The result indicates what operations need to be performed as a result of this
- * change without actually performing those operations.
- * @param changeSet a description of the changes that have occurred
- * @return a result (not {@code null}) indicating operations to be performed
+ * Apply the changes specified by the given change set to this context. Any analysis results that
+ * have been invalidated by these changes will be removed.
+ * @param changeSet a description of the changes that are to be applied
*/
- ChangeResult changed(ChangeSet changeSet);
+ void applyChanges(ChangeSet changeSet);
/**
- * Clear any cached information that is dependent on resolution. This method should be invoked if
- * the assumptions used by resolution have changed but the contents of the file have not changed.
- * Use {@link #sourceChanged(Source)} and {@link #sourcesDeleted(SourceContainer)} to indicate
- * when the contents of a file or files have changed.
+ * Create a new context in which analysis can be performed. Any sources in the specified container
+ * will be removed from this context and added to the newly created context.
+ * @param container the container containing sources that should be removed from this context and
+ * added to the returned context
+ * @return the analysis context that was created
*/
- void clearResolution();
- /**
- * Call this method when this context is no longer going to be used. At this point, the receiver
- * may choose to push some of its information back into the global cache for consumption by
- * another context for performance.
- */
- void discard();
- /**
- * Create a new context in which analysis can be performed. Any sources in the specified directory
- * in the receiver will be removed from the receiver and added to the newly created context.
- * @param directory the directory (not {@code null}) containing sources that should be removed
- * from the receiver and added to the returned context
- * @return the analysis context that was created (not {@code null})
- */
- AnalysisContext extractAnalysisContext(SourceContainer container);
+ AnalysisContext extractContext(SourceContainer container);
/**
* Return the element referenced by the given location.
* @param location the reference describing the element to be returned
@@ -142,7 +133,8 @@
*/
Element getElement(ElementLocation location);
/**
- * Return an array containing all of the errors associated with the given source.
+ * Return an array containing all of the errors associated with the given source. The array will
+ * be empty if the source is not known to this context or if there are no errors in the source.
* @param source the source whose errors are to be returned
* @return all of the errors associated with the given source
* @throws AnalysisException if the errors could not be determined because the analysis could not
@@ -150,12 +142,17 @@
*/
List<AnalysisError> getErrors(Source source);
/**
- * Parse and build an element model for the HTML file defined by the given source.
+ * Return the element model corresponding to the HTML file defined by the given source.
* @param source the source defining the HTML file whose element model is to be returned
* @return the element model corresponding to the HTML file defined by the given source
*/
HtmlElement getHtmlElement(Source source);
/**
+ * Return an array containing all of the sources known to this context that represent HTML files.
+ * @return the sources known to this context that represent HTML files
+ */
+ List<Source> get htmlSources;
+ /**
* Return the kind of the given source if it is already known, or {@code null} if the kind is not
* already known.
* @param source the source whose kind is to be returned
@@ -164,6 +161,22 @@
*/
SourceKind getKnownKindOf(Source source);
/**
+ * Return an array containing all of the sources known to this context that represent the defining
+ * compilation unit of a library that can be run within a browser. The sources that are returned
+ * represent libraries that have a 'main' method and are either referenced by an HTML file or
+ * import, directly or indirectly, a client-only library.
+ * @return the sources known to this context that represent the defining compilation unit of a
+ * library that can be run within a browser
+ */
+ List<Source> get launchableClientLibrarySources;
+ /**
+ * Return an array containing all of the sources known to this context that represent the defining
+ * compilation unit of a library that can be run outside of a browser.
+ * @return the sources known to this context that represent the defining compilation unit of a
+ * library that can be run outside of a browser
+ */
+ List<Source> get launchableServerLibrarySources;
+ /**
* Return the sources for the defining compilation units of any libraries of which the given
* source is a part. The array will normally contain a single library because most Dart sources
* are only included in a single library, but it is possible to have a part that is contained in
@@ -186,12 +199,20 @@
*/
LibraryElement getLibraryElement(Source source);
/**
- * Return the element model corresponding to the library defined by the given source, or{@code null} if the element model does not yet exist.
+ * Return the element model corresponding to the library defined by the given source, or{@code null} if the element model does not currently exist or if the analysis could not be
+ * performed.
* @param source the source defining the library whose element model is to be returned
* @return the element model corresponding to the library defined by the given source
*/
LibraryElement getLibraryElementOrNull(Source source);
/**
+ * Return an array containing all of the sources known to this context that represent the defining
+ * compilation unit of a library.
+ * @return the sources known to this context that represent the defining compilation unit of a
+ * library
+ */
+ List<Source> get librarySources;
+ /**
* Return the kind of the given source, computing it's kind if it is not already known.
* @param source the source whose kind is to be returned
* @return the kind of the given source
@@ -199,33 +220,17 @@
*/
SourceKind getOrComputeKindOf(Source source);
/**
- * Return an array containing all of the parsing errors associated with the given source.
- * @param source the source whose errors are to be returned
- * @return all of the parsing errors associated with the given source
- * @throws AnalysisException if the errors could not be determined because the analysis could not
- * be performed
- */
- List<AnalysisError> getParsingErrors(Source source);
- /**
- * Return an array containing all of the resolution errors associated with the given source.
- * @param source the source whose errors are to be returned
- * @return all of the resolution errors associated with the given source
- * @throws AnalysisException if the errors could not be determined because the analysis could not
- * be performed
- */
- List<AnalysisError> getResolutionErrors(Source source);
- /**
* Return the source factory used to create the sources that can be analyzed in this context.
* @return the source factory used to create the sources that can be analyzed in this context
*/
SourceFactory get sourceFactory;
/**
- * Add the sources contained in the specified context to the receiver's collection of sources.
+ * Add the sources contained in the specified context to this context's collection of sources.
* This method is called when an existing context's pubspec has been removed, and the contained
- * sources should be reanalyzed as part of the receiver.
- * @param context the context being merged (not {@code null})
+ * sources should be reanalyzed as part of this context.
+ * @param context the context being merged
*/
- void mergeAnalysisContext(AnalysisContext context);
+ void mergeContext(AnalysisContext context);
/**
* Parse a single source to produce an AST structure. The resulting AST structure may or may not
* be resolved, and may have a slightly different structure depending upon whether it is resolved.
@@ -244,6 +249,13 @@
*/
HtmlParseResult parseHtml(Source source);
/**
+ * Perform the next unit of work required to keep the analysis results up-to-date and return
+ * information about the consequent changes to the analysis results. If there were no results the
+ * returned array will be empty. This method can be long running.
+ * @return an array containing notices of changes to the analysis results
+ */
+ List<ChangeNotice> performAnalysisTask();
+ /**
* Parse and resolve a single source within the given context to produce a fully resolved AST.
* @param source the source to be parsed and resolved
* @param library the library defining the context in which the source file is to be resolved
@@ -252,27 +264,13 @@
*/
CompilationUnit resolve(Source source, LibraryElement library);
/**
- * Scan a single source to produce a token stream.
- * @param source the source to be scanned
- * @param errorListener the listener to which errors should be reported
- * @return the head of the token stream representing the content of the source
- * @throws AnalysisException if the analysis could not be performed
- */
- Token scan(Source source, AnalysisErrorListener errorListener);
- /**
- * Scan a single source to produce an HTML token stream.
- * @param source the source to be scanned
- * @return the scan result (not {@code null})
- * @throws AnalysisException if the analysis could not be performed
- */
- HtmlScanResult scanHtml(Source source);
- /**
* Set the source factory used to create the sources that can be analyzed in this context to the
- * given source factory.
- * @param sourceFactory the source factory used to create the sources that can be analyzed in this
+ * given source factory. Clients can safely assume that all analysis results have been
+ * invalidated.
+ * @param factory the source factory used to create the sources that can be analyzed in this
* context
*/
- void set sourceFactory(SourceFactory sourceFactory4);
+ void set sourceFactory(SourceFactory factory);
/**
* Given a collection of sources with content that has changed, return an {@link Iterable}identifying the sources that need to be resolved.
* @param changedSources an array of sources (not {@code null}, contains no {@code null}s)
@@ -324,11 +322,83 @@
}
}
/**
- * Instances of {@code ChangeResult} are returned by {@link AnalysisContext#changed(ChangeSet)} to
- * indicate what operations need to be performed as a result of the change.
- * @coverage dart.engine
+ * Instances of the class {@code ChangeNotice} represent a change to the analysis results associated
+ * with a given source.
*/
-class ChangeResult {
+class ChangeNotice {
+ /**
+ * The source for which the result is being reported.
+ */
+ Source _source;
+ /**
+ * The fully resolved AST that changed as a result of the analysis, or {@code null} if the AST was
+ * not changed.
+ */
+ CompilationUnit _compilationUnit;
+ /**
+ * The errors that changed as a result of the analysis, or {@code null} if errors were not
+ * changed.
+ */
+ List<AnalysisError> _errors;
+ /**
+ * The line information associated with the source, or {@code null} if errors were not changed.
+ */
+ LineInfo _lineInfo;
+ /**
+ * An empty array of change notices.
+ */
+ static List<ChangeNotice> EMPTY_ARRAY = new List<ChangeNotice>(0);
+ /**
+ * Initialize a newly created result representing the fact that the errors associated with a
+ * source have changed.
+ * @param source the source for which the result is being reported
+ * @param errors the errors that changed as a result of the analysis
+ * @param the line information associated with the source
+ */
+ ChangeNotice.con1(Source source2, List<AnalysisError> errors2, LineInfo lineInfo3) {
+ _jtd_constructor_127_impl(source2, errors2, lineInfo3);
+ }
+ _jtd_constructor_127_impl(Source source2, List<AnalysisError> errors2, LineInfo lineInfo3) {
+ this._source = source2;
+ this._errors = errors2;
+ this._lineInfo = lineInfo3;
+ }
+ /**
+ * Initialize a newly created result representing the fact that the resolution of a source has
+ * changed.
+ * @param source the source for which the result is being reported
+ * @param compilationUnit the fully resolved AST produced as a result of the analysis
+ */
+ ChangeNotice.con2(Source source3, CompilationUnit compilationUnit9) {
+ _jtd_constructor_128_impl(source3, compilationUnit9);
+ }
+ _jtd_constructor_128_impl(Source source3, CompilationUnit compilationUnit9) {
+ this._source = source3;
+ this._compilationUnit = compilationUnit9;
+ }
+ /**
+ * Return the fully resolved AST that changed as a result of the analysis, or {@code null} if the
+ * AST was not changed.
+ * @return the fully resolved AST that changed as a result of the analysis
+ */
+ CompilationUnit get compilationUnit => _compilationUnit;
+ /**
+ * Return the errors that changed as a result of the analysis, or {@code null} if errors were not
+ * changed.
+ * @return the errors that changed as a result of the analysis
+ */
+ List<AnalysisError> get errors => _errors;
+ /**
+ * Return the line information associated with the source, or {@code null} if errors were not
+ * changed.
+ * @return the line information associated with the source
+ */
+ LineInfo get lineInfo => _lineInfo;
+ /**
+ * Return the source for which the result is being reported.
+ * @return the source for which the result is being reported
+ */
+ Source get source => _source;
}
/**
* Instances of the class {@code ChangeSet} indicate what sources have been added, changed, or
@@ -368,8 +438,8 @@
/**
* Record that the specified source has been added and that it has the given content. If the
* content is non-{@code null}, this has the effect of overriding the default contents of the
- * source. If the contents are {@code null}, any previous the override is removed so that the
- * default contents will be used.
+ * source. If the contents are {@code null}, any previous override is removed so that the default
+ * contents will be used.
* @param source the source that was added
* @param content the content of the new source
*/
@@ -389,8 +459,8 @@
/**
* Record that the specified source has been changed and that it now has the given content. If the
* content is non-{@code null}, this has the effect of overriding the default contents of the
- * source. If the contents are {@code null}, any previous the override is removed so that the
- * default contents will be used.
+ * source. If the contents are {@code null}, any previous override is removed so that the default
+ * contents will be used.
* @param source the source that was changed
* @param content the new content of the source
*/
@@ -482,62 +552,43 @@
*/
Object _cacheLock = new Object();
/**
- * The suffix used by sources that contain Dart.
- */
- static String _DART_SUFFIX = ".dart";
- /**
- * The suffix used by sources that contain HTML.
- */
- static String _HTML_SUFFIX = ".html";
- /**
* Initialize a newly created analysis context.
*/
AnalysisContextImpl() : super() {
}
- ChangeResult changed(ChangeSet changeSet) {
+ void applyChanges(ChangeSet changeSet) {
if (changeSet.isEmpty()) {
- return new ChangeResult();
+ return;
}
{
+ List<Source> addedSources = new List<Source>();
for (MapEntry<Source, String> entry in getMapEntrySet(changeSet.addedWithContent)) {
- _sourceFactory.setContents(entry.getKey(), entry.getValue());
+ Source source = entry.getKey();
+ _sourceFactory.setContents(source, entry.getValue());
+ addedSources.add(source);
}
+ List<Source> changedSources = new List<Source>();
for (MapEntry<Source, String> entry in getMapEntrySet(changeSet.changedWithContent)) {
- _sourceFactory.setContents(entry.getKey(), entry.getValue());
+ Source source = entry.getKey();
+ _sourceFactory.setContents(source, entry.getValue());
+ changedSources.add(source);
}
- for (Source source in changeSet.addedWithContent.keys.toSet()) {
+ List<Source> removedSources = new List<Source>.from(changeSet.removed);
+ for (SourceContainer container in changeSet.removedContainers) {
+ addSourcesInContainer(removedSources, container);
+ }
+ for (Source source in addedSources) {
sourceAvailable(source);
}
- for (Source source in changeSet.changedWithContent.keys.toSet()) {
+ for (Source source in changedSources) {
sourceChanged(source);
}
- for (Source source in changeSet.removed) {
- sourceDeleted(source);
- }
- for (SourceContainer container in changeSet.removedContainers) {
- sourcesDeleted(container);
+ for (Source source in removedSources) {
+ sourceRemoved(source);
}
}
- return new ChangeResult();
}
- void clearResolution() {
- {
- _parseCache.clear();
- _htmlParseCache.clear();
- _libraryElementCache.clear();
- _publicNamespaceCache.clear();
- }
- }
- void discard() {
- {
- _sourceMap.clear();
- _parseCache.clear();
- _htmlParseCache.clear();
- _libraryElementCache.clear();
- _publicNamespaceCache.clear();
- }
- }
- AnalysisContext extractAnalysisContext(SourceContainer container) {
+ AnalysisContext extractContext(SourceContainer container) {
AnalysisContextImpl newContext = AnalysisEngine.instance.createAnalysisContext() as AnalysisContextImpl;
List<Source> sourcesToRemove = new List<Source>();
{
@@ -558,13 +609,18 @@
throw new UnsupportedOperationException();
}
HtmlElement getHtmlElement(Source source) {
+ if (!AnalysisEngine.isHtmlFileName(source.shortName)) {
+ return null;
+ }
throw new UnsupportedOperationException();
}
+ List<Source> get htmlSources => getSources(SourceKind.HTML);
SourceKind getKnownKindOf(Source source) {
- if (source.fullName.endsWith(_HTML_SUFFIX)) {
+ String name = source.shortName;
+ if (AnalysisEngine.isHtmlFileName(name)) {
return SourceKind.HTML;
}
- if (!source.fullName.endsWith(_DART_SUFFIX)) {
+ if (!AnalysisEngine.isDartFileName(name)) {
return SourceKind.UNKNOWN;
}
{
@@ -578,6 +634,8 @@
}
return null;
}
+ List<Source> get launchableClientLibrarySources => librarySources;
+ List<Source> get launchableServerLibrarySources => librarySources;
List<Source> getLibrariesContaining(Source source) {
{
SourceInfo info = _sourceMap[source];
@@ -588,6 +646,9 @@
}
}
LibraryElement getLibraryElement(Source source) {
+ if (!AnalysisEngine.isDartFileName(source.shortName)) {
+ return null;
+ }
{
LibraryElement element = _libraryElementCache[source];
if (element == null) {
@@ -617,22 +678,13 @@
return _libraryElementCache[source];
}
}
+ List<Source> get librarySources => getSources(SourceKind.LIBRARY);
SourceKind getOrComputeKindOf(Source source) {
SourceKind kind = getKnownKindOf(source);
if (kind != null) {
return kind;
}
- try {
- if (hasPartOfDirective(parse(source))) {
- return SourceKind.PART;
- }
- } on AnalysisException catch (exception) {
- return SourceKind.UNKNOWN;
- }
- return SourceKind.LIBRARY;
- }
- List<AnalysisError> getParsingErrors(Source source) {
- throw new UnsupportedOperationException();
+ return computeKindOf(source);
}
/**
* Return a namespace containing mappings for all of the public names defined by the given
@@ -641,13 +693,13 @@
* @return the public namespace of the given library
*/
Namespace getPublicNamespace(LibraryElement library) {
- Source source8 = library.definingCompilationUnit.source;
+ Source source10 = library.definingCompilationUnit.source;
{
- Namespace namespace = _publicNamespaceCache[source8];
+ Namespace namespace = _publicNamespaceCache[source10];
if (namespace == null) {
NamespaceBuilder builder = new NamespaceBuilder();
namespace = builder.createPublicNamespace(library);
- _publicNamespaceCache[source8] = namespace;
+ _publicNamespaceCache[source10] = namespace;
}
return namespace;
}
@@ -673,11 +725,8 @@
return namespace;
}
}
- List<AnalysisError> getResolutionErrors(Source source) {
- throw new UnsupportedOperationException();
- }
SourceFactory get sourceFactory => _sourceFactory;
- void mergeAnalysisContext(AnalysisContext context) {
+ void mergeContext(AnalysisContext context) {
{
for (MapEntry<Source, SourceInfo> entry in getMapEntrySet(((context as AnalysisContextImpl))._sourceMap)) {
Source newSource = entry.getKey();
@@ -727,6 +776,7 @@
return result;
}
}
+ List<ChangeNotice> performAnalysisTask() => ChangeNotice.EMPTY_ARRAY;
/**
* Given a table mapping the source for the libraries represented by the corresponding elements to
* the elements representing the libraries, record those mappings.
@@ -739,21 +789,16 @@
}
}
CompilationUnit resolve(Source source, LibraryElement library) => parse(source);
- Token scan(Source source, AnalysisErrorListener errorListener) {
- AnalysisContextImpl_ScanResult result = internalScan(source, errorListener);
- return result._token;
- }
- HtmlScanResult scanHtml(Source source) {
- HtmlScanner scanner = new HtmlScanner(source);
- try {
- source.getContents(scanner);
- } on JavaException catch (exception) {
- throw new AnalysisException.con3(exception);
+ void set sourceFactory(SourceFactory factory) {
+ if (identical(_sourceFactory, factory)) {
+ return;
+ } else if (factory.context != null) {
+ throw new IllegalStateException("Source factories cannot be shared between contexts");
+ } else if (_sourceFactory != null) {
+ _sourceFactory.context = null;
}
- return scanner.result;
- }
- void set sourceFactory(SourceFactory sourceFactory2) {
- this._sourceFactory = sourceFactory2;
+ factory.context = this;
+ _sourceFactory = factory;
}
Iterable<Source> sourcesToResolve(List<Source> changedSources) {
List<Source> librarySources = new List<Source>();
@@ -765,6 +810,46 @@
return librarySources;
}
/**
+ * Add all of the sources contained in the given source container to the given list of sources.
+ * <p>
+ * Note: This method must only be invoked while we are synchronized on {@link #cacheLock}.
+ * @param sources the list to which sources are to be added
+ * @param container the source container containing the sources to be added to the list
+ */
+ void addSourcesInContainer(List<Source> sources, SourceContainer container) {
+ for (Source source in _sourceMap.keys.toSet()) {
+ if (container.contains(source)) {
+ sources.add(source);
+ }
+ }
+ }
+ SourceKind computeKindOf(Source source) {
+ try {
+ if (hasPartOfDirective(parse(source))) {
+ return SourceKind.PART;
+ }
+ } on AnalysisException catch (exception) {
+ return SourceKind.UNKNOWN;
+ }
+ return SourceKind.LIBRARY;
+ }
+ /**
+ * Return an array containing all of the sources known to this context that have the given kind.
+ * @param kind the kind of sources to be returned
+ * @return all of the sources known to this context that have the given kind
+ */
+ List<Source> getSources(SourceKind kind5) {
+ List<Source> sources = new List<Source>();
+ {
+ for (MapEntry<Source, SourceInfo> entry in getMapEntrySet(_sourceMap)) {
+ if (identical(entry.getValue().kind, kind5)) {
+ sources.add(entry.getKey());
+ }
+ }
+ }
+ return new List.from(sources);
+ }
+ /**
* Return {@code true} if the given compilation unit has a part-of directive.
* @param unit the compilation unit being tested
* @return {@code true} if the compilation unit has a part-of directive
@@ -787,6 +872,15 @@
}
return result;
}
+ HtmlScanResult scanHtml(Source source) {
+ HtmlScanner scanner = new HtmlScanner(source);
+ try {
+ source.getContents(scanner);
+ } on JavaException catch (exception) {
+ throw new AnalysisException.con3(exception);
+ }
+ return scanner.result;
+ }
/**
* Note: This method must only be invoked while we are synchronized on {@link #cacheLock}.
* @param source the source that has been added
@@ -794,7 +888,8 @@
void sourceAvailable(Source source) {
SourceInfo existingInfo = _sourceMap[source];
if (existingInfo == null) {
- _sourceMap[source] = new SourceInfo.con1(source, getOrComputeKindOf(source));
+ SourceKind kind = computeKindOf(source);
+ _sourceMap[source] = new SourceInfo.con1(source, kind);
}
}
/**
@@ -810,6 +905,11 @@
_htmlParseCache.remove(source);
_libraryElementCache.remove(source);
_publicNamespaceCache.remove(source);
+ SourceKind oldKind = info.kind;
+ SourceKind newKind = computeKindOf(source);
+ if (newKind != oldKind) {
+ info.kind = newKind;
+ }
for (Source librarySource in info.librarySources) {
_libraryElementCache.remove(librarySource);
_publicNamespaceCache.remove(librarySource);
@@ -819,21 +919,19 @@
* Note: This method must only be invoked while we are synchronized on {@link #cacheLock}.
* @param source the source that has been deleted
*/
- void sourceDeleted(Source source) {
- _sourceMap.remove(source);
- sourceChanged(source);
- }
- /**
- * Note: This method must only be invoked while we are synchronized on {@link #cacheLock}.
- * @param container the source container specifying the sources that have been deleted
- */
- void sourcesDeleted(SourceContainer container) {
- List<Source> sourcesToRemove = new List<Source>();
- for (Source source in _sourceMap.keys.toSet()) {
- if (container.contains(source)) {
- sourcesToRemove.add(source);
- }
+ void sourceRemoved(Source source) {
+ SourceInfo info = _sourceMap[source];
+ if (info == null) {
+ return;
}
+ _parseCache.remove(source);
+ _libraryElementCache.remove(source);
+ _publicNamespaceCache.remove(source);
+ for (Source librarySource in info.librarySources) {
+ _libraryElementCache.remove(librarySource);
+ _publicNamespaceCache.remove(librarySource);
+ }
+ _sourceMap.remove(source);
}
}
/**
@@ -911,11 +1009,11 @@
}
}
void onError(AnalysisError event) {
- Source source9 = event.source;
- List<AnalysisError> errorsForSource = _errors[source9];
- if (_errors[source9] == null) {
+ Source source11 = event.source;
+ List<AnalysisError> errorsForSource = _errors[source11];
+ if (_errors[source11] == null) {
errorsForSource = new List<AnalysisError>();
- _errors[source9] = errorsForSource;
+ _errors[source11] = errorsForSource;
}
errorsForSource.add(event);
}
@@ -935,9 +1033,9 @@
*/
List<Source> _librarySources = null;
SourceInfo.con1(Source source, SourceKind kind3) {
- _jtd_constructor_161_impl(source, kind3);
+ _jtd_constructor_163_impl(source, kind3);
}
- _jtd_constructor_161_impl(Source source, SourceKind kind3) {
+ _jtd_constructor_163_impl(Source source, SourceKind kind3) {
this._kind = kind3;
}
/**
@@ -945,9 +1043,9 @@
* @param info the information holder used to initialize this holder
*/
SourceInfo.con2(SourceInfo info) {
- _jtd_constructor_162_impl(info);
+ _jtd_constructor_164_impl(info);
}
- _jtd_constructor_162_impl(SourceInfo info) {
+ _jtd_constructor_164_impl(SourceInfo info) {
_kind = info._kind;
_librarySources = new List<Source>.from(info._librarySources);
}
diff --git a/pkg/analyzer_experimental/lib/src/generated/error.dart b/pkg/analyzer_experimental/lib/src/generated/error.dart
index 2693822..b8225a1 100644
--- a/pkg/analyzer_experimental/lib/src/generated/error.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/error.dart
@@ -122,8 +122,8 @@
* the default source to be used.
* @param source the source to be used when reporting errors
*/
- void set source(Source source7) {
- this._source = source7 == null ? _defaultSource : source7;
+ void set source(Source source9) {
+ this._source = source9 == null ? _defaultSource : source9;
}
}
/**
@@ -165,11 +165,11 @@
* @param errorCode the error code to be associated with this error
* @param arguments the arguments used to build the error message
*/
- AnalysisError.con1(Source source2, ErrorCode errorCode2, List<Object> arguments) {
- _jtd_constructor_129_impl(source2, errorCode2, arguments);
+ AnalysisError.con1(Source source4, ErrorCode errorCode2, List<Object> arguments) {
+ _jtd_constructor_131_impl(source4, errorCode2, arguments);
}
- _jtd_constructor_129_impl(Source source2, ErrorCode errorCode2, List<Object> arguments) {
- this._source = source2;
+ _jtd_constructor_131_impl(Source source4, ErrorCode errorCode2, List<Object> arguments) {
+ this._source = source4;
this._errorCode = errorCode2;
this._message = JavaString.format(errorCode2.message, arguments);
}
@@ -181,11 +181,11 @@
* @param errorCode the error code to be associated with this error
* @param arguments the arguments used to build the error message
*/
- AnalysisError.con2(Source source3, int offset2, int length11, ErrorCode errorCode3, List<Object> arguments) {
- _jtd_constructor_130_impl(source3, offset2, length11, errorCode3, arguments);
+ AnalysisError.con2(Source source5, int offset2, int length11, ErrorCode errorCode3, List<Object> arguments) {
+ _jtd_constructor_132_impl(source5, offset2, length11, errorCode3, arguments);
}
- _jtd_constructor_130_impl(Source source3, int offset2, int length11, ErrorCode errorCode3, List<Object> arguments) {
- this._source = source3;
+ _jtd_constructor_132_impl(Source source5, int offset2, int length11, ErrorCode errorCode3, List<Object> arguments) {
+ this._source = source5;
this._offset = offset2;
this._length = length11;
this._errorCode = errorCode3;
@@ -228,8 +228,8 @@
* Set the source in which the error occurred to the given source.
* @param source the source in which the error occurred
*/
- void set source(Source source4) {
- this._source = source4;
+ void set source(Source source6) {
+ this._source = source6;
}
String toString() {
JavaStringBuilder builder = new JavaStringBuilder();
@@ -417,7 +417,7 @@
* 12.11.2 Const: It is a compile-time error if evaluation of a constant object results in an
* uncaught exception being thrown.
*/
- static final CompileTimeErrorCode CONST_EVAL_THROWS_EXCEPTION = new CompileTimeErrorCode('CONST_EVAL_THROWS_EXCEPTION', 15, "");
+ static final CompileTimeErrorCode CONST_EVAL_THROWS_EXCEPTION = new CompileTimeErrorCode('CONST_EVAL_THROWS_EXCEPTION', 15, "'const' constructors cannot throw exceptions");
/**
* 12.11.2 Const: If <i>T</i> is a parameterized type <i>S<U<sub>1</sub>, …,
* U<sub>m</sub>></i>, let <i>R = S</i>; It is a compile time error if <i>S</i> is not a
@@ -462,7 +462,7 @@
* 15.3.1 Typedef: It is a compile-time error if any default values are specified in the signature
* of a function type alias.
*/
- static final CompileTimeErrorCode DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS = new CompileTimeErrorCode('DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS', 22, "");
+ static final CompileTimeErrorCode DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS = new CompileTimeErrorCode('DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS', 22, "Default values aren't allowed in typedefs");
/**
* 3.1 Scoping: It is a compile-time error if there is more than one entity with the same name
* declared in the same scope.
@@ -508,159 +508,178 @@
* 12.4 Booleans: It is a compile-time error for a class to attempt to extend or implement bool.
* <p>
* 12.5 Strings: It is a compile-time error for a class to attempt to extend or implement String.
+ * @param typeName the name of the type that cannot be extended
+ * @see #IMPLEMENTS_DISALLOWED_CLASS
*/
- static final CompileTimeErrorCode EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS = new CompileTimeErrorCode('EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS', 29, "");
+ static final CompileTimeErrorCode EXTENDS_DISALLOWED_CLASS = new CompileTimeErrorCode('EXTENDS_DISALLOWED_CLASS', 29, "Classes cannot extend '%s'");
+ /**
+ * 12.2 Null: It is a compile-time error for a class to attempt to extend or implement Null.
+ * <p>
+ * 12.3 Numbers: It is a compile-time error for a class to attempt to extend or implement int.
+ * <p>
+ * 12.3 Numbers: It is a compile-time error for a class to attempt to extend or implement double.
+ * <p>
+ * 12.3 Numbers: It is a compile-time error for any type other than the types int and double to
+ * attempt to extend or implement num.
+ * <p>
+ * 12.4 Booleans: It is a compile-time error for a class to attempt to extend or implement bool.
+ * <p>
+ * 12.5 Strings: It is a compile-time error for a class to attempt to extend or implement String.
+ * @param typeName the name of the type that cannot be implemented
+ * @see #EXTENDS_DISALLOWED_CLASS
+ */
+ static final CompileTimeErrorCode IMPLEMENTS_DISALLOWED_CLASS = new CompileTimeErrorCode('IMPLEMENTS_DISALLOWED_CLASS', 30, "Classes cannot implement '%s'");
/**
* 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. It is a compile time
* error if more than one initializer corresponding to a given instance variable appears in
* <i>k</i>’s list.
*/
- static final CompileTimeErrorCode FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS = new CompileTimeErrorCode('FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS', 30, "");
+ static final CompileTimeErrorCode FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS = new CompileTimeErrorCode('FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS', 31, "");
/**
* 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. It is a compile time
* error if <i>k</i>’s initializer list contains an initializer for a final variable <i>f</i>
* whose declaration includes an initialization expression.
*/
- static final CompileTimeErrorCode FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION = new CompileTimeErrorCode('FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION', 31, "");
+ static final CompileTimeErrorCode FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION = new CompileTimeErrorCode('FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION', 32, "");
/**
* 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. It is a compile time
* error if <i>k</i>’s initializer list contains an initializer for a variable that is initialized
* by means of an initializing formal of <i>k</i>.
*/
- static final CompileTimeErrorCode FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER = new CompileTimeErrorCode('FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER', 32, "");
+ static final CompileTimeErrorCode FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER = new CompileTimeErrorCode('FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER', 33, "");
/**
* 7.6.1 Generative Constructors: It is a compile-time error if an initializing formal is used by
* a function other than a non-redirecting generative constructor.
*/
- static final CompileTimeErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = new CompileTimeErrorCode('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR', 33, "");
+ static final CompileTimeErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = new CompileTimeErrorCode('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR', 34, "");
/**
* 5 Variables: It is a compile-time error if a final instance variable that has been initialized
* at its point of declaration is also initialized in a constructor.
*/
- static final CompileTimeErrorCode FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR = new CompileTimeErrorCode('FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR', 34, "");
+ static final CompileTimeErrorCode FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR = new CompileTimeErrorCode('FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR', 35, "");
/**
* 5 Variables: It is a compile-time error if a final instance variable that has is initialized by
* means of an initializing formal of a constructor is also initialized elsewhere in the same
* constructor.
*/
- static final CompileTimeErrorCode FINAL_INITIALIZED_MULTIPLE_TIMES = new CompileTimeErrorCode('FINAL_INITIALIZED_MULTIPLE_TIMES', 35, "");
+ static final CompileTimeErrorCode FINAL_INITIALIZED_MULTIPLE_TIMES = new CompileTimeErrorCode('FINAL_INITIALIZED_MULTIPLE_TIMES', 36, "");
/**
* 5 Variables: It is a compile-time error if a library, static or local variable <i>v</i> is
* final and <i>v</i> is not initialized at its point of declaration.
*/
- static final CompileTimeErrorCode FINAL_NOT_INITIALIZED = new CompileTimeErrorCode('FINAL_NOT_INITIALIZED', 36, "");
+ static final CompileTimeErrorCode FINAL_NOT_INITIALIZED = new CompileTimeErrorCode('FINAL_NOT_INITIALIZED', 37, "");
/**
* 7.2 Getters: It is a compile-time error if a class has both a getter and a method with the same
* name.
*/
- static final CompileTimeErrorCode GETTER_AND_METHOD_WITH_SAME_NAME = new CompileTimeErrorCode('GETTER_AND_METHOD_WITH_SAME_NAME', 37, "");
+ static final CompileTimeErrorCode GETTER_AND_METHOD_WITH_SAME_NAME = new CompileTimeErrorCode('GETTER_AND_METHOD_WITH_SAME_NAME', 38, "");
/**
* 7.10 Superinterfaces: It is a compile-time error if the implements clause of a class includes
* type dynamic.
*/
- static final CompileTimeErrorCode IMPLEMENTS_DYNAMIC = new CompileTimeErrorCode('IMPLEMENTS_DYNAMIC', 38, "");
+ static final CompileTimeErrorCode IMPLEMENTS_DYNAMIC = new CompileTimeErrorCode('IMPLEMENTS_DYNAMIC', 39, "");
/**
* 7.10 Superinterfaces: It is a compile-time error if the implements clause of a class <i>C</i>
* includes a type expression that does not denote a class available in the lexical scope of
* <i>C</i>.
* @param typeName the name of the interface that was not found
*/
- static final CompileTimeErrorCode IMPLEMENTS_NON_CLASS = new CompileTimeErrorCode('IMPLEMENTS_NON_CLASS', 39, "Classes can only implement other classes");
+ static final CompileTimeErrorCode IMPLEMENTS_NON_CLASS = new CompileTimeErrorCode('IMPLEMENTS_NON_CLASS', 40, "Classes can only implement other classes");
/**
* 7.10 Superinterfaces: It is a compile-time error if a type <i>T</i> appears more than once in
* the implements clause of a class.
*/
- static final CompileTimeErrorCode IMPLEMENTS_REPEATED = new CompileTimeErrorCode('IMPLEMENTS_REPEATED', 40, "");
+ static final CompileTimeErrorCode IMPLEMENTS_REPEATED = new CompileTimeErrorCode('IMPLEMENTS_REPEATED', 41, "");
/**
* 7.10 Superinterfaces: It is a compile-time error if the interface of a class <i>C</i> is a
* superinterface of itself.
*/
- static final CompileTimeErrorCode IMPLEMENTS_SELF = new CompileTimeErrorCode('IMPLEMENTS_SELF', 41, "");
+ static final CompileTimeErrorCode IMPLEMENTS_SELF = new CompileTimeErrorCode('IMPLEMENTS_SELF', 42, "");
/**
* 14.1 Imports: It is a compile-time error to import two different libraries with the same name.
*/
- static final CompileTimeErrorCode IMPORT_DUPLICATED_LIBRARY_NAME = new CompileTimeErrorCode('IMPORT_DUPLICATED_LIBRARY_NAME', 42, "");
+ static final CompileTimeErrorCode IMPORT_DUPLICATED_LIBRARY_NAME = new CompileTimeErrorCode('IMPORT_DUPLICATED_LIBRARY_NAME', 43, "");
/**
* 14.1 Imports: It is a compile-time error if the compilation unit found at the specified URI is
* not a library declaration.
*/
- static final CompileTimeErrorCode IMPORT_OF_NON_LIBRARY = new CompileTimeErrorCode('IMPORT_OF_NON_LIBRARY', 43, "");
+ static final CompileTimeErrorCode IMPORT_OF_NON_LIBRARY = new CompileTimeErrorCode('IMPORT_OF_NON_LIBRARY', 44, "");
/**
* 13.9 Switch: It is a compile-time error if values of the expressions <i>e<sub>k</sub></i> are
* not instances of the same class <i>C</i>, for all <i>1 <= k <= n</i>.
*/
- static final CompileTimeErrorCode INCONSITENT_CASE_EXPRESSION_TYPES = new CompileTimeErrorCode('INCONSITENT_CASE_EXPRESSION_TYPES', 44, "");
+ static final CompileTimeErrorCode INCONSITENT_CASE_EXPRESSION_TYPES = new CompileTimeErrorCode('INCONSITENT_CASE_EXPRESSION_TYPES', 45, "");
/**
* 7.6.1 Generative Constructors: An initializing formal has the form <i>this.id</i>. It is a
* compile-time error if <i>id</i> is not the name of an instance variable of the immediately
* enclosing class.
*/
- static final CompileTimeErrorCode INITIALIZER_FOR_NON_EXISTANT_FIELD = new CompileTimeErrorCode('INITIALIZER_FOR_NON_EXISTANT_FIELD', 45, "");
+ static final CompileTimeErrorCode INITIALIZER_FOR_NON_EXISTANT_FIELD = new CompileTimeErrorCode('INITIALIZER_FOR_NON_EXISTANT_FIELD', 46, "");
/**
* TODO(brianwilkerson) Remove this when we have decided on how to report errors in compile-time
* constants. Until then, this acts as a placeholder for more informative errors.
*/
- static final CompileTimeErrorCode INVALID_CONSTANT = new CompileTimeErrorCode('INVALID_CONSTANT', 46, "");
+ static final CompileTimeErrorCode INVALID_CONSTANT = new CompileTimeErrorCode('INVALID_CONSTANT', 47, "");
/**
* 7.6 Constructors: It is a compile-time error if the name of a constructor is not a constructor
* name.
*/
- static final CompileTimeErrorCode INVALID_CONSTRUCTOR_NAME = new CompileTimeErrorCode('INVALID_CONSTRUCTOR_NAME', 47, "");
+ static final CompileTimeErrorCode INVALID_CONSTRUCTOR_NAME = new CompileTimeErrorCode('INVALID_CONSTRUCTOR_NAME', 48, "");
/**
* 7.6.2 Factories: It is a compile-time error if <i>M</i> is not the name of the immediately
* enclosing class.
*/
- static final CompileTimeErrorCode INVALID_FACTORY_NAME_NOT_A_CLASS = new CompileTimeErrorCode('INVALID_FACTORY_NAME_NOT_A_CLASS', 48, "");
+ static final CompileTimeErrorCode INVALID_FACTORY_NAME_NOT_A_CLASS = new CompileTimeErrorCode('INVALID_FACTORY_NAME_NOT_A_CLASS', 49, "");
/**
* 7.1 Instance Methods: It is a static warning if an instance method <i>m1</i> overrides an
* instance member <i>m2</i>, the signature of <i>m2</i> explicitly specifies a default value for
* a formal parameter <i>p</i> and the signature of <i>m1</i> specifies a different default value
* for <i>p</i>.
*/
- static final CompileTimeErrorCode INVALID_OVERRIDE_DEFAULT_VALUE = new CompileTimeErrorCode('INVALID_OVERRIDE_DEFAULT_VALUE', 49, "");
+ static final CompileTimeErrorCode INVALID_OVERRIDE_DEFAULT_VALUE = new CompileTimeErrorCode('INVALID_OVERRIDE_DEFAULT_VALUE', 50, "");
/**
* 7.1: It is a compile-time error if an instance method <i>m1</i> overrides an instance member
* <i>m2</i> and <i>m1</i> does not declare all the named parameters declared by <i>m2</i>.
*/
- static final CompileTimeErrorCode INVALID_OVERRIDE_NAMED = new CompileTimeErrorCode('INVALID_OVERRIDE_NAMED', 50, "");
+ static final CompileTimeErrorCode INVALID_OVERRIDE_NAMED = new CompileTimeErrorCode('INVALID_OVERRIDE_NAMED', 51, "");
/**
* 7.1 Instance Methods: It is a compile-time error if an instance method m1 overrides an instance
* member <i>m2</i> and <i>m1</i> has fewer optional positional parameters than <i>m2</i>.
*/
- static final CompileTimeErrorCode INVALID_OVERRIDE_POSITIONAL = new CompileTimeErrorCode('INVALID_OVERRIDE_POSITIONAL', 51, "");
+ static final CompileTimeErrorCode INVALID_OVERRIDE_POSITIONAL = new CompileTimeErrorCode('INVALID_OVERRIDE_POSITIONAL', 52, "");
/**
* 7.1 Instance Methods: It is a compile-time error if an instance method <i>m1</i> overrides an
* instance member <i>m2</i> and <i>m1</i> has a different number of required parameters than
* <i>m2</i>.
*/
- static final CompileTimeErrorCode INVALID_OVERRIDE_REQUIRED = new CompileTimeErrorCode('INVALID_OVERRIDE_REQUIRED', 52, "");
+ static final CompileTimeErrorCode INVALID_OVERRIDE_REQUIRED = new CompileTimeErrorCode('INVALID_OVERRIDE_REQUIRED', 53, "");
/**
* 12.10 This: It is a compile-time error if this appears in a top-level function or variable
* initializer, in a factory constructor, or in a static method or variable initializer, or in the
* initializer of an instance variable.
*/
- static final CompileTimeErrorCode INVALID_REFERENCE_TO_THIS = new CompileTimeErrorCode('INVALID_REFERENCE_TO_THIS', 53, "");
+ static final CompileTimeErrorCode INVALID_REFERENCE_TO_THIS = new CompileTimeErrorCode('INVALID_REFERENCE_TO_THIS', 54, "");
/**
* 12.7 Maps: It is a compile-time error if the first type argument to a map literal is not
* String.
*/
- static final CompileTimeErrorCode INVALID_TYPE_ARGUMENT_FOR_KEY = new CompileTimeErrorCode('INVALID_TYPE_ARGUMENT_FOR_KEY', 54, "");
+ static final CompileTimeErrorCode INVALID_TYPE_ARGUMENT_FOR_KEY = new CompileTimeErrorCode('INVALID_TYPE_ARGUMENT_FOR_KEY', 55, "");
/**
* 12.6 Lists: It is a compile time error if the type argument of a constant list literal includes
* a type parameter.
*/
- static final CompileTimeErrorCode INVALID_TYPE_ARGUMENT_IN_CONST_LIST = new CompileTimeErrorCode('INVALID_TYPE_ARGUMENT_IN_CONST_LIST', 55, "");
+ static final CompileTimeErrorCode INVALID_TYPE_ARGUMENT_IN_CONST_LIST = new CompileTimeErrorCode('INVALID_TYPE_ARGUMENT_IN_CONST_LIST', 56, "");
/**
* 12.7 Maps: It is a compile time error if the type arguments of a constant map literal include a
* type parameter.
*/
- static final CompileTimeErrorCode INVALID_TYPE_ARGUMENT_IN_CONST_MAP = new CompileTimeErrorCode('INVALID_TYPE_ARGUMENT_IN_CONST_MAP', 56, "");
+ static final CompileTimeErrorCode INVALID_TYPE_ARGUMENT_IN_CONST_MAP = new CompileTimeErrorCode('INVALID_TYPE_ARGUMENT_IN_CONST_MAP', 57, "");
/**
* 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. It is a compile-time
* error if <i>k</i>'s initializer list contains an initializer for a variable that is not an
* instance variable declared in the immediately surrounding class.
*/
- static final CompileTimeErrorCode INVALID_VARIABLE_IN_INITIALIZER = new CompileTimeErrorCode('INVALID_VARIABLE_IN_INITIALIZER', 57, "");
+ static final CompileTimeErrorCode INVALID_VARIABLE_IN_INITIALIZER = new CompileTimeErrorCode('INVALID_VARIABLE_IN_INITIALIZER', 58, "");
/**
* 13.13 Break: It is a compile-time error if no such statement <i>s<sub>E</sub></i> exists within
* the innermost function in which <i>s<sub>b</sub></i> occurs.
@@ -669,7 +688,7 @@
* <i>s<sub>E</sub></i> exists within the innermost function in which <i>s<sub>c</sub></i> occurs.
* @param labelName the name of the unresolvable label
*/
- static final CompileTimeErrorCode LABEL_IN_OUTER_SCOPE = new CompileTimeErrorCode('LABEL_IN_OUTER_SCOPE', 58, "Cannot reference label '%s' declared in an outer method");
+ static final CompileTimeErrorCode LABEL_IN_OUTER_SCOPE = new CompileTimeErrorCode('LABEL_IN_OUTER_SCOPE', 59, "Cannot reference label '%s' declared in an outer method");
/**
* 13.13 Break: It is a compile-time error if no such statement <i>s<sub>E</sub></i> exists within
* the innermost function in which <i>s<sub>b</sub></i> occurs.
@@ -678,47 +697,47 @@
* <i>s<sub>E</sub></i> exists within the innermost function in which <i>s<sub>c</sub></i> occurs.
* @param labelName the name of the unresolvable label
*/
- static final CompileTimeErrorCode LABEL_UNDEFINED = new CompileTimeErrorCode('LABEL_UNDEFINED', 59, "Cannot reference undefined label '%s'");
+ static final CompileTimeErrorCode LABEL_UNDEFINED = new CompileTimeErrorCode('LABEL_UNDEFINED', 60, "Cannot reference undefined label '%s'");
/**
* 7 Classes: It is a compile time error if a class <i>C</i> declares a member with the same name
* as <i>C</i>.
*/
- static final CompileTimeErrorCode MEMBER_WITH_CLASS_NAME = new CompileTimeErrorCode('MEMBER_WITH_CLASS_NAME', 60, "");
+ static final CompileTimeErrorCode MEMBER_WITH_CLASS_NAME = new CompileTimeErrorCode('MEMBER_WITH_CLASS_NAME', 61, "");
/**
* 9 Mixins: It is a compile-time error if a declared or derived mixin explicitly declares a
* constructor.
*/
- static final CompileTimeErrorCode MIXIN_DECLARES_CONSTRUCTOR = new CompileTimeErrorCode('MIXIN_DECLARES_CONSTRUCTOR', 61, "");
+ static final CompileTimeErrorCode MIXIN_DECLARES_CONSTRUCTOR = new CompileTimeErrorCode('MIXIN_DECLARES_CONSTRUCTOR', 62, "");
/**
* 9 Mixins: It is a compile-time error if a mixin is derived from a class whose superclass is not
* Object.
*/
- static final CompileTimeErrorCode MIXIN_INHERITS_FROM_NOT_OBJECT = new CompileTimeErrorCode('MIXIN_INHERITS_FROM_NOT_OBJECT', 62, "");
+ static final CompileTimeErrorCode MIXIN_INHERITS_FROM_NOT_OBJECT = new CompileTimeErrorCode('MIXIN_INHERITS_FROM_NOT_OBJECT', 63, "");
/**
* 9.1 Mixin Application: It is a compile-time error if <i>M</i> does not denote a class or mixin
* available in the immediately enclosing scope.
* @param typeName the name of the mixin that was not found
*/
- static final CompileTimeErrorCode MIXIN_OF_NON_CLASS = new CompileTimeErrorCode('MIXIN_OF_NON_CLASS', 63, "Classes can only mixin other classes");
+ static final CompileTimeErrorCode MIXIN_OF_NON_CLASS = new CompileTimeErrorCode('MIXIN_OF_NON_CLASS', 64, "Classes can only mixin other classes");
/**
* 9.1 Mixin Application: If <i>M</i> is a class, it is a compile time error if a well formed
* mixin cannot be derived from <i>M</i>.
*/
- static final CompileTimeErrorCode MIXIN_OF_NON_MIXIN = new CompileTimeErrorCode('MIXIN_OF_NON_MIXIN', 64, "");
+ static final CompileTimeErrorCode MIXIN_OF_NON_MIXIN = new CompileTimeErrorCode('MIXIN_OF_NON_MIXIN', 65, "");
/**
* 9 Mixins: It is a compile-time error if a declared or derived mixin refers to super.
*/
- static final CompileTimeErrorCode MIXIN_REFERENCES_SUPER = new CompileTimeErrorCode('MIXIN_REFERENCES_SUPER', 65, "");
+ static final CompileTimeErrorCode MIXIN_REFERENCES_SUPER = new CompileTimeErrorCode('MIXIN_REFERENCES_SUPER', 66, "");
/**
* 9.1 Mixin Application: It is a compile-time error if <i>S</i> does not denote a class available
* in the immediately enclosing scope.
*/
- static final CompileTimeErrorCode MIXIN_WITH_NON_CLASS_SUPERCLASS = new CompileTimeErrorCode('MIXIN_WITH_NON_CLASS_SUPERCLASS', 66, "");
+ static final CompileTimeErrorCode MIXIN_WITH_NON_CLASS_SUPERCLASS = new CompileTimeErrorCode('MIXIN_WITH_NON_CLASS_SUPERCLASS', 67, "");
/**
* 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. Then <i>k</i> may
* include at most one superinitializer in its initializer list or a compile time error occurs.
*/
- static final CompileTimeErrorCode MULTIPLE_SUPER_INITIALIZERS = new CompileTimeErrorCode('MULTIPLE_SUPER_INITIALIZERS', 67, "");
+ static final CompileTimeErrorCode MULTIPLE_SUPER_INITIALIZERS = new CompileTimeErrorCode('MULTIPLE_SUPER_INITIALIZERS', 68, "");
/**
* 12.11.1 New: It is a compile time error if <i>S</i> is not a generic type with <i>m</i> type
* parameters.
@@ -726,12 +745,12 @@
* @param argumentCount the number of type arguments provided
* @param parameterCount the number of type parameters that were declared
*/
- static final CompileTimeErrorCode NEW_WITH_INVALID_TYPE_PARAMETERS = new CompileTimeErrorCode('NEW_WITH_INVALID_TYPE_PARAMETERS', 68, "The type '%s' is declared with %d type parameters, but %d type arguments were given");
+ static final CompileTimeErrorCode NEW_WITH_INVALID_TYPE_PARAMETERS = new CompileTimeErrorCode('NEW_WITH_INVALID_TYPE_PARAMETERS', 69, "The type '%s' is declared with %d type parameters, but %d type arguments were given");
/**
* 13.2 Expression Statements: It is a compile-time error if a non-constant map literal that has
* no explicit type arguments appears in a place where a statement is expected.
*/
- static final CompileTimeErrorCode NON_CONST_MAP_AS_EXPRESSION_STATEMENT = new CompileTimeErrorCode('NON_CONST_MAP_AS_EXPRESSION_STATEMENT', 69, "");
+ static final CompileTimeErrorCode NON_CONST_MAP_AS_EXPRESSION_STATEMENT = new CompileTimeErrorCode('NON_CONST_MAP_AS_EXPRESSION_STATEMENT', 70, "");
/**
* 13.9 Switch: Given a switch statement of the form <i>switch (e) { label<sub>11</sub> …
* label<sub>1j1</sub> case e<sub>1</sub>: s<sub>1</sub> … label<sub>n1</sub> …
@@ -741,116 +760,116 @@
* s<sub>n</sub>}</i>, it is a compile-time error if the expressions <i>e<sub>k</sub></i> are not
* compile-time constants, for all <i>1 <= k <= n</i>.
*/
- static final CompileTimeErrorCode NON_CONSTANT_CASE_EXPRESSION = new CompileTimeErrorCode('NON_CONSTANT_CASE_EXPRESSION', 70, "Case expressions must be constant");
+ static final CompileTimeErrorCode NON_CONSTANT_CASE_EXPRESSION = new CompileTimeErrorCode('NON_CONSTANT_CASE_EXPRESSION', 71, "Case expressions must be constant");
/**
* 6.2.2 Optional Formals: It is a compile-time error if the default value of an optional
* parameter is not a compile-time constant.
*/
- static final CompileTimeErrorCode NON_CONSTANT_DEFAULT_VALUE = new CompileTimeErrorCode('NON_CONSTANT_DEFAULT_VALUE', 71, "Default values of an optional parameter must be constant");
+ static final CompileTimeErrorCode NON_CONSTANT_DEFAULT_VALUE = new CompileTimeErrorCode('NON_CONSTANT_DEFAULT_VALUE', 72, "Default values of an optional parameter must be constant");
/**
* 12.6 Lists: It is a compile time error if an element of a constant list literal is not a
* compile-time constant.
*/
- static final CompileTimeErrorCode NON_CONSTANT_LIST_ELEMENT = new CompileTimeErrorCode('NON_CONSTANT_LIST_ELEMENT', 72, "'const' lists must have all constant values");
+ static final CompileTimeErrorCode NON_CONSTANT_LIST_ELEMENT = new CompileTimeErrorCode('NON_CONSTANT_LIST_ELEMENT', 73, "'const' lists must have all constant values");
/**
* 12.7 Maps: It is a compile time error if either a key or a value of an entry in a constant map
* literal is not a compile-time constant.
*/
- static final CompileTimeErrorCode NON_CONSTANT_MAP_KEY = new CompileTimeErrorCode('NON_CONSTANT_MAP_KEY', 73, "The keys in a 'const' map must be constant");
+ static final CompileTimeErrorCode NON_CONSTANT_MAP_KEY = new CompileTimeErrorCode('NON_CONSTANT_MAP_KEY', 74, "The keys in a 'const' map must be constant");
/**
* 12.7 Maps: It is a compile time error if either a key or a value of an entry in a constant map
* literal is not a compile-time constant.
*/
- static final CompileTimeErrorCode NON_CONSTANT_MAP_VALUE = new CompileTimeErrorCode('NON_CONSTANT_MAP_VALUE', 74, "The values in a 'const' map must be constant");
+ static final CompileTimeErrorCode NON_CONSTANT_MAP_VALUE = new CompileTimeErrorCode('NON_CONSTANT_MAP_VALUE', 75, "The values in a 'const' map must be constant");
/**
* 7.6.3 Constant Constructors: Any expression that appears within the initializer list of a
* constant constructor must be a potentially constant expression, or a compile-time error occurs.
*/
- static final CompileTimeErrorCode NON_CONSTANT_VALUE_IN_INITIALIZER = new CompileTimeErrorCode('NON_CONSTANT_VALUE_IN_INITIALIZER', 75, "");
+ static final CompileTimeErrorCode NON_CONSTANT_VALUE_IN_INITIALIZER = new CompileTimeErrorCode('NON_CONSTANT_VALUE_IN_INITIALIZER', 76, "");
/**
* 7.9 Superclasses: It is a compile-time error to specify an extends clause for class Object.
*/
- static final CompileTimeErrorCode OBJECT_CANNOT_EXTEND_ANOTHER_CLASS = new CompileTimeErrorCode('OBJECT_CANNOT_EXTEND_ANOTHER_CLASS', 76, "");
+ static final CompileTimeErrorCode OBJECT_CANNOT_EXTEND_ANOTHER_CLASS = new CompileTimeErrorCode('OBJECT_CANNOT_EXTEND_ANOTHER_CLASS', 77, "");
/**
* 7.1.1 Operators: It is a compile-time error to declare an optional parameter in an operator.
*/
- static final CompileTimeErrorCode OPTIONAL_PARAMETER_IN_OPERATOR = new CompileTimeErrorCode('OPTIONAL_PARAMETER_IN_OPERATOR', 77, "");
+ static final CompileTimeErrorCode OPTIONAL_PARAMETER_IN_OPERATOR = new CompileTimeErrorCode('OPTIONAL_PARAMETER_IN_OPERATOR', 78, "");
/**
* 8 Interfaces: It is a compile-time error if an interface member <i>m1</i> overrides an
* interface member <i>m2</i> and <i>m1</i> does not declare all the named parameters declared by
* <i>m2</i> in the same order.
*/
- static final CompileTimeErrorCode OVERRIDE_MISSING_NAMED_PARAMETERS = new CompileTimeErrorCode('OVERRIDE_MISSING_NAMED_PARAMETERS', 78, "");
+ static final CompileTimeErrorCode OVERRIDE_MISSING_NAMED_PARAMETERS = new CompileTimeErrorCode('OVERRIDE_MISSING_NAMED_PARAMETERS', 79, "");
/**
* 8 Interfaces: It is a compile-time error if an interface member <i>m1</i> overrides an
* interface member <i>m2</i> and <i>m1</i> has a different number of required parameters than
* <i>m2</i>.
*/
- static final CompileTimeErrorCode OVERRIDE_MISSING_REQUIRED_PARAMETERS = new CompileTimeErrorCode('OVERRIDE_MISSING_REQUIRED_PARAMETERS', 79, "");
+ static final CompileTimeErrorCode OVERRIDE_MISSING_REQUIRED_PARAMETERS = new CompileTimeErrorCode('OVERRIDE_MISSING_REQUIRED_PARAMETERS', 80, "");
/**
* 14.3 Parts: It is a compile time error if the contents of the URI are not a valid part
* declaration.
*/
- static final CompileTimeErrorCode PART_OF_NON_PART = new CompileTimeErrorCode('PART_OF_NON_PART', 80, "");
+ static final CompileTimeErrorCode PART_OF_NON_PART = new CompileTimeErrorCode('PART_OF_NON_PART', 81, "");
/**
* 14.1 Imports: It is a compile-time error if the current library declares a top-level member
* named <i>p</i>.
*/
- static final CompileTimeErrorCode PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER = new CompileTimeErrorCode('PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER', 81, "");
+ static final CompileTimeErrorCode PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER = new CompileTimeErrorCode('PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER', 82, "");
/**
* 6.2.2 Optional Formals: It is a compile-time error if the name of a named optional parameter
* begins with an ‘_’ character.
*/
- static final CompileTimeErrorCode PRIVATE_OPTIONAL_PARAMETER = new CompileTimeErrorCode('PRIVATE_OPTIONAL_PARAMETER', 82, "");
+ static final CompileTimeErrorCode PRIVATE_OPTIONAL_PARAMETER = new CompileTimeErrorCode('PRIVATE_OPTIONAL_PARAMETER', 83, "");
/**
* 12.1 Constants: It is a compile-time error if the value of a compile-time constant expression
* depends on itself.
*/
- static final CompileTimeErrorCode RECURSIVE_COMPILE_TIME_CONSTANT = new CompileTimeErrorCode('RECURSIVE_COMPILE_TIME_CONSTANT', 83, "");
+ static final CompileTimeErrorCode RECURSIVE_COMPILE_TIME_CONSTANT = new CompileTimeErrorCode('RECURSIVE_COMPILE_TIME_CONSTANT', 84, "");
/**
* 7.6.2 Factories: It is a compile-time error if a redirecting factory constructor redirects to
* itself, either directly or indirectly via a sequence of redirections.
*/
- static final CompileTimeErrorCode RECURSIVE_FACTORY_REDIRECT = new CompileTimeErrorCode('RECURSIVE_FACTORY_REDIRECT', 84, "");
+ static final CompileTimeErrorCode RECURSIVE_FACTORY_REDIRECT = new CompileTimeErrorCode('RECURSIVE_FACTORY_REDIRECT', 85, "");
/**
* 15.3.1 Typedef: It is a compile-time error if a typedef refers to itself via a chain of
* references that does not include a class type.
*/
- static final CompileTimeErrorCode RECURSIVE_FUNCTION_TYPE_ALIAS = new CompileTimeErrorCode('RECURSIVE_FUNCTION_TYPE_ALIAS', 85, "");
+ static final CompileTimeErrorCode RECURSIVE_FUNCTION_TYPE_ALIAS = new CompileTimeErrorCode('RECURSIVE_FUNCTION_TYPE_ALIAS', 86, "");
/**
* 8.1 Superinterfaces: It is a compile-time error if an interface is a superinterface of itself.
*/
- static final CompileTimeErrorCode RECURSIVE_INTERFACE_INHERITANCE = new CompileTimeErrorCode('RECURSIVE_INTERFACE_INHERITANCE', 86, "");
+ static final CompileTimeErrorCode RECURSIVE_INTERFACE_INHERITANCE = new CompileTimeErrorCode('RECURSIVE_INTERFACE_INHERITANCE', 87, "");
/**
* 7.6.2 Factories: It is a compile-time error if <i>k</i> is prefixed with the const modifier but
* <i>k’</i> is not a constant constructor.
*/
- static final CompileTimeErrorCode REDIRECT_TO_NON_CONST_CONSTRUCTOR = new CompileTimeErrorCode('REDIRECT_TO_NON_CONST_CONSTRUCTOR', 87, "");
+ static final CompileTimeErrorCode REDIRECT_TO_NON_CONST_CONSTRUCTOR = new CompileTimeErrorCode('REDIRECT_TO_NON_CONST_CONSTRUCTOR', 88, "");
/**
* 13.3 Local Variable Declaration: It is a compile-time error if <i>e</i> refers to the name
* <i>v</i> or the name <i>v=</i>.
*/
- static final CompileTimeErrorCode REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER = new CompileTimeErrorCode('REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER', 88, "");
+ static final CompileTimeErrorCode REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER = new CompileTimeErrorCode('REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER', 89, "");
/**
* 16.1.1 Reserved Words: A reserved word may not be used as an identifier; it is a compile-time
* error if a reserved word is used where an identifier is expected.
*/
- static final CompileTimeErrorCode RESERVED_WORD_AS_IDENTIFIER = new CompileTimeErrorCode('RESERVED_WORD_AS_IDENTIFIER', 89, "");
+ static final CompileTimeErrorCode RESERVED_WORD_AS_IDENTIFIER = new CompileTimeErrorCode('RESERVED_WORD_AS_IDENTIFIER', 90, "");
/**
* 13.11 Return: It is a compile-time error if a return statement of the form <i>return e;</i>
* appears in a generative constructor.
*/
- static final CompileTimeErrorCode RETURN_IN_GENERATIVE_CONSTRUCTOR = new CompileTimeErrorCode('RETURN_IN_GENERATIVE_CONSTRUCTOR', 90, "");
+ static final CompileTimeErrorCode RETURN_IN_GENERATIVE_CONSTRUCTOR = new CompileTimeErrorCode('RETURN_IN_GENERATIVE_CONSTRUCTOR', 91, "");
/**
* 6.1 Function Declarations: It is a compile-time error to preface a function declaration with
* the built-in identifier static.
*/
- static final CompileTimeErrorCode STATIC_TOP_LEVEL_FUNCTION = new CompileTimeErrorCode('STATIC_TOP_LEVEL_FUNCTION', 91, "");
+ static final CompileTimeErrorCode STATIC_TOP_LEVEL_FUNCTION = new CompileTimeErrorCode('STATIC_TOP_LEVEL_FUNCTION', 92, "");
/**
* 5 Variables: It is a compile-time error to preface a top level variable declaration with the
* built-in identifier static.
*/
- static final CompileTimeErrorCode STATIC_TOP_LEVEL_VARIABLE = new CompileTimeErrorCode('STATIC_TOP_LEVEL_VARIABLE', 92, "");
+ static final CompileTimeErrorCode STATIC_TOP_LEVEL_VARIABLE = new CompileTimeErrorCode('STATIC_TOP_LEVEL_VARIABLE', 93, "");
/**
* 12.15.4 Super Invocation: A super method invocation <i>i</i> has the form
* <i>super.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>: a<sub>n+1</sub>, …
@@ -859,17 +878,17 @@
* initializer list, in class Object, in a factory constructor, or in a static method or variable
* initializer.
*/
- static final CompileTimeErrorCode SUPER_IN_INVALID_CONTEXT = new CompileTimeErrorCode('SUPER_IN_INVALID_CONTEXT', 93, "");
+ static final CompileTimeErrorCode SUPER_IN_INVALID_CONTEXT = new CompileTimeErrorCode('SUPER_IN_INVALID_CONTEXT', 94, "");
/**
* 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. It is a compile-time
* error if a generative constructor of class Object includes a superinitializer.
*/
- static final CompileTimeErrorCode SUPER_INITIALIZER_IN_OBJECT = new CompileTimeErrorCode('SUPER_INITIALIZER_IN_OBJECT', 94, "");
+ static final CompileTimeErrorCode SUPER_INITIALIZER_IN_OBJECT = new CompileTimeErrorCode('SUPER_INITIALIZER_IN_OBJECT', 95, "");
/**
* 12.8 Throw: It is a compile-time error if an expression of the form throw; is not enclosed
* within a on-catch clause.
*/
- static final CompileTimeErrorCode THROW_WITHOUT_VALUE_OUTSIDE_ON = new CompileTimeErrorCode('THROW_WITHOUT_VALUE_OUTSIDE_ON', 95, "");
+ static final CompileTimeErrorCode THROW_WITHOUT_VALUE_OUTSIDE_ON = new CompileTimeErrorCode('THROW_WITHOUT_VALUE_OUTSIDE_ON', 96, "");
/**
* 12.11 Instance Creation: It is a compile-time error if a constructor of a non-generic type
* invoked by a new expression or a constant object expression is passed any type arguments.
@@ -878,14 +897,14 @@
* <i>G<T<sub>1</sub>, …, T<sub>n</sub>></i> and <i>G</i> is not a generic type with
* <i>n</i> type parameters.
*/
- static final CompileTimeErrorCode TYPE_ARGUMENTS_FOR_NON_GENERIC_CLASS = new CompileTimeErrorCode('TYPE_ARGUMENTS_FOR_NON_GENERIC_CLASS', 96, "");
+ static final CompileTimeErrorCode TYPE_ARGUMENTS_FOR_NON_GENERIC_CLASS = new CompileTimeErrorCode('TYPE_ARGUMENTS_FOR_NON_GENERIC_CLASS', 97, "");
/**
* 7.6.1 Generative Constructors: Let <i>C</i> be the class in which the superinitializer appears
* and let <i>S</i> be the superclass of <i>C</i>. Let <i>k</i> be a generative constructor. It is
* a compile-time error if class <i>S</i> does not declare a generative constructor named <i>S</i>
* (respectively <i>S.id</i>)
*/
- static final CompileTimeErrorCode UNDEFINED_CONSTRUCTOR_IN_INITIALIZER = new CompileTimeErrorCode('UNDEFINED_CONSTRUCTOR_IN_INITIALIZER', 97, "");
+ static final CompileTimeErrorCode UNDEFINED_CONSTRUCTOR_IN_INITIALIZER = new CompileTimeErrorCode('UNDEFINED_CONSTRUCTOR_IN_INITIALIZER', 98, "");
/**
* 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. Each final instance
* variable <i>f</i> declared in the immediately enclosing class must have an initializer in
@@ -897,7 +916,7 @@
* </ol>
* or a compile-time error occurs.
*/
- static final CompileTimeErrorCode UNINITIALIZED_FINAL_FIELD = new CompileTimeErrorCode('UNINITIALIZED_FINAL_FIELD', 98, "");
+ static final CompileTimeErrorCode UNINITIALIZED_FINAL_FIELD = new CompileTimeErrorCode('UNINITIALIZED_FINAL_FIELD', 99, "");
/**
* 14.1 Imports: It is a compile-time error if <i>x</i> is not a compile-time constant, or if
* <i>x</i> involves string interpolation.
@@ -908,7 +927,7 @@
* 14.5 URIs: It is a compile-time error if the string literal <i>x</i> that describes a URI is
* not a compile-time constant, or if <i>x</i> involves string interpolation.
*/
- static final CompileTimeErrorCode URI_WITH_INTERPOLATION = new CompileTimeErrorCode('URI_WITH_INTERPOLATION', 99, "URIs cannot use string interpolation");
+ static final CompileTimeErrorCode URI_WITH_INTERPOLATION = new CompileTimeErrorCode('URI_WITH_INTERPOLATION', 100, "URIs cannot use string interpolation");
/**
* 7.1.1 Operators: It is a compile-time error if the arity of the user-declared operator []= is
* not 2. It is a compile time error if the arity of a user-declared operator with one of the
@@ -916,12 +935,12 @@
* It is a compile time error if the arity of the user-declared operator - is not 0 or 1. It is a
* compile time error if the arity of the user-declared operator ~ is not 0.
*/
- static final CompileTimeErrorCode WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR = new CompileTimeErrorCode('WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR', 100, "");
+ static final CompileTimeErrorCode WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR = new CompileTimeErrorCode('WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR', 101, "");
/**
* 7.3 Setters: It is a compile-time error if a setter’s formal parameter list does not include
* exactly one required formal parameter <i>p</i>.
*/
- static final CompileTimeErrorCode WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER = new CompileTimeErrorCode('WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER', 101, "");
+ static final CompileTimeErrorCode WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER = new CompileTimeErrorCode('WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER', 102, "");
/**
* 12.11 Instance Creation: It is a compile-time error if a constructor of a generic type with
* <i>n</i> type parameters invoked by a new expression or a constant object expression is passed
@@ -931,8 +950,8 @@
* <i>G<T<sub>1</sub>, …, T<sub>n</sub>></i> and <i>G</i> is not a generic type with
* <i>n</i> type parameters.
*/
- static final CompileTimeErrorCode WRONG_NUMBER_OF_TYPE_ARGUMENTS = new CompileTimeErrorCode('WRONG_NUMBER_OF_TYPE_ARGUMENTS', 102, "");
- static final List<CompileTimeErrorCode> values = [AMBIGUOUS_EXPORT, AMBIGUOUS_IMPORT, ARGUMENT_DEFINITION_TEST_NON_PARAMETER, BUILT_IN_IDENTIFIER_AS_TYPE, BUILT_IN_IDENTIFIER_AS_TYPE_NAME, BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME, BUILT_IN_IDENTIFIER_AS_TYPE_VARIABLE_NAME, CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, COMPILE_TIME_CONSTANT_RAISES_EXCEPTION, COMPILE_TIME_CONSTANT_RAISES_EXCEPTION_DIVIDE_BY_ZERO, CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD, CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD, CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD, CONST_FORMAL_PARAMETER, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, CONST_EVAL_THROWS_EXCEPTION, CONST_WITH_INVALID_TYPE_PARAMETERS, CONST_WITH_NON_CONST, CONST_WITH_NON_CONSTANT_ARGUMENT, CONST_WITH_NON_TYPE, CONST_WITH_TYPE_PARAMETERS, CONST_WITH_UNDEFINED_CONSTRUCTOR, DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS, DUPLICATE_DEFINITION, DUPLICATE_MEMBER_NAME, DUPLICATE_MEMBER_NAME_INSTANCE_STATIC, DUPLICATE_NAMED_ARGUMENT, EXPORT_OF_NON_LIBRARY, EXTENDS_NON_CLASS, EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS, FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS, FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION, FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER, FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR, FINAL_INITIALIZED_MULTIPLE_TIMES, FINAL_NOT_INITIALIZED, GETTER_AND_METHOD_WITH_SAME_NAME, IMPLEMENTS_DYNAMIC, IMPLEMENTS_NON_CLASS, IMPLEMENTS_REPEATED, IMPLEMENTS_SELF, IMPORT_DUPLICATED_LIBRARY_NAME, IMPORT_OF_NON_LIBRARY, INCONSITENT_CASE_EXPRESSION_TYPES, INITIALIZER_FOR_NON_EXISTANT_FIELD, INVALID_CONSTANT, INVALID_CONSTRUCTOR_NAME, INVALID_FACTORY_NAME_NOT_A_CLASS, INVALID_OVERRIDE_DEFAULT_VALUE, INVALID_OVERRIDE_NAMED, INVALID_OVERRIDE_POSITIONAL, INVALID_OVERRIDE_REQUIRED, INVALID_REFERENCE_TO_THIS, INVALID_TYPE_ARGUMENT_FOR_KEY, INVALID_TYPE_ARGUMENT_IN_CONST_LIST, INVALID_TYPE_ARGUMENT_IN_CONST_MAP, INVALID_VARIABLE_IN_INITIALIZER, LABEL_IN_OUTER_SCOPE, LABEL_UNDEFINED, MEMBER_WITH_CLASS_NAME, MIXIN_DECLARES_CONSTRUCTOR, MIXIN_INHERITS_FROM_NOT_OBJECT, MIXIN_OF_NON_CLASS, MIXIN_OF_NON_MIXIN, MIXIN_REFERENCES_SUPER, MIXIN_WITH_NON_CLASS_SUPERCLASS, MULTIPLE_SUPER_INITIALIZERS, NEW_WITH_INVALID_TYPE_PARAMETERS, NON_CONST_MAP_AS_EXPRESSION_STATEMENT, NON_CONSTANT_CASE_EXPRESSION, NON_CONSTANT_DEFAULT_VALUE, NON_CONSTANT_LIST_ELEMENT, NON_CONSTANT_MAP_KEY, NON_CONSTANT_MAP_VALUE, NON_CONSTANT_VALUE_IN_INITIALIZER, OBJECT_CANNOT_EXTEND_ANOTHER_CLASS, OPTIONAL_PARAMETER_IN_OPERATOR, OVERRIDE_MISSING_NAMED_PARAMETERS, OVERRIDE_MISSING_REQUIRED_PARAMETERS, PART_OF_NON_PART, PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER, PRIVATE_OPTIONAL_PARAMETER, RECURSIVE_COMPILE_TIME_CONSTANT, RECURSIVE_FACTORY_REDIRECT, RECURSIVE_FUNCTION_TYPE_ALIAS, RECURSIVE_INTERFACE_INHERITANCE, REDIRECT_TO_NON_CONST_CONSTRUCTOR, REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER, RESERVED_WORD_AS_IDENTIFIER, RETURN_IN_GENERATIVE_CONSTRUCTOR, STATIC_TOP_LEVEL_FUNCTION, STATIC_TOP_LEVEL_VARIABLE, SUPER_IN_INVALID_CONTEXT, SUPER_INITIALIZER_IN_OBJECT, THROW_WITHOUT_VALUE_OUTSIDE_ON, TYPE_ARGUMENTS_FOR_NON_GENERIC_CLASS, UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, UNINITIALIZED_FINAL_FIELD, URI_WITH_INTERPOLATION, WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR, WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER, WRONG_NUMBER_OF_TYPE_ARGUMENTS];
+ static final CompileTimeErrorCode WRONG_NUMBER_OF_TYPE_ARGUMENTS = new CompileTimeErrorCode('WRONG_NUMBER_OF_TYPE_ARGUMENTS', 103, "");
+ static final List<CompileTimeErrorCode> values = [AMBIGUOUS_EXPORT, AMBIGUOUS_IMPORT, ARGUMENT_DEFINITION_TEST_NON_PARAMETER, BUILT_IN_IDENTIFIER_AS_TYPE, BUILT_IN_IDENTIFIER_AS_TYPE_NAME, BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME, BUILT_IN_IDENTIFIER_AS_TYPE_VARIABLE_NAME, CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, COMPILE_TIME_CONSTANT_RAISES_EXCEPTION, COMPILE_TIME_CONSTANT_RAISES_EXCEPTION_DIVIDE_BY_ZERO, CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD, CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD, CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD, CONST_FORMAL_PARAMETER, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, CONST_EVAL_THROWS_EXCEPTION, CONST_WITH_INVALID_TYPE_PARAMETERS, CONST_WITH_NON_CONST, CONST_WITH_NON_CONSTANT_ARGUMENT, CONST_WITH_NON_TYPE, CONST_WITH_TYPE_PARAMETERS, CONST_WITH_UNDEFINED_CONSTRUCTOR, DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS, DUPLICATE_DEFINITION, DUPLICATE_MEMBER_NAME, DUPLICATE_MEMBER_NAME_INSTANCE_STATIC, DUPLICATE_NAMED_ARGUMENT, EXPORT_OF_NON_LIBRARY, EXTENDS_NON_CLASS, EXTENDS_DISALLOWED_CLASS, IMPLEMENTS_DISALLOWED_CLASS, FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS, FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION, FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER, FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR, FINAL_INITIALIZED_MULTIPLE_TIMES, FINAL_NOT_INITIALIZED, GETTER_AND_METHOD_WITH_SAME_NAME, IMPLEMENTS_DYNAMIC, IMPLEMENTS_NON_CLASS, IMPLEMENTS_REPEATED, IMPLEMENTS_SELF, IMPORT_DUPLICATED_LIBRARY_NAME, IMPORT_OF_NON_LIBRARY, INCONSITENT_CASE_EXPRESSION_TYPES, INITIALIZER_FOR_NON_EXISTANT_FIELD, INVALID_CONSTANT, INVALID_CONSTRUCTOR_NAME, INVALID_FACTORY_NAME_NOT_A_CLASS, INVALID_OVERRIDE_DEFAULT_VALUE, INVALID_OVERRIDE_NAMED, INVALID_OVERRIDE_POSITIONAL, INVALID_OVERRIDE_REQUIRED, INVALID_REFERENCE_TO_THIS, INVALID_TYPE_ARGUMENT_FOR_KEY, INVALID_TYPE_ARGUMENT_IN_CONST_LIST, INVALID_TYPE_ARGUMENT_IN_CONST_MAP, INVALID_VARIABLE_IN_INITIALIZER, LABEL_IN_OUTER_SCOPE, LABEL_UNDEFINED, MEMBER_WITH_CLASS_NAME, MIXIN_DECLARES_CONSTRUCTOR, MIXIN_INHERITS_FROM_NOT_OBJECT, MIXIN_OF_NON_CLASS, MIXIN_OF_NON_MIXIN, MIXIN_REFERENCES_SUPER, MIXIN_WITH_NON_CLASS_SUPERCLASS, MULTIPLE_SUPER_INITIALIZERS, NEW_WITH_INVALID_TYPE_PARAMETERS, NON_CONST_MAP_AS_EXPRESSION_STATEMENT, NON_CONSTANT_CASE_EXPRESSION, NON_CONSTANT_DEFAULT_VALUE, NON_CONSTANT_LIST_ELEMENT, NON_CONSTANT_MAP_KEY, NON_CONSTANT_MAP_VALUE, NON_CONSTANT_VALUE_IN_INITIALIZER, OBJECT_CANNOT_EXTEND_ANOTHER_CLASS, OPTIONAL_PARAMETER_IN_OPERATOR, OVERRIDE_MISSING_NAMED_PARAMETERS, OVERRIDE_MISSING_REQUIRED_PARAMETERS, PART_OF_NON_PART, PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER, PRIVATE_OPTIONAL_PARAMETER, RECURSIVE_COMPILE_TIME_CONSTANT, RECURSIVE_FACTORY_REDIRECT, RECURSIVE_FUNCTION_TYPE_ALIAS, RECURSIVE_INTERFACE_INHERITANCE, REDIRECT_TO_NON_CONST_CONSTRUCTOR, REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER, RESERVED_WORD_AS_IDENTIFIER, RETURN_IN_GENERATIVE_CONSTRUCTOR, STATIC_TOP_LEVEL_FUNCTION, STATIC_TOP_LEVEL_VARIABLE, SUPER_IN_INVALID_CONTEXT, SUPER_INITIALIZER_IN_OBJECT, THROW_WITHOUT_VALUE_OUTSIDE_ON, TYPE_ARGUMENTS_FOR_NON_GENERIC_CLASS, UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, UNINITIALIZED_FINAL_FIELD, URI_WITH_INTERPOLATION, WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR, WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER, WRONG_NUMBER_OF_TYPE_ARGUMENTS];
final String __name;
final int __ordinal;
int get ordinal => __ordinal;
diff --git a/pkg/analyzer_experimental/lib/src/generated/html.dart b/pkg/analyzer_experimental/lib/src/generated/html.dart
index 1114485..f3c33b8 100644
--- a/pkg/analyzer_experimental/lib/src/generated/html.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/html.dart
@@ -42,10 +42,10 @@
* @param offset the offset from the beginning of the file to the first character in the token
*/
Token.con1(TokenType type, int offset) {
- _jtd_constructor_147_impl(type, offset);
+ _jtd_constructor_149_impl(type, offset);
}
- _jtd_constructor_147_impl(TokenType type, int offset) {
- _jtd_constructor_148_impl(type, offset, type.lexeme);
+ _jtd_constructor_149_impl(TokenType type, int offset) {
+ _jtd_constructor_150_impl(type, offset, type.lexeme);
}
/**
* Initialize a newly created token.
@@ -54,9 +54,9 @@
* @param value the lexeme represented by this token (not {@code null})
*/
Token.con2(TokenType type4, int offset3, String value7) {
- _jtd_constructor_148_impl(type4, offset3, value7);
+ _jtd_constructor_150_impl(type4, offset3, value7);
}
- _jtd_constructor_148_impl(TokenType type4, int offset3, String value7) {
+ _jtd_constructor_150_impl(TokenType type4, int offset3, String value7) {
this._type = type4;
this._value = value7;
this._offset = offset3;
diff --git a/pkg/analyzer_experimental/lib/src/generated/instrumentation.dart b/pkg/analyzer_experimental/lib/src/generated/instrumentation.dart
index f4c632b..c01a787 100644
--- a/pkg/analyzer_experimental/lib/src/generated/instrumentation.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/instrumentation.dart
@@ -75,15 +75,17 @@
}
}
class InstrumentationBuilder_8 implements InstrumentationBuilder {
- InstrumentationBuilder data(String name, int value) => this;
- InstrumentationBuilder data2(String name, String value) => this;
- InstrumentationBuilder data3(String name, List<String> value) => this;
+ InstrumentationBuilder data(String name, bool value) => this;
+ InstrumentationBuilder data2(String name, int value) => this;
+ InstrumentationBuilder data3(String name, String value) => this;
+ InstrumentationBuilder data4(String name, List<String> value) => this;
InstrumentationLevel get instrumentationLevel => InstrumentationLevel.OFF;
void log() {
}
- InstrumentationBuilder metric(String name, int value) => this;
- InstrumentationBuilder metric2(String name, String value) => this;
- InstrumentationBuilder metric3(String name, List<String> value) => this;
+ InstrumentationBuilder metric(String name, bool value) => this;
+ InstrumentationBuilder metric2(String name, int value) => this;
+ InstrumentationBuilder metric3(String name, String value) => this;
+ InstrumentationBuilder metric4(String name, List<String> value) => this;
}
class InstrumentationLogger_9 implements InstrumentationLogger {
InstrumentationBuilder createBuilder(String name) => Instrumentation._NULL_INSTRUMENTATION_BUILDER;
@@ -104,7 +106,7 @@
* @param value the value of the data to be collected
* @return this builder
*/
- InstrumentationBuilder data(String name, int value);
+ InstrumentationBuilder data(String name, bool value);
/**
* Append the given data to the data being collected by this builder. The information is declared
* to potentially contain data that is either user identifiable or contains user intellectual
@@ -113,7 +115,7 @@
* @param value the value of the data to be collected
* @return this builder
*/
- InstrumentationBuilder data2(String name, String value);
+ InstrumentationBuilder data2(String name, int value);
/**
* Append the given data to the data being collected by this builder. The information is declared
* to potentially contain data that is either user identifiable or contains user intellectual
@@ -122,7 +124,16 @@
* @param value the value of the data to be collected
* @return this builder
*/
- InstrumentationBuilder data3(String name, List<String> value);
+ InstrumentationBuilder data3(String name, String value);
+ /**
+ * Append the given data to the data being collected by this builder. The information is declared
+ * to potentially contain data that is either user identifiable or contains user intellectual
+ * property (but is not guaranteed to contain either).
+ * @param name the name used to identify the data
+ * @param value the value of the data to be collected
+ * @return this builder
+ */
+ InstrumentationBuilder data4(String name, List<String> value);
/**
* Answer the {@link InstrumentationLevel} of this {@code InstrumentationBuilder}.
* @return one of {@link InstrumentationLevel#EVERYTHING}, {@link InstrumentationLevel#METRICS},{@link InstrumentationLevel#OFF}
@@ -142,7 +153,7 @@
* @param value the value of the data to be collected
* @return this builder
*/
- InstrumentationBuilder metric(String name, int value);
+ InstrumentationBuilder metric(String name, bool value);
/**
* Append the given metric to the data being collected by this builder. The information is
* declared to contain only metrics data (data that is not user identifiable and does not contain
@@ -151,7 +162,7 @@
* @param value the value of the data to be collected
* @return this builder
*/
- InstrumentationBuilder metric2(String name, String value);
+ InstrumentationBuilder metric2(String name, int value);
/**
* Append the given metric to the data being collected by this builder. The information is
* declared to contain only metrics data (data that is not user identifiable and does not contain
@@ -160,7 +171,16 @@
* @param value the value of the data to be collected
* @return this builder
*/
- InstrumentationBuilder metric3(String name, List<String> value);
+ InstrumentationBuilder metric3(String name, String value);
+ /**
+ * Append the given metric to the data being collected by this builder. The information is
+ * declared to contain only metrics data (data that is not user identifiable and does not contain
+ * user intellectual property).
+ * @param name the name used to identify the data
+ * @param value the value of the data to be collected
+ * @return this builder
+ */
+ InstrumentationBuilder metric4(String name, List<String> value);
}
/**
* The instrumentation recording level representing (1) recording {@link #EVERYTHING} recording of
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_core.dart b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
index 1170ca1..877ce04 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_core.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
@@ -408,6 +408,10 @@
return a.toLowerCase() == b.toLowerCase();
}
+bool javaBooleanOr(bool a, bool b) {
+ return a || b;
+}
+
class JavaStringBuilder {
StringBuffer sb = new StringBuffer();
String toString() => sb.toString();
diff --git a/pkg/analyzer_experimental/lib/src/generated/parser.dart b/pkg/analyzer_experimental/lib/src/generated/parser.dart
index b23627d..ee8a24c 100644
--- a/pkg/analyzer_experimental/lib/src/generated/parser.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/parser.dart
@@ -1732,6 +1732,16 @@
return new ContinueStatement.full(continueKeyword, label, semicolon);
}
/**
+ * Parse a declared identifier declaration.
+ * @param commentAndMetadata the metadata to be associated with the directive
+ * @return the declared identifier that was parsed
+ */
+ DeclaredIdentifier parseDeclaredIdentifier(CommentAndMetadata commentAndMetadata) {
+ FinalConstVarOrType finalConstVarOrType = parseFinalConstVarOrType(false);
+ SimpleIdentifier identifier = parseSimpleIdentifier();
+ return new DeclaredIdentifier.full(commentAndMetadata.comment, commentAndMetadata.metadata, finalConstVarOrType.keyword, finalConstVarOrType.type, identifier);
+ }
+ /**
* Parse a directive.
* <pre>
* directive ::=
@@ -2151,7 +2161,7 @@
* | declaredIdentifier 'in' expression
* | identifier 'in' expression
* forInitializerStatement ::=
- * variableDeclarationList ';'
+ * localVariableDeclaration ';'
* | expression? ';'
* </pre>
* @return the for statement that was parsed
@@ -2165,6 +2175,7 @@
VariableDeclarationList variableList = null;
Expression initialization = null;
if (!matches5(TokenType.SEMICOLON)) {
+ CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
if (matchesIdentifier() && matches3(peek(), Keyword.IN)) {
List<VariableDeclaration> variables = new List<VariableDeclaration>();
SimpleIdentifier variableName = parseSimpleIdentifier();
@@ -2188,7 +2199,7 @@
if (variable.initializer != null) {
reportError4(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, []);
}
- loopVariable = new DeclaredIdentifier.full(null, null, variableList.keyword, variableList.type, variable.name);
+ loopVariable = new DeclaredIdentifier.full(commentAndMetadata.comment, commentAndMetadata.metadata, variableList.keyword, variableList.type, variable.name);
}
Token inKeyword = expect(Keyword.IN);
Expression iterator = parseExpression2();
@@ -4766,9 +4777,9 @@
* @param message the message template used to create the message to be displayed for the error
*/
ParserErrorCode.con1(String ___name, int ___ordinal, ErrorSeverity severity2, String message2) {
- _jtd_constructor_269_impl(___name, ___ordinal, severity2, message2);
+ _jtd_constructor_271_impl(___name, ___ordinal, severity2, message2);
}
- _jtd_constructor_269_impl(String ___name, int ___ordinal, ErrorSeverity severity2, String message2) {
+ _jtd_constructor_271_impl(String ___name, int ___ordinal, ErrorSeverity severity2, String message2) {
__name = ___name;
__ordinal = ___ordinal;
this._severity = severity2;
@@ -4779,10 +4790,10 @@
* @param message the message template used to create the message to be displayed for the error
*/
ParserErrorCode.con2(String ___name, int ___ordinal, String message) {
- _jtd_constructor_270_impl(___name, ___ordinal, message);
+ _jtd_constructor_272_impl(___name, ___ordinal, message);
}
- _jtd_constructor_270_impl(String ___name, int ___ordinal, String message) {
- _jtd_constructor_269_impl(___name, ___ordinal, ErrorSeverity.ERROR, message);
+ _jtd_constructor_272_impl(String ___name, int ___ordinal, String message) {
+ _jtd_constructor_271_impl(___name, ___ordinal, ErrorSeverity.ERROR, message);
}
ErrorSeverity get errorSeverity => _severity;
String get message => _message;
@@ -5097,10 +5108,10 @@
Object visitFormalParameterList(FormalParameterList node) {
String groupEnd = null;
_writer.print('(');
- NodeList<FormalParameter> parameters13 = node.parameters;
- int size7 = parameters13.length;
+ NodeList<FormalParameter> parameters14 = node.parameters;
+ int size7 = parameters14.length;
for (int i = 0; i < size7; i++) {
- FormalParameter parameter = parameters13[i];
+ FormalParameter parameter = parameters14[i];
if (i > 0) {
_writer.print(", ");
}
diff --git a/pkg/analyzer_experimental/lib/src/generated/resolver.dart b/pkg/analyzer_experimental/lib/src/generated/resolver.dart
index aba27db..002d360 100644
--- a/pkg/analyzer_experimental/lib/src/generated/resolver.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/resolver.dart
@@ -55,14 +55,14 @@
* @return the compilation unit element that was built
* @throws AnalysisException if the analysis could not be performed
*/
- CompilationUnitElementImpl buildCompilationUnit2(Source source13, CompilationUnit unit) {
+ CompilationUnitElementImpl buildCompilationUnit2(Source source15, CompilationUnit unit) {
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
unit.accept(builder);
- CompilationUnitElementImpl element = new CompilationUnitElementImpl(source13.shortName);
+ CompilationUnitElementImpl element = new CompilationUnitElementImpl(source15.shortName);
element.accessors = holder.accessors;
element.functions = holder.functions;
- element.source = source13;
+ element.source = source15;
element.typeAliases = holder.typeAliases;
element.types = holder.types;
element.topLevelVariables = holder.topLevelVariables;
@@ -176,7 +176,12 @@
element.const2 = node.constKeyword != null;
_currentHolder.addConstructor(element);
node.element = element;
- if (constructorName != null) {
+ if (constructorName == null) {
+ Identifier returnType4 = node.returnType;
+ if (returnType4 != null) {
+ element.nameOffset = returnType4.offset;
+ }
+ } else {
constructorName.element = element;
}
return null;
@@ -392,13 +397,12 @@
nameOfMethod = "unary-";
}
MethodElementImpl element = new MethodElementImpl.con2(nameOfMethod, methodName.offset);
- sc.Token keyword = node.modifierKeyword;
- element.abstract = matches(keyword, sc.Keyword.ABSTRACT);
+ element.abstract = node.isAbstract();
element.functions = holder.functions;
element.labels = holder.labels;
element.localVariables = holder.localVariables;
element.parameters = holder.parameters;
- element.static = matches(keyword, sc.Keyword.STATIC);
+ element.static = node.isStatic();
_currentHolder.addMethod(element);
methodName.element = element;
} else {
@@ -750,9 +754,9 @@
* @param unit the AST structure representing the HTML
* @throws AnalysisException if the analysis could not be performed
*/
- HtmlElementImpl buildHtmlElement2(Source source14, ht.HtmlUnit unit) {
- HtmlElementImpl result = new HtmlElementImpl(_context, source14.shortName);
- result.source = source14;
+ HtmlElementImpl buildHtmlElement2(Source source16, ht.HtmlUnit unit) {
+ HtmlElementImpl result = new HtmlElementImpl(_context, source16.shortName);
+ result.source = source16;
_htmlElement = result;
unit.accept(this);
_htmlElement = null;
@@ -969,12 +973,12 @@
}
ClassElement classElement = ((type13 as InterfaceType)).element;
ConstructorElement constructor;
- SimpleIdentifier name14 = node.name;
- if (name14 == null) {
+ SimpleIdentifier name15 = node.name;
+ if (name15 == null) {
constructor = classElement.unnamedConstructor;
} else {
- constructor = classElement.getNamedConstructor(name14.name);
- name14.element = constructor;
+ constructor = classElement.getNamedConstructor(name15.name);
+ name15.element = constructor;
}
node.element = constructor;
return null;
@@ -1051,8 +1055,8 @@
if (getter != null) {
FunctionType getterType = getter.type;
if (getterType != null) {
- Type2 returnType4 = getterType.returnType;
- if (!isExecutableType(returnType4)) {
+ Type2 returnType5 = getterType.returnType;
+ if (!isExecutableType(returnType5)) {
_resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
}
}
@@ -1069,8 +1073,8 @@
ClassElement targetClass = targetType.element as ClassElement;
PropertyAccessorElement accessor = lookUpGetterInType(targetClass, methodName2.name);
if (accessor != null) {
- Type2 returnType5 = accessor.type.returnType.substitute2(((targetType as InterfaceType)).typeArguments, TypeVariableTypeImpl.getTypes(targetClass.typeVariables));
- if (!isExecutableType(returnType5)) {
+ Type2 returnType6 = accessor.type.returnType.substitute2(((targetType as InterfaceType)).typeArguments, TypeVariableTypeImpl.getTypes(targetClass.typeVariables));
+ if (!isExecutableType(returnType6)) {
_resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
return null;
}
@@ -1102,8 +1106,8 @@
PropertyAccessorElement getter3 = ((element as PropertyInducingElement)).getter;
FunctionType getterType = getter3.type;
if (getterType != null) {
- Type2 returnType6 = getterType.returnType;
- if (!isExecutableType(returnType6)) {
+ Type2 returnType7 = getterType.returnType;
+ if (!isExecutableType(returnType7)) {
_resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
}
}
@@ -1375,11 +1379,11 @@
* @param name the name being searched for
* @return the parameter with the given name
*/
- ParameterElement findNamedParameter(List<ParameterElement> parameters, String name25) {
+ ParameterElement findNamedParameter(List<ParameterElement> parameters, String name26) {
for (ParameterElement parameter in parameters) {
if (identical(parameter.parameterKind, ParameterKind.NAMED)) {
String parameteName = parameter.name;
- if (parameteName != null && parameteName == name25) {
+ if (parameteName != null && parameteName == name26) {
return parameter;
}
}
@@ -1755,10 +1759,10 @@
List<ParameterElement> parameters11 = invokedMethod.parameters;
for (Expression argument in argumentList.arguments) {
if (argument is NamedExpression) {
- SimpleIdentifier name15 = ((argument as NamedExpression)).name.label;
- ParameterElement parameter = findNamedParameter(parameters11, name15.name);
+ SimpleIdentifier name16 = ((argument as NamedExpression)).name.label;
+ ParameterElement parameter = findNamedParameter(parameters11, name16.name);
if (parameter != null) {
- recordResolution(name15, parameter);
+ recordResolution(name16, parameter);
}
}
}
@@ -2206,10 +2210,10 @@
* @param analysisContext the analysis context in which the library is being analyzed
*/
LibraryResolver.con1(AnalysisContextImpl analysisContext) {
- _jtd_constructor_237_impl(analysisContext);
+ _jtd_constructor_239_impl(analysisContext);
}
- _jtd_constructor_237_impl(AnalysisContextImpl analysisContext) {
- _jtd_constructor_238_impl(analysisContext, null);
+ _jtd_constructor_239_impl(AnalysisContextImpl analysisContext) {
+ _jtd_constructor_240_impl(analysisContext, null);
}
/**
* Initialize a newly created library resolver to resolve libraries within the given context.
@@ -2217,9 +2221,9 @@
* @param errorListener the listener to which analysis errors will be reported
*/
LibraryResolver.con2(AnalysisContextImpl analysisContext2, AnalysisErrorListener additionalAnalysisErrorListener) {
- _jtd_constructor_238_impl(analysisContext2, additionalAnalysisErrorListener);
+ _jtd_constructor_240_impl(analysisContext2, additionalAnalysisErrorListener);
}
- _jtd_constructor_238_impl(AnalysisContextImpl analysisContext2, AnalysisErrorListener additionalAnalysisErrorListener) {
+ _jtd_constructor_240_impl(AnalysisContextImpl analysisContext2, AnalysisErrorListener additionalAnalysisErrorListener) {
this._analysisContext = analysisContext2;
this._recordingErrorListener = new RecordingErrorListener();
if (additionalAnalysisErrorListener == null) {
@@ -3184,7 +3188,7 @@
Object visitAssignmentExpression(AssignmentExpression node) {
sc.TokenType operator11 = node.operator.type;
if (operator11 != sc.TokenType.EQ) {
- return recordReturnType(node, node.element);
+ return recordReturnType(node, node.element, null);
}
return recordType(node, getType(node.rightHandSide));
}
@@ -3233,7 +3237,7 @@
}
break;
}
- return recordReturnType(node, node.element);
+ return recordReturnType(node, node.element, null);
}
/**
* The Dart Language Specification, 12.4: <blockquote>The static type of a boolean literal is{@code bool}.</blockquote>
@@ -3323,17 +3327,22 @@
* If <i>F</i> is not a function type, the static type of <i>i</i> is dynamic. Otherwise the
* static type of <i>i</i> is the declared return type of <i>F</i>.</blockquote>
*/
- Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) => recordReturnType(node, node.element);
+ Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) => recordReturnType(node, node.element, null);
/**
* The Dart Language Specification, 12.29: <blockquote>An assignable expression of the form
* <i>e<sub>1</sub>[e<sub>2</sub>]</i> is evaluated as a method invocation of the operator method
* <i>[]</i> on <i>e<sub>1</sub></i> with argument <i>e<sub>2</sub></i>.</blockquote>
*/
Object visitIndexExpression(IndexExpression node) {
- if (node.inSetterContext()) {
- return recordArgumentType(node, node.element);
+ Type2 type = getType(node.realTarget);
+ List<Type2> typeArgs = null;
+ if (type is InterfaceType) {
+ typeArgs = ((type as InterfaceType)).typeArguments;
}
- return recordReturnType(node, node.element);
+ if (node.inSetterContext()) {
+ return recordArgumentType(node, node.element, typeArgs);
+ }
+ return recordReturnType(node, node.element, typeArgs);
}
/**
* The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
@@ -3436,7 +3445,7 @@
* <i>i</i> is dynamic. Otherwise the static type of <i>i</i> is the declared return type of
* <i>F</i>.</blockquote>
*/
- Object visitMethodInvocation(MethodInvocation node) => recordReturnType(node, node.methodName.element);
+ Object visitMethodInvocation(MethodInvocation node) => recordReturnType(node, node.methodName.element, null);
Object visitNamedExpression(NamedExpression node) => recordType(node, getType(node.expression));
/**
* The Dart Language Specification, 12.2: <blockquote>The static type of {@code null} is bottom.
@@ -3504,7 +3513,7 @@
if (identical(operator13, sc.TokenType.BANG)) {
return recordType(node, _typeProvider.boolType);
}
- return recordReturnType(node, node.element);
+ return recordReturnType(node, node.element, null);
}
/**
* The Dart Language Specification, 12.13: <blockquote> Property extraction allows for a member of
@@ -3673,11 +3682,11 @@
* @return the return type that was computed
*/
Type2 computeReturnType(FunctionDeclaration node) {
- TypeName returnType7 = node.returnType;
- if (returnType7 == null) {
+ TypeName returnType8 = node.returnType;
+ if (returnType8 == null) {
return computeReturnType2(node.functionExpression);
}
- return returnType7.type;
+ return returnType8.type;
}
/**
* Given a function expression, compute the return type of the function. The return type of
@@ -3757,12 +3766,20 @@
* represented by the given element.
* @param expression the node whose type is to be recorded
* @param element the element representing the method invoked by the given node
+ * @param typeArguments the array of {@link Type}s to perform a substitution on the parameter
+ * types from the type in the passed {@link Element}, or <code>null</code>
*/
- Object recordArgumentType(IndexExpression expression, MethodElement element) {
+ Object recordArgumentType(IndexExpression expression, MethodElement element, List<Type2> typeArguments10) {
if (element != null) {
List<ParameterElement> parameters12 = element.parameters;
if (parameters12 != null && parameters12.length == 2) {
- return recordType(expression, parameters12[1].type);
+ ClassElement classElement = parameters12[1].getAncestor(ClassElement);
+ List<Type2> typeParameters = classElement == null ? null : classElement.type.typeArguments;
+ if (typeArguments10 == null || typeParameters == null || typeArguments10.length != typeParameters.length) {
+ return recordType(expression, parameters12[1].type);
+ } else {
+ return recordType(expression, parameters12[1].type.substitute2(typeArguments10, typeParameters));
+ }
}
}
return recordType(expression, _dynamicType);
@@ -3772,26 +3789,34 @@
* represented by the given element.
* @param expression the node whose type is to be recorded
* @param element the element representing the method or function invoked by the given node
+ * @param typeArguments the array of {@link Type}s to perform a substitution on the parameter
+ * types from the type in the passed {@link Element}, or <code>null</code>
*/
- Object recordReturnType(Expression expression, Element element) {
+ Object recordReturnType(Expression expression, Element element, List<Type2> typeArguments11) {
if (element is PropertyAccessorElement) {
FunctionType propertyType = ((element as PropertyAccessorElement)).type;
if (propertyType != null) {
- Type2 returnType8 = propertyType.returnType;
- if (returnType8 is FunctionType) {
- Type2 innerReturnType = ((returnType8 as FunctionType)).returnType;
+ Type2 returnType9 = propertyType.returnType;
+ if (returnType9 is FunctionType) {
+ Type2 innerReturnType = ((returnType9 as FunctionType)).returnType;
if (innerReturnType != null) {
return recordType(expression, innerReturnType);
}
}
- if (returnType8 != null) {
- return recordType(expression, returnType8);
+ if (returnType9 != null) {
+ return recordType(expression, returnType9);
}
}
} else if (element is ExecutableElement) {
FunctionType type17 = ((element as ExecutableElement)).type;
if (type17 != null) {
- return recordType(expression, type17.returnType);
+ ClassElement classElement = element.getAncestor(ClassElement);
+ List<Type2> typeParameters = classElement == null ? null : classElement.type.typeArguments;
+ if (typeArguments11 == null || typeParameters == null || typeArguments11.length != typeParameters.length) {
+ return recordType(expression, type17.returnType);
+ } else {
+ return recordType(expression, type17.returnType.substitute2(typeArguments11, typeParameters));
+ }
}
} else if (element is VariableElement) {
Type2 variableType = ((element as VariableElement)).type;
@@ -3821,7 +3846,7 @@
* @param returnType the return type of the function, or {@code null} if no type was declared
* @param parameters the elements representing the parameters to the function
*/
- void setTypeInformation(FunctionTypeImpl functionType, Type2 returnType11, FormalParameterList parameterList) {
+ void setTypeInformation(FunctionTypeImpl functionType, Type2 returnType12, FormalParameterList parameterList) {
List<Type2> normalParameterTypes = new List<Type2>();
List<Type2> optionalParameterTypes = new List<Type2>();
LinkedHashMap<String, Type2> namedParameterTypes = new LinkedHashMap<String, Type2>();
@@ -3842,7 +3867,7 @@
functionType.normalParameterTypes = new List.from(normalParameterTypes);
functionType.optionalParameterTypes = new List.from(optionalParameterTypes);
functionType.namedParameterTypes = namedParameterTypes;
- functionType.returnType = returnType11;
+ functionType.returnType = returnType12;
}
get thisType_J2DAccessor => _thisType;
set thisType_J2DAccessor(__v) => _thisType = __v;
@@ -3894,6 +3919,11 @@
*/
InterfaceType get mapType;
/**
+ * Return the type representing the built-in type 'num'.
+ * @return the type representing the built-in type 'num'
+ */
+ InterfaceType get numType;
+ /**
* Return the type representing the built-in type 'Object'.
* @return the type representing the built-in type 'Object'
*/
@@ -3953,6 +3983,10 @@
*/
InterfaceType _mapType;
/**
+ * The type representing the built-in type 'num'.
+ */
+ InterfaceType _numType;
+ /**
* The type representing the built-in type 'Object'.
*/
InterfaceType _objectType;
@@ -3983,6 +4017,7 @@
InterfaceType get intType => _intType;
InterfaceType get listType => _listType;
InterfaceType get mapType => _mapType;
+ InterfaceType get numType => _numType;
InterfaceType get objectType => _objectType;
InterfaceType get stackTraceType => _stackTraceType;
InterfaceType get stringType => _stringType;
@@ -4016,6 +4051,7 @@
_intType = getType(namespace, "int");
_listType = getType(namespace, "List");
_mapType = getType(namespace, "Map");
+ _numType = getType(namespace, "num");
_objectType = getType(namespace, "Object");
_stackTraceType = getType(namespace, "StackTrace");
_stringType = getType(namespace, "String");
@@ -4485,17 +4521,17 @@
* @return the type specified by the type name
*/
InterfaceType resolveType(TypeName typeName, ErrorCode undefinedError, ErrorCode nonTypeError, ErrorCode nonInterfaceType) {
- Identifier name16 = typeName.name;
- Element element = nameScope.lookup(name16, definingLibrary);
+ Identifier name17 = typeName.name;
+ Element element = nameScope.lookup(name17, definingLibrary);
if (element == null) {
- reportError(undefinedError, name16, [name16.name]);
+ reportError(undefinedError, name17, [name17.name]);
} else if (element is ClassElement) {
Type2 classType = ((element as ClassElement)).type;
typeName.type = classType;
if (classType is InterfaceType) {
return classType as InterfaceType;
}
- reportError(nonInterfaceType, name16, [name16.name]);
+ reportError(nonInterfaceType, name17, [name17.name]);
} else if (element is MultiplyDefinedElement) {
List<Element> elements = ((element as MultiplyDefinedElement)).conflictingElements;
InterfaceType type = getType(elements);
@@ -4503,7 +4539,7 @@
typeName.type = type;
}
} else {
- reportError(nonTypeError, name16, [name16.name]);
+ reportError(nonTypeError, name17, [name17.name]);
}
return null;
}
@@ -4548,7 +4584,7 @@
* @param returnType the return type of the function, or {@code null} if no type was declared
* @param parameters the elements representing the parameters to the function
*/
- void setTypeInformation(FunctionTypeImpl functionType, TypeName returnType12, List<ParameterElement> parameters) {
+ void setTypeInformation(FunctionTypeImpl functionType, TypeName returnType13, List<ParameterElement> parameters) {
List<Type2> normalParameterTypes = new List<Type2>();
List<Type2> optionalParameterTypes = new List<Type2>();
LinkedHashMap<String, Type2> namedParameterTypes = new LinkedHashMap<String, Type2>();
@@ -4573,10 +4609,10 @@
if (!namedParameterTypes.isEmpty) {
functionType.namedParameterTypes = namedParameterTypes;
}
- if (returnType12 == null) {
+ if (returnType13 == null) {
functionType.returnType = _dynamicType;
} else {
- functionType.returnType = returnType12.type;
+ functionType.returnType = returnType13.type;
}
}
}
@@ -4669,8 +4705,8 @@
void defineParameters(ExecutableElement functionElement) {
Scope parameterScope = enclosingScope;
if (functionElement.enclosingElement is ExecutableElement) {
- String name17 = functionElement.name;
- if (name17 != null && !name17.isEmpty) {
+ String name18 = functionElement.name;
+ if (name18 != null && !name18.isEmpty) {
parameterScope.define(functionElement);
}
}
@@ -4738,10 +4774,10 @@
* @param onSwitchMember {@code true} if this label is associated with a {@code switch} member
*/
LabelScope.con1(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMember) {
- _jtd_constructor_248_impl(outerScope, onSwitchStatement, onSwitchMember);
+ _jtd_constructor_250_impl(outerScope, onSwitchStatement, onSwitchMember);
}
- _jtd_constructor_248_impl(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMember) {
- _jtd_constructor_249_impl(outerScope, EMPTY_LABEL, new LabelElementImpl(_EMPTY_LABEL_IDENTIFIER, onSwitchStatement, onSwitchMember));
+ _jtd_constructor_250_impl(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMember) {
+ _jtd_constructor_251_impl(outerScope, EMPTY_LABEL, new LabelElementImpl(_EMPTY_LABEL_IDENTIFIER, onSwitchStatement, onSwitchMember));
}
/**
* Initialize a newly created scope to represent the given label.
@@ -4750,9 +4786,9 @@
* @param element the element to which the label resolves
*/
LabelScope.con2(LabelScope outerScope2, String label4, LabelElement element19) {
- _jtd_constructor_249_impl(outerScope2, label4, element19);
+ _jtd_constructor_251_impl(outerScope2, label4, element19);
}
- _jtd_constructor_249_impl(LabelScope outerScope2, String label4, LabelElement element19) {
+ _jtd_constructor_251_impl(LabelScope outerScope2, String label4, LabelElement element19) {
this._outerScope = outerScope2;
this._label = label4;
this._element = element19;
@@ -5009,9 +5045,9 @@
* @param element the element to be added
*/
void addIfPublic(Map<String, Element> definedNames, Element element) {
- String name18 = element.name;
- if (name18 != null && !Scope.isPrivateName(name18)) {
- definedNames[name18] = element;
+ String name19 = element.name;
+ if (name19 != null && !Scope.isPrivateName(name19)) {
+ definedNames[name19] = element;
}
}
/**
@@ -5353,11 +5389,11 @@
* compile time constant.
* @param parameters the list of parameters to be validated
*/
- void validateDefaultValues(FormalParameterList parameters14) {
- if (parameters14 == null) {
+ void validateDefaultValues(FormalParameterList parameters15) {
+ if (parameters15 == null) {
return;
}
- for (FormalParameter parameter in parameters14.parameters) {
+ for (FormalParameter parameter in parameters15.parameters) {
if (parameter is DefaultFormalParameter) {
DefaultFormalParameter defaultParameter = parameter as DefaultFormalParameter;
Expression defaultValue2 = defaultParameter.defaultValue;
@@ -5395,15 +5431,26 @@
*/
TypeProvider _typeProvider;
/**
+ * This is set to <code>true</code> iff the visitor is currently visiting children nodes of a{@link ConstructorDeclaration} and the constructor is 'const'.
+ * @see #visitConstructorDeclaration(ConstructorDeclaration)
+ */
+ bool _isEnclosingConstructorConst = false;
+ /**
* The method or function that we are currently visiting, or {@code null} if we are not inside a
* method or function.
*/
ExecutableElement _currentFunction;
+ /**
+ * A list of types used by the {@link CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS} and{@link CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS} error codes.
+ */
+ List<InterfaceType> _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT;
ErrorVerifier(ErrorReporter errorReporter, LibraryElement currentLibrary, TypeProvider typeProvider) {
this._errorReporter = errorReporter;
this._currentLibrary = currentLibrary;
this._typeProvider = typeProvider;
+ _isEnclosingConstructorConst = false;
_dynamicType = typeProvider.dynamicType;
+ _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT = <InterfaceType> [typeProvider.numType, typeProvider.intType, typeProvider.doubleType, typeProvider.boolType, typeProvider.stringType];
}
Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) {
checkForArgumentDefinitionTestNonParameter(node);
@@ -5433,10 +5480,12 @@
ExecutableElement previousFunction = _currentFunction;
try {
_currentFunction = node.element;
+ _isEnclosingConstructorConst = node.constKeyword != null;
checkForConstConstructorWithNonFinalField(node);
checkForConflictingConstructorNameAndMember(node);
return super.visitConstructorDeclaration(node);
} finally {
+ _isEnclosingConstructorConst = false;
_currentFunction = previousFunction;
}
}
@@ -5444,6 +5493,10 @@
checkForNonBoolCondition(node.condition);
return super.visitDoStatement(node);
}
+ Object visitExtendsClause(ExtendsClause node) {
+ checkForExtendsDisallowedClass(node);
+ return super.visitExtendsClause(node);
+ }
Object visitFieldFormalParameter(FieldFormalParameter node) {
checkForConstFormalParameter(node);
return super.visitFieldFormalParameter(node);
@@ -5468,12 +5521,17 @@
}
Object visitFunctionTypeAlias(FunctionTypeAlias node) {
checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
+ checkForDefaultValueInFunctionTypeAlias(node);
return super.visitFunctionTypeAlias(node);
}
Object visitIfStatement(IfStatement node) {
checkForNonBoolCondition(node.condition);
return super.visitIfStatement(node);
}
+ Object visitImplementsClause(ImplementsClause node) {
+ checkForImplementsDisallowedClass(node);
+ return super.visitImplementsClause(node);
+ }
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
ConstructorName constructorName4 = node.constructorName;
TypeName typeName = constructorName4.type;
@@ -5507,6 +5565,10 @@
checkForCaseExpressionTypeImplementsEquals(node);
return super.visitSwitchStatement(node);
}
+ Object visitThrowExpression(ThrowExpression node) {
+ checkForConstEvalThrowsException(node);
+ return super.visitThrowExpression(node);
+ }
Object visitTypeParameter(TypeParameter node) {
checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_VARIABLE_NAME);
return super.visitTypeParameter(node);
@@ -5603,19 +5665,19 @@
ConstructorElement constructorElement = node.element;
SimpleIdentifier constructorName = node.name;
if (constructorName != null && constructorElement != null && !constructorName.isSynthetic()) {
- String name20 = constructorName.name;
+ String name21 = constructorName.name;
ClassElement classElement = constructorElement.enclosingElement;
List<FieldElement> fields3 = classElement.fields;
for (FieldElement field in fields3) {
- if (field.name == name20) {
- _errorReporter.reportError(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD, node, [name20]);
+ if (field.name == name21) {
+ _errorReporter.reportError(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD, node, [name21]);
return true;
}
}
List<MethodElement> methods3 = classElement.methods;
for (MethodElement method in methods3) {
- if (method.name == name20) {
- _errorReporter.reportError(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD, node, [name20]);
+ if (method.name == name21) {
+ _errorReporter.reportError(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD, node, [name21]);
return true;
}
}
@@ -5630,7 +5692,7 @@
* @see CompileTimeErrorCode#CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD
*/
bool checkForConstConstructorWithNonFinalField(ConstructorDeclaration node) {
- if (node.constKeyword == null) {
+ if (!_isEnclosingConstructorConst) {
return false;
}
ConstructorElement constructorElement = node.element;
@@ -5647,6 +5709,20 @@
return false;
}
/**
+ * This verifies that the passed throw expression is not enclosed in a 'const' constructor
+ * declaration.
+ * @param node the throw expression expression to evaluate
+ * @return return <code>true</code> if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#CONST_EVAL_THROWS_EXCEPTION
+ */
+ bool checkForConstEvalThrowsException(ThrowExpression node) {
+ if (_isEnclosingConstructorConst) {
+ _errorReporter.reportError(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node, []);
+ return true;
+ }
+ return false;
+ }
+ /**
* This verifies that the passed normal formal parameter is not 'const'.
* @param node the normal formal parameter to evaluate
* @return return <code>true</code> if and only if an error code is generated on the passed node
@@ -5691,13 +5767,90 @@
* @see CompileTimeErrorCode#CONST_WITH_NON_CONST
*/
bool checkForConstWithNonConst(InstanceCreationExpression node) {
- if (node.isConst() && !node.element.isConst()) {
+ ConstructorElement constructorElement = node.element;
+ if (node.isConst() && constructorElement != null && !constructorElement.isConst()) {
_errorReporter.reportError(CompileTimeErrorCode.CONST_WITH_NON_CONST, node, []);
return true;
}
return false;
}
/**
+ * This verifies that there are no default parameters in the passed function type alias.
+ * @param node the function type alias to evaluate
+ * @return return <code>true</code> if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS
+ */
+ bool checkForDefaultValueInFunctionTypeAlias(FunctionTypeAlias node) {
+ bool result = false;
+ FormalParameterList formalParameterList = node.parameters;
+ NodeList<FormalParameter> parameters13 = formalParameterList.parameters;
+ for (FormalParameter formalParameter in parameters13) {
+ if (formalParameter is DefaultFormalParameter) {
+ DefaultFormalParameter defaultFormalParameter = formalParameter as DefaultFormalParameter;
+ if (defaultFormalParameter.defaultValue != null) {
+ _errorReporter.reportError(CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS, node, []);
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+ /**
+ * This verifies that the passed extends clause does not extend classes such as num or String.
+ * @param node the extends clause to test
+ * @return return <code>true</code> if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS
+ */
+ bool checkForExtendsDisallowedClass(ExtendsClause extendsClause) => checkForExtendsOrImplementsDisallowedClass(extendsClause.superclass, CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS);
+ /**
+ * This verifies that the passed type name does not extend or implement classes such as 'num' or
+ * 'String'.
+ * @param node the type name to test
+ * @return return <code>true</code> if and only if an error code is generated on the passed node
+ * @see #checkForExtendsDisallowedClass(ExtendsClause)
+ * @see #checkForImplementsDisallowedClass(ImplementsClause)
+ * @see CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS
+ * @see CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS
+ */
+ bool checkForExtendsOrImplementsDisallowedClass(TypeName typeName, ErrorCode errorCode) {
+ if (typeName.isSynthetic()) {
+ return false;
+ }
+ Type2 superType = typeName.type;
+ for (InterfaceType disallowedType in _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT) {
+ if (superType == disallowedType) {
+ if (superType == _typeProvider.numType) {
+ ASTNode grandParent = typeName.parent.parent;
+ if (grandParent is ClassDeclaration) {
+ ClassElement classElement = ((grandParent as ClassDeclaration)).element;
+ Type2 classType = classElement.type;
+ if (classType != null && (classType == _typeProvider.intType || classType == _typeProvider.doubleType)) {
+ return false;
+ }
+ }
+ }
+ _errorReporter.reportError(errorCode, typeName, [disallowedType.name]);
+ return true;
+ }
+ }
+ return false;
+ }
+ /**
+ * This verifies that the passed implements clause does not implement classes such as 'num' or
+ * 'String'.
+ * @param node the implements clause to test
+ * @return return <code>true</code> if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS
+ */
+ bool checkForImplementsDisallowedClass(ImplementsClause implementsClause) {
+ bool result = false;
+ for (TypeName type in implementsClause.interfaces) {
+ result = javaBooleanOr(result, checkForExtendsOrImplementsDisallowedClass(type, CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS));
+ ;
+ }
+ return result;
+ }
+ /**
* This verifies that the passed assignment expression represents a valid assignment.
* @param node the assignment expression to evaluate
* @return return <code>true</code> if and only if an error code is generated on the passed node
diff --git a/pkg/analyzer_experimental/lib/src/generated/scanner.dart b/pkg/analyzer_experimental/lib/src/generated/scanner.dart
index 269367d..9afb79d 100644
--- a/pkg/analyzer_experimental/lib/src/generated/scanner.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/scanner.dart
@@ -255,10 +255,10 @@
* @param syntax the lexeme for the keyword
*/
Keyword.con1(String ___name, int ___ordinal, String syntax) {
- _jtd_constructor_276_impl(___name, ___ordinal, syntax);
+ _jtd_constructor_278_impl(___name, ___ordinal, syntax);
}
- _jtd_constructor_276_impl(String ___name, int ___ordinal, String syntax) {
- _jtd_constructor_277_impl(___name, ___ordinal, syntax, false);
+ _jtd_constructor_278_impl(String ___name, int ___ordinal, String syntax) {
+ _jtd_constructor_279_impl(___name, ___ordinal, syntax, false);
}
/**
* Initialize a newly created keyword to have the given syntax. The keyword is a pseudo-keyword if
@@ -267,9 +267,9 @@
* @param isPseudoKeyword {@code true} if this keyword is a pseudo-keyword
*/
Keyword.con2(String ___name, int ___ordinal, String syntax2, bool isPseudoKeyword) {
- _jtd_constructor_277_impl(___name, ___ordinal, syntax2, isPseudoKeyword);
+ _jtd_constructor_279_impl(___name, ___ordinal, syntax2, isPseudoKeyword);
}
- _jtd_constructor_277_impl(String ___name, int ___ordinal, String syntax2, bool isPseudoKeyword) {
+ _jtd_constructor_279_impl(String ___name, int ___ordinal, String syntax2, bool isPseudoKeyword) {
__name = ___name;
__ordinal = ___ordinal;
this._syntax = syntax2;
@@ -1654,15 +1654,15 @@
*/
int _precedence = 0;
TokenClass.con1(String ___name, int ___ordinal) {
- _jtd_constructor_286_impl(___name, ___ordinal);
+ _jtd_constructor_288_impl(___name, ___ordinal);
}
- _jtd_constructor_286_impl(String ___name, int ___ordinal) {
- _jtd_constructor_287_impl(___name, ___ordinal, 0);
+ _jtd_constructor_288_impl(String ___name, int ___ordinal) {
+ _jtd_constructor_289_impl(___name, ___ordinal, 0);
}
TokenClass.con2(String ___name, int ___ordinal, int precedence2) {
- _jtd_constructor_287_impl(___name, ___ordinal, precedence2);
+ _jtd_constructor_289_impl(___name, ___ordinal, precedence2);
}
- _jtd_constructor_287_impl(String ___name, int ___ordinal, int precedence2) {
+ _jtd_constructor_289_impl(String ___name, int ___ordinal, int precedence2) {
__name = ___name;
__ordinal = ___ordinal;
this._precedence = precedence2;
@@ -1788,15 +1788,15 @@
*/
String _lexeme;
TokenType.con1(String ___name, int ___ordinal) {
- _jtd_constructor_288_impl(___name, ___ordinal);
+ _jtd_constructor_290_impl(___name, ___ordinal);
}
- _jtd_constructor_288_impl(String ___name, int ___ordinal) {
- _jtd_constructor_289_impl(___name, ___ordinal, TokenClass.NO_CLASS, null);
+ _jtd_constructor_290_impl(String ___name, int ___ordinal) {
+ _jtd_constructor_291_impl(___name, ___ordinal, TokenClass.NO_CLASS, null);
}
TokenType.con2(String ___name, int ___ordinal, TokenClass tokenClass2, String lexeme2) {
- _jtd_constructor_289_impl(___name, ___ordinal, tokenClass2, lexeme2);
+ _jtd_constructor_291_impl(___name, ___ordinal, tokenClass2, lexeme2);
}
- _jtd_constructor_289_impl(String ___name, int ___ordinal, TokenClass tokenClass2, String lexeme2) {
+ _jtd_constructor_291_impl(String ___name, int ___ordinal, TokenClass tokenClass2, String lexeme2) {
__name = ___name;
__ordinal = ___ordinal;
this._tokenClass = tokenClass2 == null ? TokenClass.NO_CLASS : tokenClass2;
diff --git a/pkg/analyzer_experimental/lib/src/generated/sdk.dart b/pkg/analyzer_experimental/lib/src/generated/sdk.dart
index b8855c6..116f6ed 100644
--- a/pkg/analyzer_experimental/lib/src/generated/sdk.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/sdk.dart
@@ -261,15 +261,15 @@
if (argument is SimpleStringLiteral) {
library.path = ((argument as SimpleStringLiteral)).value;
} else if (argument is NamedExpression) {
- String name19 = ((argument as NamedExpression)).name.label.name;
+ String name20 = ((argument as NamedExpression)).name.label.name;
Expression expression15 = ((argument as NamedExpression)).expression;
- if (name19 == _CATEGORY) {
+ if (name20 == _CATEGORY) {
library.category = ((expression15 as SimpleStringLiteral)).value;
- } else if (name19 == _IMPLEMENTATION) {
+ } else if (name20 == _IMPLEMENTATION) {
library.implementation = ((expression15 as BooleanLiteral)).value;
- } else if (name19 == _DOCUMENTED) {
+ } else if (name20 == _DOCUMENTED) {
library.documented = ((expression15 as BooleanLiteral)).value;
- } else if (name19 == _PLATFORMS) {
+ } else if (name20 == _PLATFORMS) {
if (expression15 is SimpleIdentifier) {
String identifier = ((expression15 as SimpleIdentifier)).name;
if (identifier == _VM_PLATFORM) {
diff --git a/pkg/analyzer_experimental/lib/src/generated/source.dart b/pkg/analyzer_experimental/lib/src/generated/source.dart
index e99a657..9c5ca55 100644
--- a/pkg/analyzer_experimental/lib/src/generated/source.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/source.dart
@@ -5,6 +5,7 @@
import 'dart:uri';
import 'java_core.dart';
+import 'engine.dart' show AnalysisContext;
/**
* Instances of the class {@code SourceFactory} resolve possibly relative URI's against an existing{@link Source source}.
@@ -12,6 +13,10 @@
*/
class SourceFactory {
/**
+ * The analysis context that this source factory is associated with.
+ */
+ AnalysisContext _context;
+ /**
* The resolvers used to resolve absolute URI's.
*/
List<UriResolver> _resolvers;
@@ -25,9 +30,9 @@
* @param resolvers the resolvers used to resolve absolute URI's
*/
SourceFactory.con1(ContentCache contentCache2, List<UriResolver> resolvers2) {
- _jtd_constructor_300_impl(contentCache2, resolvers2);
+ _jtd_constructor_302_impl(contentCache2, resolvers2);
}
- _jtd_constructor_300_impl(ContentCache contentCache2, List<UriResolver> resolvers2) {
+ _jtd_constructor_302_impl(ContentCache contentCache2, List<UriResolver> resolvers2) {
this._contentCache = contentCache2;
this._resolvers = resolvers2;
}
@@ -36,10 +41,10 @@
* @param resolvers the resolvers used to resolve absolute URI's
*/
SourceFactory.con2(List<UriResolver> resolvers) {
- _jtd_constructor_301_impl(resolvers);
+ _jtd_constructor_303_impl(resolvers);
}
- _jtd_constructor_301_impl(List<UriResolver> resolvers) {
- _jtd_constructor_300_impl(new ContentCache(), resolvers);
+ _jtd_constructor_303_impl(List<UriResolver> resolvers) {
+ _jtd_constructor_302_impl(new ContentCache(), resolvers);
}
/**
* Return a source object representing the given absolute URI, or {@code null} if the URI is not a
@@ -65,6 +70,11 @@
*/
Source fromEncoding(String encoding) => forUri(encoding);
/**
+ * Return the analysis context that this source factory is associated with.
+ * @return the analysis context that this source factory is associated with
+ */
+ AnalysisContext get context => _context;
+ /**
* Return a source object representing the URI that results from resolving the given (possibly
* relative) contained URI against the URI associated with an existing source object, or{@code null} if either the contained URI is invalid or if it cannot be resolved against the
* source object's URI.
@@ -74,7 +84,7 @@
*/
Source resolveUri(Source containingSource, String containedUri) {
try {
- return resolveUri2(containingSource, new Uri.fromComponents(path: containedUri));
+ return resolveUri2(containingSource, new Uri(containedUri));
} on URISyntaxException catch (exception) {
return null;
}
@@ -90,6 +100,16 @@
_contentCache.setContents(source, contents);
}
/**
+ * Set the analysis context that this source factory is associated with to the given context.
+ * <p>
+ * <b>Note:</b> This method should only be invoked by{@link AnalysisContextImpl#setSourceFactory(SourceFactory)} and is only public out of
+ * necessity.
+ * @param context the analysis context that this source factory is associated with
+ */
+ void set context(AnalysisContext context2) {
+ this._context = context2;
+ }
+ /**
* Return the contents of the given source, or {@code null} if this factory does not override the
* contents of the source.
* <p>
@@ -174,6 +194,11 @@
*/
bool exists();
/**
+ * Return the analysis context in which this source is defined.
+ * @return the analysis context in which this source is defined
+ */
+ AnalysisContext get context;
+ /**
* Get the contents of this source and pass it to the given receiver. Exactly one of the methods
* defined on the receiver will be invoked unless an exception is thrown. The method that will be
* invoked depends on which of the possible representations of the contents is the most efficient.
diff --git a/pkg/analyzer_experimental/lib/src/generated/source_io.dart b/pkg/analyzer_experimental/lib/src/generated/source_io.dart
index d57574f..470a12b 100644
--- a/pkg/analyzer_experimental/lib/src/generated/source_io.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/source_io.dart
@@ -8,7 +8,8 @@
import 'dart:uri';
import 'java_core.dart';
import 'java_io.dart';
-import 'package:analyzer_experimental/src/generated/sdk.dart' show DartSdk;
+import 'sdk.dart' show DartSdk;
+import 'engine.dart' show AnalysisContext;
export 'source.dart';
/**
@@ -36,10 +37,10 @@
* @param file the file represented by this source
*/
FileBasedSource.con1(SourceFactory factory, JavaFile file) {
- _jtd_constructor_296_impl(factory, file);
+ _jtd_constructor_298_impl(factory, file);
}
- _jtd_constructor_296_impl(SourceFactory factory, JavaFile file) {
- _jtd_constructor_297_impl(factory, file, false);
+ _jtd_constructor_298_impl(SourceFactory factory, JavaFile file) {
+ _jtd_constructor_299_impl(factory, file, false);
}
/**
* Initialize a newly created source object.
@@ -48,15 +49,16 @@
* @param inSystemLibrary {@code true} if this source is in one of the system libraries
*/
FileBasedSource.con2(SourceFactory factory2, JavaFile file3, bool inSystemLibrary2) {
- _jtd_constructor_297_impl(factory2, file3, inSystemLibrary2);
+ _jtd_constructor_299_impl(factory2, file3, inSystemLibrary2);
}
- _jtd_constructor_297_impl(SourceFactory factory2, JavaFile file3, bool inSystemLibrary2) {
+ _jtd_constructor_299_impl(SourceFactory factory2, JavaFile file3, bool inSystemLibrary2) {
this._factory = factory2;
this._file = file3;
this._inSystemLibrary = inSystemLibrary2;
}
bool operator ==(Object object) => object != null && identical(this.runtimeType, object.runtimeType) && _file == ((object as FileBasedSource))._file;
bool exists() => _file.exists();
+ AnalysisContext get context => _factory.context;
void getContents(Source_ContentReceiver receiver) {
{
String contents = _factory.getContents(this);
@@ -133,6 +135,9 @@
return null;
}
JavaFile resolvedFile = _sdk.mapDartUri(uri.toString());
+ if (resolvedFile == null) {
+ return null;
+ }
return new FileBasedSource.con2(factory, resolvedFile, true);
}
}
@@ -216,19 +221,19 @@
* @param directory the directory (not {@code null})
*/
DirectoryBasedSourceContainer.con1(JavaFile directory) {
- _jtd_constructor_294_impl(directory);
+ _jtd_constructor_296_impl(directory);
}
- _jtd_constructor_294_impl(JavaFile directory) {
- _jtd_constructor_295_impl(directory.getPath());
+ _jtd_constructor_296_impl(JavaFile directory) {
+ _jtd_constructor_297_impl(directory.getPath());
}
/**
* Construct a container representing the specified path and containing any sources whose{@link Source#getFullName()} starts with the specified path.
* @param path the path (not {@code null} and not empty)
*/
DirectoryBasedSourceContainer.con2(String path3) {
- _jtd_constructor_295_impl(path3);
+ _jtd_constructor_297_impl(path3);
}
- _jtd_constructor_295_impl(String path3) {
+ _jtd_constructor_297_impl(String path3) {
this._path = appendFileSeparator(path3);
}
bool contains(Source source) => source.fullName.startsWith(_path);
diff --git a/pkg/analyzer_experimental/pubspec.yaml b/pkg/analyzer_experimental/pubspec.yaml
index de2c719..5cd79cb 100644
--- a/pkg/analyzer_experimental/pubspec.yaml
+++ b/pkg/analyzer_experimental/pubspec.yaml
@@ -4,5 +4,6 @@
description: Experimental static analyzer for Dart.
homepage: http://www.dartlang.org
dependencies:
- unittest: any
args: any
+dev_dependencies:
+ unittest: any
diff --git a/pkg/analyzer_experimental/test/generated/ast_test.dart b/pkg/analyzer_experimental/test/generated/ast_test.dart
index 68db34a..fec113d 100644
--- a/pkg/analyzer_experimental/test/generated/ast_test.dart
+++ b/pkg/analyzer_experimental/test/generated/ast_test.dart
@@ -357,9 +357,9 @@
* @return the type name that was created
*/
static TypeName typeName(ClassElement element55, List<TypeName> arguments) {
- SimpleIdentifier name21 = identifier2(element55.name);
- name21.element = element55;
- TypeName typeName = typeName2(name21, arguments);
+ SimpleIdentifier name22 = identifier2(element55.name);
+ name22.element = element55;
+ TypeName typeName = typeName2(name22, arguments);
typeName.type = element55.type;
return typeName;
}
diff --git a/pkg/analyzer_experimental/test/generated/element_test.dart b/pkg/analyzer_experimental/test/generated/element_test.dart
index f8712ad..62f3f6e 100644
--- a/pkg/analyzer_experimental/test/generated/element_test.dart
+++ b/pkg/analyzer_experimental/test/generated/element_test.dart
@@ -1159,7 +1159,7 @@
}
static LocalVariableElementImpl localVariableElement(Identifier name) => new LocalVariableElementImpl(name);
static LocalVariableElementImpl localVariableElement2(String name) => new LocalVariableElementImpl(ASTFactory.identifier2(name));
- static MethodElementImpl methodElement(String methodName, Type2 returnType13, List<Type2> argumentTypes) {
+ static MethodElementImpl methodElement(String methodName, Type2 returnType14, List<Type2> argumentTypes) {
MethodElementImpl method = new MethodElementImpl.con1(ASTFactory.identifier2(methodName));
int count = argumentTypes.length;
List<ParameterElement> parameters = new List<ParameterElement>(count);
@@ -1172,7 +1172,7 @@
method.parameters = parameters;
FunctionTypeImpl methodType = new FunctionTypeImpl.con1(method);
methodType.normalParameterTypes = argumentTypes;
- methodType.returnType = returnType13;
+ methodType.returnType = returnType14;
method.type = methodType;
return method;
}
@@ -1466,8 +1466,8 @@
}
void test_getReturnType() {
FunctionTypeImpl type = new FunctionTypeImpl.con1(new FunctionElementImpl.con1(ASTFactory.identifier2("f")));
- Type2 returnType9 = type.returnType;
- JUnitTestCase.assertEquals(VoidTypeImpl.instance, returnType9);
+ Type2 returnType10 = type.returnType;
+ JUnitTestCase.assertEquals(VoidTypeImpl.instance, returnType10);
}
void test_getTypeArguments() {
FunctionTypeImpl type = new FunctionTypeImpl.con1(new FunctionElementImpl.con1(ASTFactory.identifier2("f")));
@@ -1670,8 +1670,8 @@
FunctionTypeImpl type = new FunctionTypeImpl.con1(new FunctionElementImpl.con1(ASTFactory.identifier2("f")));
Type2 expectedType = new InterfaceTypeImpl.con1(new ClassElementImpl(ASTFactory.identifier2("C")));
type.returnType = expectedType;
- Type2 returnType10 = type.returnType;
- JUnitTestCase.assertEquals(expectedType, returnType10);
+ Type2 returnType11 = type.returnType;
+ JUnitTestCase.assertEquals(expectedType, returnType11);
}
void test_setTypeArguments() {
FunctionTypeImpl type = new FunctionTypeImpl.con1(new FunctionElementImpl.con1(ASTFactory.identifier2("f")));
diff --git a/pkg/analyzer_experimental/test/generated/parser_test.dart b/pkg/analyzer_experimental/test/generated/parser_test.dart
index 41eae27..01613ab 100644
--- a/pkg/analyzer_experimental/test/generated/parser_test.dart
+++ b/pkg/analyzer_experimental/test/generated/parser_test.dart
@@ -263,10 +263,10 @@
}
void test_parseArgument_named() {
NamedExpression expression = ParserTestCase.parse6("parseArgument", "n: x", []);
- Label name22 = expression.name;
- JUnitTestCase.assertNotNull(name22);
- JUnitTestCase.assertNotNull(name22.label);
- JUnitTestCase.assertNotNull(name22.colon);
+ Label name23 = expression.name;
+ JUnitTestCase.assertNotNull(name23);
+ JUnitTestCase.assertNotNull(name23.label);
+ JUnitTestCase.assertNotNull(name23.colon);
JUnitTestCase.assertNotNull(expression.expression);
}
void test_parseArgument_unnamed() {
@@ -1356,6 +1356,28 @@
JUnitTestCase.assertNull(statement.label);
JUnitTestCase.assertNotNull(statement.semicolon);
}
+ void test_parseDeclaredIdentifier_const() {
+ DeclaredIdentifier declaredIdentifier = ParserTestCase.parse("parseDeclaredIdentifier", <Object> [emptyCommentAndMetadata()], "const A a");
+ JUnitTestCase.assertNotNull(declaredIdentifier.keyword);
+ JUnitTestCase.assertTrue(declaredIdentifier.isConst());
+ JUnitTestCase.assertNotNull(declaredIdentifier.type);
+ }
+ void test_parseDeclaredIdentifier_final() {
+ DeclaredIdentifier declaredIdentifier = ParserTestCase.parse("parseDeclaredIdentifier", <Object> [emptyCommentAndMetadata()], "final A a");
+ JUnitTestCase.assertNotNull(declaredIdentifier.keyword);
+ JUnitTestCase.assertTrue(declaredIdentifier.isFinal());
+ JUnitTestCase.assertNotNull(declaredIdentifier.type);
+ }
+ void test_parseDeclaredIdentifier_type() {
+ DeclaredIdentifier declaredIdentifier = ParserTestCase.parse("parseDeclaredIdentifier", <Object> [emptyCommentAndMetadata()], "A a");
+ JUnitTestCase.assertNull(declaredIdentifier.keyword);
+ JUnitTestCase.assertNotNull(declaredIdentifier.type);
+ }
+ void test_parseDeclaredIdentifier_var() {
+ DeclaredIdentifier declaredIdentifier = ParserTestCase.parse("parseDeclaredIdentifier", <Object> [emptyCommentAndMetadata()], "var a");
+ JUnitTestCase.assertNotNull(declaredIdentifier.keyword);
+ JUnitTestCase.assertNull(declaredIdentifier.type);
+ }
void test_parseDirective_export() {
ExportDirective directive = ParserTestCase.parse("parseDirective", <Object> [emptyCommentAndMetadata()], "export 'lib/lib.dart';");
JUnitTestCase.assertNotNull(directive.keyword);
@@ -1779,11 +1801,12 @@
JUnitTestCase.assertNotNull(statement.rightParenthesis);
JUnitTestCase.assertNotNull(statement.body);
}
- void test_parseForStatement_each_noType() {
- ForEachStatement statement = ParserTestCase.parse6("parseForStatement", "for (element in list) {}", []);
+ void test_parseForStatement_each_noType_metadata() {
+ ForEachStatement statement = ParserTestCase.parse6("parseForStatement", "for (@A var element in list) {}", []);
JUnitTestCase.assertNotNull(statement.forKeyword);
JUnitTestCase.assertNotNull(statement.leftParenthesis);
JUnitTestCase.assertNotNull(statement.loopVariable);
+ EngineTestCase.assertSize(1, statement.loopVariable.metadata);
JUnitTestCase.assertNotNull(statement.inKeyword);
JUnitTestCase.assertNotNull(statement.iterator);
JUnitTestCase.assertNotNull(statement.rightParenthesis);
@@ -4393,6 +4416,22 @@
final __test = new SimpleParserTest();
runJUnitTest(__test, __test.test_parseContinueStatement_noLabel);
});
+ _ut.test('test_parseDeclaredIdentifier_const', () {
+ final __test = new SimpleParserTest();
+ runJUnitTest(__test, __test.test_parseDeclaredIdentifier_const);
+ });
+ _ut.test('test_parseDeclaredIdentifier_final', () {
+ final __test = new SimpleParserTest();
+ runJUnitTest(__test, __test.test_parseDeclaredIdentifier_final);
+ });
+ _ut.test('test_parseDeclaredIdentifier_type', () {
+ final __test = new SimpleParserTest();
+ runJUnitTest(__test, __test.test_parseDeclaredIdentifier_type);
+ });
+ _ut.test('test_parseDeclaredIdentifier_var', () {
+ final __test = new SimpleParserTest();
+ runJUnitTest(__test, __test.test_parseDeclaredIdentifier_var);
+ });
_ut.test('test_parseDirective_export', () {
final __test = new SimpleParserTest();
runJUnitTest(__test, __test.test_parseDirective_export);
@@ -4541,9 +4580,9 @@
final __test = new SimpleParserTest();
runJUnitTest(__test, __test.test_parseForStatement_each_identifier);
});
- _ut.test('test_parseForStatement_each_noType', () {
+ _ut.test('test_parseForStatement_each_noType_metadata', () {
final __test = new SimpleParserTest();
- runJUnitTest(__test, __test.test_parseForStatement_each_noType);
+ runJUnitTest(__test, __test.test_parseForStatement_each_noType_metadata);
});
_ut.test('test_parseForStatement_each_type', () {
final __test = new SimpleParserTest();
@@ -8229,6 +8268,7 @@
'parseConstructorFieldInitializer_0': new MethodTrampoline(0, (Parser target) => target.parseConstructorFieldInitializer()),
'parseConstructorName_0': new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
'parseContinueStatement_0': new MethodTrampoline(0, (Parser target) => target.parseContinueStatement()),
+ 'parseDeclaredIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseDeclaredIdentifier(arg0)),
'parseDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseDirective(arg0)),
'parseDocumentationComment_0': new MethodTrampoline(0, (Parser target) => target.parseDocumentationComment()),
'parseDoStatement_0': new MethodTrampoline(0, (Parser target) => target.parseDoStatement()),
diff --git a/pkg/analyzer_experimental/test/generated/resolver_test.dart b/pkg/analyzer_experimental/test/generated/resolver_test.dart
index e1343b4..963a3e9 100644
--- a/pkg/analyzer_experimental/test/generated/resolver_test.dart
+++ b/pkg/analyzer_experimental/test/generated/resolver_test.dart
@@ -577,13 +577,13 @@
_listener.assertNoErrors();
}
void test_visitSimpleFormalParameter_type() {
- InterfaceType intType8 = _typeProvider.intType;
- ClassElement intElement = intType8.element;
+ InterfaceType intType9 = _typeProvider.intType;
+ ClassElement intElement = intType9.element;
FormalParameter node = ASTFactory.simpleFormalParameter4(ASTFactory.typeName(intElement, []), "p");
SimpleIdentifier identifier18 = node.identifier;
ParameterElementImpl element = new ParameterElementImpl(identifier18);
identifier18.element = element;
- JUnitTestCase.assertSame(intType8, resolve5(node, [intElement]));
+ JUnitTestCase.assertSame(intType9, resolve5(node, [intElement]));
_listener.assertNoErrors();
}
void test_visitTypeName_noParameters_noArguments() {
@@ -921,12 +921,6 @@
assertErrors([CompileTimeErrorCode.COMPILE_TIME_CONSTANT_RAISES_EXCEPTION]);
verify([source]);
}
- void fail_constEvalThrowsException() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class C {", " const C() { throw null; }", "}", "f() { return const C(); }"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION]);
- verify([source]);
- }
void fail_constWithNonConstantArgument() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["class T {", " T(a) {};", "}", "f(p) { return const T(p); }"]));
resolve(source, []);
@@ -951,12 +945,6 @@
assertErrors([CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR]);
verify([source]);
}
- void fail_defaultValueInFunctionTypeAlias() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["typedef F([x = 0]);"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS]);
- verify([source]);
- }
void fail_duplicateDefinition() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["f() {", " int m = 0;", " m(a) {}", "}"]));
resolve(source, []);
@@ -988,76 +976,16 @@
assertErrors([CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY]);
verify([source]);
}
- void fail_extendsOrImplementsDisallowedClass_extends_bool() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends bool {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_extends_double() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends double {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_extends_int() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends int {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
void fail_extendsOrImplementsDisallowedClass_extends_null() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends Null {}"]));
resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_extends_num() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends num {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_extends_String() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends String {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_implements_bool() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements bool {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_implements_double() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements double {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_implements_int() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements int {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
+ assertErrors([CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
verify([source]);
}
void fail_extendsOrImplementsDisallowedClass_implements_null() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements Null {}"]));
resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_implements_num() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements num {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
- verify([source]);
- }
- void fail_extendsOrImplementsDisallowedClass_implements_String() {
- Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements String {}"]));
- resolve(source, []);
- assertErrors([CompileTimeErrorCode.EXTENDS_OR_IMPLEMENTS_DISALLOWED_CLASS]);
+ assertErrors([CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS]);
verify([source]);
}
void fail_fieldInitializedByMultipleInitializers() {
@@ -1652,6 +1580,12 @@
assertErrors([CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD]);
verify([source]);
}
+ void test_constEvalThrowsException() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class C {", " const C() { throw null; }", "}", "f() { return const C(); }"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION]);
+ verify([source]);
+ }
void test_constFormalParameter_fieldFormalParameter() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["class A {", " var x;", " A(const this.x) {}", "}"]));
resolve(source, []);
@@ -1682,6 +1616,12 @@
assertErrors([CompileTimeErrorCode.CONST_WITH_NON_CONST]);
verify([source]);
}
+ void test_defaultValueInFunctionTypeAlias() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["typedef F([x = 0]);"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS]);
+ verify([source]);
+ }
void test_duplicateMemberError() {
Source librarySource = addSource("/lib.dart", EngineTestCase.createSource(["library lib;", "", "part 'a.dart';", "part 'b.dart';"]));
Source sourceA = addSource("/a.dart", EngineTestCase.createSource(["part of lib;", "", "class A {}"]));
@@ -1696,6 +1636,66 @@
assertErrors([CompileTimeErrorCode.EXTENDS_NON_CLASS]);
verify([source]);
}
+ void test_extendsOrImplementsDisallowedClass_extends_bool() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends bool {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_extends_double() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends double {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_extends_int() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends int {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_extends_num() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends num {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_extends_String() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A extends String {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_implements_bool() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements bool {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_implements_double() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements double {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_implements_int() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements int {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_implements_num() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements num {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
+ void test_extendsOrImplementsDisallowedClass_implements_String() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["class A implements String {}"]));
+ resolve(source, []);
+ assertErrors([CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS]);
+ verify([source]);
+ }
void test_implementsNonClass() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["int A;", "class B implements A {}"]));
resolve(source, []);
@@ -1797,6 +1797,10 @@
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_constConstructorWithNonFinalField);
});
+ _ut.test('test_constEvalThrowsException', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_constEvalThrowsException);
+ });
_ut.test('test_constFormalParameter_fieldFormalParameter', () {
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_constFormalParameter_fieldFormalParameter);
@@ -1817,6 +1821,10 @@
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_constWithNonConst);
});
+ _ut.test('test_defaultValueInFunctionTypeAlias', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_defaultValueInFunctionTypeAlias);
+ });
_ut.test('test_duplicateMemberError', () {
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_duplicateMemberError);
@@ -1825,6 +1833,46 @@
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_extendsNonClass);
});
+ _ut.test('test_extendsOrImplementsDisallowedClass_extends_String', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_extends_String);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_extends_bool', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_extends_bool);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_extends_double', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_extends_double);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_extends_int', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_extends_int);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_extends_num', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_extends_num);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_implements_String', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_implements_String);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_implements_bool', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_implements_bool);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_implements_double', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_implements_double);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_implements_int', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_implements_int);
+ });
+ _ut.test('test_extendsOrImplementsDisallowedClass_implements_num', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_extendsOrImplementsDisallowedClass_implements_num);
+ });
_ut.test('test_implementsNonClass', () {
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_implementsNonClass);
@@ -3314,10 +3362,10 @@
* structures that are expected to have been resolved have an element associated with them.
*/
ResolutionVerifier() {
- _jtd_constructor_317_impl();
+ _jtd_constructor_319_impl();
}
- _jtd_constructor_317_impl() {
- _jtd_constructor_318_impl(null);
+ _jtd_constructor_319_impl() {
+ _jtd_constructor_320_impl(null);
}
/**
* Initialize a newly created verifier to verify that all of the identifiers in the visited AST
@@ -3328,9 +3376,9 @@
* therefore not cause the test to fail
*/
ResolutionVerifier.con1(Set<ASTNode> knownExceptions2) {
- _jtd_constructor_318_impl(knownExceptions2);
+ _jtd_constructor_320_impl(knownExceptions2);
}
- _jtd_constructor_318_impl(Set<ASTNode> knownExceptions2) {
+ _jtd_constructor_320_impl(Set<ASTNode> knownExceptions2) {
this._knownExceptions = knownExceptions2;
}
/**
@@ -3526,17 +3574,6 @@
JUnitTestCase.fail("Not yet tested");
_listener.assertNoErrors();
}
- void fail_visitIndexExpression_typeParameters() {
- InterfaceType intType6 = _typeProvider.intType;
- InterfaceType listType2 = _typeProvider.listType;
- MethodElement methodElement = getMethod(listType2, "[]");
- SimpleIdentifier identifier = ASTFactory.identifier2("list");
- identifier.staticType = listType2.substitute5(<Type2> [intType6]);
- IndexExpression indexExpression2 = ASTFactory.indexExpression(identifier, ASTFactory.integer(0));
- indexExpression2.element = methodElement;
- JUnitTestCase.assertSame(intType6, analyze(indexExpression2));
- _listener.assertNoErrors();
- }
void fail_visitMethodInvocation() {
JUnitTestCase.fail("Not yet tested");
_listener.assertNoErrors();
@@ -3577,9 +3614,9 @@
_listener.assertNoErrors();
}
void test_visitAssignmentExpression_simple() {
- InterfaceType intType7 = _typeProvider.intType;
- Expression node = ASTFactory.assignmentExpression(resolvedVariable(intType7, "i"), TokenType.EQ, resolvedInteger(0));
- JUnitTestCase.assertSame(intType7, analyze(node));
+ InterfaceType intType6 = _typeProvider.intType;
+ Expression node = ASTFactory.assignmentExpression(resolvedVariable(intType6, "i"), TokenType.EQ, resolvedInteger(0));
+ JUnitTestCase.assertSame(intType6, analyze(node));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_equals() {
@@ -3767,20 +3804,43 @@
_listener.assertNoErrors();
}
void test_visitIndexExpression_getter() {
- InterfaceType listType3 = _typeProvider.listType;
- SimpleIdentifier identifier = resolvedVariable(listType3, "a");
+ InterfaceType listType2 = _typeProvider.listType;
+ SimpleIdentifier identifier = resolvedVariable(listType2, "a");
IndexExpression node = ASTFactory.indexExpression(identifier, resolvedInteger(2));
- node.element = listType3.element.methods[0];
- JUnitTestCase.assertSame(listType3.typeArguments[0], analyze(node));
+ node.element = listType2.element.methods[0];
+ JUnitTestCase.assertSame(listType2.typeArguments[0], analyze(node));
_listener.assertNoErrors();
}
void test_visitIndexExpression_setter() {
- InterfaceType listType4 = _typeProvider.listType;
- SimpleIdentifier identifier = resolvedVariable(listType4, "a");
+ InterfaceType listType3 = _typeProvider.listType;
+ SimpleIdentifier identifier = resolvedVariable(listType3, "a");
IndexExpression node = ASTFactory.indexExpression(identifier, resolvedInteger(2));
- node.element = listType4.element.methods[1];
+ node.element = listType3.element.methods[1];
ASTFactory.assignmentExpression(node, TokenType.EQ, ASTFactory.integer(0));
- JUnitTestCase.assertSame(listType4.typeArguments[0], analyze(node));
+ JUnitTestCase.assertSame(listType3.typeArguments[0], analyze(node));
+ _listener.assertNoErrors();
+ }
+ void test_visitIndexExpression_typeParameters() {
+ InterfaceType intType7 = _typeProvider.intType;
+ InterfaceType listType4 = _typeProvider.listType;
+ MethodElement methodElement = getMethod(listType4, "[]");
+ SimpleIdentifier identifier = ASTFactory.identifier2("list");
+ identifier.staticType = listType4.substitute5(<Type2> [intType7]);
+ IndexExpression indexExpression2 = ASTFactory.indexExpression(identifier, ASTFactory.integer(0));
+ indexExpression2.element = methodElement;
+ JUnitTestCase.assertSame(intType7, analyze(indexExpression2));
+ _listener.assertNoErrors();
+ }
+ void test_visitIndexExpression_typeParameters_inSetterContext() {
+ InterfaceType intType8 = _typeProvider.intType;
+ InterfaceType listType5 = _typeProvider.listType;
+ MethodElement methodElement = getMethod(listType5, "[]=");
+ SimpleIdentifier identifier = ASTFactory.identifier2("list");
+ identifier.staticType = listType5.substitute5(<Type2> [intType8]);
+ IndexExpression indexExpression3 = ASTFactory.indexExpression(identifier, ASTFactory.integer(0));
+ indexExpression3.element = methodElement;
+ ASTFactory.assignmentExpression(indexExpression3, TokenType.EQ, ASTFactory.integer(0));
+ JUnitTestCase.assertSame(intType8, analyze(indexExpression3));
_listener.assertNoErrors();
}
void test_visitInstanceCreationExpression_named() {
@@ -4126,14 +4186,14 @@
* @param body the body of the function
* @return a resolved function expression
*/
- FunctionExpression resolvedFunctionExpression(FormalParameterList parameters15, FunctionBody body) {
- for (FormalParameter parameter in parameters15.parameters) {
+ FunctionExpression resolvedFunctionExpression(FormalParameterList parameters16, FunctionBody body) {
+ for (FormalParameter parameter in parameters16.parameters) {
ParameterElementImpl element = new ParameterElementImpl(parameter.identifier);
element.parameterKind = parameter.kind;
element.type = _typeProvider.dynamicType;
parameter.identifier.element = element;
}
- FunctionExpression node = ASTFactory.functionExpression2(parameters15, body);
+ FunctionExpression node = ASTFactory.functionExpression2(parameters16, body);
FunctionElementImpl element = new FunctionElementImpl.con1(null);
element.type = new FunctionTypeImpl.con1(element);
node.element = element;
@@ -4301,6 +4361,14 @@
final __test = new StaticTypeAnalyzerTest();
runJUnitTest(__test, __test.test_visitIndexExpression_setter);
});
+ _ut.test('test_visitIndexExpression_typeParameters', () {
+ final __test = new StaticTypeAnalyzerTest();
+ runJUnitTest(__test, __test.test_visitIndexExpression_typeParameters);
+ });
+ _ut.test('test_visitIndexExpression_typeParameters_inSetterContext', () {
+ final __test = new StaticTypeAnalyzerTest();
+ runJUnitTest(__test, __test.test_visitIndexExpression_typeParameters_inSetterContext);
+ });
_ut.test('test_visitInstanceCreationExpression_named', () {
final __test = new StaticTypeAnalyzerTest();
runJUnitTest(__test, __test.test_visitInstanceCreationExpression_named);
@@ -4802,6 +4870,12 @@
assertNoErrors();
verify([source]);
}
+ void test_defaultValueInFunctionTypeAlias() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["typedef F([x]);"]));
+ resolve(source, []);
+ assertErrors([]);
+ verify([source]);
+ }
void test_duplicateDefinition_getter() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["bool get a => true;"]));
resolve(source, []);
@@ -4838,6 +4912,18 @@
assertNoErrors();
verify([source]);
}
+ void test_indexExpression_typeParameters() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["f() {", " List<int> a;", " a[0];", " List<List<int>> b;", " b[0][0];", " List<List<List<int>>> c;", " c[0][0][0];", "}"]));
+ resolve(source, []);
+ assertNoErrors();
+ verify([source]);
+ }
+ void test_indexExpression_typeParameters_invalidAssignmentWarning() {
+ Source source = addSource("/test.dart", EngineTestCase.createSource(["f() {", " List<List<int>> b;", " b[0][0] = 'hi';", "}"]));
+ resolve(source, []);
+ assertErrors([StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
void test_invalidAssignment() {
Source source = addSource("/test.dart", EngineTestCase.createSource(["f() {", " var x;", " var y;", " x = y;", "}"]));
resolve(source, []);
@@ -5038,6 +5124,10 @@
final __test = new SimpleResolverTest();
runJUnitTest(__test, __test.test_constConstructorWithNonFinalField_syntheticField);
});
+ _ut.test('test_defaultValueInFunctionTypeAlias', () {
+ final __test = new SimpleResolverTest();
+ runJUnitTest(__test, __test.test_defaultValueInFunctionTypeAlias);
+ });
_ut.test('test_duplicateDefinition_getter', () {
final __test = new SimpleResolverTest();
runJUnitTest(__test, __test.test_duplicateDefinition_getter);
@@ -5062,6 +5152,14 @@
final __test = new SimpleResolverTest();
runJUnitTest(__test, __test.test_getterAndSetterWithDifferentTypes);
});
+ _ut.test('test_indexExpression_typeParameters', () {
+ final __test = new SimpleResolverTest();
+ runJUnitTest(__test, __test.test_indexExpression_typeParameters);
+ });
+ _ut.test('test_indexExpression_typeParameters_invalidAssignmentWarning', () {
+ final __test = new SimpleResolverTest();
+ runJUnitTest(__test, __test.test_indexExpression_typeParameters_invalidAssignmentWarning);
+ });
_ut.test('test_invalidAssignment', () {
final __test = new SimpleResolverTest();
runJUnitTest(__test, __test.test_invalidAssignment);
diff --git a/pkg/analyzer_experimental/test/generated/test_support.dart b/pkg/analyzer_experimental/test/generated/test_support.dart
index 7312a7c..4ca21f2 100644
--- a/pkg/analyzer_experimental/test/generated/test_support.dart
+++ b/pkg/analyzer_experimental/test/generated/test_support.dart
@@ -12,6 +12,7 @@
import 'package:analyzer_experimental/src/generated/error.dart';
import 'package:analyzer_experimental/src/generated/scanner.dart';
import 'package:analyzer_experimental/src/generated/element.dart' show InterfaceType, MethodElement, PropertyAccessorElement;
+import 'package:analyzer_experimental/src/generated/engine.dart' show AnalysisContext;
import 'package:unittest/unittest.dart' as _ut;
/**
@@ -44,17 +45,17 @@
* Initialize a newly created error listener to collect errors.
*/
GatheringErrorListener() : super() {
- _jtd_constructor_315_impl();
+ _jtd_constructor_317_impl();
}
- _jtd_constructor_315_impl() {
+ _jtd_constructor_317_impl() {
}
/**
* Initialize a newly created error listener to collect errors.
*/
GatheringErrorListener.con1(String rawSource2) {
- _jtd_constructor_316_impl(rawSource2);
+ _jtd_constructor_318_impl(rawSource2);
}
- _jtd_constructor_316_impl(String rawSource2) {
+ _jtd_constructor_318_impl(String rawSource2) {
this._rawSource = rawSource2;
this._markedSource = rawSource2;
}
@@ -274,15 +275,15 @@
writer.print(expectedErrors.length);
writer.print(" errors:");
for (AnalysisError error in expectedErrors) {
- Source source11 = error.source;
- LineInfo lineInfo = _lineInfoMap[source11];
+ Source source13 = error.source;
+ LineInfo lineInfo = _lineInfoMap[source13];
writer.println();
if (lineInfo == null) {
int offset10 = error.offset;
- writer.printf(" %s %s (%d..%d)", [source11 == null ? "" : source11.shortName, error.errorCode, offset10, offset10 + error.length]);
+ writer.printf(" %s %s (%d..%d)", [source13 == null ? "" : source13.shortName, error.errorCode, offset10, offset10 + error.length]);
} else {
LineInfo_Location location = lineInfo.getLocation(error.offset);
- writer.printf(" %s %s (%d, %d/%d)", [source11 == null ? "" : source11.shortName, error.errorCode, location.lineNumber, location.columnNumber, error.length]);
+ writer.printf(" %s %s (%d, %d/%d)", [source13 == null ? "" : source13.shortName, error.errorCode, location.lineNumber, location.columnNumber, error.length]);
}
}
writer.println();
@@ -290,15 +291,15 @@
writer.print(_errors.length);
writer.print(" errors:");
for (AnalysisError error in _errors) {
- Source source12 = error.source;
- LineInfo lineInfo = _lineInfoMap[source12];
+ Source source14 = error.source;
+ LineInfo lineInfo = _lineInfoMap[source14];
writer.println();
if (lineInfo == null) {
int offset11 = error.offset;
- writer.printf(" %s %s (%d..%d): %s", [source12 == null ? "" : source12.shortName, error.errorCode, offset11, offset11 + error.length, error.message]);
+ writer.printf(" %s %s (%d..%d): %s", [source14 == null ? "" : source14.shortName, error.errorCode, offset11, offset11 + error.length, error.message]);
} else {
LineInfo_Location location = lineInfo.getLocation(error.offset);
- writer.printf(" %s %s (%d, %d/%d): %s", [source12 == null ? "" : source12.shortName, error.errorCode, location.lineNumber, location.columnNumber, error.length, error.message]);
+ writer.printf(" %s %s (%d, %d/%d): %s", [source14 == null ? "" : source14.shortName, error.errorCode, location.lineNumber, location.columnNumber, error.length, error.message]);
}
}
JUnitTestCase.fail(writer.toString());
@@ -608,6 +609,9 @@
bool operator ==(Object object) {
return this == object;
}
+ AnalysisContext get context {
+ throw new UnsupportedOperationException();
+ }
void getContents(Source_ContentReceiver receiver) {
throw new UnsupportedOperationException();
}
diff --git a/pkg/args/pubspec.yaml b/pkg/args/pubspec.yaml
index 959c189..14802e7 100644
--- a/pkg/args/pubspec.yaml
+++ b/pkg/args/pubspec.yaml
@@ -6,7 +6,5 @@
Libraries for defining parsers for parsing raw command-line arguments into
a set of options and values using GNU and POSIX style options.
-
-dependencies:
- unittest:
- sdk: unittest
+dev_dependencies:
+ unittest: any
diff --git a/pkg/http/pubspec.yaml b/pkg/http/pubspec.yaml
index d41e64ad..66cd21a 100644
--- a/pkg/http/pubspec.yaml
+++ b/pkg/http/pubspec.yaml
@@ -2,6 +2,5 @@
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
description: A composable, Future-based API for making HTTP requests.
-dependencies:
- unittest:
- sdk: unittest
+dev_dependencies:
+ unittest: any
diff --git a/pkg/intl/lib/date_format.dart b/pkg/intl/lib/date_format.dart
index a0d964f..88b54d66 100644
--- a/pkg/intl/lib/date_format.dart
+++ b/pkg/intl/lib/date_format.dart
@@ -558,7 +558,7 @@
/** Parse the template pattern and return a list of field objects.*/
List parsePattern(String pattern) {
if (pattern == null) return null;
- return _reverse(_parsePatternHelper(pattern));
+ return _parsePatternHelper(pattern).reversed.toList();
}
/** Recursive helper for parsing the template pattern. */
@@ -584,15 +584,4 @@
}
}
}
-
- /** Polyfill for missing library function. */
- List _reverse(List list) {
- // TODO(alanknight): Use standardized list reverse when implemented.
- // See Issue 2804.
- var result = new List();
- for (var i = list.length-1; i >= 0; i--) {
- result.addLast(list[i]);
- }
- return result;
- }
}
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 84ba5c9..0961d38 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -19,6 +19,28 @@
import 'package:pathos/path.dart' as path;
/**
+ * If the import path following package: is something else, modify the
+ * [intlImportPath] variable to change the import directives in the generated
+ * code.
+ */
+var intlImportPath = 'intl';
+
+/**
+ * If the path to the generated files is something other than the current
+ * directory, update the [generatedImportPath] variable to change the import
+ * directives in the generated code.
+ */
+var generatedImportPath = '';
+
+/**
+ * Given a base file, return the file prefixed with the path to import it.
+ * By default, that is in the current directory, but if [generatedImportPath]
+ * has been set, then use that as a prefix.
+ */
+String importForGeneratedFile(String file) =>
+ generatedImportPath.isEmpty ? file : "$generatedImportPath/$file";
+
+/**
* A list of all the locales for which we have translations. Code that does
* the reading of translations should add to this.
*/
@@ -96,8 +118,8 @@
*/
library messages_${locale.replaceAll('-','_')};
-import 'package:intl/intl.dart';
-import 'package:intl/message_lookup_by_library.dart';
+import 'package:$intlImportPath/intl.dart';
+import 'package:$intlImportPath/message_lookup_by_library.dart';
final messages = new MessageLookup();
@@ -114,7 +136,9 @@
var output = new StringBuffer();
output.write(mainPrologue);
for (var each in allLocales) {
- output.write("import 'messages_$each.dart' as ${asLibraryName(each)};\n");
+ var baseFile = 'messages_$each.dart';
+ var file = importForGeneratedFile(baseFile);
+ output.write("import '$file' as ${asLibraryName(each)};\n");
}
output.write(
"\nMessageLookupByLibrary _findExact(localeName) {\n"
@@ -131,7 +155,7 @@
* Constant string used in [generateMainImportFile] for the beginning of the
* file.
*/
-const mainPrologue = """
+var mainPrologue = """
/**
* DO NOT EDIT. This is code generated via pkg/intl/generate_localized.dart
* This is a library that looks up messages for specific locales by
@@ -141,9 +165,9 @@
library messages_all;
import 'dart:async';
-import 'package:intl/message_lookup_by_library.dart';
-import 'package:intl/src/intl_helpers.dart';
-import 'package:intl/intl.dart';
+import 'package:$intlImportPath/message_lookup_by_library.dart';
+import 'package:$intlImportPath/src/intl_helpers.dart';
+import 'package:$intlImportPath/intl.dart';
""";
diff --git a/pkg/intl/pubspec.yaml b/pkg/intl/pubspec.yaml
index a568a3a..616a4b4 100644
--- a/pkg/intl/pubspec.yaml
+++ b/pkg/intl/pubspec.yaml
@@ -4,6 +4,7 @@
homepage: http://www.dartlang.org
documentation: http://api.dartlang.org/docs/pkg/intl
dependencies:
- unittest: any
analyzer_experimental: any
pathos: any
+dev_dependencies:
+ unittest: any
diff --git a/pkg/intl/test/data_directory.dart b/pkg/intl/test/data_directory.dart
index 9cf6253..de16e00 100644
--- a/pkg/intl/test/data_directory.dart
+++ b/pkg/intl/test/data_directory.dart
@@ -13,6 +13,7 @@
*/
library data_directory;
+import "dart:io";
import "package:pathos/path.dart" as path;
String get dataDirectory {
@@ -40,8 +41,16 @@
if (foundIntlDir) {
return path.joinAll(pathUpToIntl);
} else {
- return path.join(path.current, 'pkg', 'intl');
+ if (new Directory(path.join(path.current, 'pkg', 'intl')).existsSync()) {
+ return path.join(path.current, 'pkg', 'intl');
+ }
+ if (new Directory(
+ path.join(path.current, '..', 'pkg', 'intl')).existsSync()) {
+ return path.join(path.current, '..', 'pkg', 'intl');
+ }
}
+ throw new UnsupportedError(
+ 'Cannot find ${path.join('pkg','intl')} directory.');
}
String get datesRelativeToIntl => path.join('lib', 'src', 'data', 'dates');
\ 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 0b00fdb..92aa3e6 100644
--- a/pkg/intl/test/message_extraction/message_extraction_test.dart
+++ b/pkg/intl/test/message_extraction/message_extraction_test.dart
@@ -55,20 +55,21 @@
test("Test round trip message extraction, translation, code generation, "
"and printing", () {
deleteGeneratedFiles();
- extractMessages(null).then((result) {
+ return extractMessages(null).then((result) {
return generateTranslationFiles(result);
}).then((result) {
return generateCodeFromTranslation(result);
}).then((result) {
return runGeneratedCode(result);
- }).then(verifyResult);
+ }).then(verifyResult)
+ .whenComplete(deleteGeneratedFiles);
});
}
void deleteGeneratedFiles() {
var files = [dir('intl_messages.json'), dir('translation_fr.json'),
- dir('messages_fr.dart'), dir('message_de_DE.dart'),
- dir('messages_all.dart')];
+ dir('messages_fr.dart'), dir('messages_de_DE.dart'),
+ dir('translation_de_DE.json'), dir('messages_all.dart')];
files.map((name) => new File(name)).forEach((x) {
if (x.existsSync()) x.deleteSync();});
}
@@ -124,7 +125,7 @@
Future<ProcessResult> runGeneratedCode(ProcessResult previousResult) =>
run(previousResult, ['sample_with_messages.dart']);
-void verifyResult(results) {
+verifyResult(results) {
var lineIterator;
verify(String s) {
lineIterator.moveNext();
diff --git a/pkg/intl/tool/generate_locale_data_files.dart b/pkg/intl/tool/generate_locale_data_files.dart
index a6fe140..76ff2bd 100644
--- a/pkg/intl/tool/generate_locale_data_files.dart
+++ b/pkg/intl/tool/generate_locale_data_files.dart
@@ -19,6 +19,7 @@
import 'dart:io';
import 'dart:json' as json;
import '../test/data_directory.dart';
+import 'package:pathos/path.dart' as path;
main() {
initializeDateFormatting("en_IGNORED", null);
@@ -28,22 +29,23 @@
}
void writeLocaleList() {
- var file = new File('${dataDirectory}localeList.dart');
+ var file = new File(path.join(dataDirectory, 'localeList.dart'));
var output = file.openWrite();
- output.addString(
+ output.write(
'// Copyright (c) 2012, the Dart project authors. Please see the '
'AUTHORS file\n// for details. All rights reserved. Use of this source'
'code is governed by a\n// BSD-style license that can be found in the'
' LICENSE file.\n\n'
+ 'part of date_symbol_data_json;\n\n'
'/// Hard-coded list of all available locales for dates.\n');
- output.addString('final availableLocalesForDateFormatting = const [');
+ output.write('final availableLocalesForDateFormatting = const [');
List<String> allLocales = DateFormat.allLocalesWithSymbols();
allLocales.forEach((locale) {
- output.addString('"$locale"');
+ output.write('"$locale"');
if (locale == allLocales.last) {
- output.addString('];');
+ output.write('];');
} else {
- output.addString(',\n ');
+ output.write(',\n ');
}
});
output.close();
@@ -60,19 +62,19 @@
}
void writeSymbols(locale, symbols) {
- var file = new File('${dataDirectory}symbols/${locale}.json');
+ var file = new File(path.join(dataDirectory, 'symbols', '${locale}.json'));
var output = file.openWrite();
writeToJSON(symbols, output);
output.close();
}
void writePatterns(locale, patterns) {
- var file = new File('${dataDirectory}patterns/${locale}.json');
+ var file = new File(path.join(dataDirectory, 'patterns', '${locale}.json'));
var output = file.openWrite();
- output.addString(json.stringify(patterns));
+ output.write(json.stringify(patterns));
output.close();
}
void writeToJSON(dynamic data, IOSink out) {
- out.addString(json.stringify(data.serializeToMap()));
+ out.write(json.stringify(data.serializeToMap()));
}
diff --git a/pkg/logging/pubspec.yaml b/pkg/logging/pubspec.yaml
index 6e6a540..16c4428 100644
--- a/pkg/logging/pubspec.yaml
+++ b/pkg/logging/pubspec.yaml
@@ -8,7 +8,6 @@
Logger and java.util.logging.Logger.
dependencies:
- meta:
- sdk: meta
- unittest:
- sdk: unittest
+ meta: any
+dev_dependencies:
+ unittest: any
diff --git a/pkg/oauth2/lib/oauth2.dart b/pkg/oauth2/lib/oauth2.dart
index 4dfaadd..7fdb205 100644
--- a/pkg/oauth2/lib/oauth2.dart
+++ b/pkg/oauth2/lib/oauth2.dart
@@ -56,7 +56,7 @@
/// // If the OAuth2 credentials have already been saved from a previous
/// // run, we just want to reload them.
/// if (exists) {
-/// return credentialsFile.readAsText().then((json) {
+/// return credentialsFile.readAsString().then((json) {
/// var credentials = new oauth2.Credentials.fromJson(json);
/// return new oauth2.Client(identifier, secret, credentials);
/// });
diff --git a/pkg/oauth2/pubspec.yaml b/pkg/oauth2/pubspec.yaml
index ae3d11d..f531f46 100644
--- a/pkg/oauth2/pubspec.yaml
+++ b/pkg/oauth2/pubspec.yaml
@@ -6,7 +6,6 @@
behalf of a user, and making authorized HTTP requests with the user's
OAuth2 credentials.
dependencies:
- unittest:
- sdk: unittest
- http:
- sdk: http
+ http: any
+dev_dependencies:
+ unittest: any
diff --git a/pkg/pkg.status b/pkg/pkg.status
index e919f3d..b90eaa1 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -12,11 +12,19 @@
# Skip non-test files ending with "_test".
scheduled_test/lib/*: Skip
+scheduled_test/test/scheduled_test_test: Pass, Slow # Issue 9231
+
# WebDriver tests have 3rd party dependencies (we need to run
# selenium_standalone.jar), so we skip these in our automated
# testing.
webdriver/test/webdriver_test: Skip
+[$compiler == none && $runtime == vm]
+intl/test/date_time_format_file_even_test: Pass, Crash # Issue 9342
+intl/test/date_time_format_file_odd_test: Pass, Crash # Issue 9342
+intl/test/date_time_format_local_even_test: Pass, Crash # Issue 9342
+intl/test/date_time_format_local_odd_test: Pass, Crash # Issue 9342
+
[$compiler == dart2dart]
*: Skip
@@ -29,6 +37,9 @@
# Issue 8440 forces us to use pathos in the scheduled_test tests, which would
# otherwise be dart2js-compatible.
scheduled_test/test/*: Skip
+source_maps/test/vlq_test: Fail # A VLQ test checks for large numbers that
+ # overflow in JS (numbers slightly larger than
+ # 32 bits where we do bitwise operations).
# Skip tests that use local file access if we're running in any browser
[ $runtime == opera || $runtime == ff || $runtime == ie9 || $runtime == dartium || $runtime == chrome || $runtime == safari || $runtime == drt || $runtime == jsshell]
@@ -57,6 +68,9 @@
[ $runtime == ie9 ]
intl/test/date_time_format_http_request_test: Fail # Issue 8983
+[ $runtime == safari ]
+fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
+
# Skip browser-specific Intl tests on VM
[ $runtime == vm ]
intl/test/find_default_locale_browser_test: Skip
@@ -74,7 +88,8 @@
[ $compiler == dart2js ]
# Skip intl_message tests that use mirrors on dart2js until it's been
# implemented there.
-serialization/test/serialization_test: Skip
+serialization/test/serialization_test: Skip # Issue 6490
+serialization/test/no_library_test: Skip # Issue 6490
analyzer_experimental/test/generated/ast_test: Skip
analyzer_experimental/test/generated/element_test: Skip
analyzer_experimental/test/generated/parser_test: Skip
@@ -112,3 +127,8 @@
[ $arch == simmips ]
*: Skip
+
+# Skip serialization test that explicitly has no library declaration in the
+# test on Dartium, which requires all tests to have a library.
+[ $runtime == dartium || $runtime == drt ]
+serialization/test/no_library_test: Skip # Expected Failure
diff --git a/pkg/scheduled_test/lib/descriptor.dart b/pkg/scheduled_test/lib/descriptor.dart
index b8baeca..f832b9a 100644
--- a/pkg/scheduled_test/lib/descriptor.dart
+++ b/pkg/scheduled_test/lib/descriptor.dart
@@ -6,9 +6,9 @@
/// the purpose of creating or validating it as part of a scheduled test.
///
/// You can use [dir] and [file] to define a filesystem structure. Then, you can
-/// call [Entry.create] to schedule a task that will create that structure on
-/// the physical filesystem, or [Entry.validate] to schedule an assertion that
-/// that structure exists. For example:
+/// call [Descriptor.create] to schedule a task that will create that structure
+/// on the physical filesystem, or [Descriptor.validate] to schedule an
+/// assertion that that structure exists. For example:
///
/// import 'package:scheduled_test/descriptor.dart' as d;
/// import 'package:scheduled_test/scheduled_test.dart';
@@ -67,17 +67,19 @@
import '../../../pkg/pathos/lib/path.dart' as path;
import 'scheduled_test.dart';
-import 'src/descriptor/async.dart';
-import 'src/descriptor/directory.dart';
-import 'src/descriptor/entry.dart';
-import 'src/descriptor/file.dart';
-import 'src/descriptor/nothing.dart';
+import 'src/descriptor/async_descriptor.dart';
+import 'src/descriptor/descriptor.dart';
+import 'src/descriptor/directory_descriptor.dart';
+import 'src/descriptor/file_descriptor.dart';
+import 'src/descriptor/nothing_descriptor.dart';
+import 'src/descriptor/pattern_descriptor.dart';
-export 'src/descriptor/async.dart';
-export 'src/descriptor/directory.dart';
-export 'src/descriptor/entry.dart';
-export 'src/descriptor/file.dart';
-export 'src/descriptor/nothing.dart';
+export 'src/descriptor/async_descriptor.dart';
+export 'src/descriptor/descriptor.dart';
+export 'src/descriptor/directory_descriptor.dart';
+export 'src/descriptor/file_descriptor.dart';
+export 'src/descriptor/nothing_descriptor.dart';
+export 'src/descriptor/pattern_descriptor.dart';
/// The root path for descriptors. Top-level descriptors will be created and
/// validated at this path. Defaults to the current working directory.
@@ -90,21 +92,39 @@
}
String _defaultRoot;
-/// Creates a new text [File] descriptor with [name] and [contents].
-File file(Pattern name, [String contents='']) => new File(name, contents);
+/// Creates a new text [FileDescriptor] with [name] and [contents].
+FileDescriptor file(String name, [String contents='']) =>
+ new FileDescriptor(name, contents);
-/// Creates a new binary [File] descriptor with [name] and [contents].
-File binaryFile(Pattern name, List<int> contents) =>
- new File.binary(name, contents);
+/// Creates a new binary [FileDescriptor] descriptor with [name] and [contents].
+FileDescriptor binaryFile(String name, List<int> contents) =>
+ new FileDescriptor.binary(name, contents);
-/// Creates a new [Directory] descriptor with [name] and [contents].
-Directory dir(Pattern name, [Iterable<Entry> contents]) =>
- new Directory(name, contents == null ? <Entry>[] : contents);
+/// Creates a new [DirectoryDescriptor] descriptor with [name] and [contents].
+DirectoryDescriptor dir(String name, [Iterable<Descriptor> contents]) =>
+ new DirectoryDescriptor(name, contents == null? <Descriptor>[] : contents);
/// Creates a new descriptor wrapping a [Future]. This descriptor forwards all
/// asynchronous operations to the result of [future].
-Async async(Future<Entry> future) => new Async(future);
+AsyncDescriptor async(Future<Descriptor> future) =>
+ new AsyncDescriptor(future);
-/// Creates a new [Nothing] descriptor that asserts that no entry named [name]
-/// exists.
-Nothing nothing(Pattern name) => new Nothing(name);
+/// Creates a new [NothingDescriptor] descriptor that asserts that no entry
+/// named [name] exists.
+NothingDescriptor nothing(String name) => new NothingDescriptor(name);
+
+/// Creates a new [PatternDescriptor] descriptor that asserts than an entry with
+/// a name matching [pattern] exists, and matches the [Descriptor] returned
+/// by [fn].
+PatternDescriptor pattern(Pattern name, EntryCreator fn) =>
+ new PatternDescriptor(name, fn);
+
+/// A convenience method for creating a [PatternDescriptor] descriptor that
+/// constructs a [FileDescriptor] descriptor.
+PatternDescriptor filePattern(Pattern name, [String contents='']) =>
+ pattern(name, (realName) => file(realName, contents));
+
+/// A convenience method for creating a [PatternDescriptor] descriptor that
+/// constructs a [DirectoryDescriptor] descriptor.
+PatternDescriptor dirPattern(Pattern name, [Iterable<Descriptor> contents]) =>
+ pattern(name, (realName) => dir(realName, contents));
diff --git a/pkg/scheduled_test/lib/scheduled_process.dart b/pkg/scheduled_test/lib/scheduled_process.dart
index 0e277da..57af0b6 100644
--- a/pkg/scheduled_test/lib/scheduled_process.dart
+++ b/pkg/scheduled_test/lib/scheduled_process.dart
@@ -21,10 +21,13 @@
/// If the test fails, this will automatically print out any stdout and stderr
/// from the process to aid debugging.
class ScheduledProcess {
- // A description of the process. Used for error reporting.
+ /// A description of the process. Used for error reporting.
String get description => _description;
String _description;
+ /// Whether a description was passed explicitly by the user.
+ bool _explicitDescription;
+
/// The encoding used for the process's input and output streams.
final Encoding _encoding;
@@ -78,7 +81,9 @@
/// containing a mix of strings and [Future]s.
ScheduledProcess.start(executable, arguments,
{options, String description, Encoding encoding: Encoding.UTF_8})
- : _encoding = encoding {
+ : _encoding = encoding,
+ _explicitDescription = description != null,
+ _description = description {
assert(currentSchedule.state == ScheduleState.SET_UP);
_updateDescription(executable, arguments);
@@ -105,6 +110,7 @@
/// Updates [_description] to reflect [executable] and [arguments], which are
/// the same values as in [start].
void _updateDescription(executable, arguments) {
+ if (_explicitDescription) return;
if (executable is Future) {
_description = "future process";
} else if (arguments is Future || arguments.any((e) => e is Future)) {
diff --git a/pkg/scheduled_test/lib/src/descriptor/async.dart b/pkg/scheduled_test/lib/src/descriptor/async.dart
deleted file mode 100644
index c33a68c..0000000
--- a/pkg/scheduled_test/lib/src/descriptor/async.dart
+++ /dev/null
@@ -1,42 +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 descriptor.async;
-
-import 'dart:async';
-import 'dart:io' as io;
-
-import '../../descriptor.dart' as descriptor;
-import '../../scheduled_test.dart';
-import '../utils.dart';
-import 'utils.dart';
-
-/// A descriptor that wraps a [Future<Entry>] and forwards all asynchronous
-/// operations to the result of the future. It's designed for use when the
-/// full filesystem description isn't known when initializing the schedule.
-///
-/// Async descriptors don't support [load], since their names aren't
-/// synchronously available.
-class Async extends descriptor.Entry {
- /// The [Future] that will complete to the [Entry] this descriptor is
- /// wrapping.
- final Future<descriptor.Entry> future;
-
- Async(this.future)
- : super('<async descriptor>');
-
- Future create([String parent]) =>
- schedule(() => future.then((entry) => entry.create(parent)));
-
- Future validate([String parent]) =>
- schedule(() => future.then((entry) => entry.validate(parent)));
-
- Stream<List<int>> load(String path) => errorStream("Async descriptors don't "
- "support load().");
-
- Stream<List<int>> read() => errorStream("Async descriptors don't support "
- "read().");
-
- String describe() => "async descriptor";
-}
diff --git a/pkg/scheduled_test/lib/src/descriptor/async_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/async_descriptor.dart
new file mode 100644
index 0000000..79092dc
--- /dev/null
+++ b/pkg/scheduled_test/lib/src/descriptor/async_descriptor.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 descriptor.async;
+
+import 'dart:async';
+import 'dart:io' as io;
+
+import '../../descriptor.dart';
+import '../../scheduled_test.dart';
+import '../utils.dart';
+
+/// A descriptor that wraps a [Future<Descriptor>] and forwards all asynchronous
+/// operations to the result of the future. It's designed for use when the full
+/// filesystem description isn't known when initializing the schedule.
+///
+/// [AsyncDescriptor]s don't support [load], since their names aren't
+/// synchronously available.
+class AsyncDescriptor extends Descriptor {
+ /// The [Future] that will complete to the [Descriptor] this descriptor is
+ /// wrapping.
+ final Future<Descriptor> future;
+
+ AsyncDescriptor(this.future)
+ : super('<async descriptor>');
+
+ Future create([String parent]) =>
+ schedule(() => future.then((entry) => entry.create(parent)));
+
+ Future validate([String parent]) => schedule(() => validateNow(parent));
+
+ Future validateNow([String parent]) =>
+ future.then((entry) => entry.validateNow(parent));
+
+ Stream<List<int>> load(String path) => errorStream("AsyncDescriptors don't "
+ "support load().");
+
+ Stream<List<int>> read() => errorStream("AsyncDescriptors don't support "
+ "read().");
+
+ String describe() => "async descriptor";
+}
diff --git a/pkg/scheduled_test/lib/src/descriptor/entry.dart b/pkg/scheduled_test/lib/src/descriptor/descriptor.dart
similarity index 67%
rename from pkg/scheduled_test/lib/src/descriptor/entry.dart
rename to pkg/scheduled_test/lib/src/descriptor/descriptor.dart
index 9605a1c..1d3a14a 100644
--- a/pkg/scheduled_test/lib/src/descriptor/entry.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/descriptor.dart
@@ -7,19 +7,15 @@
import 'dart:async';
import '../utils.dart';
-import 'utils.dart';
/// The base class for various declarative descriptions of filesystem entries.
/// All asynchronous operations on descriptors are [schedule]d unless otherwise
/// noted.
-abstract class Entry {
- /// The name of this entry. For most operations, this must be a [String];
- /// however, if the entry will only be used for validation, it may be a
- /// non-[String] [Pattern]. In this case, there must be only one entry
- /// matching it in the physical filesystem for validation to succeed.
- final Pattern name;
+abstract class Descriptor {
+ /// The name of this entry.
+ final String name;
- Entry(this.name);
+ Descriptor(this.name);
/// Schedules the creation of the described entry within the [parent]
/// directory. Returns a [Future] that completes after the creation is done.
@@ -35,6 +31,10 @@
/// [parent] defaults to [defaultRoot].
Future validate([String parent]);
+ /// An unscheduled version of [validate]. This is useful if validation errors
+ /// need to be caught, since otherwise they'd be registered by the schedule.
+ Future validateNow([String parent]);
+
/// Treats [this] as an in-memory filesystem and returns a stream of the
/// contents of the child entry located at [path]. This only works if [this]
/// is a directory entry. This operation is not [schedule]d.
@@ -45,7 +45,7 @@
/// All errors in loading the file will be passed through the returned
/// [Stream].
Stream<List<int>> load(String pathToLoad) => errorStream("Can't load "
- "'$pathToLoad' from within $nameDescription: not a directory.");
+ "'$pathToLoad' from within '$name': not a directory.");
/// Returns the contents of [this] as a stream. This only works if [this] is a
/// file entry. This operation is not [schedule]d.
@@ -54,17 +54,6 @@
/// [Stream].
Stream<List<int>> read();
- /// Asserts that the name of the descriptor is a [String] and returns it.
- String get stringName {
- if (name is String) return name;
- throw 'Pattern $nameDescription must be a string.';
- }
-
- /// Returns a human-readable description of [name], for error reporting. For
- /// string names, this will just be the name in quotes; for regular
- /// expressions, it will use JavaScript-style `/.../` notation.
- String get nameDescription => describePattern(name);
-
/// Returns a detailed tree-style description of [this].
String describe();
}
diff --git a/pkg/scheduled_test/lib/src/descriptor/directory.dart b/pkg/scheduled_test/lib/src/descriptor/directory.dart
deleted file mode 100644
index 594fb56..0000000
--- a/pkg/scheduled_test/lib/src/descriptor/directory.dart
+++ /dev/null
@@ -1,96 +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 descriptor.file;
-
-import 'dart:async';
-import 'dart:io' as io;
-
-import '../../../../../pkg/pathos/lib/path.dart' as path;
-
-import '../../descriptor.dart' as descriptor;
-import '../../scheduled_test.dart';
-import '../utils.dart';
-import 'utils.dart';
-
-/// A path builder to ensure that [load] uses POSIX paths.
-final path.Builder _path = new path.Builder(style: path.Style.posix);
-
-/// A descriptor describing a directory containing multiple files.
-class Directory extends descriptor.Entry {
- /// The entries contained within this directory.
- final Iterable<descriptor.Entry> contents;
-
- Directory(Pattern name, this.contents)
- : super(name);
-
- Future create([String parent]) => schedule(() {
- if (parent == null) parent = descriptor.defaultRoot;
- var fullPath = path.join(parent, stringName);
- return new io.Directory(fullPath).create(recursive: true).then((_) {
- return Future.wait(
- contents.map((entry) => entry.create(fullPath)).toList());
- });
- }, 'creating directory:\n${describe()}');
-
- Future validate([String parent]) => schedule(() {
- if (parent == null) parent = descriptor.defaultRoot;
- var fullPath = entryMatchingPattern('Directory', parent, name);
- return Future.wait(
- contents.map((entry) => entry.validate(fullPath)).toList());
- }, 'validating directory:\n${describe()}');
-
- Stream<List<int>> load(String pathToLoad) {
- return futureStream(new Future.immediate(null).then((_) {
- if (_path.isAbsolute(pathToLoad)) {
- throw "Can't load absolute path '$pathToLoad'.";
- }
-
- var split = _path.split(_path.normalize(pathToLoad));
- if (split.isEmpty || split.first == '.' || split.first == '..') {
- throw "Can't load '$pathToLoad' from within $nameDescription.";
- }
-
- var matchingEntries = contents.where((entry) =>
- entry.stringName == split.first).toList();
-
- if (matchingEntries.length == 0) {
- throw "Couldn't find an entry named '${split.first}' within "
- "$nameDescription.";
- } else if (matchingEntries.length > 1) {
- throw "Found multiple entries named '${split.first}' within "
- "$nameDescription.";
- } else {
- var remainingPath = split.sublist(1);
- if (remainingPath.isEmpty) {
- return matchingEntries.first.read();
- } else {
- return matchingEntries.first.load(_path.joinAll(remainingPath));
- }
- }
- }));
- }
-
- Stream<List<int>> read() => errorStream("Can't read the contents of "
- "$nameDescription: is a directory.");
-
- String describe() {
- var description = name;
- if (name is! String) description = 'directory matching $nameDescription';
- if (contents.isEmpty) return description;
-
- var buffer = new StringBuffer();
- buffer.writeln(description);
- for (var entry in contents.take(contents.length - 1)) {
- var entryString = prefixLines(entry.describe(), prefix: '| ')
- .replaceFirst('| ', '|-- ');
- buffer.writeln(entryString);
- }
-
- var lastEntryString = prefixLines(contents.last.describe(), prefix: ' ')
- .replaceFirst(' ', "'-- ");
- buffer.write(lastEntryString);
- return buffer.toString();
- }
-}
diff --git a/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
new file mode 100644
index 0000000..690f92f
--- /dev/null
+++ b/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
@@ -0,0 +1,130 @@
+// 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 descriptor.file;
+
+import 'dart:async';
+import 'dart:io';
+
+import '../../../../../pkg/pathos/lib/path.dart' as path;
+
+import '../../descriptor.dart';
+import '../../scheduled_test.dart';
+import '../utils.dart';
+
+/// A path builder to ensure that [load] uses POSIX paths.
+final path.Builder _path = new path.Builder(style: path.Style.posix);
+
+/// A descriptor describing a directory containing multiple files.
+class DirectoryDescriptor extends Descriptor {
+ /// The entries contained within this directory. This is intentionally
+ /// mutable.
+ final List<Descriptor> contents;
+
+ DirectoryDescriptor(String name, Iterable<Descriptor> contents)
+ : super(name),
+ contents = contents.toList();
+
+ Future create([String parent]) => schedule(() {
+ if (parent == null) parent = defaultRoot;
+ var fullPath = path.join(parent, name);
+ return new Directory(fullPath).create(recursive: true).then((_) {
+ return Future.wait(
+ contents.map((entry) => entry.create(fullPath)).toList());
+ });
+ }, 'creating directory:\n${describe()}');
+
+ Future validate([String parent]) => schedule(() => validateNow(parent),
+ 'validating directory:\n${describe()}');
+
+ Future validateNow([String parent]) {
+ if (parent == null) parent = defaultRoot;
+ var fullPath = path.join(parent, name);
+ if (!new Directory(fullPath).existsSync()) {
+ throw "Directory not found: '$fullPath'.";
+ }
+
+ return Future.wait(contents.map((entry) {
+ return new Future.of(() => entry.validateNow(fullPath))
+ .then((_) => null)
+ .catchError((e) => e.error);
+ })).then((results) {
+ var errors = results.where((e) => e != null);
+ if (errors.isEmpty) return;
+ throw _DirectoryValidationError.merge(errors);
+ });
+ }
+
+ Stream<List<int>> load(String pathToLoad) {
+ return futureStream(new Future.immediate(null).then((_) {
+ if (_path.isAbsolute(pathToLoad)) {
+ throw "Can't load absolute path '$pathToLoad'.";
+ }
+
+ var split = _path.split(_path.normalize(pathToLoad));
+ if (split.isEmpty || split.first == '.' || split.first == '..') {
+ throw "Can't load '$pathToLoad' from within '$name'.";
+ }
+
+ var matchingEntries = contents.where((entry) =>
+ entry.name == split.first).toList();
+
+ if (matchingEntries.length == 0) {
+ throw "Couldn't find an entry named '${split.first}' within '$name'.";
+ } else if (matchingEntries.length > 1) {
+ throw "Found multiple entries named '${split.first}' within '$name'.";
+ } else {
+ var remainingPath = split.sublist(1);
+ if (remainingPath.isEmpty) {
+ return matchingEntries.first.read();
+ } else {
+ return matchingEntries.first.load(_path.joinAll(remainingPath));
+ }
+ }
+ }));
+ }
+
+ Stream<List<int>> read() => errorStream("Can't read the contents of '$name': "
+ "is a directory.");
+
+ String describe() {
+ if (contents.isEmpty) return name;
+
+ var buffer = new StringBuffer();
+ buffer.writeln(name);
+ for (var entry in contents.take(contents.length - 1)) {
+ var entryString = prefixLines(entry.describe(), prefix: '| ')
+ .replaceFirst('| ', '|-- ');
+ buffer.writeln(entryString);
+ }
+
+ var lastEntryString = prefixLines(contents.last.describe(), prefix: ' ')
+ .replaceFirst(' ', "'-- ");
+ buffer.write(lastEntryString);
+ return buffer.toString();
+ }
+}
+
+/// A class for formatting errors thrown by [DirectoryDescriptor].
+class _DirectoryValidationError {
+ final Collection<String> errors;
+
+ /// Flatten nested [_DirectoryValidationError]s in [errors] to create a single
+ /// list of errors.
+ static _DirectoryValidationError merge(Iterable errors) {
+ return new _DirectoryValidationError(errors.expand((error) {
+ if (error is _DirectoryValidationError) return error.errors;
+ return [error];
+ }));
+ }
+
+ _DirectoryValidationError(Iterable errors)
+ : errors = errors.map((e) => e.toString()).toList();
+
+ String toString() {
+ if (errors.length == 1) return errors.single;
+ return errors.map((e) => prefixLines(e, prefix: ' ', firstPrefix: '* '))
+ .join('\n');
+ }
+}
diff --git a/pkg/scheduled_test/lib/src/descriptor/file.dart b/pkg/scheduled_test/lib/src/descriptor/file.dart
deleted file mode 100644
index 15b9ef4..0000000
--- a/pkg/scheduled_test/lib/src/descriptor/file.dart
+++ /dev/null
@@ -1,107 +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 descriptor.file;
-
-import 'dart:async';
-import 'dart:io' as io;
-import 'dart:math' as math;
-import 'dart:utf';
-
-import '../../../../../pkg/pathos/lib/path.dart' as path;
-
-import '../../descriptor.dart' as descriptor;
-import '../../scheduled_test.dart';
-import '../utils.dart';
-import 'utils.dart';
-
-/// A descriptor describing a single file.
-class File extends descriptor.Entry {
- /// Whether this descriptor describes a binary file. This is only used when
- /// displaying error messages.
- final bool isBinary;
-
- /// The contents of the file, in bytes.
- final List<int> contents;
-
- /// The contents of the file as a String. Assumes UTF-8 encoding.
- String get textContents => new String.fromCharCodes(contents);
-
- File.binary(Pattern name, List<int> contents)
- : this._(name, contents, true);
-
- File(Pattern name, String contents)
- : this._(name, encodeUtf8(contents), false);
-
- File._(Pattern name, this.contents, this.isBinary)
- : super(name);
-
- Future create([String parent]) => schedule(() {
- if (parent == null) parent = descriptor.defaultRoot;
- return new io.File(path.join(parent, stringName)).writeAsBytes(contents);
- }, 'creating file $nameDescription');
-
- Future validate([String parent]) => schedule(() {
- if (parent == null) parent = descriptor.defaultRoot;
- var fullPath = entryMatchingPattern('File', parent, name);
- return new io.File(fullPath).readAsBytes()
- .then((actualContents) {
- if (orderedIterableEquals(contents, actualContents)) return;
- if (isBinary) {
- // TODO(nweiz): show a hex dump here if the data is small enough.
- throw "File $nameDescription didn't contain the expected binary "
- "data.";
- }
- var description = nameDescription;
- if (name is! String) {
- description = "'${path.basename(fullPath)}' (matching $description)";
- }
- throw _textMismatchMessage(description, textContents,
- new String.fromCharCodes(actualContents));;
- });
- }, 'validating file $nameDescription');
-
- Stream<List<int>> read() => new Future.immediate(contents).asStream();
-
- String describe() {
- if (name is String) return name;
- return 'file matching $nameDescription';
- }
-}
-
-String _textMismatchMessage(String description, String expected,
- String actual) {
- final expectedLines = expected.split('\n');
- final actualLines = actual.split('\n');
-
- var results = [];
-
- // Compare them line by line to see which ones match.
- var length = math.max(expectedLines.length, actualLines.length);
- for (var i = 0; i < length; i++) {
- if (i >= actualLines.length) {
- // Missing output.
- results.add('? ${expectedLines[i]}');
- } else if (i >= expectedLines.length) {
- // Unexpected extra output.
- results.add('X ${actualLines[i]}');
- } else {
- var expectedLine = expectedLines[i];
- var actualLine = actualLines[i];
-
- if (expectedLine != actualLine) {
- // Mismatched lines.
- results.add('X $actualLine');
- } else {
- // Matched lines.
- results.add('| $actualLine');
- }
- }
- }
-
- return "File $description should contain:\n"
- "${prefixLines(expected)}\n"
- "but actually contained:\n"
- "${results.join('\n')}";
-}
diff --git a/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
new file mode 100644
index 0000000..ffcf567
--- /dev/null
+++ b/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
@@ -0,0 +1,104 @@
+// 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 descriptor.file;
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:math' as math;
+import 'dart:utf';
+
+import '../../../../../pkg/pathos/lib/path.dart' as path;
+
+import '../../descriptor.dart';
+import '../../scheduled_test.dart';
+import '../utils.dart';
+
+/// A descriptor describing a single file.
+class FileDescriptor extends Descriptor {
+ /// Whether this descriptor describes a binary file. This is only used when
+ /// displaying error messages.
+ final bool isBinary;
+
+ /// The contents of the file, in bytes.
+ final List<int> contents;
+
+ /// The contents of the file as a String. Assumes UTF-8 encoding.
+ String get textContents => new String.fromCharCodes(contents);
+
+ FileDescriptor.binary(String name, List<int> contents)
+ : this._(name, contents, true);
+
+ FileDescriptor(String name, String contents)
+ : this._(name, encodeUtf8(contents), false);
+
+ FileDescriptor._(String name, this.contents, this.isBinary)
+ : super(name);
+
+ Future create([String parent]) => schedule(() {
+ if (parent == null) parent = defaultRoot;
+ return new File(path.join(parent, name)).writeAsBytes(contents);
+ }, "creating file '$name'");
+
+ Future validate([String parent]) =>
+ schedule(() => validateNow(parent), "validating file '$name'");
+
+ Future validateNow([String parent]) {
+ if (parent == null) parent = defaultRoot;
+ var fullPath = path.join(parent, name);
+ if (!new File(fullPath).existsSync()) {
+ throw "File not found: '$fullPath'.";
+ }
+
+ return new File(fullPath).readAsBytes()
+ .then((actualContents) {
+ if (orderedIterableEquals(contents, actualContents)) return;
+ if (isBinary) {
+ // TODO(nweiz): show a hex dump here if the data is small enough.
+ throw "File '$name' didn't contain the expected binary data.";
+ }
+ throw _textMismatchMessage(textContents,
+ new String.fromCharCodes(actualContents));
+ });
+ }
+
+ Stream<List<int>> read() => new Future.immediate(contents).asStream();
+
+ String describe() => name;
+
+ String _textMismatchMessage(String expected, String actual) {
+ final expectedLines = expected.split('\n');
+ final actualLines = actual.split('\n');
+
+ var results = [];
+
+ // Compare them line by line to see which ones match.
+ var length = math.max(expectedLines.length, actualLines.length);
+ for (var i = 0; i < length; i++) {
+ if (i >= actualLines.length) {
+ // Missing output.
+ results.add('? ${expectedLines[i]}');
+ } else if (i >= expectedLines.length) {
+ // Unexpected extra output.
+ results.add('X ${actualLines[i]}');
+ } else {
+ var expectedLine = expectedLines[i];
+ var actualLine = actualLines[i];
+
+ if (expectedLine != actualLine) {
+ // Mismatched lines.
+ results.add('X $actualLine');
+ } else {
+ // Matched lines.
+ results.add('| $actualLine');
+ }
+ }
+ }
+
+ return "File '$name' should contain:\n"
+ "${prefixLines(expected)}\n"
+ "but actually contained:\n"
+ "${results.join('\n')}";
+ }
+}
diff --git a/pkg/scheduled_test/lib/src/descriptor/nothing.dart b/pkg/scheduled_test/lib/src/descriptor/nothing.dart
deleted file mode 100644
index 9a1f1b4..0000000
--- a/pkg/scheduled_test/lib/src/descriptor/nothing.dart
+++ /dev/null
@@ -1,60 +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 descriptor.async;
-
-import 'dart:async';
-import 'dart:io';
-
-import '../../../../../pkg/pathos/lib/path.dart' as path;
-
-import '../../descriptor.dart' as descriptor;
-import '../../scheduled_test.dart';
-import '../utils.dart';
-import 'utils.dart';
-
-/// A descriptor that validates that no file exists with the given name.
-/// Creating this descriptor is a no-op and loading from it is invalid.
-class Nothing extends descriptor.Entry {
- Nothing(Pattern name)
- : super(name);
-
- Future create([String parent]) => new Future.immediate(null);
-
- Future validate([String parent]) => schedule(() {
- if (parent == null) parent = descriptor.defaultRoot;
- if (name is String) {
- var fullPath = path.join(parent, name);
- if (new File(fullPath).existsSync()) {
- throw "Expected nothing to exist at '$fullPath', but found a file.";
- } else if (new Directory(fullPath).existsSync()) {
- throw "Expected nothing to exist at '$fullPath', but found a "
- "directory.";
- } else {
- return;
- }
- }
-
- return new Directory(parent).list().toList().then((entries) {
- var matchingEntries = entries
- .map((entry) => entry is File ? entry.fullPathSync() : entry.path)
- .where((entry) => path.basename(entry).contains(name))
- .toList();
- matchingEntries.sort();
-
- if (matchingEntries.length == 0) return;
- throw "Expected nothing to exist in '$parent' matching $nameDescription, "
- "but found:\n"
- "${matchingEntries.map((entry) => '* $entry').join('\n')}";
- });
- }, "validating $nameDescription doesn't exist");
-
- Stream<List<int>> load(String pathToLoad) => errorStream("Nothing "
- "descriptors don't support load().");
-
- Stream<List<int>> read() => errorStream("Nothing descriptors don't support "
- "read().");
-
- String describe() => "nothing at $nameDescription";
-}
diff --git a/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
new file mode 100644
index 0000000..00fa706
--- /dev/null
+++ b/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
@@ -0,0 +1,47 @@
+// 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 descriptor.async;
+
+import 'dart:async';
+import 'dart:io';
+
+import '../../../../../pkg/pathos/lib/path.dart' as path;
+
+import '../../descriptor.dart';
+import '../../scheduled_test.dart';
+import '../utils.dart';
+
+/// A descriptor that validates that no file exists with the given name.
+/// Creating this descriptor is a no-op and loading from it is invalid.
+class NothingDescriptor extends Descriptor {
+ NothingDescriptor(String name)
+ : super(name);
+
+ Future create([String parent]) => new Future.immediate(null);
+
+ Future validate([String parent]) => schedule(() => validateNow(parent),
+ "validating '$name' doesn't exist");
+
+ Future validateNow([String parent]) => new Future.of(() {
+ if (parent == null) parent = defaultRoot;
+ var fullPath = path.join(parent, name);
+ if (new File(fullPath).existsSync()) {
+ throw "Expected nothing to exist at '$fullPath', but found a file.";
+ } else if (new Directory(fullPath).existsSync()) {
+ throw "Expected nothing to exist at '$fullPath', but found a "
+ "directory.";
+ } else {
+ return;
+ }
+ });
+
+ Stream<List<int>> load(String pathToLoad) => errorStream("Nothing "
+ "descriptors don't support load().");
+
+ Stream<List<int>> read() => errorStream("Nothing descriptors don't support "
+ "read().");
+
+ String describe() => "nothing at '$name'";
+}
diff --git a/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
new file mode 100644
index 0000000..1cea5f5
--- /dev/null
+++ b/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
@@ -0,0 +1,121 @@
+// 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 descriptor.pattern;
+
+import 'dart:async';
+import 'dart:io';
+
+import '../../../../../pkg/pathos/lib/path.dart' as path;
+
+import '../../descriptor.dart';
+import '../../scheduled_test.dart';
+import '../utils.dart';
+
+/// A function that takes a name for a [Descriptor] and returns a [Descriptor].
+/// This is used for [PatternDescriptor]s, where the name isn't known
+/// ahead-of-time.
+typedef Descriptor EntryCreator(String name);
+
+/// A descriptor that matches filesystem entities by [Pattern] rather than
+/// by [String]. It's used only for validation.
+///
+/// This class takes an [EntryCreator], which should return a [Descriptor] that
+/// will be used to validate the concrete filesystem entities that match the
+/// [pattern].
+class PatternDescriptor extends Descriptor {
+ /// The [Pattern] this matches filenames against. Note that the pattern must
+ /// match the entire basename of the file.
+ final Pattern pattern;
+
+ /// The function used to generate the [Descriptor] for filesystem entities
+ /// matching [pattern].
+ final EntryCreator _fn;
+
+ PatternDescriptor(Pattern pattern, this._fn)
+ : super('$pattern'),
+ pattern = pattern;
+
+ /// Validates that there is some filesystem entity in [parent] that matches
+ /// [pattern] and the child entry. This finds all entities in [parent]
+ /// matching [pattern], then passes each of their names to the [EntityCreator]
+ /// and validates the result. If exactly one succeeds, [this] is considered
+ /// valid.
+ Future validate([String parent]) => schedule(() => validateNow(parent),
+ "validating ${describe()}");
+
+ Future validateNow([String parent]) {
+ if (parent == null) parent = defaultRoot;
+ // TODO(nweiz): make sure this works with symlinks.
+ var matchingEntries = new Directory(parent).listSync()
+ .map((entry) => entry is File ? entry.fullPathSync() : entry.path)
+ .where((entry) => fullMatch(path.basename(entry), pattern))
+ .toList();
+ matchingEntries.sort();
+
+ if (matchingEntries.isEmpty) {
+ throw "No entry found in '$parent' matching ${_patternDescription}.";
+ }
+
+ return Future.wait(matchingEntries.map((entry) {
+ var descriptor = _fn(path.basename(entry));
+ return descriptor.validateNow(parent).then((_) {
+ return new Pair(null, descriptor.describe());
+ }).catchError((e) {
+ return new Pair(e.error.toString(), descriptor.describe());
+ });
+ })).then((results) {
+ var matches = results.where((result) => result.first == null).toList();
+ // If exactly one entry matching [pattern] validated, we're happy.
+ if (matches.length == 1) return;
+
+ // If more than one entry matching [pattern] validated, that's bad.
+ if (matches.length > 1) {
+ var resultString = matches.map((result) {
+ return prefixLines(result.last, firstPrefix: '* ', prefix: ' ');
+ }).join('\n');
+
+ throw "Multiple valid entries found in '$parent' matching "
+ "$_patternDescription:\n"
+ "$resultString";
+ }
+
+ // If no entries matching [pattern] validated, that's also bad.
+ var resultString = results.map((result) {
+ return prefixLines(
+ "Caught error\n"
+ "${prefixLines(result.first)}\n"
+ "while validating\n"
+ "${prefixLines(result.last)}",
+ firstPrefix: '* ', prefix: ' ');
+ }).join('\n');
+
+ throw "No valid entries found in '$parent' matching "
+ "$_patternDescription:\n"
+ "$resultString";
+ });
+ }
+
+ String describe() => "entry matching $_patternDescription";
+
+ String get _patternDescription {
+ if (pattern is String) return "'$pattern'";
+ if (pattern is! RegExp) return '$pattern';
+
+ var regExp = pattern as RegExp;
+ var flags = new StringBuffer();
+ if (!regExp.isCaseSensitive) flags.write('i');
+ if (regExp.isMultiLine) flags.write('m');
+ return '/${regExp.pattern}/$flags';
+ }
+
+ Future create([String parent]) => new Future.immediateError(
+ new UnsupportedError("Pattern descriptors don't support create()."));
+
+ Stream<List<int>> load(String pathToLoad) => errorStream(
+ new UnsupportedError("Pattern descriptors don't support load()."));
+
+ Stream<List<int>> read() => errorStream(new UnsupportedError("Pattern "
+ "descriptors don't support read()."));
+}
diff --git a/pkg/scheduled_test/lib/src/descriptor/utils.dart b/pkg/scheduled_test/lib/src/descriptor/utils.dart
deleted file mode 100644
index c53b429..0000000
--- a/pkg/scheduled_test/lib/src/descriptor/utils.dart
+++ /dev/null
@@ -1,54 +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 descriptor.utils;
-
-import 'dart:io';
-
-import '../../../../../pkg/pathos/lib/path.dart' as path;
-
-/// Returns a single filesystem entry within [parent] whose name matches
-/// [pattern]. If [pattern] is a string, looks for an exact match; otherwise,
-/// looks for an entry that contains [pattern].
-///
-/// If there are no entries in [parent] matching [pattern], or more than one,
-/// this will throw an exception.
-///
-/// [type] is used for error reporting. It should be capitalized.
-String entryMatchingPattern(String type, String parent, Pattern pattern) {
- if (pattern is String) {
- var fullPath = path.join(parent, pattern);
- if (new File(fullPath).existsSync() || new Directory(fullPath).existsSync()) {
- return fullPath;
- }
- throw "$type not found: '$fullPath'.";
- }
-
- var matchingEntries = new Directory(parent).listSync()
- .map((entry) => entry is File ? entry.fullPathSync() : entry.path)
- .where((entry) => path.basename(entry).contains(pattern))
- .toList();
- matchingEntries.sort();
-
- if (matchingEntries.length == 0) {
- throw "No entry found in '$parent' matching ${describePattern(pattern)}.";
- } else if (matchingEntries.length > 1) {
- throw "Multiple entries found in '$parent' matching "
- "${describePattern(pattern)}:\n"
- "${matchingEntries.map((entry) => '* $entry').join('\n')}";
- } else {
- return matchingEntries.first;
- }
-}
-
-/// Returns a human-readable description of [pattern].
-String describePattern(Pattern pattern) {
- if (pattern is String) return "'$pattern'";
- if (pattern is! RegExp) return '$pattern';
-
- var flags = new StringBuffer();
- if (!pattern.isCaseSensitive) flags.write('i');
- if (pattern.isMultiLine) flags.write('m');
- return '/${pattern.pattern}/$flags';
-}
diff --git a/pkg/scheduled_test/lib/src/schedule.dart b/pkg/scheduled_test/lib/src/schedule.dart
index 1e97ecc..977fc3f7 100644
--- a/pkg/scheduled_test/lib/src/schedule.dart
+++ b/pkg/scheduled_test/lib/src/schedule.dart
@@ -13,6 +13,7 @@
import 'schedule_error.dart';
import 'substitute_future.dart';
import 'task.dart';
+import 'utils.dart';
import 'value_future.dart';
/// The schedule of tasks to run for a single test. This has three separate task
@@ -86,7 +87,10 @@
TaskQueue _currentQueue;
/// The time to wait before terminating a task queue for inactivity. Defaults
- /// to 30 seconds. This can be set to `null` to disable timeouts entirely.
+ /// to 5 seconds. This can be set to `null` to disable timeouts entirely. Note
+ /// that the timeout is the maximum time a task is allowed between
+ /// interactions with the schedule, *not* the maximum time an entire test is
+ /// allowed. See also [heartbeat].
///
/// If a task queue times out, an error will be raised that can be handled as
/// usual in the [onException] and [onComplete] queues. If [onException] times
@@ -96,7 +100,7 @@
/// If a task times out and then later completes with an error, that error
/// cannot be handled. The user will still be notified of it.
Duration get timeout => _timeout;
- Duration _timeout = new Duration(seconds: 30);
+ Duration _timeout = new Duration(seconds: 5);
set timeout(Duration duration) {
_timeout = duration;
heartbeat();
@@ -554,14 +558,11 @@
String generateTree([Task highlight]) {
assert(highlight == null || highlight.queue == this);
return _contents.map((task) {
- var lines = task.toString().split("\n");
- var firstLine = task == highlight ?
- "> ${lines.first}" : "* ${lines.first}";
- lines = new List.from(lines.skip(1).map((line) => "| $line"));
- lines.insertRange(0, 1, firstLine);
+ var taskString = prefixLines(task.toString(),
+ firstPrefix: task == highlight ? "> " : "* ");
if (task == highlight && !task.children.isEmpty) {
- for (var child in task.children) {
+ var childrenString = task.children.map((child) {
var prefix = ">";
if (child.state == TaskState.ERROR) {
prefix = "X";
@@ -569,13 +570,13 @@
prefix = "*";
}
- var childLines = child.toString().split("\n");
- lines.add(" $prefix ${childLines.first}");
- lines.addAll(childLines.skip(1).map((line) => " | $line"));
- }
+ return prefixLines(child.toString(),
+ firstPrefix: " $prefix ", prefix: " | ");
+ }).join('\n');
+ taskString = '$taskString\n$childrenString';
}
- return lines.join("\n");
+ return taskString;
}).join("\n");
}
}
diff --git a/pkg/scheduled_test/lib/src/schedule_error.dart b/pkg/scheduled_test/lib/src/schedule_error.dart
index 7f1856b..a1f8a96 100644
--- a/pkg/scheduled_test/lib/src/schedule_error.dart
+++ b/pkg/scheduled_test/lib/src/schedule_error.dart
@@ -48,6 +48,14 @@
error = error.error;
}
+ if (stackTrace == null) {
+ try {
+ throw '';
+ } catch (_, thrownStackTrace) {
+ stackTrace = thrownStackTrace;
+ }
+ }
+
return new ScheduleError(schedule, error, stackTrace, cause);
}
diff --git a/pkg/scheduled_test/lib/src/utils.dart b/pkg/scheduled_test/lib/src/utils.dart
index 898b72e..57c341d 100644
--- a/pkg/scheduled_test/lib/src/utils.dart
+++ b/pkg/scheduled_test/lib/src/utils.dart
@@ -30,9 +30,19 @@
onError: (e) => completer.completeError(e));
}
-/// Prepends each line in [text] with [prefix].
-String prefixLines(String text, {String prefix: '| '}) =>
- text.split('\n').map((line) => '$prefix$line').join('\n');
+/// Prepends each line in [text] with [prefix]. If [firstPrefix] is passed, the
+/// first line is prefixed with that instead.
+String prefixLines(String text, {String prefix: '| ', String firstPrefix}) {
+ var lines = text.split('\n');
+ if (firstPrefix == null) {
+ return lines.map((line) => '$prefix$line').join('\n');
+ }
+
+ var firstLine = "$firstPrefix${lines.first}";
+ lines = lines.skip(1).map((line) => '$prefix$line').toList();
+ lines.insert(0, firstLine);
+ return lines.join('\n');
+}
/// Returns a [Future] that completes after pumping the event queue [times]
/// times. By default, this should pump the event queue enough times to allow
@@ -82,24 +92,22 @@
/// Returns a [Future] that will complete to the first element of [stream].
/// Unlike [Stream.first], this is safe to use with single-subscription streams.
Future streamFirst(Stream stream) {
- // TODO(nweiz): remove this when issue 8512 is fixed.
- var cancelled = false;
+ var stackTrace;
+ try {
+ throw '';
+ } catch (_, thrownStackTrace) {
+ stackTrace = thrownStackTrace;
+ }
+
var completer = new Completer();
var subscription;
subscription = stream.listen((value) {
- if (!cancelled) {
- cancelled = true;
- subscription.cancel();
- completer.complete(value);
- }
+ subscription.cancel();
+ completer.complete(value);
}, onError: (e) {
- if (!cancelled) {
- completer.completeError(e.error, e.stackTrace);
- }
+ completer.completeError(e.error, e.stackTrace);
}, onDone: () {
- if (!cancelled) {
- completer.completeError(new StateError("No elements"));
- }
+ completer.completeError(new StateError("No elements"), stackTrace);
}, unsubscribeOnError: true);
return completer.future;
}
@@ -167,3 +175,10 @@
return map;
});
}
+
+/// Returns whether [pattern] matches all of [string].
+bool fullMatch(String string, Pattern pattern) {
+ var matches = pattern.allMatches(string);
+ if (matches.isEmpty) return false;
+ return matches.first.start == 0 && matches.first.end == string.length;
+}
diff --git a/pkg/scheduled_test/test/descriptor_test.dart b/pkg/scheduled_test/test/descriptor_test.dart
index d203bbe..ff0efe5 100644
--- a/pkg/scheduled_test/test/descriptor_test.dart
+++ b/pkg/scheduled_test/test/descriptor_test.dart
@@ -45,26 +45,6 @@
});
});
- expectTestsPass('file().create() with a RegExp name fails', () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- d.file(new RegExp(r'name\.txt'), 'contents').create();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.map((e) => e.error), equals([
- r"Pattern /name\.txt/ must be a string."
- ]), verbose: true);
- });
- }, passing: ['test 2']);
-
expectTestsPass('file().validate() completes successfully if the filesystem '
'matches the descriptor', () {
test('test', () {
@@ -128,107 +108,6 @@
});
}, passing: ['test 2']);
- expectTestsPass('file().validate() with a RegExp completes successfully if '
- 'the filesystem matches the descriptor', () {
- test('test', () {
- scheduleSandbox();
-
- schedule(() {
- return new File(path.join(sandbox, 'name.txt'))
- .writeAsString('contents');
- });
-
- d.file(new RegExp(r'na..\.txt'), 'contents').validate();
- });
- });
-
- expectTestsPass("file().validate() with a RegExp fails if there's a file "
- "with the wrong contents", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- schedule(() {
- return new File(path.join(sandbox, 'name.txt'))
- .writeAsString('some\nwrongtents');
- });
-
- d.file(new RegExp(r'na..\.txt'), 'some\ncontents\nand stuff').validate();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.map((e) => e.error), equals([
- "File 'name.txt' (matching /na..\\.txt/) should contain:\n"
- "| some\n"
- "| contents\n"
- "| and stuff\n"
- "but actually contained:\n"
- "| some\n"
- "X wrongtents\n"
- "? and stuff"
- ]), verbose: true);
- });
- }, passing: ['test 2']);
-
- expectTestsPass("file().validate() with a RegExp fails if there's no "
- "file", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- d.file(new RegExp(r'na..\.txt'), 'contents').validate();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(1));
- expect(errors.first.error,
- matches(r"^No entry found in '[^']+' matching /na\.\.\\\.txt/\.$"));
- });
- }, passing: ['test 2']);
-
- expectTestsPass("file().validate() with a RegExp fails if there are multiple "
- "matching files", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- schedule(() {
- return Future.wait([
- new File(path.join(sandbox, 'name.txt')).writeAsString('contents'),
- new File(path.join(sandbox, 'nape.txt')).writeAsString('contents'),
- new File(path.join(sandbox, 'nail.txt')).writeAsString('contents')
- ]);
- });
-
- d.file(new RegExp(r'na..\.txt'), 'contents').validate();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(1));
- expect(errors.first.error,
- matches(
- r"^Multiple entries found in '[^']+' matching /na\.\.\\\.txt/:\n"
- r"\* .*[\\/]nail\.txt\n"
- r"\* .*[\\/]name\.txt\n"
- r"\* .*[\\/]nape\.txt"));
- });
- }, passing: ['test 2']);
-
expectTestsPass("file().read() returns the contents of the file as a stream",
() {
test('test', () {
@@ -251,13 +130,6 @@
});
});
- expectTestsPass("file().describe() with a RegExp describes the file", () {
- test('test', () {
- expect(d.file(new RegExp(r'na..\.txt'), 'contents').describe(),
- equals(r'file matching /na..\.txt/'));
- });
- });
-
expectTestsPass('binaryFile().create() creates a file', () {
test('test', () {
scheduleSandbox();
@@ -355,26 +227,6 @@
});
});
- expectTestsPass("directory().create() with a RegExp name fails", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- d.dir(new RegExp('dir')).create();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.map((e) => e.error), equals([
- "Pattern /dir/ must be a string."
- ]), verbose: true);
- });
- }, passing: ['test 2']);
-
expectTestsPass("directory().validate() completes successfully if the "
"filesystem matches the descriptor", () {
test('test', () {
@@ -443,7 +295,7 @@
test('test 2', () {
expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
expect(errors.length, equals(1));
- expect(errors.first.error,
+ expect(errors.first.error.toString(),
matches(r"^Directory not found: '[^']+[\\/]dir[\\/]subdir'\.$"));
});
}, passing: ['test 2']);
@@ -485,11 +337,58 @@
test('test 2', () {
expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
expect(errors.length, equals(1));
- expect(errors.first.error,
+ expect(errors.first.error.toString(),
matches(r"^File not found: '[^']+[\\/]dir[\\/]file2\.txt'\.$"));
});
}, passing: ['test 2']);
+ expectTestsPass("directory().validate() fails if multiple children aren't "
+ "found or have the wrong contents", () {
+ var errors;
+ test('test 1', () {
+ scheduleSandbox();
+
+ currentSchedule.onException.schedule(() {
+ errors = currentSchedule.errors;
+ });
+
+ schedule(() {
+ var dirPath = path.join(sandbox, 'dir');
+ var subdirPath = path.join(dirPath, 'subdir');
+ return new Directory(subdirPath).create(recursive: true).then((_) {
+ return Future.wait([
+ new File(path.join(dirPath, 'file1.txt'))
+ .writeAsString('contents1'),
+ new File(path.join(subdirPath, 'subfile2.txt'))
+ .writeAsString('subwrongtents2')
+ ]);
+ });
+ });
+
+ d.dir('dir', [
+ d.dir('subdir', [
+ d.file('subfile1.txt', 'subcontents1'),
+ d.file('subfile2.txt', 'subcontents2')
+ ]),
+ d.file('file1.txt', 'contents1'),
+ d.file('file2.txt', 'contents2')
+ ]).validate();
+ });
+
+ test('test 2', () {
+ expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+ expect(errors.length, equals(1));
+ expect(errors.first.error.toString(), matches(
+ r"^\* File not found: '[^']+[\\/]dir[\\/]subdir[\\/]subfile1\.txt'\."
+ r"\n"
+ r"\* File 'subfile2\.txt' should contain:\n"
+ r" \| subcontents2\n"
+ r" but actually contained:\n"
+ r" X subwrongtents2\n"
+ r"\* File not found: '[^']+[\\/]dir[\\/]file2\.txt'\.$"));
+ });
+ }, passing: ['test 2']);
+
expectTestsPass("directory().validate() fails if a file has the wrong "
"contents", () {
var errors;
@@ -529,7 +428,7 @@
test('test 2', () {
expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.map((e) => e.error), equals([
+ expect(errors.map((e) => e.error.toString()), equals([
"File 'subfile1.txt' should contain:\n"
"| subcontents1\n"
"but actually contained:\n"
@@ -538,161 +437,6 @@
});
}, passing: ['test 2']);
- expectTestsPass("directory().validate() with a RegExp completes successfully "
- "if the filesystem matches the descriptor", () {
- test('test', () {
- scheduleSandbox();
-
- schedule(() {
- var dirPath = path.join(sandbox, 'dir');
- var subdirPath = path.join(dirPath, 'subdir');
- return new Directory(subdirPath).create(recursive: true).then((_) {
- return Future.wait([
- new File(path.join(dirPath, 'file1.txt'))
- .writeAsString('contents1'),
- new File(path.join(dirPath, 'file2.txt'))
- .writeAsString('contents2'),
- new File(path.join(subdirPath, 'subfile1.txt'))
- .writeAsString('subcontents1'),
- new File(path.join(subdirPath, 'subfile2.txt'))
- .writeAsString('subcontents2')
- ]);
- });
- });
-
- d.dir(new RegExp('d.r'), [
- d.dir('subdir', [
- d.file('subfile1.txt', 'subcontents1'),
- d.file('subfile2.txt', 'subcontents2')
- ]),
- d.file('file1.txt', 'contents1'),
- d.file('file2.txt', 'contents2')
- ]).validate();
- });
- });
-
- expectTestsPass("directory().validate() with a RegExp fails if there's a dir "
- "with the wrong contents", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- schedule(() {
- var dirPath = path.join(sandbox, 'dir');
- var subdirPath = path.join(dirPath, 'subdir');
- return new Directory(subdirPath).create(recursive: true).then((_) {
- return Future.wait([
- new File(path.join(dirPath, 'file1.txt'))
- .writeAsString('contents1'),
- new File(path.join(subdirPath, 'subfile1.txt'))
- .writeAsString('subcontents1'),
- new File(path.join(subdirPath, 'subfile2.txt'))
- .writeAsString('subcontents2')
- ]);
- });
- });
-
- d.dir(new RegExp('d.r'), [
- d.dir('subdir', [
- d.file('subfile1.txt', 'subcontents1'),
- d.file('subfile2.txt', 'subcontents2')
- ]),
- d.file('file1.txt', 'contents1'),
- d.file('file2.txt', 'contents2')
- ]).validate();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(1));
- expect(errors.first.error,
- matches(r"^File not found: '[^']+[\\/]dir[\\/]file2\.txt'\.$"));
- });
- }, passing: ['test 2']);
-
- expectTestsPass("directory().validate() with a RegExp fails if there's no "
- "dir", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- d.dir(new RegExp('d.r'), [
- d.dir('subdir', [
- d.file('subfile1.txt', 'subcontents1'),
- d.file('subfile2.txt', 'subcontents2')
- ]),
- d.file('file1.txt', 'contents1'),
- d.file('file2.txt', 'contents2')
- ]).validate();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(1));
- expect(errors.first.error,
- matches(r"^No entry found in '[^']+' matching /d\.r/\.$"));
- });
- }, passing: ['test 2']);
-
- expectTestsPass("directory().validate() with a RegExp fails if there are "
- "multiple matching dirs", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- schedule(() {
- return Future.wait(['dir', 'dar', 'dor'].map((dir) {
- var dirPath = path.join(sandbox, dir);
- var subdirPath = path.join(dirPath, 'subdir');
- return new Directory(subdirPath).create(recursive: true).then((_) {
- return Future.wait([
- new File(path.join(dirPath, 'file1.txt'))
- .writeAsString('contents1'),
- new File(path.join(dirPath, 'file2.txt'))
- .writeAsString('contents2'),
- new File(path.join(subdirPath, 'subfile1.txt'))
- .writeAsString('subcontents1'),
- new File(path.join(subdirPath, 'subfile2.txt'))
- .writeAsString('subcontents2')
- ]);
- });
- }));
- });
-
- d.dir(new RegExp('d.r'), [
- d.dir('subdir', [
- d.file('subfile1.txt', 'subcontents1'),
- d.file('subfile2.txt', 'subcontents2')
- ]),
- d.file('file1.txt', 'contents1'),
- d.file('file2.txt', 'contents2')
- ]).validate();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(1));
- expect(errors.first.error,
- matches(
- r"^Multiple entries found in '[^']+' matching /d\.r/:\n"
- r"\* .*[\\/]dar\n"
- r"\* .*[\\/]dir\n"
- r"\* .*[\\/]dor"));
- });
- }, passing: ['test 2']);
-
expectTestsPass("directory().load() loads a file", () {
test('test', () {
var dir = d.dir('dir', [d.file('name.txt', 'contents')]);
@@ -762,16 +506,6 @@
});
});
- expectTestsPass("directory().load() fails to load a file with a RegExp name",
- () {
- test('test', () {
- var dir = d.dir('dir', [d.file(new RegExp(r'name\.txt'), 'contents')]);
-
- expect(dir.load('name.txt').toList(),
- throwsA(equals(r"Pattern /name\.txt/ must be a string.")));
- });
- });
-
expectTestsPass("directory().load() fails to load a file that doesn't exist",
() {
test('test', () {
@@ -802,15 +536,13 @@
test('test', () {
var dir = d.dir('dir', [
d.file('file1.txt', 'contents1'),
- d.file('file2.txt', 'contents2'),
- d.file(new RegExp(r're\.txt'), 're-contents')
+ d.file('file2.txt', 'contents2')
]);
expect(dir.describe(), equals(
"dir\n"
"|-- file1.txt\n"
- "|-- file2.txt\n"
- "'-- file matching /re\\.txt/"));
+ "'-- file2.txt"));
});
});
@@ -841,21 +573,6 @@
});
});
- expectTestsPass("directory().describe() with a RegExp describes the "
- "directory", () {
- test('test', () {
- var dir = d.dir(new RegExp(r'd.r'), [
- d.file('file1.txt', 'contents1'),
- d.file('file2.txt', 'contents2')
- ]);
-
- expect(dir.describe(), equals(
- "directory matching /d.r/\n"
- "|-- file1.txt\n"
- "'-- file2.txt"));
- });
- });
-
expectTestsPass("directory().describe() with no contents returns the "
"directory name", () {
test('test', () {
@@ -976,7 +693,7 @@
expect(d.async(new Future.immediate(d.file('name.txt')))
.load('path').toList(),
- throwsA(equals("Async descriptors don't support load().")));
+ throwsA(equals("AsyncDescriptors don't support load().")));
});
});
@@ -985,7 +702,7 @@
scheduleSandbox();
expect(d.async(new Future.immediate(d.file('name.txt'))).read().toList(),
- throwsA(equals("Async descriptors don't support read().")));
+ throwsA(equals("AsyncDescriptors don't support read().")));
});
});
@@ -1015,15 +732,6 @@
});
});
- expectTestsPass("nothing().validate() with a RegExp succeeds if nothing's "
- "there", () {
- test('test', () {
- scheduleSandbox();
-
- d.nothing(new RegExp('f.o')).validate();
- });
- });
-
expectTestsPass("nothing().validate() fails if there's a file", () {
var errors;
test('test 1', () {
@@ -1068,33 +776,6 @@
});
}, passing: ['test 2']);
- expectTestsPass("nothing().validate() with a RegExp fails if there are "
- "multiple entries", () {
- var errors;
- test('test 1', () {
- scheduleSandbox();
-
- currentSchedule.onException.schedule(() {
- errors = currentSchedule.errors;
- });
-
- d.dir('foo').create();
- d.file('faa', 'contents').create();
- d.file('not-foo', 'contents').create();
- d.nothing(new RegExp(r'^f..$')).validate();
- });
-
- test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(1));
- expect(errors.first.error,
- matches(r"^Expected nothing to exist in '[^']+' matching "
- r"/\^f\.\.\$/, but found:\n"
- r"\* .*[\\/]faa\n"
- r"\* .*[\\/]foo$"));
- });
- }, passing: ['test 2']);
-
expectTestsPass("nothing().load() fails", () {
test('test', () {
scheduleSandbox();
@@ -1112,6 +793,156 @@
throwsA(equals("Nothing descriptors don't support read().")));
});
});
+
+ expectTestsPass("pattern().validate() succeeds if there's a file matching "
+ "the pattern and the child entry", () {
+ test('test', () {
+ scheduleSandbox();
+
+ d.file('foo', 'blap').create();
+
+ d.filePattern(new RegExp(r'f..'), 'blap').validate();
+ });
+ });
+
+ expectTestsPass("pattern().validate() succeeds if there's a dir matching "
+ "the pattern and the child entry", () {
+ test('test', () {
+ scheduleSandbox();
+
+ d.dir('foo', [
+ d.file('bar', 'baz')
+ ]).create();
+
+ d.dirPattern(new RegExp(r'f..'), [
+ d.file('bar', 'baz')
+ ]).validate();
+ });
+ });
+
+ expectTestsPass("pattern().validate() succeeds if there's multiple files "
+ "matching the pattern but only one matching the child entry", () {
+ test('test', () {
+ scheduleSandbox();
+
+ d.file('foo', 'blap').create();
+ d.file('fee', 'blak').create();
+ d.file('faa', 'blut').create();
+
+ d.filePattern(new RegExp(r'f..'), 'blap').validate();
+ });
+ });
+
+ expectTestsPass("pattern().validate() fails if there's no file matching the "
+ "pattern", () {
+ var errors;
+ test('test 1', () {
+ scheduleSandbox();
+
+ currentSchedule.onException.schedule(() {
+ errors = currentSchedule.errors;
+ });
+
+ d.filePattern(new RegExp(r'f..'), 'bar').validate();
+ });
+
+ test('test 2', () {
+ expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+ expect(errors.length, equals(1));
+ expect(errors.first.error,
+ matches(r"^No entry found in '[^']+' matching /f\.\./\.$"));
+ });
+ }, passing: ['test 2']);
+
+ expectTestsPass("pattern().validate() fails if there's a file matching the "
+ "pattern but not the entry", () {
+ var errors;
+ test('test 1', () {
+ scheduleSandbox();
+
+ currentSchedule.onException.schedule(() {
+ errors = currentSchedule.errors;
+ });
+
+ d.file('foo', 'bap').create();
+ d.filePattern(new RegExp(r'f..'), 'bar').validate();
+ });
+
+ test('test 2', () {
+ expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+ expect(errors.length, equals(1));
+ expect(errors.first.error,
+ matches(r"^Caught error\n"
+ r"| File 'foo' should contain:\n"
+ r"| | bar\n"
+ r"| but actually contained:\n"
+ r"| X bap\n"
+ r"while validating\n"
+ r"| foo$"));
+ });
+ }, passing: ['test 2']);
+
+ expectTestsPass("pattern().validate() fails if there's a dir matching the "
+ "pattern but not the entry", () {
+ var errors;
+ test('test 1', () {
+ scheduleSandbox();
+
+ currentSchedule.onException.schedule(() {
+ errors = currentSchedule.errors;
+ });
+
+ d.dir('foo', [
+ d.file('bar', 'bap')
+ ]).create();
+
+ d.dirPattern(new RegExp(r'f..'), [
+ d.file('bar', 'baz')
+ ]).validate();
+ });
+
+ test('test 2', () {
+ expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+ expect(errors.length, equals(1));
+ expect(errors.first.error,
+ matches(r"^Caught error\n"
+ r"| File 'bar' should contain:\n"
+ r"| | baz\n"
+ r"| but actually contained:\n"
+ r"| X bap"
+ r"while validating\n"
+ r"| foo\n"
+ r"| '-- bar$"));
+ });
+ }, passing: ['test 2']);
+
+ expectTestsPass("pattern().validate() fails if there's multiple files "
+ "matching the pattern and the child entry", () {
+ var errors;
+ test('test 1', () {
+ scheduleSandbox();
+
+ currentSchedule.onException.schedule(() {
+ errors = currentSchedule.errors;
+ });
+
+ d.file('foo', 'bar').create();
+ d.file('fee', 'bar').create();
+ d.file('faa', 'bar').create();
+ d.filePattern(new RegExp(r'f..'), 'bar').validate();
+ });
+
+ test('test 2', () {
+ expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+ expect(errors.length, equals(1));
+ expect(errors.first.error, matches(
+ r"^Multiple valid entries found in '[^']+' matching "
+ r"\/f\.\./:\n"
+ r"\* faa\n"
+ r"\* fee\n"
+ r"\* foo$"));
+ });
+ }, passing: ['test 2']);
}
void scheduleSandbox() {
diff --git a/pkg/scheduled_test/test/scheduled_server_test.dart b/pkg/scheduled_test/test/scheduled_server_test.dart
index 5fc7812..aeb654f 100644
--- a/pkg/scheduled_test/test/scheduled_server_test.dart
+++ b/pkg/scheduled_test/test/scheduled_server_test.dart
@@ -35,10 +35,18 @@
test('test 2', () {
expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(2));
+ // TODO(nweiz): There can be three errors due to issue 9151. The
+ // HttpParserException is reported without a stack trace, and so when it's
+ // wrapped twice it registers as a different exception each time (because
+ // it's given an ad-hoc stack trace). Always expect two exceptions when
+ // issue 9151 is fixed.
+ expect(errors.length, inInclusiveRange(2, 3));
expect(errors[0].error, equals("'scheduled server 0' received GET /hello "
"when no more requests were expected."));
expect(errors[1].error, new isInstanceOf<HttpParserException>());
+ if (errors.length > 2) {
+ expect(errors[2].error, new isInstanceOf<HttpParserException>());
+ }
});
}, passing: ['test 2']);
@@ -99,11 +107,19 @@
});
test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(2));
+ // TODO(nweiz): There can be three errors due to issue 9151. The
+ // HttpParserException is reported without a stack trace, and so when it's
+ // wrapped twice it registers as a different exception each time (because
+ // it's given an ad-hoc stack trace). Always expect two exceptions when
+ // issue 9151 is fixed.
+ expect(errors.length, inInclusiveRange(2, 3));
expect(errors[0].error, equals("'scheduled server 0' received GET /hello "
"earlier than expected."));
expect(errors[1].error, new isInstanceOf<HttpParserException>());
+ if (errors.length > 2) {
+ expect(errors[2].error, new isInstanceOf<HttpParserException>());
+ }
+ expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
});
}, passing: ['test 2']);
@@ -147,11 +163,18 @@
});
test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(2));
+ // TODO(nweiz): There can be three errors due to issue 9151. The
+ // HttpParserException is reported without a stack trace, and so when it's
+ // wrapped twice it registers as a different exception each time (because
+ // it's given an ad-hoc stack trace). Always expect two exceptions when
+ // issue 9151 is fixed.
+ expect(errors.length, inInclusiveRange(2, 3));
expect(errors[0].error, equals("'scheduled server 0' expected GET "
"/goodbye, but got GET /hello."));
expect(errors[1].error, new isInstanceOf<HttpParserException>());
+ if (errors.length > 2) {
+ expect(errors[2].error, new isInstanceOf<HttpParserException>());
+ }
});
}, passing: ['test 2']);
@@ -173,11 +196,18 @@
});
test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(2));
+ // TODO(nweiz): There can be three errors due to issue 9151. The
+ // HttpParserException is reported without a stack trace, and so when it's
+ // wrapped twice it registers as a different exception each time (because
+ // it's given an ad-hoc stack trace). Always expect two exceptions when
+ // issue 9151 is fixed.
+ expect(errors.length, inInclusiveRange(2, 3));
expect(errors[0].error, equals("'scheduled server 0' expected GET "
"/hello, but got HEAD /hello."));
expect(errors[1].error, new isInstanceOf<HttpParserException>());
+ if (errors.length > 2) {
+ expect(errors[2].error, new isInstanceOf<HttpParserException>());
+ }
});
}, passing: ['test 2']);
@@ -271,11 +301,18 @@
});
test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(2));
+ // TODO(nweiz): There can be three errors due to issue 9151. The
+ // HttpParserException is reported without a stack trace, and so when it's
+ // wrapped twice it registers as a different exception each time (because
+ // it's given an ad-hoc stack trace). Always expect two exceptions when
+ // issue 9151 is fixed.
+ expect(errors.length, inInclusiveRange(2, 3));
expect(errors[0].error, equals("'scheduled server 0' received GET "
"/hello/3 when no more requests were expected."));
expect(errors[1].error, new isInstanceOf<HttpParserException>());
+ if (errors.length > 2) {
+ expect(errors[2].error, new isInstanceOf<HttpParserException>());
+ }
});
}, passing: ['test 2']);
@@ -296,10 +333,17 @@
});
test('test 2', () {
- expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
- expect(errors.length, equals(2));
+ // TODO(nweiz): There can be three errors due to issue 9151. The
+ // HttpParserException is reported without a stack trace, and so when it's
+ // wrapped twice it registers as a different exception each time (because
+ // it's given an ad-hoc stack trace). Always expect two exceptions when
+ // issue 9151 is fixed.
+ expect(errors.length, inInclusiveRange(2, 3));
expect(errors[0].error, equals('oh no'));
expect(errors[1].error, new isInstanceOf<HttpParserException>());
+ if (errors.length > 2) {
+ expect(errors[2].error, new isInstanceOf<HttpParserException>());
+ }
});
}, passing: ['test 2']);
}
diff --git a/pkg/scheduled_test/test/utils.dart b/pkg/scheduled_test/test/utils.dart
index 8f0bd23..7750e8a 100644
--- a/pkg/scheduled_test/test/utils.dart
+++ b/pkg/scheduled_test/test/utils.dart
@@ -4,6 +4,7 @@
library test_utils;
+import 'dart:io';
import 'dart:async';
import '../lib/src/utils.dart';
diff --git a/pkg/serialization/lib/src/polyfill_identity_set.dart b/pkg/serialization/lib/src/polyfill_identity_set.dart
deleted file mode 100644
index 56a7865..0000000
--- a/pkg/serialization/lib/src/polyfill_identity_set.dart
+++ /dev/null
@@ -1,306 +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.
-
-// TODO(alanknight): Replace with proper identity collection. Issue 4161
-library identity_set;
-
-import 'dart:collection';
-
-// Hash map implementation with open addressing and quadratic probing.
-class IdentityMap<K, V> implements HashMap<K, V> {
-
- // The [_keys] list contains the keys inserted in the map.
- // The [_keys] list must be a raw list because it
- // will contain both elements of type K, and the [_DELETED_KEY] of type
- // [_DeletedKeySentinel].
- // The alternative of declaring the [_keys] list as of type Object
- // does not work, because the HashSetIterator constructor would fail:
- // HashSetIterator(HashSet<E> set)
- // : _nextValidIndex = -1,
- // _entries = set_._backingMap._keys {
- // _advance();
- // }
- // With K being type int, for example, it would fail because
- // List<Object> is not assignable to type List<int> of entries.
- List _keys;
-
- // The values inserted in the map. For a filled entry index in this
- // list, there is always the corresponding key in the [keys_] list
- // at the same entry index.
- List<V> _values;
-
- // The load limit is the number of entries we allow until we double
- // the size of the lists.
- int _loadLimit;
-
- // The current number of entries in the map. Will never be greater
- // than [_loadLimit].
- int _numberOfEntries;
-
- // The current number of deleted entries in the map.
- int _numberOfDeleted;
-
- // The sentinel when a key is deleted from the map.
- static const _DeletedKeySentinel _DELETED_KEY = const _DeletedKeySentinel();
-
- // The initial capacity of a hash map.
- static const int _INITIAL_CAPACITY = 8; // must be power of 2
-
- IdentityMap() {
- _numberOfEntries = 0;
- _numberOfDeleted = 0;
- _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY);
- _keys = new List(_INITIAL_CAPACITY);
- _values = new List<V>(_INITIAL_CAPACITY);
- }
-
- factory IdentityMap.from(Map<K, V> other) {
- Map<K, V> result = new IdentityMap<K, V>();
- other.forEach((K key, V value) { result[key] = value; });
- return result;
- }
-
- static int _computeLoadLimit(int capacity) {
- return (capacity * 3) ~/ 4;
- }
-
- static int _firstProbe(int hashCode, int length) {
- return hashCode & (length - 1);
- }
-
- static int _nextProbe(int currentProbe, int numberOfProbes, int length) {
- return (currentProbe + numberOfProbes) & (length - 1);
- }
-
- int _probeForAdding(K key) {
- if (key == null) throw new ArgumentError(null);
- int hash = _firstProbe(key.hashCode, _keys.length);
- int numberOfProbes = 1;
- int initialHash = hash;
- // insertionIndex points to a slot where a key was deleted.
- int insertionIndex = -1;
- while (true) {
- // [existingKey] can be either of type [K] or [_DeletedKeySentinel].
- Object existingKey = _keys[hash];
- if (existingKey == null) {
- // We are sure the key is not already in the set.
- // If the current slot is empty and we didn't find any
- // insertion slot before, return this slot.
- if (insertionIndex < 0) return hash;
- // If we did find an insertion slot before, return it.
- return insertionIndex;
- } else if (identical(existingKey, key)) {
- // The key is already in the map. Return its slot.
- return hash;
- } else if ((insertionIndex < 0) &&
- (identical(existingKey, _DELETED_KEY))) {
- // The slot contains a deleted element. Because previous calls to this
- // method may not have had this slot deleted, we must continue iterate
- // to find if there is a slot with the given key.
- insertionIndex = hash;
- }
-
- // We did not find an insertion slot. Look at the next one.
- hash = _nextProbe(hash, numberOfProbes++, _keys.length);
- // _ensureCapacity has guaranteed the following cannot happen.
- // assert(hash != initialHash);
- }
- }
-
- int _probeForLookup(K key) {
- if (key == null) throw new ArgumentError(null);
- int hash = _firstProbe(key.hashCode, _keys.length);
- int numberOfProbes = 1;
- int initialHash = hash;
- while (true) {
- // [existingKey] can be either of type [K] or [_DeletedKeySentinel].
- Object existingKey = _keys[hash];
- // If the slot does not contain anything (in particular, it does not
- // contain a deleted key), we know the key is not in the map.
- if (existingKey == null) return -1;
- // The key is in the map, return its index.
- if (identical(existingKey, key)) return hash;
- // Go to the next probe.
- hash = _nextProbe(hash, numberOfProbes++, _keys.length);
- // _ensureCapacity has guaranteed the following cannot happen.
- // assert(hash != initialHash);
- }
- }
-
- void _ensureCapacity() {
- int newNumberOfEntries = _numberOfEntries + 1;
- // Test if adding an element will reach the load limit.
- if (newNumberOfEntries >= _loadLimit) {
- _grow(_keys.length * 2);
- return;
- }
-
- // Make sure that we don't have poor performance when a map
- // contains lots of deleted entries: we _grow if
- // there are more deleted entried than free entries.
- int capacity = _keys.length;
- int numberOfFreeOrDeleted = capacity - newNumberOfEntries;
- int numberOfFree = numberOfFreeOrDeleted - _numberOfDeleted;
- // assert(numberOfFree > 0);
- if (_numberOfDeleted > numberOfFree) {
- _grow(_keys.length);
- }
- }
-
- static bool _isPowerOfTwo(int x) {
- return ((x & (x - 1)) == 0);
- }
-
- void _grow(int newCapacity) {
- assert(_isPowerOfTwo(newCapacity));
- int capacity = _keys.length;
- _loadLimit = _computeLoadLimit(newCapacity);
- List oldKeys = _keys;
- List<V> oldValues = _values;
- _keys = new List(newCapacity);
- _values = new List<V>(newCapacity);
- for (int i = 0; i < capacity; i++) {
- // [key] can be either of type [K] or [_DeletedKeySentinel].
- Object key = oldKeys[i];
- // If there is no key, we don't need to deal with the current slot.
- if (key == null || identical(key, _DELETED_KEY)) {
- continue;
- }
- V value = oldValues[i];
- // Insert the {key, value} pair in their new slot.
- int newIndex = _probeForAdding(key);
- _keys[newIndex] = key;
- _values[newIndex] = value;
- }
- _numberOfDeleted = 0;
- }
-
- void clear() {
- _numberOfEntries = 0;
- _numberOfDeleted = 0;
- int length = _keys.length;
- for (int i = 0; i < length; i++) {
- _keys[i] = null;
- _values[i] = null;
- }
- }
-
- void operator []=(K key, V value) {
- _ensureCapacity();
- int index = _probeForAdding(key);
- if ((_keys[index] == null) || (identical(_keys[index], _DELETED_KEY))) {
- _numberOfEntries++;
- }
- _keys[index] = key;
- _values[index] = value;
- }
-
- V operator [](K key) {
- int index = _probeForLookup(key);
- if (index < 0) return null;
- return _values[index];
- }
-
- V putIfAbsent(K key, V ifAbsent()) {
- int index = _probeForLookup(key);
- if (index >= 0) return _values[index];
-
- V value = ifAbsent();
- this[key] = value;
- return value;
- }
-
- V remove(K key) {
- int index = _probeForLookup(key);
- if (index >= 0) {
- _numberOfEntries--;
- V value = _values[index];
- _values[index] = null;
- // Set the key to the sentinel to not break the probing chain.
- _keys[index] = _DELETED_KEY;
- _numberOfDeleted++;
- return value;
- }
- return null;
- }
-
- bool get isEmpty {
- return _numberOfEntries == 0;
- }
-
- int get length {
- return _numberOfEntries;
- }
-
- void forEach(void f(K key, V value)) {
- int length = _keys.length;
- for (int i = 0; i < length; i++) {
- var key = _keys[i];
- if ((key != null) && (!identical(key, _DELETED_KEY))) {
- f(key, _values[i]);
- }
- }
- }
-
-
- Collection<K> get keys {
- List<K> list = new List<K>(length);
- int i = 0;
- forEach((K key, V value) {
- list[i++] = key;
- });
- return list;
- }
-
- Collection<V> get values {
- List<V> list = new List<V>(length);
- int i = 0;
- forEach((K key, V value) {
- list[i++] = value;
- });
- return list;
- }
-
- bool containsKey(K key) {
- return (_probeForLookup(key) != -1);
- }
-
- bool containsValue(V value) {
- int length = _values.length;
- for (int i = 0; i < length; i++) {
- var key = _keys[i];
- if ((key != null) && (!identical(key, _DELETED_KEY))) {
- if (_values[i] == value) return true;
- }
- }
- return false;
- }
-
- String toString() {
- return Maps.mapToString(this);
- }
-}
-
-
-/**
- * A singleton sentinel used to represent when a key is deleted from the map.
- * We can't use [: const Object() :] as a sentinel because it would end up
- * canonicalized and then we cannot distinguish the deleted key from the
- * canonicalized [: Object() :].
- */
-class _DeletedKeySentinel {
- const _DeletedKeySentinel();
-}
-
-
-/**
- * This class represents a pair of two objects, used by LinkedHashMap
- * to store a {key, value} in a list.
- */
-class _KeyValuePair<K, V> {
- _KeyValuePair(this.key, this.value) {}
-
- final K key;
- V value;
-}
\ No newline at end of file
diff --git a/pkg/serialization/lib/src/serialization_rule.dart b/pkg/serialization/lib/src/serialization_rule.dart
index 408d40b..01b3b05 100644
--- a/pkg/serialization/lib/src/serialization_rule.dart
+++ b/pkg/serialization/lib/src/serialization_rule.dart
@@ -398,8 +398,9 @@
var qualifiedName = r.resolveReference(state.first);
var lookupFull = r.objectNamed(qualifiedName, (x) => null);
if (lookupFull != null) return lookupFull;
- var lib = qualifiedName.substring(0, qualifiedName.indexOf("."));
- var type = qualifiedName.substring(qualifiedName.indexOf(".") + 1);
+ var separatorIndex = qualifiedName.lastIndexOf(".");
+ var lib = qualifiedName.substring(0, separatorIndex);
+ var type = qualifiedName.substring(separatorIndex + 1);
var lookup = r.objectNamed(type, (x) => null);
if (lookup != null) return lookup;
var libMirror = currentMirrorSystem().libraries[lib];
@@ -541,6 +542,7 @@
Iterator get iterator => _inflated.iterator;
indexOf(x, [pos = 0]) => _inflated.toList().indexOf(x);
lastIndexOf(x, [pos]) => _inflated.toList().lastIndexOf(x);
+ sublist(start, [end]) => _inflated.sublist(start, end);
Map<int, dynamic> asMap() => IterableMixinWorkaround.asMapList(this);
diff --git a/pkg/serialization/pubspec.yaml b/pkg/serialization/pubspec.yaml
index c3ab332..e66e029 100644
--- a/pkg/serialization/pubspec.yaml
+++ b/pkg/serialization/pubspec.yaml
@@ -4,6 +4,5 @@
documentation: http://api.dartlang.org/docs/pkg/serialization
description: >
Provide a serialization facility for Dart objects.
-dependencies:
- unittest:
- sdk: unittest
+dev_dependencies:
+ unittest: any
diff --git a/pkg/serialization/test/no_library_test.dart b/pkg/serialization/test/no_library_test.dart
new file mode 100644
index 0000000..30c1067
--- /dev/null
+++ b/pkg/serialization/test/no_library_test.dart
@@ -0,0 +1,22 @@
+// 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:serialization/serialization.dart';
+import 'package:unittest/unittest.dart';
+
+class Thing {
+ var name;
+}
+
+void main() {
+
+ test("Serializing something without a library directive", () {
+ var thing = new Thing()..name = 'testThing';
+ var s = new Serialization()
+ ..addRuleFor(thing);
+ var serialized = s.write(thing);
+ var newThing = s.read(serialized);
+ expect(thing.name, newThing.name);
+ });
+}
\ No newline at end of file
diff --git a/pkg/source_maps/README.md b/pkg/source_maps/README.md
new file mode 100644
index 0000000..df182d9
--- /dev/null
+++ b/pkg/source_maps/README.md
@@ -0,0 +1,27 @@
+Source Maps
+===========
+
+This project implements a Dart pub package to work with source maps. The
+implementation is based on the [source map version 3 spec][spec] which was
+originated from the [Closure Compiler][closure] and has been implemented in
+Chrome and Firefox.
+
+In this package we provide:
+ * Data types defining file locations and spans: these are not part of the
+ original source map specification. These data types are great for tracking
+ source locations on source maps, but they can also be used by tools to
+ reporting useful error messages that include on source locations.
+ * A builder that creates a source map programatically and produces the encoded
+ source map format.
+ * A parser that reads the source map format and provides APIs to read the
+ mapping information.
+
+Some upcoming features we are planning to add to this package are:
+ * A printer that lets you generate code, but record source map information in
+ the process.
+ * A tool that can compose source maps together. This would be useful for
+ instance, if you have 2 tools that produce source maps and you call one with
+ the result of the other.
+
+[closure]: http://code.google.com/p/closure-compiler/wiki/SourceMaps
+[spec]: https://docs.google.com/a/google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
diff --git a/pkg/source_maps/lib/builder.dart b/pkg/source_maps/lib/builder.dart
new file mode 100644
index 0000000..ad80fa0
--- /dev/null
+++ b/pkg/source_maps/lib/builder.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.
+
+/// Contains a builder object useful for creating source maps programatically.
+library source_maps.builder;
+
+// TODO(sigmund): add a builder for multi-section mappings.
+
+import 'dart:json' as json;
+import 'dart:collection';
+
+import 'span.dart';
+import 'src/vlq.dart';
+
+/// Builds a source map given a set of mappings.
+class SourceMapBuilder {
+
+ final List<Entry> _entries = <Entry>[];
+
+ /// Indices associated with file urls that will be part of the source map. We
+ /// use a linked hash-map so that `_urls.keys[_urls[u]] == u`
+ final Map<String, int> _urls = new LinkedHashMap<String, int>();
+
+ /// Indices associated with identifiers that will be part of the source map.
+ /// We use a linked hash-map so that `_names.keys[_names[n]] == n`
+ final Map<String, int> _names = new LinkedHashMap<String, int>();
+
+ /// Adds an entry mapping the [targetOffset] to [source].
+ void addFromOffset(Location source,
+ SourceFile targetFile, int targetOffset, String identifier) {
+ if (targetFile == null) {
+ throw new ArgumentError('targetFile cannot be null');
+ }
+ _entries.add(new Entry(source,
+ new FileLocation(targetFile, targetOffset), identifier));
+ }
+
+ /// Adds an entry mapping [target] to [source].
+ void addSpan(Span source, Span target) {
+ var name = source.isIdentifier ? source.text : null;
+ _entries.add(new Entry(source.start, target.start, name));
+ }
+
+ void addLocation(Location source, Location target, String identifier) {
+ _entries.add(new Entry(source, target, identifier));
+ }
+
+ /// Encodes all mappings added to this builder as a json map.
+ Map build(String fileUrl) {
+ var buff = new StringBuffer();
+ var line = 0;
+ var column = 0;
+ var srcLine = 0;
+ var srcColumn = 0;
+ var srcUrlId = 0;
+ var srcNameId = 0;
+ var first = true;
+
+ // The encoding needs to be sorted by the target offsets.
+ _entries.sort();
+ for (var entry in _entries) {
+ int nextLine = entry.target.line;
+ if (nextLine > line) {
+ for (int i = line; i < nextLine; ++i) {
+ buff.write(';');
+ }
+ line = nextLine;
+ column = 0;
+ first = true;
+ }
+
+ if (!first) buff.write(',');
+ first = false;
+ column = _append(buff, column, entry.target.column);
+
+ if (entry.source == null) continue;
+
+ srcUrlId = _append(buff, srcUrlId,
+ _indexOf(_urls, entry.source.sourceUrl));
+ srcLine = _append(buff, srcLine, entry.source.line);
+ srcColumn = _append(buff, srcColumn, entry.source.column);
+
+ if (entry.identifierName == null) continue;
+ srcNameId = _append(buff, srcNameId,
+ _indexOf(_names, entry.identifierName));
+ }
+
+ var result = {
+ 'version': 3,
+ 'sourceRoot': '',
+ 'sources': _urls.keys.toList(),
+ 'names' : _names.keys.toList(),
+ 'mappings' : buff.toString()
+ };
+ if (fileUrl != null) {
+ result['file'] = fileUrl;
+ }
+ return result;
+ }
+
+ /// Encodes all mappings added to this builder as a json string.
+ String toJson(String fileUrl) => json.stringify(build(fileUrl));
+
+ /// Get the index of [value] in [map], or create one if it doesn't exist.
+ int _indexOf(Map<String, int> map, String value) {
+ return map.putIfAbsent(value, () {
+ int index = map.length;
+ map[value] = index;
+ return index;
+ });
+ }
+
+ /// Appends to [buff] a VLQ encoding of [newValue] using the difference
+ /// between [oldValue] and [newValue]
+ static int _append(StringBuffer buff, int oldValue, int newValue) {
+ buff.writeAll(encodeVlq(newValue - oldValue));
+ return newValue;
+ }
+}
+
+/// An entry in the source map builder.
+class Entry implements Comparable {
+ /// Span denoting the original location in the input source file
+ final Location source;
+
+ /// Span indicating the corresponding location in the target file.
+ final Location target;
+
+ /// An identifier name, when this location is the start of an identifier.
+ final String identifierName;
+
+ Entry(this.source, this.target, this.identifierName);
+
+ /// Implements [Comparable] to ensure that entries are ordered by their
+ /// location in the target file. We sort primarily by the target offset
+ /// because source map files are encoded by printing each mapping in order as
+ /// they appear in the target file.
+ int compareTo(Entry other) {
+ int res = target.compareTo(other.target);
+ if (res != 0) return res;
+ res = source.sourceUrl.compareTo(other.source.sourceUrl);
+ if (res != 0) return res;
+ return source.compareTo(other.source);
+ }
+}
diff --git a/pkg/source_maps/lib/parser.dart b/pkg/source_maps/lib/parser.dart
new file mode 100644
index 0000000..3849913
--- /dev/null
+++ b/pkg/source_maps/lib/parser.dart
@@ -0,0 +1,391 @@
+// 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.
+
+/// Contains the top-level function to parse source maps version 3.
+library source_maps.parser;
+
+import 'dart:json' as json;
+
+import 'span.dart';
+import 'src/utils.dart';
+import 'src/vlq.dart';
+
+/// Parses a source map directly from a json string.
+// TODO(sigmund): evaluate whether other maps should have the json parsed, or
+// the string represenation.
+Mapping parse(String jsonMap, {Map<String, Map> otherMaps}) =>
+ parseJson(json.parse(jsonMap), otherMaps: otherMaps);
+
+/// Parses a source map directly from a json map object.
+Mapping parseJson(Map map, {Map<String, Map> otherMaps}) {
+ if (map['version'] != 3) {
+ throw new ArgumentError(
+ 'unexpected source map version: ${map["version"]}. '
+ 'Only version 3 is supported.');
+ }
+
+ // TODO(sigmund): relax this? dart2js doesn't generate the file entry.
+ if (!map.containsKey('file')) {
+ throw new ArgumentError('missing "file" in source map');
+ }
+
+ if (map.containsKey('sections')) {
+ if (map.containsKey('mappings') || map.containsKey('sources') ||
+ map.containsKey('names')) {
+ throw new FormatException('map containing "sections" '
+ 'cannot contain "mappings", "sources", or "names".');
+ }
+ return new MultiSectionMapping.fromJson(map['sections'], otherMaps);
+ }
+ return new SingleMapping.fromJson(map);
+}
+
+
+/// A mapping parsed our of a source map.
+abstract class Mapping {
+ Span spanFor(int line, int column, {Map<String, SourceFile> files});
+
+ Span spanForLocation(Location loc, {Map<String, SourceFile> files}) {
+ return spanFor(loc.line, loc.column, files: files);
+ }
+}
+
+/// A meta-level map containing sections.
+class MultiSectionMapping extends Mapping {
+ /// For each section, the start line offset.
+ final List<int> _lineStart = <int>[];
+
+ /// For each section, the start column offset.
+ final List<int> _columnStart = <int>[];
+
+ /// For each section, the actual source map information, which is not adjusted
+ /// for offsets.
+ final List<Mapping> _maps = <Mapping>[];
+
+ /// Creates a section mapping from json.
+ MultiSectionMapping.fromJson(List sections, Map<String, Map> otherMaps) {
+ for (var section in sections) {
+ var offset = section['offset'];
+ if (offset == null) throw new FormatException('section missing offset');
+
+ var line = section['offset']['line'];
+ if (line == null) throw new FormatException('offset missing line');
+
+ var column = section['offset']['column'];
+ if (column == null) throw new FormatException('offset missing column');
+
+ _lineStart.add(line);
+ _columnStart.add(column);
+
+ var url = section['url'];
+ var map = section['map'];
+
+ if (url != null && map != null) {
+ throw new FormatException("section can't use both url and map entries");
+ } else if (url != null) {
+ if (otherMaps == null || otherMaps[url] == null) {
+ throw new FormatException(
+ 'section contains refers to $url, but no map was '
+ 'given for it. Make sure a map is passed in "otherMaps"');
+ }
+ _maps.add(parseJson(otherMaps[url], otherMaps: otherMaps));
+ } else if (map != null) {
+ _maps.add(parseJson(map, otherMaps: otherMaps));
+ } else {
+ throw new FormatException('section missing url or map');
+ }
+ }
+ if (_lineStart.length == 0) {
+ throw new FormatException('expected at least one section');
+ }
+ }
+
+ int _indexFor(line, column) {
+ for(int i = 0; i < _lineStart.length; i++) {
+ if (line < _lineStart[i]) return i - 1;
+ if (line == _lineStart[i] && column < _columnStart[i]) return i - 1;
+ }
+ return _lineStart.length - 1;
+ }
+
+ Span spanFor(int line, int column, {Map<String, SourceFile> files}) {
+ int index = _indexFor(line, column);
+ return _maps[index].spanFor(
+ line - _lineStart[index], column - _columnStart[index], files: files);
+ }
+
+ String toString() {
+ var buff = new StringBuffer("$runtimeType : [");
+ for (int i = 0; i < _lineStart.length; i++) {
+ buff..write('(')
+ ..write(_lineStart[i])
+ ..write(',')
+ ..write(_columnStart[i])
+ ..write(':')
+ ..write(_maps[i])
+ ..write(')');
+ }
+ buff.write(']');
+ return buff.toString();
+ }
+}
+
+/// A map containing direct source mappings.
+// TODO(sigmund): integrate mapping and sourcemap builder?
+class SingleMapping extends Mapping {
+ /// Url of the target file.
+ final String targetUrl;
+
+ /// Source urls used in the mapping, indexed by id.
+ final List<String> urls;
+
+ /// Source names used in the mapping, indexed by id.
+ final List<String> names;
+
+ /// Entries indicating the beginning of each span.
+ final List<TargetLineEntry> lines = <TargetLineEntry>[];
+
+ SingleMapping.fromJson(Map map)
+ : targetUrl = map['file'],
+ // TODO(sigmund): add support for 'sourceRoot'
+ urls = map['sources'],
+ names = map['names'] {
+ int line = 0;
+ int column = 0;
+ int srcUrlId = 0;
+ int srcLine = 0;
+ int srcColumn = 0;
+ int srcNameId = 0;
+ var tokenizer = new _MappingTokenizer(map['mappings']);
+ var entries = <TargetEntry>[];
+
+ while (tokenizer.hasTokens) {
+ if (tokenizer.nextKind.isNewLine) {
+ if (!entries.isEmpty) {
+ lines.add(new TargetLineEntry(line, entries));
+ entries = <TargetEntry>[];
+ }
+ line++;
+ column = 0;
+ tokenizer._consumeNewLine();
+ continue;
+ }
+
+ // Decode the next entry, using the previous encountered values to
+ // decode the relative values.
+ //
+ // We expect 1, 4, or 5 values. If present, values are expected in the
+ // following order:
+ // 0: the starting column in the current line of the generated file
+ // 1: the id of the original source file
+ // 2: the starting line in the original source
+ // 3: the starting column in the original source
+ // 4: the id of the original symbol name
+ // The values are relative to the previous encountered values.
+ if (tokenizer.nextKind.isNewSegment) throw _segmentError(0, line);
+ column += tokenizer._consumeValue();
+ if (!tokenizer.nextKind.isValue) {
+ entries.add(new TargetEntry(column));
+ } else {
+ srcUrlId += tokenizer._consumeValue();
+ if (srcUrlId >= urls.length) {
+ throw new StateError(
+ 'Invalid source url id. $targetUrl, $line, $srcUrlId');
+ }
+ if (!tokenizer.nextKind.isValue) throw _segmentError(2, line);
+ srcLine += tokenizer._consumeValue();
+ if (!tokenizer.nextKind.isValue) throw _segmentError(3, line);
+ srcColumn += tokenizer._consumeValue();
+ if (!tokenizer.nextKind.isValue) {
+ entries.add(new TargetEntry(column, srcUrlId, srcLine, srcColumn));
+ } else {
+ srcNameId += tokenizer._consumeValue();
+ if (srcNameId >= names.length) {
+ throw new StateError(
+ 'Invalid name id: $targetUrl, $line, $srcNameId');
+ }
+ entries.add(
+ new TargetEntry(column, srcUrlId, srcLine, srcColumn, srcNameId));
+ }
+ }
+ if (tokenizer.nextKind.isNewSegment) tokenizer._consumeNewSegment();
+ }
+ if (!entries.isEmpty) {
+ lines.add(new TargetLineEntry(line, entries));
+ }
+ }
+
+ _segmentError(int seen, int line) => new StateError(
+ 'Invalid entry in sourcemap, expected 1, 4, or 5'
+ ' values, but got $seen.\ntargeturl: $targetUrl, line: $line');
+
+ /// Returns [TargetLineEntry] which includes the location in the target [line]
+ /// number. In particular, the resulting entry is the last entry whose line
+ /// number is lower or equal to [line].
+ TargetLineEntry _findLine(int line) {
+ int index = binarySearch(lines, (e) => e.line > line);
+ return (index <= 0) ? null : lines[index - 1];
+ }
+
+ /// Returns [TargetEntry] which includes the location denoted by
+ /// [line], [column]. If [lineEntry] corresponds to [line], then this will be
+ /// the last entry whose column is lower or equal than [column]. If
+ /// [lineEntry] corresponds to a line prior to [line], then the result will be
+ /// the very last entry on that line.
+ TargetEntry _findColumn(int line, int column, TargetLineEntry lineEntry) {
+ if (lineEntry == null || lineEntry.entries.length == 0) return null;
+ if (lineEntry.line != line) return lineEntry.entries.last;
+ var entries = lineEntry.entries;
+ int index = binarySearch(entries, (e) => e.column > column);
+ return (index <= 0) ? null : entries[index - 1];
+ }
+
+ Span spanFor(int line, int column, {Map<String, SourceFile> files}) {
+ var lineEntry = _findLine(line);
+ var entry = _findColumn(line, column, _findLine(line));
+ if (entry == null) return null;
+ var url = urls[entry.sourceUrlId];
+ if (files != null && files[url] != null) {
+ var file = files[url];
+ var start = file.getOffset(entry.sourceLine, entry.sourceColumn);
+ if (entry.sourceNameId != null) {
+ var text = names[entry.sourceNameId];
+ return new FileSpan(files[url], start, start + text.length, true);
+ } else {
+ return new FileSpan(files[url], start);
+ }
+ } else {
+ // Offset and other context is not available.
+ if (entry.sourceNameId != null) {
+ return new FixedSpan(url, 0, entry.sourceLine, entry.sourceColumn,
+ text: names[entry.sourceNameId], isIdentifier: true);
+ } else {
+ return new FixedSpan(url, 0, entry.sourceLine, entry.sourceColumn);
+ }
+ }
+ }
+
+ String toString() {
+ return (new StringBuffer("$runtimeType : [")
+ ..write('targetUrl: ')
+ ..write(targetUrl)
+ ..write(', urls: ')
+ ..write(urls)
+ ..write(', names: ')
+ ..write(names)
+ ..write(', lines: ')
+ ..write(lines)
+ ..write(']')).toString();
+ }
+
+ String get debugString {
+ var buff = new StringBuffer();
+ for (var lineEntry in lines) {
+ var line = lineEntry.line;
+ for (var entry in lineEntry.entries) {
+ buff..write(targetUrl)
+ ..write(': ')
+ ..write(line)
+ ..write(':')
+ ..write(entry.column)
+ ..write(' --> ')
+ ..write(urls[entry.sourceUrlId])
+ ..write(': ')
+ ..write(entry.sourceLine)
+ ..write(':')
+ ..write(entry.sourceColumn);
+ if (entry.sourceNameId != null) {
+ buff..write(' (')
+ ..write(names[entry.sourceNameId])
+ ..write(')');
+ }
+ buff.write('\n');
+ }
+ }
+ return buff.toString();
+ }
+}
+
+/// A line entry read from a source map.
+class TargetLineEntry {
+ final int line;
+ List<TargetEntry> entries = <TargetEntry>[];
+ TargetLineEntry(this.line, this.entries);
+
+ String toString() => '$runtimeType: $line $entries';
+}
+
+/// A target segment entry read from a source map
+class TargetEntry {
+ final int column;
+ final int sourceUrlId;
+ final int sourceLine;
+ final int sourceColumn;
+ final int sourceNameId;
+ TargetEntry(this.column, [this.sourceUrlId, this.sourceLine,
+ this.sourceColumn, this.sourceNameId]);
+
+ String toString() => '$runtimeType: '
+ '($column, $sourceUrlId, $sourceLine, $sourceColumn, $sourceNameId)';
+}
+
+/** A character iterator over a string that can peek one character ahead. */
+class _MappingTokenizer implements Iterator<String> {
+ final String _internal;
+ final int _length;
+ int index = -1;
+ _MappingTokenizer(String internal)
+ : _internal = internal,
+ _length = internal.length;
+
+ // Iterator API is used by decodeVlq to consume VLQ entries.
+ bool moveNext() => ++index < _length;
+ String get current =>
+ (index >= 0 && index < _length) ? _internal[index] : null;
+
+ bool get hasTokens => index < _length - 1 && _length > 0;
+
+ _TokenKind get nextKind {
+ if (!hasTokens) return _TokenKind.EOF;
+ var next = _internal[index + 1];
+ if (next == ';') return _TokenKind.LINE;
+ if (next == ',') return _TokenKind.SEGMENT;
+ return _TokenKind.VALUE;
+ }
+
+ int _consumeValue() => decodeVlq(this);
+ void _consumeNewLine() { ++index; }
+ void _consumeNewSegment() { ++index; }
+
+ // Print the state of the iterator, with colors indicating the current
+ // position.
+ String toString() {
+ var buff = new StringBuffer();
+ for (int i = 0; i < index; i++) {
+ buff.write(_internal[i]);
+ }
+ buff.write('[31m');
+ buff.write(current == null ? '' : current);
+ buff.write('[0m');
+ for (int i = index + 1; i < _internal.length; i++) {
+ buff.write(_internal[i]);
+ }
+ buff.write(' ($index)');
+ return buff.toString();
+ }
+}
+
+class _TokenKind {
+ static const _TokenKind LINE = const _TokenKind(isNewLine: true);
+ static const _TokenKind SEGMENT = const _TokenKind(isNewSegment: true);
+ static const _TokenKind EOF = const _TokenKind(isEof: true);
+ static const _TokenKind VALUE = const _TokenKind();
+ final bool isNewLine;
+ final bool isNewSegment;
+ final bool isEof;
+ bool get isValue => !isNewLine && !isNewSegment && !isEof;
+
+ const _TokenKind(
+ {this.isNewLine: false, this.isNewSegment: false, this.isEof: false});
+}
diff --git a/pkg/source_maps/lib/printer.dart b/pkg/source_maps/lib/printer.dart
new file mode 100644
index 0000000..333aadc
--- /dev/null
+++ b/pkg/source_maps/lib/printer.dart
@@ -0,0 +1,89 @@
+// 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.
+
+/// Contains a code printer that generates code by recording the source maps.
+library source_maps.printer;
+
+import 'dart:utf' show stringToCodepoints;
+import 'builder.dart';
+import 'span.dart';
+
+const int _LF = 10;
+const int _CR = 13;
+
+/// A printer that keeps track of offset locations and records source maps
+/// locations.
+class Printer {
+ final String filename;
+ final StringBuffer _buff = new StringBuffer();
+ final SourceMapBuilder _maps = new SourceMapBuilder();
+ String get text => _buff.toString();
+ String get map => _maps.toJson(filename);
+
+ /// Current source location mapping.
+ Location _loc;
+
+ /// Current line in the buffer;
+ int _line = 0;
+
+ /// Current column in the buffer.
+ int _column = 0;
+
+ Printer(this.filename);
+
+ /// Add [str] contents to the output, tracking new lines to track correct
+ /// positions for span locations. When [projectMarks] is true, this method
+ /// adds a source map location on each new line, projecting that every new
+ /// line in the target file (printed here) corresponds to a new line in the
+ /// source file.
+ void add(String str, {projectMarks: false}) {
+ var chars = stringToCodepoints(str);
+ var length = chars.length;
+ for (int i = 0; i < length; i++) {
+ var c = chars[i];
+ if (c == _LF || (c == _CR && (i + 1 == length || chars[i + 1] != _LF))) {
+ // Return not followed by line-feed is treated as a new line.
+ _line++;
+ _column = 0;
+ if (projectMarks && _loc != null) {
+ if (_loc is FixedLocation) {
+ mark(new FixedLocation(0, _loc.sourceUrl, _loc.line + 1, 0));
+ } else if (_loc is FileLocation) {
+ var file = (_loc as FileLocation).file;
+ mark(new FileLocation(file, file.getOffset(_loc.line + 1, 0)));
+ }
+ }
+ } else {
+ _column++;
+ }
+ }
+ _buff.write(str);
+ }
+
+
+ /// Append a [total] number of spaces in the target file. Typically used for
+ /// formatting indentation.
+ void addSpaces(int total) {
+ for (int i = 0; i < total; i++) _buff.write(' ');
+ _column += total;
+ }
+
+ /// Marks that the current point in the target file corresponds to the [mark]
+ /// in the source file, which can be either a [Location] or a [Span]. When the
+ /// mark is an identifier's Span, this also records the name of the identifier
+ /// in the source map information.
+ void mark(mark) {
+ var loc;
+ var identifier = null;
+ if (mark is Location) {
+ loc = mark;
+ } else if (mark is Span) {
+ loc = mark.start;
+ if (mark.isIdentifier) identifier = mark.text;
+ }
+ _maps.addLocation(loc,
+ new FixedLocation(_buff.length, null, _line, _column), identifier);
+ _loc = loc;
+ }
+}
diff --git a/pkg/source_maps/lib/source_maps.dart b/pkg/source_maps/lib/source_maps.dart
new file mode 100644
index 0000000..4e24dea
--- /dev/null
+++ b/pkg/source_maps/lib/source_maps.dart
@@ -0,0 +1,25 @@
+// 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.
+
+/// Source maps library.
+///
+/// Create a source map using [SourceMapBuilder]. For example:
+/// var json = (new SourceMapBuilder()
+/// ..add(inputSpan1, outputSpan1)
+/// ..add(inputSpan2, outputSpan2)
+/// ..add(inputSpan3, outputSpan3)
+/// .toJson(outputFile);
+///
+/// Use the [Span] and [SourceFile] classes to specify span locations.
+///
+/// Parse a source map using [parse], and call `spanFor` on the returned mapping
+/// object. For example:
+/// var mapping = parse(json);
+/// mapping.spanFor(outputSpan1.line, outputSpan1.column)
+library source_maps;
+
+export "builder.dart";
+export "parser.dart";
+export "printer.dart";
+export "span.dart";
diff --git a/pkg/source_maps/lib/span.dart b/pkg/source_maps/lib/span.dart
new file mode 100644
index 0000000..1982994
--- /dev/null
+++ b/pkg/source_maps/lib/span.dart
@@ -0,0 +1,330 @@
+// 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.
+
+/// Dart classes representing the souce spans and source files.
+library source_maps.span;
+
+import 'dart:utf' show stringToCodepoints, codepointsToString;
+import 'dart:math' show min;
+
+import 'src/utils.dart';
+
+/// A simple class that describe a segment of source text.
+abstract class Span implements Comparable {
+ /// The start location of this span.
+ final Location start;
+
+ /// The end location of this span, exclusive.
+ final Location end;
+
+ /// Url of the source (typically a file) containing this span.
+ String get sourceUrl => start.sourceUrl;
+
+ /// The length of this span, in characters.
+ int get length => end.offset - start.offset;
+
+ /// The source text for this span, if available.
+ String get text;
+
+ /// Whether [text] corresponds to an identifier symbol.
+ final bool isIdentifier;
+
+ Span(this.start, this.end, bool isIdentifier)
+ : isIdentifier = isIdentifier != null ? isIdentifier : false {
+ _checkRange();
+ }
+
+ /// Creates a new span that is the union of two existing spans [start] and
+ /// [end]. Note that the resulting span might contain some positions that were
+ /// not in either of the original spans if [start] and [end] are disjoint.
+ Span.union(Span start, Span end)
+ : start = start.start, end = end.end, isIdentifier = false {
+ _checkRange();
+ }
+
+ void _checkRange() {
+ if (start.offset < 0) throw new ArgumentError('start $start must be >= 0');
+ if (end.offset < start.offset) {
+ throw new ArgumentError('end $end must be >= start $start');
+ }
+ }
+
+ /// Compares two spans. If the spans are not in the same source, this method
+ /// generates an error.
+ int compareTo(Span other) {
+ int d = start.compareTo(other.start);
+ return d == 0 ? end.compareTo(other.end) : d;
+ }
+
+ /// Gets the location in standard printed form `filename:line:column`, where
+ /// line and column are adjusted by 1 to match the convention in editors.
+ String get formatLocation => start.formatString;
+
+ String getLocationMessage(String message,
+ {bool useColors: false, String color}) {
+ return '$formatLocation: $message';
+ }
+
+ bool operator ==(Span other) =>
+ sourceUrl == other.sourceUrl && start == other.start && end == other.end;
+
+ String toString() => '<$runtimeType: $start $end $formatLocation $text>';
+}
+
+/// A location in the source text
+abstract class Location implements Comparable {
+ /// Url of the source containing this span.
+ String get sourceUrl;
+
+ /// The offset of this location, 0-based.
+ final int offset;
+
+ /// The 0-based line in the source of this location.
+ int get line;
+
+ /// The 0-based column in the source of this location.
+ int get column;
+
+ Location(this.offset);
+
+ /// Compares two locations. If the locations are not in the same source, this
+ /// method generates an error.
+ int compareTo(Location other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw new ArgumentError('can only compare locations of the same source');
+ }
+ return offset - other.offset;
+ }
+
+ String toString() => '(Location $offset)';
+ String get formatString => '$sourceUrl:${line + 1}:${column + 1}';
+}
+
+/// Implementation of [Location] with fixed values given at allocation time.
+class FixedLocation extends Location {
+ final String sourceUrl;
+ final int line;
+ final int column;
+
+ FixedLocation(int offset, this.sourceUrl, this.line, this.column)
+ : super(offset);
+}
+
+/// Implementation of [Span] where all the values are given at allocation time.
+class FixedSpan extends Span {
+ /// The source text for this span, if available.
+ final String text;
+
+ /// Creates a span which starts and end in the same line.
+ FixedSpan(String sourceUrl, int start, int line, int column,
+ {String text: '', bool isIdentifier: false})
+ : text = text, super(new FixedLocation(start, sourceUrl, line, column),
+ new FixedLocation(start + text.length, sourceUrl, line,
+ column + text.length),
+ isIdentifier);
+}
+
+/// [Location] with values computed from an underling [SourceFile].
+class FileLocation extends Location {
+ /// The source file containing this location.
+ final SourceFile file;
+
+ String get sourceUrl => file.url;
+ int get line => file.getLine(offset);
+ int get column => file.getColumn(line, offset);
+
+ FileLocation(this.file, int offset): super(offset);
+}
+
+/// [Span] where values are computed from an underling [SourceFile].
+class FileSpan extends Span {
+ /// The source file containing this span.
+ final SourceFile file;
+
+ /// The source text for this span, if available.
+ String get text => file.getText(start.offset, end.offset);
+
+ factory FileSpan(SourceFile file, int start,
+ [int end, bool isIdentifier = false]) {
+ var startLoc = new FileLocation(file, start);
+ var endLoc = end == null ? startLoc : new FileLocation(file, end);
+ return new FileSpan.locations(startLoc, endLoc, isIdentifier);
+ }
+
+ FileSpan.locations(FileLocation start, FileLocation end,
+ bool isIdentifier)
+ : file = start.file, super(start, end, isIdentifier);
+
+ /// Creates a new span that is the union of two existing spans [start] and
+ /// [end]. Note that the resulting span might contain some positions that were
+ /// not in either of the original spans if [start] and [end] are disjoint.
+ FileSpan.union(FileSpan start, FileSpan end)
+ : file = start.file, super.union(start, end) {
+ if (start.file != end.file) {
+ throw new ArgumentError('start and end must be from the same file');
+ }
+ }
+
+ String getLocationMessage(String message,
+ {bool useColors: false, String color}) {
+ return file.getLocationMessage(message, start.offset, end.offset,
+ useColors: useColors, color: color);
+ }
+}
+
+// Constants to determine end-of-lines.
+const int _LF = 10;
+const int _CR = 13;
+
+// Color constants used for generating messages.
+const String _RED_COLOR = '\u001b[31m';
+const String _NO_COLOR = '\u001b[0m';
+
+/// Stores information about a source file, to permit computation of the line
+/// and column. Also contains a nice default error message highlighting the code
+/// location.
+class SourceFile {
+ /// Url where the source file is located.
+ final String url;
+ final List<int> _lineStarts;
+ final List<int> _decodedChars;
+
+ SourceFile(this.url, this._lineStarts, this._decodedChars);
+
+ SourceFile.text(this.url, String text)
+ : _lineStarts = <int>[0],
+ _decodedChars = stringToCodepoints(text) {
+ for (int i = 0; i < _decodedChars.length; i++) {
+ var c = _decodedChars[i];
+ if (c == _CR) {
+ // Return not followed by newline is treated as a newline
+ int j = i + 1;
+ if (j >= _decodedChars.length || _decodedChars[j] != _LF) {
+ c = _LF;
+ }
+ }
+ if (c == _LF) _lineStarts.add(i + 1);
+ }
+ }
+
+ /// Returns a span in this [SourceFile] with the given offsets.
+ Span span(int start, [int end, bool isIdentifier = false]) =>
+ new FileSpan(this, start, end, isIdentifier);
+
+ /// Returns a location in this [SourceFile] with the given offset.
+ Location location(int offset) => new FileLocation(this, offset);
+
+ /// Gets the 0-based line corresponding to an offset.
+ int getLine(int offset) {
+ return binarySearch(_lineStarts, (o) => o > offset) - 1;
+ }
+
+ /// Gets the 0-based column corresponding to an offset.
+ int getColumn(int line, int offset) {
+ return offset - _lineStarts[line];
+ }
+
+ /// Get the offset for a given line and column
+ int getOffset(int line, int column) {
+ return _lineStarts[min(line, _lineStarts.length - 1)] + column;
+ }
+
+ /// Gets the text at the given offsets.
+ String getText(int start, [int end]) {
+ return codepointsToString(_decodedChars.sublist(start, end));
+ }
+
+ /// Create a pretty string representation from a span.
+ String getLocationMessage(String message, int start, int end,
+ {bool useColors: false, String color}) {
+ // TODO(jmesserly): it would be more useful to pass in an object that
+ // controls how the errors are printed. This method is a bit too smart.
+ var line = getLine(start);
+ var column = getColumn(line, start);
+
+ var src = url == null ? '' : url;
+ var msg = '$src:${line + 1}:${column + 1}: $message';
+
+ if (_decodedChars == null) {
+ // We don't have any text to include, so exit.
+ return msg;
+ }
+
+ var buf = new StringBuffer(msg);
+ buf.write('\n');
+ var textLine;
+
+ // +1 for 0-indexing, +1 again to avoid the last line
+ if ((line + 2) < _lineStarts.length) {
+ textLine = getText(_lineStarts[line], _lineStarts[line + 1]);
+ } else {
+ textLine = getText(_lineStarts[line]);
+ textLine = '$textLine\n';
+ }
+
+ int toColumn = min(column + end - start, textLine.length);
+ if (useColors) {
+ if (color == null) {
+ color = _RED_COLOR;
+ }
+ buf.write(textLine.substring(0, column));
+ buf.write(color);
+ buf.write(textLine.substring(column, toColumn));
+ buf.write(_NO_COLOR);
+ buf.write(textLine.substring(toColumn));
+ } else {
+ buf.write(textLine);
+ }
+
+ int i = 0;
+ for (; i < column; i++) {
+ buf.write(' ');
+ }
+
+ if (useColors) buf.write(color);
+ for (; i < toColumn; i++) {
+ buf.write('^');
+ }
+ if (useColors) buf.write(_NO_COLOR);
+ return buf.toString();
+ }
+}
+
+/// A convenience type to treat a code segment as if it were a separate
+/// [SourceFile]. A [SourceFileSegment] shifts all locations by an offset, which
+/// allows you to set source-map locations based on the locations relative to
+/// the start of the segment, but that get translated to absolute locations in
+/// the original source file.
+class SourceFileSegment extends SourceFile {
+ final int _baseOffset;
+ final int _baseLine;
+ final int _baseColumn;
+
+ SourceFileSegment(String url, String textSegment, Location startOffset)
+ : _baseOffset = startOffset.offset,
+ _baseLine = startOffset.line,
+ _baseColumn = startOffset.column,
+ super.text(url, textSegment);
+
+ Span span(int start, [int end, bool isIdentifier = false]) =>
+ super.span(start + _baseOffset,
+ end == null ? null : end + _baseOffset, isIdentifier);
+
+ Location location(int offset) => super.location(offset + _baseOffset);
+
+ int getLine(int offset) =>
+ super.getLine(offset - _baseOffset) + _baseLine;
+
+ int getColumn(int line, int offset) {
+ var col = super.getColumn(line - _baseLine, offset - _baseOffset);
+ return line == _baseLine ? col + _baseColumn : col;
+ }
+
+ int getOffset(int line, int column) =>
+ super.getOffset(line - _baseLine,
+ line == _baseLine ? column - _baseColumn : column) + _baseOffset;
+
+ String getText(int start, [int end]) =>
+ super.getText(start - _baseOffset, end - _baseOffset);
+}
diff --git a/pkg/source_maps/lib/src/utils.dart b/pkg/source_maps/lib/src/utils.dart
new file mode 100644
index 0000000..78f098e
--- /dev/null
+++ b/pkg/source_maps/lib/src/utils.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.
+
+/// Utilities that shouldn't be in this package.
+library source_maps.utils;
+
+/// Find the first entry in a sorted [list] that matches a monotonic predicate.
+/// Given a result `n`, that all items before `n` will not match, `n` matches,
+/// and all items after `n` match too. The result is -1 when there are no
+/// items, 0 when all items match, and list.length when none does.
+// TODO(sigmund): remove this function after dartbug.com/5624 is fixed.
+int binarySearch(List list, bool matches(item)) {
+ if (list.length == 0) return -1;
+ if (matches(list.first)) return 0;
+ if (!matches(list.last)) return list.length;
+
+ int min = 0;
+ int max = list.length - 1;
+ while (min < max) {
+ var half = min + ((max - min) ~/ 2);
+ if (matches(list[half])) {
+ max = half;
+ } else {
+ min = half + 1;
+ }
+ }
+ return max;
+}
diff --git a/pkg/source_maps/lib/src/vlq.dart b/pkg/source_maps/lib/src/vlq.dart
new file mode 100644
index 0000000..e4ab4eb
--- /dev/null
+++ b/pkg/source_maps/lib/src/vlq.dart
@@ -0,0 +1,103 @@
+// 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.
+
+
+/// Utilities to encode and decode VLQ values used in source maps.
+///
+/// Sourcemaps are encoded with variable length numbers as base64 encoded
+/// strings with the least significant digit coming first. Each base64 digit
+/// encodes a 5-bit value (0-31) and a continuation bit. Signed values can be
+/// represented by using the least significant bit of the value as the sign bit.
+///
+/// For more details see the source map [version 3 documentation][spec].
+/// [spec]: https://docs.google.com/a/google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
+library source_maps.src.vlq;
+
+import 'dart:math';
+
+const int VLQ_BASE_SHIFT = 5;
+
+const int VLQ_BASE_MASK = (1 << 5) - 1;
+
+const int VLQ_CONTINUATION_BIT = 1 << 5;
+
+const int VLQ_CONTINUATION_MASK = 1 << 5;
+
+const String BASE64_DIGITS =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+final Map<String, int> _digits = () {
+ var map = <String, int>{};
+ for (int i = 0; i < 64; i++) {
+ map[BASE64_DIGITS[i]] = i;
+ }
+ return map;
+}();
+
+final int MAX_INT32 = pow(2, 31) - 1;
+final int MIN_INT32 = -pow(2, 31);
+
+/// Creates the VLQ encoding of [value] as a sequence of characters
+Iterable<String> encodeVlq(int value) {
+ if (value < MIN_INT32 || value > MAX_INT32) {
+ throw new ArgumentError('expected 32 bit int, got: $value');
+ }
+ var res = <String>[];
+ int signBit = 0;
+ if (value < 0) {
+ signBit = 1;
+ value = -value;
+ }
+ value = (value << 1) | signBit;
+ do {
+ int digit = value & VLQ_BASE_MASK;
+ value >>= VLQ_BASE_SHIFT;
+ if (value > 0) {
+ digit |= VLQ_CONTINUATION_BIT;
+ }
+ res.add(BASE64_DIGITS[digit]);
+ } while (value > 0);
+ return res;
+}
+
+/// Decodes a value written as a sequence of VLQ characters. The first input
+/// character will be `chars.current` after calling `chars.moveNext` once. The
+/// iterator is advanced until a stop character is found (a character without
+/// the [VLQ_CONTINUATION_BIT]).
+int decodeVlq(Iterator<String> chars) {
+ int result = 0;
+ bool stop = false;
+ int shift = 0;
+ while (!stop) {
+ if (!chars.moveNext()) throw new StateError('incomplete VLQ value');
+ var char = chars.current;
+ if (!_digits.containsKey(char)) {
+ throw new FormatException('invalid character in VLQ encoding: $char');
+ }
+ var digit = _digits[char];
+ stop = (digit & VLQ_CONTINUATION_BIT) == 0;
+ digit &= VLQ_BASE_MASK;
+ result += (digit << shift);
+ shift += VLQ_BASE_SHIFT;
+ }
+
+ // Result uses the least significant bit as a sign bit. We convert it into a
+ // two-complement value. For example,
+ // 2 (10 binary) becomes 1
+ // 3 (11 binary) becomes -1
+ // 4 (100 binary) becomes 2
+ // 5 (101 binary) becomes -2
+ // 6 (110 binary) becomes 3
+ // 7 (111 binary) becomes -3
+ bool negate = (result & 1) == 1;
+ result = result >> 1;
+ result = negate ? -result : result;
+
+ // TODO(sigmund): can we detect this earlier?
+ if (result < MIN_INT32 || result > MAX_INT32) {
+ throw new FormatException(
+ 'expected an encoded 32 bit int, but we got: $result');
+ }
+ return result;
+}
diff --git a/pkg/source_maps/pubspec.yaml b/pkg/source_maps/pubspec.yaml
new file mode 100644
index 0000000..a559b58
--- /dev/null
+++ b/pkg/source_maps/pubspec.yaml
@@ -0,0 +1,6 @@
+name: source_maps
+author: "Dart Team <misc@dartlang.org>"
+homepage: https://github.com/dart-lang/source-maps
+description: Library to programmatically manipulate source map files.
+dev_dependencies:
+ unittest: any
diff --git a/pkg/source_maps/test/builder_test.dart b/pkg/source_maps/test/builder_test.dart
new file mode 100644
index 0000000..7bf2ee4
--- /dev/null
+++ b/pkg/source_maps/test/builder_test.dart
@@ -0,0 +1,32 @@
+// 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 test.source_maps_test;
+
+import 'dart:json' as json;
+import 'package:unittest/unittest.dart';
+import 'package:source_maps/source_maps.dart';
+import 'common.dart';
+
+main() {
+ test('builder - with span', () {
+ var map = (new SourceMapBuilder()
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputExpr, outputExpr))
+ .build(output.url);
+ expect(map, equals(EXPECTED_MAP));
+ });
+
+ test('builder - with location', () {
+ var str = (new SourceMapBuilder()
+ ..addLocation(inputVar1.start, outputVar1.start, 'longVar1')
+ ..addLocation(inputFunction.start, outputFunction.start, 'longName')
+ ..addLocation(inputVar2.start, outputVar2.start, 'longVar2')
+ ..addLocation(inputExpr.start, outputExpr.start, null))
+ .toJson(output.url);
+ expect(str, json.stringify(EXPECTED_MAP));
+ });
+}
diff --git a/pkg/source_maps/test/common.dart b/pkg/source_maps/test/common.dart
new file mode 100644
index 0000000..661979b
--- /dev/null
+++ b/pkg/source_maps/test/common.dart
@@ -0,0 +1,97 @@
+// 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.
+
+/// Common input/output used by builder, parser and end2end tests
+library test.common;
+
+import 'package:source_maps/source_maps.dart';
+import 'package:unittest/unittest.dart';
+
+/// Content of the source file
+const String INPUT = '''
+/** this is a comment. */
+int longVar1 = 3;
+
+// this is a comment too
+int longName(int longVar2) {
+ return longVar1 + longVar2;
+}
+''';
+var input = new SourceFile.text('input.dart', INPUT);
+
+/// A span in the input file
+Span ispan(int start, int end, [bool isIdentifier = false]) =>
+ new FileSpan(input, start, end, isIdentifier);
+
+Span inputVar1 = ispan(30, 38, true);
+Span inputFunction = ispan(74, 82, true);
+Span inputVar2 = ispan(87, 95, true);
+Span inputExpr = ispan(108, 127);
+
+/// Content of the target file
+const String OUTPUT = '''
+var x = 3;
+f(y) => x + y;
+''';
+var output = new SourceFile.text('output.dart', OUTPUT);
+
+/// A span in the output file
+Span ospan(int start, int end, [bool isIdentifier = false]) =>
+ new FileSpan(output, start, end, isIdentifier);
+
+Span outputVar1 = ospan(4, 5, true);
+Span outputFunction = ospan(11, 12, true);
+Span outputVar2 = ospan(13, 14, true);
+Span outputExpr = ospan(19, 24);
+
+/// Expected output mapping when recording the following four mappings:
+/// inputVar1 <= outputVar1
+/// inputFunction <= outputFunction
+/// inputVar2 <= outputVar2
+/// inputExpr <= outputExpr
+///
+/// This mapping is stored in the tests so we can independently test the builder
+/// and parser algorithms without relying entirely on end2end tests.
+const Map<String, dynamic> EXPECTED_MAP = const {
+ 'version': 3,
+ 'sourceRoot': '',
+ 'sources': const ['input.dart'],
+ 'names': const ['longVar1','longName','longVar2'],
+ 'mappings': 'IACIA;AAGAC,EAAaC,MACR',
+ 'file': 'output.dart'
+};
+
+check(Span outputSpan, Mapping mapping, Span inputSpan, bool realOffsets) {
+ var line = outputSpan.start.line;
+ var column = outputSpan.start.column;
+ var files = realOffsets ? {'input.dart': input} : null;
+ var span = mapping.spanFor(line, column, files: files);
+ var span2 = mapping.spanForLocation(outputSpan.start, files: files);
+
+ // Both mapping APIs are equivalent.
+ expect(span.start.offset, span2.start.offset);
+ expect(span.start.line, span2.start.line);
+ expect(span.start.column, span2.start.column);
+ expect(span.end.offset, span2.end.offset);
+ expect(span.end.line, span2.end.line);
+ expect(span.end.column, span2.end.column);
+
+ // Mapping matches our input location (modulo using real offsets)
+ expect(span.start.line, inputSpan.start.line);
+ expect(span.start.column, inputSpan.start.column);
+ expect(span.sourceUrl, inputSpan.sourceUrl);
+ expect(span.start.offset, realOffsets ? inputSpan.start.offset : 0);
+
+ // Mapping includes the identifier, if any
+ if (inputSpan.isIdentifier) {
+ expect(span.end.line, inputSpan.end.line);
+ expect(span.end.column, inputSpan.end.column);
+ expect(span.end.offset, span.start.offset + inputSpan.text.length);
+ if (realOffsets) expect(span.end.offset, inputSpan.end.offset);
+ } else {
+ expect(span.end.offset, span.start.offset);
+ expect(span.end.line, span.start.line);
+ expect(span.end.column, span.start.column);
+ }
+}
diff --git a/pkg/source_maps/test/end2end_test.dart b/pkg/source_maps/test/end2end_test.dart
new file mode 100644
index 0000000..5ea958a
--- /dev/null
+++ b/pkg/source_maps/test/end2end_test.dart
@@ -0,0 +1,106 @@
+// 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 test.end2end_test;
+
+import 'package:unittest/unittest.dart';
+import 'package:source_maps/source_maps.dart';
+import 'common.dart';
+
+main() {
+ test('end-to-end setup', () {
+ expect(inputVar1.text, 'longVar1');
+ expect(inputFunction.text, 'longName');
+ expect(inputVar2.text, 'longVar2');
+ expect(inputExpr.text, 'longVar1 + longVar2');
+
+ expect(outputVar1.text, 'x');
+ expect(outputFunction.text, 'f');
+ expect(outputVar2.text, 'y');
+ expect(outputExpr.text, 'x + y');
+ });
+
+ test('build + parse', () {
+ var map = (new SourceMapBuilder()
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputExpr, outputExpr))
+ .build(output.url);
+ var mapping = parseJson(map);
+ check(outputVar1, mapping, inputVar1, false);
+ check(outputVar2, mapping, inputVar2, false);
+ check(outputFunction, mapping, inputFunction, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('build + parse with file', () {
+ var json = (new SourceMapBuilder()
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputExpr, outputExpr))
+ .toJson(output.url);
+ var mapping = parse(json);
+ check(outputVar1, mapping, inputVar1, true);
+ check(outputVar2, mapping, inputVar2, true);
+ check(outputFunction, mapping, inputFunction, true);
+ check(outputExpr, mapping, inputExpr, true);
+ });
+
+ test('printer projecting marks + parse', () {
+ var out = INPUT.replaceAll('long', '_s');
+ var file = new SourceFile.text('output2.dart', out);
+ var printer = new Printer('output2.dart');
+ printer.mark(ispan(0, 0));
+
+ bool first = true;
+ var segments = INPUT.split('long');
+ expect(segments.length, 6);
+ printer.add(segments[0], projectMarks: true);
+ printer.mark(inputVar1);
+ printer.add('_s');
+ printer.add(segments[1], projectMarks: true);
+ printer.mark(inputFunction);
+ printer.add('_s');
+ printer.add(segments[2], projectMarks: true);
+ printer.mark(inputVar2);
+ printer.add('_s');
+ printer.add(segments[3], projectMarks: true);
+ printer.mark(inputExpr);
+ printer.add('_s');
+ printer.add(segments[4], projectMarks: true);
+ printer.add('_s');
+ printer.add(segments[5], projectMarks: true);
+
+ expect(printer.text, out);
+
+ var mapping = parse(printer.map);
+ checkHelper(Span inputSpan, int adjustment) {
+ var start = inputSpan.start.offset - adjustment;
+ var end = (inputSpan.end.offset - adjustment) - 2;
+ var span = new FileSpan(file, start, end, inputSpan.isIdentifier);
+ check(span, mapping, inputSpan, true);
+ }
+
+ checkHelper(inputVar1, 0);
+ checkHelper(inputFunction, 2);
+ checkHelper(inputVar2, 4);
+ checkHelper(inputExpr, 6);
+
+ // We projected correctly lines that have no mappings
+ check(new FileSpan(file, 66, 66, false), mapping, ispan(45, 45), true);
+ check(new FileSpan(file, 63, 64, false), mapping, ispan(45, 45), true);
+ check(new FileSpan(file, 68, 68, false), mapping, ispan(70, 70), true);
+ check(new FileSpan(file, 71, 71, false), mapping, ispan(70, 70), true);
+
+ // Start of the last line
+ var oOffset = out.length - 2;
+ var iOffset = INPUT.length - 2;
+ check(new FileSpan(file, oOffset, oOffset, false), mapping,
+ ispan(iOffset, iOffset), true);
+ check(new FileSpan(file, oOffset + 1, oOffset + 1, false), mapping,
+ ispan(iOffset, iOffset), true);
+ });
+}
diff --git a/pkg/source_maps/test/parser_test.dart b/pkg/source_maps/test/parser_test.dart
new file mode 100644
index 0000000..1c32cbd
--- /dev/null
+++ b/pkg/source_maps/test/parser_test.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.
+
+library test.parser_test;
+
+import 'dart:json' as json;
+import 'package:unittest/unittest.dart';
+import 'package:source_maps/source_maps.dart';
+import 'common.dart';
+
+main() {
+ test('parse', () {
+ var mapping = parseJson(EXPECTED_MAP);
+ check(outputVar1, mapping, inputVar1, false);
+ check(outputVar2, mapping, inputVar2, false);
+ check(outputFunction, mapping, inputFunction, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('parse + json', () {
+ var mapping = parse(json.stringify(EXPECTED_MAP));
+ check(outputVar1, mapping, inputVar1, false);
+ check(outputVar2, mapping, inputVar2, false);
+ check(outputFunction, mapping, inputFunction, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('parse with file', () {
+ var mapping = parseJson(EXPECTED_MAP);
+ check(outputVar1, mapping, inputVar1, true);
+ check(outputVar2, mapping, inputVar2, true);
+ check(outputFunction, mapping, inputFunction, true);
+ check(outputExpr, mapping, inputExpr, true);
+ });
+}
diff --git a/pkg/source_maps/test/printer_test.dart b/pkg/source_maps/test/printer_test.dart
new file mode 100644
index 0000000..d038ad5
--- /dev/null
+++ b/pkg/source_maps/test/printer_test.dart
@@ -0,0 +1,82 @@
+// 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 test.printer_test;
+
+import 'dart:json' as json;
+import 'package:unittest/unittest.dart';
+import 'package:source_maps/printer.dart';
+import 'package:source_maps/span.dart';
+import 'common.dart';
+
+main() {
+ test('printer', () {
+ var printer = new Printer('output.dart');
+ printer..add('var ')
+ ..mark(inputVar1)
+ ..add('x = 3;\n')
+ ..mark(inputFunction)
+ ..add('f(')
+ ..mark(inputVar2)
+ ..add('y) => ')
+ ..mark(inputExpr)
+ ..add('x + y;\n');
+ expect(printer.text, OUTPUT);
+ expect(printer.map, json.stringify(EXPECTED_MAP));
+ });
+
+ test('printer projecting marks', () {
+ var out = INPUT.replaceAll('long', '_s');
+ var printer = new Printer('output2.dart');
+
+ var segments = INPUT.split('long');
+ expect(segments.length, 6);
+ printer..mark(ispan(0, 0))
+ ..add(segments[0], projectMarks: true)
+ ..mark(inputVar1)
+ ..add('_s')
+ ..add(segments[1], projectMarks: true)
+ ..mark(inputFunction)
+ ..add('_s')
+ ..add(segments[2], projectMarks: true)
+ ..mark(inputVar2)
+ ..add('_s')
+ ..add(segments[3], projectMarks: true)
+ ..mark(inputExpr)
+ ..add('_s')
+ ..add(segments[4], projectMarks: true)
+ ..add('_s')
+ ..add(segments[5], projectMarks: true);
+
+ expect(printer.text, out);
+ // 8 new lines in the source map:
+ expect(printer.map.split(';').length, 8);
+
+ asFixed(Span s) => new FixedSpan(s.sourceUrl,
+ s.start.offset, s.start.line, s.start.column,
+ text: s.text, isIdentifier: s.isIdentifier);
+
+ // The result is the same if we use fixed positions
+ var printer2 = new Printer('output2.dart');
+ printer2..mark(new FixedSpan('input.dart', 0, 0, 0))
+ ..add(segments[0], projectMarks: true)
+ ..mark(asFixed(inputVar1))
+ ..add('_s')
+ ..add(segments[1], projectMarks: true)
+ ..mark(asFixed(inputFunction))
+ ..add('_s')
+ ..add(segments[2], projectMarks: true)
+ ..mark(asFixed(inputVar2))
+ ..add('_s')
+ ..add(segments[3], projectMarks: true)
+ ..mark(asFixed(inputExpr))
+ ..add('_s')
+ ..add(segments[4], projectMarks: true)
+ ..add('_s')
+ ..add(segments[5], projectMarks: true);
+
+ expect(printer2.text, out);
+ expect(printer2.map, printer.map);
+ });
+}
diff --git a/pkg/source_maps/test/run.dart b/pkg/source_maps/test/run.dart
new file mode 100755
index 0000000..9a19785
--- /dev/null
+++ b/pkg/source_maps/test/run.dart
@@ -0,0 +1,38 @@
+#!/usr/bin/env dart
+// 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 test.run;
+
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+import 'dart:io' show Options;
+
+import 'builder_test.dart' as builder_test;
+import 'end2end_test.dart' as end2end_test;
+import 'parser_test.dart' as parser_test;
+import 'printer_test.dart' as printer_test;
+import 'span_test.dart' as span_test;
+import 'utils_test.dart' as utils_test;
+import 'vlq_test.dart' as vlq_test;
+
+main() {
+ var args = new Options().arguments;
+ var pattern = new RegExp(args.length > 0 ? args[0] : '.');
+ useCompactVMConfiguration();
+
+ void addGroup(testFile, testMain) {
+ if (pattern.hasMatch(testFile)) {
+ group(testFile.replaceAll('_test.dart', ':'), testMain);
+ }
+ }
+
+ addGroup('builder_test.dart', builder_test.main);
+ addGroup('end2end_test.dart', end2end_test.main);
+ addGroup('parser_test.dart', parser_test.main);
+ addGroup('printer_test.dart', printer_test.main);
+ addGroup('span_test.dart', span_test.main);
+ addGroup('utils_test.dart', utils_test.main);
+ addGroup('vlq_test.dart', vlq_test.main);
+}
diff --git a/pkg/source_maps/test/span_test.dart b/pkg/source_maps/test/span_test.dart
new file mode 100644
index 0000000..8f61b58
--- /dev/null
+++ b/pkg/source_maps/test/span_test.dart
@@ -0,0 +1,215 @@
+// 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 test.span_test;
+
+import 'package:unittest/unittest.dart';
+import 'package:source_maps/span.dart';
+
+const String TEST_FILE = '''
++23456789_
+ + _123456789_123456789_123456789_123456789_123456789_123456789_123456789_
+ + _123456789_1
+123+56789_123456789_1234567
+1234+6789_1234
+12345+789_123456789_12345
+123456+89_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+1234567+9_123456789_123456789_123456789_123456789_123456789_123456789_123
+12345678+_123456789_123456789_123456789_123456789_1
+123456789+123456789_123456789_12345678
+123456789_+23456789_123456789_123456789_123
+123456789_1+3456789_123456789
+''';
+
+List<int> newLines = TEST_FILE.split('\n').map((s) => s.length).toList();
+
+main() {
+ var file = new SourceFile.text('file', TEST_FILE);
+ span(int start, int end) => file.span(start, end);
+ loc(int offset) => file.location(offset);
+
+ test('validate test input', () {
+ expect(newLines,
+ const [10, 80, 31, 27, 14, 25, 79, 73, 51, 38, 43, 29, 0]);
+ });
+
+ test('get line and column', () {
+ line(int n) => file.getLine(n);
+ col(int n) => file.getColumn(file.getLine(n), n);
+
+ expect(line(8), 0);
+ expect(line(10), 0);
+ expect(line(11), 1);
+ expect(line(12), 1);
+ expect(line(91), 1);
+ expect(line(92), 2);
+ expect(line(93), 2);
+ expect(col(11), 0);
+ expect(col(12), 1);
+ expect(col(91), 80);
+ expect(col(92), 0);
+ expect(col(93), 1);
+
+ int j = 0;
+ int lineOffset = 0;
+ for (int i = 0; i < TEST_FILE.length; i++) {
+ if (i > lineOffset + newLines[j]) {
+ lineOffset += newLines[j] + 1;
+ j++;
+ }
+ expect(line(i), j, reason: 'position: $i');
+ expect(col(i), i - lineOffset, reason: 'position: $i');
+ }
+ });
+
+ test('get text', () {
+ // fifth line (including 4 new lines), columns 2 .. 11
+ var line = 10 + 80 + 31 + 27 + 4;
+ expect(file.getText(line + 2, line + 11), '34+6789_1');
+ });
+
+ test('get location message', () {
+ // fifth line (including 4 new lines), columns 2 .. 11
+ var line = 10 + 80 + 31 + 27 + 4;
+ expect(file.getLocationMessage('the message', line + 2, line + 11),
+ 'file:5:3: the message\n'
+ '1234+6789_1234\n'
+ ' ^^^^^^^^^');
+ });
+
+ test('get location message - no file url', () {
+ var line = 10 + 80 + 31 + 27 + 4;
+ expect(new SourceFile.text(null, TEST_FILE).getLocationMessage(
+ 'the message', line + 2, line + 11),
+ ':5:3: the message\n'
+ '1234+6789_1234\n'
+ ' ^^^^^^^^^');
+ });
+
+ test('location getters', () {
+ expect(loc(8).line, 0);
+ expect(loc(8).column, 8);
+ expect(loc(9).line, 0);
+ expect(loc(9).column, 9);
+ expect(loc(8).formatString, 'file:1:9');
+ expect(loc(12).line, 1);
+ expect(loc(12).column, 1);
+ expect(loc(95).line, 2);
+ expect(loc(95).column, 3);
+ });
+
+ test('location compare', () {
+ var list = [9, 8, 11, 14, 6, 6, 1, 1].map((n) => loc(n)).toList();
+ list.sort();
+ var lastOffset = 0;
+ for (var location in list) {
+ expect(location.offset, greaterThanOrEqualTo(lastOffset));
+ lastOffset = location.offset;
+ }
+ });
+
+ test('span getters', () {
+ expect(span(8, 9).start.line, 0);
+ expect(span(8, 9).start.column, 8);
+ expect(span(8, 9).end.line, 0);
+ expect(span(8, 9).end.column, 9);
+ expect(span(8, 9).text, '9');
+ expect(span(8, 9).isIdentifier, false);
+ expect(span(8, 9).formatLocation, 'file:1:9');
+
+ var line = 10 + 80 + 31 + 27 + 4;
+ expect(span(line + 2, line + 11).getLocationMessage('the message'),
+ 'file:5:3: the message\n'
+ '1234+6789_1234\n'
+ ' ^^^^^^^^^');
+
+ expect(span(12, 95).start.line, 1);
+ expect(span(12, 95).start.column, 1);
+ expect(span(12, 95).end.line, 2);
+ expect(span(12, 95).end.column, 3);
+ expect(span(12, 95).text,
+ '+ _123456789_123456789_123456789_123456789_123456789_1234567'
+ '89_123456789_\n +');
+ expect(span(12, 95).formatLocation, 'file:2:2');
+ });
+
+ test('span union', () {
+ var union = new FileSpan.union(span(8, 9), span(12, 95));
+ expect(union.start.offset, 8);
+ expect(union.start.line, 0);
+ expect(union.start.column, 8);
+ expect(union.end.offset, 95);
+ expect(union.end.line, 2);
+ expect(union.end.column, 3);
+ expect(union.text,
+ '9_\n'
+ ' + _123456789_123456789_123456789_123456789_123456789_'
+ '123456789_123456789_\n +');
+ expect(union.formatLocation, 'file:1:9');
+ });
+
+ test('span compare', () {
+ var list = [span(9, 10), span(8, 9), span(11, 12), span(14, 19),
+ span(6, 12), span(6, 8), span(1, 9), span(1, 2)];
+ list.sort();
+ var lastStart = 0;
+ var lastEnd = 0;
+ for (var span in list) {
+ expect(span.start.offset, greaterThanOrEqualTo(lastStart));
+ if (span.start.offset == lastStart) {
+ expect(span.end.offset, greaterThanOrEqualTo(lastEnd));
+ }
+ lastStart = span.start.offset;
+ lastEnd = span.end.offset;
+ }
+ });
+
+ test('file segment', () {
+ var segment = new SourceFileSegment('file',
+ TEST_FILE.substring(12), loc(12));
+ sline(int n) => segment.getLine(n);
+ scol(int n) => segment.getColumn(segment.getLine(n), n);
+
+ line(int n) => file.getLine(n);
+ col(int n) => file.getColumn(file.getLine(n), n);
+
+ int j = 0;
+ int lineOffset = 0;
+ for (int i = 12; i < TEST_FILE.length; i++) {
+ if (i > lineOffset + newLines[j]) {
+ lineOffset += newLines[j] + 1;
+ j++;
+ }
+ expect(segment.location(i - 12).offset, i);
+ expect(segment.location(i - 12).line, line(i));
+ expect(segment.location(i - 12).column, col(i));
+ expect(segment.span(i - 12).start.offset, i);
+ expect(segment.span(i - 12).start.line, line(i));
+ expect(segment.span(i - 12).start.column, col(i));
+
+ expect(sline(i), line(i));
+ expect(scol(i), col(i));
+ }
+ });
+
+ test('span isIdentifier defaults to false', () {
+ var start = new TestLocation(0);
+ var end = new TestLocation(1);
+ expect(new TestSpan(start, end).isIdentifier, false);
+ expect(file.span(8, 9, null).isIdentifier, false);
+ expect(new FixedSpan('', 8, 1, 8, isIdentifier: null).isIdentifier, false);
+ });
+}
+
+class TestSpan extends Span {
+ TestSpan(Location start, Location end) : super(start, end, null);
+ get text => null;
+}
+
+class TestLocation extends Location {
+ String get sourceUrl => '';
+ TestLocation(int offset) : super(offset);
+ get line => 0;
+ get column => 0;
+}
diff --git a/pkg/source_maps/test/utils_test.dart b/pkg/source_maps/test/utils_test.dart
new file mode 100644
index 0000000..79a7de7
--- /dev/null
+++ b/pkg/source_maps/test/utils_test.dart
@@ -0,0 +1,54 @@
+// 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.
+
+/// Tests for the binary search utility algorithm.
+library test.utils_test;
+
+import 'package:unittest/unittest.dart';
+import 'package:source_maps/src/utils.dart';
+
+main() {
+ group('binary search', () {
+ test('empty', () {
+ expect(binarySearch([], (x) => true), -1);
+ });
+
+ test('single element', () {
+ expect(binarySearch([1], (x) => true), 0);
+ expect(binarySearch([1], (x) => false), 1);
+ });
+
+ test('no matches', () {
+ var list = [1, 2, 3, 4, 5, 6, 7];
+ expect(binarySearch(list, (x) => false), list.length);
+ });
+
+ test('all match', () {
+ var list = [1, 2, 3, 4, 5, 6, 7];
+ expect(binarySearch(list, (x) => true), 0);
+ });
+
+ test('compare with linear search', () {
+ for (int size = 0; size < 100; size++) {
+ var list = [];
+ for (int i = 0; i < size; i++) {
+ list.add(i);
+ }
+ for (int pos = 0; pos <= size; pos++) {
+ expect(binarySearch(list, (x) => x >= pos),
+ _linearSearch(list, (x) => x >= pos));
+ }
+ }
+ });
+ });
+}
+
+_linearSearch(list, predicate) {
+ if (list.length == 0) return -1;
+ for (int i = 0; i < list.length; i++) {
+ if (predicate(list[i])) return i;
+ }
+ return list.length;
+}
+
diff --git a/pkg/source_maps/test/vlq_test.dart b/pkg/source_maps/test/vlq_test.dart
new file mode 100644
index 0000000..0abdc47
--- /dev/null
+++ b/pkg/source_maps/test/vlq_test.dart
@@ -0,0 +1,59 @@
+// 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 test.vlq_test;
+
+import 'dart:math';
+import 'package:unittest/unittest.dart';
+import 'package:source_maps/src/vlq.dart';
+
+main() {
+ test('encode and decode - simple values', () {
+ expect(encodeVlq(1).join(''), 'C');
+ expect(encodeVlq(2).join(''), 'E');
+ expect(encodeVlq(3).join(''), 'G');
+ expect(encodeVlq(100).join(''), 'oG');
+ expect(decodeVlq('C'.split('').iterator), 1);
+ expect(decodeVlq('E'.split('').iterator), 2);
+ expect(decodeVlq('G'.split('').iterator), 3);
+ expect(decodeVlq('oG'.split('').iterator), 100);
+ });
+
+ test('encode and decode', () {
+ for (int i = -10000; i < 10000; i++) {
+ _checkEncodeDecode(i);
+ }
+ });
+
+ test('only 32-bit ints allowed', () {
+ var max_int = pow(2, 31) - 1;
+ var min_int = -pow(2, 31);
+ _checkEncodeDecode(max_int - 1);
+ _checkEncodeDecode(min_int + 1);
+ _checkEncodeDecode(max_int);
+ _checkEncodeDecode(min_int);
+
+ expect(encodeVlq(min_int).join(''), 'hgggggE');
+ expect(decodeVlq('hgggggE'.split('').iterator), min_int);
+
+ expect(() => encodeVlq(max_int + 1), throws);
+ expect(() => encodeVlq(max_int + 2), throws);
+ expect(() => encodeVlq(min_int - 1), throws);
+ expect(() => encodeVlq(min_int - 2), throws);
+
+
+ // if we allowed more than 32 bits, these would be the expected encodings
+ // for the large numbers above.
+ expect(() => decodeVlq('ggggggE'.split('').iterator), throws);
+ expect(() => decodeVlq('igggggE'.split('').iterator), throws);
+ expect(() => decodeVlq('jgggggE'.split('').iterator), throws);
+ expect(() => decodeVlq('lgggggE'.split('').iterator), throws);
+ });
+}
+
+_checkEncodeDecode(int value) {
+ var encoded = encodeVlq(value);
+ expect(decodeVlq(encoded.iterator), value);
+ expect(decodeVlq(encoded.join('').split('').iterator), value);
+}
diff --git a/pkg/unittest/lib/src/test_case.dart b/pkg/unittest/lib/src/test_case.dart
index 7eb835f..f8eb233 100644
--- a/pkg/unittest/lib/src/test_case.dart
+++ b/pkg/unittest/lib/src/test_case.dart
@@ -82,9 +82,8 @@
var f = testFunction();
--_callbackFunctionsOutstanding;
if (f is Future) {
- f.then((_) => _finishTest())
+ return f.then((_) => _finishTest())
.catchError((e) => fail("${e.error}"));
- return f;
} else {
_finishTest();
return null;
diff --git a/pkg/unittest/pubspec.yaml b/pkg/unittest/pubspec.yaml
index 07be11a..f9051e3 100644
--- a/pkg/unittest/pubspec.yaml
+++ b/pkg/unittest/pubspec.yaml
@@ -5,6 +5,5 @@
description: >
A library for writing dart unit tests.
dependencies:
- meta:
- sdk: meta
+ meta: any
diff --git a/pkg/unittest/test/unittest_test.dart b/pkg/unittest/test/unittest_test.dart
index c6ab7a0..e0127bd 100644
--- a/pkg/unittest/test/unittest_test.dart
+++ b/pkg/unittest/test/unittest_test.dart
@@ -19,8 +19,8 @@
var actual; // actual test results (from buildStatusString in config.onDone)
var _testconfig; // test configuration to capture onDone
-_defer(void fn()) {
- return (new Future.immediate(null)).then((_) => guardAsync(fn));
+Future _defer(void fn()) {
+ return new Future.of(fn);
}
String buildStatusString(int passed, int failed, int errors,
@@ -154,80 +154,42 @@
});
} else if (testName == 'async setup/teardown test') {
group('good setup/good teardown', () {
- setUp(() {
- var completer = new Completer();
- _defer(() {
- completer.complete(0);
- });
- return completer.future;
+ setUp(() {
+ return new Future.immediate(0);
});
tearDown(() {
- var completer = new Completer();
- _defer(() {
- completer.complete(0);
- });
- return completer.future;
+ return new Future.immediate(0);
});
test('foo1', (){});
});
group('good setup/bad teardown', () {
- setUp(() {
- var completer = new Completer();
- _defer(() {
- completer.complete(0);
- });
- return completer.future;
+ setUp(() {
+ return new Future.immediate(0);
});
tearDown(() {
- var completer = new Completer();
- _defer(() {
- //throw "Failed to complete tearDown";
- completer.completeError(
- new AsyncError("Failed to complete tearDown"));
- });
- return completer.future;
+ return new Future.immediateError("Failed to complete tearDown");
});
test('foo2', (){});
});
group('bad setup/good teardown', () {
- setUp(() {
- var completer = new Completer();
- _defer(() {
- //throw "Failed to complete setUp";
- completer.completeError(new AsyncError("Failed to complete setUp"));
- });
- return completer.future;
+ setUp(() {
+ return new Future.immediateError("Failed to complete setUp");
});
tearDown(() {
- var completer = new Completer();
- _defer(() {
- completer.complete(0);
- });
- return completer.future;
+ return new Future.immediate(0);
});
test('foo3', (){});
});
group('bad setup/bad teardown', () {
- setUp(() {
- var completer = new Completer();
- _defer(() {
- //throw "Failed to complete setUp";
- completer.completeError(new AsyncError("Failed to complete setUp"));
- });
- return completer.future;
+ setUp(() {
+ return new Future.immediateError("Failed to complete setUp");
});
tearDown(() {
- var completer = new Completer();
- _defer(() {
- //throw "Failed to complete tearDown";
- completer.completeError(
- new AsyncError("Failed to complete tearDown"));
- });
- return completer.future;
+ return new Future.immediateError("Failed to complete tearDown");
});
test('foo4', (){});
});
- // The next test is just to make sure we make steady progress
+ // The next test is just to make sure we make steady progress
// through the tests.
test('post groups', () {});
} else if (testName == 'test returning future') {
@@ -390,7 +352,7 @@
'been marked as pass.:testTwo:'),
buildStatusString(2, 1, 0,
'testOne::testTwo:Expected: false but: was <true>.:testThree'),
- buildStatusString(2, 0, 3,
+ buildStatusString(2, 0, 3,
'good setup/good teardown foo1::'
'good setup/bad teardown foo2:good setup/bad teardown '
'foo2: Test teardown failed: Failed to complete tearDown:'
diff --git a/pkg/yaml/pubspec.yaml b/pkg/yaml/pubspec.yaml
index 7c944d2..4b17267 100644
--- a/pkg/yaml/pubspec.yaml
+++ b/pkg/yaml/pubspec.yaml
@@ -2,6 +2,5 @@
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
description: A parser for YAML.
-dependencies:
- unittest:
- sdk: unittest
+dev_dependencies:
+ unittest: any
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index 0dbc958..33be02e 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -23,7 +23,7 @@
V(Directory_CreateTemp, 1) \
V(Directory_Delete, 2) \
V(Directory_Rename, 2) \
- V(Directory_List, 2) \
+ V(Directory_List, 3) \
V(Directory_NewServicePort, 0) \
V(File_Open, 2) \
V(File_Exists, 1) \
@@ -42,12 +42,14 @@
V(File_Flush, 1) \
V(File_Create, 1) \
V(File_CreateLink, 2) \
+ V(File_LinkTarget, 1) \
V(File_Delete, 1) \
V(File_Directory, 1) \
V(File_FullPath, 1) \
V(File_OpenStdio, 1) \
V(File_GetStdioHandleType, 1) \
V(File_GetType, 2) \
+ V(File_AreIdentical, 2) \
V(File_NewServicePort, 0) \
V(Logger_PrintString, 1)
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 9d2ac70..7dd8534 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -25,6 +25,7 @@
const char* DartUtils::kIdFieldName = "_id";
+uint8_t DartUtils::magic_number[] = { 0xf5, 0xf5, 0xdc, 0xdc };
static bool IsWindowsHost() {
#if defined(TARGET_OS_WINDOWS)
@@ -187,31 +188,46 @@
}
-Dart_Handle DartUtils::ReadStringFromFile(const char* filename) {
+static const uint8_t* ReadFile(const char* filename,
+ intptr_t* file_len,
+ const char** error_msg) {
File* file = File::Open(filename, File::kRead);
if (file == NULL) {
const char* format = "Unable to open file: %s";
intptr_t len = snprintf(NULL, 0, format, filename);
// TODO(iposva): Allocate from the zone instead of leaking error string
// here. On the other hand the binary is about the exit anyway.
- char* error_msg = reinterpret_cast<char*>(malloc(len + 1));
- snprintf(error_msg, len + 1, format, filename);
- return Dart_Error(error_msg);
+ char* msg = reinterpret_cast<char*>(malloc(len + 1));
+ snprintf(msg, len + 1, format, filename);
+ *error_msg = msg;
+ return NULL;
}
- intptr_t len = file->Length();
- uint8_t* text_buffer = reinterpret_cast<uint8_t*>(malloc(len));
+ *file_len = file->Length();
+ uint8_t* text_buffer = reinterpret_cast<uint8_t*>(malloc(*file_len));
if (text_buffer == NULL) {
delete file;
- return Dart_Error("Unable to allocate buffer");
+ *error_msg = "Unable to allocate buffer";
+ return NULL;
}
- if (!file->ReadFully(text_buffer, len)) {
+ if (!file->ReadFully(text_buffer, *file_len)) {
delete file;
free(text_buffer);
- return Dart_Error("Unable to fully read contents");
+ *error_msg = "Unable to fully read contents";
+ return NULL;
}
delete file;
+ return text_buffer;
+}
+
+
+Dart_Handle DartUtils::ReadStringFromFile(const char* filename) {
+ const char* error_msg = NULL;
+ intptr_t len;
+ const uint8_t* text_buffer = ReadFile(filename, &len, &error_msg);
+ if (text_buffer == NULL) {
+ return Dart_Error(error_msg);
+ }
Dart_Handle str = Dart_NewStringFromUTF8(text_buffer, len);
- free(text_buffer);
return str;
}
@@ -325,16 +341,27 @@
}
-static Dart_Handle ReadSource(Dart_Handle script_uri,
- Dart_Handle builtin_lib) {
- Dart_Handle script_path = DartUtils::FilePathFromUri(script_uri, builtin_lib);
- if (Dart_IsError(script_path)) {
- return script_path;
+const uint8_t* DartUtils::SniffForMagicNumber(const uint8_t* text_buffer,
+ intptr_t* buffer_len,
+ bool* is_snapshot) {
+ intptr_t len = sizeof(magic_number);
+ for (intptr_t i = 0; i < len; i++) {
+ if (text_buffer[i] != magic_number[i]) {
+ *is_snapshot = false;
+ return text_buffer;
+ }
}
- const char* script_path_cstr;
- Dart_StringToCString(script_path, &script_path_cstr);
- Dart_Handle source = DartUtils::ReadStringFromFile(script_path_cstr);
- return source;
+ *is_snapshot = true;
+ ASSERT(*buffer_len > len);
+ *buffer_len -= len;
+ return text_buffer + len;
+}
+
+
+void DartUtils::WriteMagicNumber(File* file) {
+ // Write a magic number and version information into the snapshot file.
+ bool bytes_written = file->WriteFully(magic_number, sizeof(magic_number));
+ ASSERT(bytes_written);
}
@@ -345,11 +372,27 @@
if (Dart_IsError(resolved_script_uri)) {
return resolved_script_uri;
}
- Dart_Handle source = ReadSource(resolved_script_uri, builtin_lib);
- if (Dart_IsError(source)) {
- return source;
+ Dart_Handle script_path = DartUtils::FilePathFromUri(resolved_script_uri,
+ builtin_lib);
+ if (Dart_IsError(script_path)) {
+ return script_path;
}
- return Dart_LoadEmbeddedScript(resolved_script_uri, source, 0, 0);
+ const char* script_path_cstr;
+ Dart_StringToCString(script_path, &script_path_cstr);
+ const char* error_msg = NULL;
+ intptr_t len;
+ const uint8_t* text_buffer = ReadFile(script_path_cstr, &len, &error_msg);
+ if (text_buffer == NULL) {
+ return Dart_Error(error_msg);
+ }
+ bool is_snapshot = false;
+ text_buffer = SniffForMagicNumber(text_buffer, &len, &is_snapshot);
+ if (is_snapshot) {
+ return Dart_LoadScriptFromSnapshot(text_buffer, len);
+ } else {
+ Dart_Handle source = Dart_NewStringFromUTF8(text_buffer, len);
+ return Dart_LoadScript(resolved_script_uri, source, 0, 0);
+ }
}
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 35b7866..da7653e 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -10,6 +10,9 @@
#include "include/dart_api.h"
#include "platform/globals.h"
+// Forward declarations.
+class File;
+
/* Handles error handles returned from Dart API functions. If a value
* is an error, uses Dart_PropagateError to throw it to the enclosing
* Dart activation. Otherwise, returns the original handle.
@@ -157,6 +160,18 @@
Dart_Handle url,
Dart_Handle builtin_lib);
+ // Sniffs the specified text_buffer to see if it contains the magic number
+ // representing a script snapshot. If the text_buffer is a script snapshot
+ // the return value is an updated pointer to the text_buffer pointing past
+ // the magic number value. The 'buffer_len' parameter is also appropriately
+ // adjusted.
+ static const uint8_t* SniffForMagicNumber(const uint8_t* text_buffer,
+ intptr_t* buffer_len,
+ bool* is_snapshot);
+
+ // Write a magic number to indicate a script snapshot file.
+ static void WriteMagicNumber(File* file);
+
// Global state that stores the original working directory..
static const char* original_working_directory;
@@ -175,6 +190,8 @@
static const char* kIdFieldName;
+ static uint8_t magic_number[];
+
private:
static const char* GetCanonicalPath(const char* reference_dir,
const char* filename);
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index 1493b2d..c218595 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -117,6 +117,9 @@
Dart_Handle recursive = Dart_GetNativeArgument(args, 1);
// Create the list to hold the directory listing here, and pass it to the
// SyncDirectoryListing object, which adds elements to it.
+ Dart_Handle follow_links = Dart_GetNativeArgument(args, 2);
+ // Create the list to hold the directory listing here, and pass it to the
+ // SyncDirectoryListing object, which adds elements to it.
Dart_Handle results =
Dart_New(DartUtils::GetDartClass(DartUtils::kCoreLibURL, "List"),
Dart_Null(),
@@ -125,6 +128,7 @@
SyncDirectoryListing sync_listing(results);
Directory::List(DartUtils::GetStringValue(path),
DartUtils::GetBooleanValue(recursive),
+ DartUtils::GetBooleanValue(follow_links),
&sync_listing);
Dart_SetReturnValue(args, results);
Dart_ExitScope();
@@ -194,13 +198,17 @@
static CObject* DirectoryListRequest(const CObjectArray& request,
Dart_Port response_port) {
- if (request.Length() == 3 && request[1]->IsString() && request[2]->IsBool()) {
+ if (request.Length() == 4 &&
+ request[1]->IsString() &&
+ request[2]->IsBool() &&
+ request[3]->IsBool()) {
AsyncDirectoryListing* dir_listing =
new AsyncDirectoryListing(response_port);
CObjectString path(request[1]);
CObjectBool recursive(request[2]);
+ CObjectBool follow_links(request[3]);
bool completed = Directory::List(
- path.CString(), recursive.Value(), dir_listing);
+ path.CString(), recursive.Value(), follow_links.Value(), dir_listing);
delete dir_listing;
CObjectArray* response = new CObjectArray(CObject::NewArray(2));
response->SetAt(
@@ -315,6 +323,12 @@
}
+bool AsyncDirectoryListing::HandleLink(char* link_name) {
+ CObjectArray* response = NewResponse(kListLink, link_name);
+ return Dart_PostCObject(response_port_, response->AsApiCObject());
+}
+
+
bool AsyncDirectoryListing::HandleError(const char* dir_name) {
CObject* err = CObject::NewOSError();
CObjectArray* response = new CObjectArray(CObject::NewArray(3));
@@ -332,6 +346,14 @@
return true;
}
+bool SyncDirectoryListing::HandleLink(char* link_name) {
+ Dart_Handle link_name_dart = DartUtils::NewString(link_name);
+ Dart_Handle link =
+ Dart_New(link_class_, Dart_Null(), 1, &link_name_dart);
+ Dart_Invoke(results_, add_string_, 1, &link);
+ return true;
+}
+
bool SyncDirectoryListing::HandleFile(char* file_name) {
Dart_Handle file_name_dart = DartUtils::NewString(file_name);
Dart_Handle file =
diff --git a/runtime/bin/directory.h b/runtime/bin/directory.h
index 87bea9f..331b4c4 100644
--- a/runtime/bin/directory.h
+++ b/runtime/bin/directory.h
@@ -16,6 +16,7 @@
virtual ~DirectoryListing() {}
virtual bool HandleDirectory(char* dir_name) = 0;
virtual bool HandleFile(char* file_name) = 0;
+ virtual bool HandleLink(char* file_name) = 0;
virtual bool HandleError(const char* dir_name) = 0;
};
@@ -25,8 +26,9 @@
enum Response {
kListFile = 0,
kListDirectory = 1,
- kListError = 2,
- kListDone = 3
+ kListLink = 2,
+ kListError = 3,
+ kListDone = 4
};
explicit AsyncDirectoryListing(Dart_Port response_port)
@@ -34,6 +36,7 @@
virtual ~AsyncDirectoryListing() {}
virtual bool HandleDirectory(char* dir_name);
virtual bool HandleFile(char* file_name);
+ virtual bool HandleLink(char* file_name);
virtual bool HandleError(const char* dir_name);
private:
@@ -53,10 +56,13 @@
DartUtils::GetDartClass(DartUtils::kIOLibURL, "Directory");
file_class_ =
DartUtils::GetDartClass(DartUtils::kIOLibURL, "File");
+ link_class_ =
+ DartUtils::GetDartClass(DartUtils::kIOLibURL, "Link");
}
virtual ~SyncDirectoryListing() {}
virtual bool HandleDirectory(char* dir_name);
virtual bool HandleFile(char* file_name);
+ virtual bool HandleLink(char* file_name);
virtual bool HandleError(const char* dir_name);
private:
@@ -64,6 +70,7 @@
Dart_Handle add_string_;
Dart_Handle directory_class_;
Dart_Handle file_class_;
+ Dart_Handle link_class_;
DISALLOW_IMPLICIT_CONSTRUCTORS(SyncDirectoryListing);
};
@@ -90,6 +97,7 @@
static bool List(const char* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing);
static ExistsResult Exists(const char* path);
static char* Current();
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index fd58c81..9a2d166 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -57,6 +57,7 @@
// Forward declarations.
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing);
static bool DeleteRecursively(PathBuffer* path);
@@ -70,14 +71,16 @@
static bool HandleDir(char* dir_name,
PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
if (strcmp(dir_name, ".") == 0) return true;
if (strcmp(dir_name, "..") == 0) return true;
if (!path->Add(dir_name)) {
PostError(listing, path->data);
return false;
+ }
return listing->HandleDirectory(path->data) &&
- (!recursive || ListRecursively(path, recursive, listing));
+ (!recursive || ListRecursively(path, recursive, follow_links, listing));
}
@@ -92,8 +95,20 @@
}
+static bool HandleLink(char* link_name,
+ PathBuffer* path,
+ DirectoryListing *listing) {
+ if (!path->Add(link_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleLink(path->data);
+}
+
+
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
if (!path->Add(File::PathSeparator())) {
PostError(listing, path->data);
@@ -124,6 +139,7 @@
success = HandleDir(entry.d_name,
path,
recursive,
+ follow_links,
listing) && success;
break;
case DT_REG:
@@ -132,6 +148,14 @@
listing) && success;
break;
case DT_LNK:
+ if (!follow_links) {
+ success = HandleLink(entry.d_name,
+ path,
+ listing) && success;
+ break;
+ }
+ // Else fall through to next case.
+ // Fall through.
case DT_UNKNOWN: {
// On some file systems the entry type is not determined by
// readdir_r. For those and for links we use stat to determine
@@ -142,7 +166,12 @@
success = false;
break;
}
- int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+ int stat_success;
+ if (follow_links) {
+ stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+ } else {
+ stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+ }
if (stat_success == -1) {
success = false;
PostError(listing, path->data);
@@ -153,13 +182,18 @@
success = HandleDir(entry.d_name,
path,
recursive,
+ follow_links,
listing) && success;
} else if (S_ISREG(entry_info.st_mode)) {
success = HandleFile(entry.d_name,
path,
listing) && success;
+ } else if (S_ISLNK(entry_info.st_mode)) {
+ ASSERT(!follow_links);
+ success = HandleLink(entry.d_name,
+ path,
+ listing) && success;
}
- ASSERT(!S_ISLNK(entry_info.st_mode));
break;
}
default:
@@ -282,13 +316,14 @@
bool Directory::List(const char* dir_name,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
PathBuffer path;
if (!path.Add(dir_name)) {
PostError(listing, dir_name);
return false;
}
- return ListRecursively(&path, recursive, listing);
+ return ListRecursively(&path, recursive, follow_links, listing);
}
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index 30cc860..f6ad163 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -57,6 +57,7 @@
// Forward declarations.
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing);
static bool DeleteRecursively(PathBuffer* path);
@@ -70,6 +71,7 @@
static bool HandleDir(char* dir_name,
PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
if (strcmp(dir_name, ".") == 0) return true;
if (strcmp(dir_name, "..") == 0) return true;
@@ -78,7 +80,7 @@
return false;
}
return listing->HandleDirectory(path->data) &&
- (!recursive || ListRecursively(path, recursive, listing));
+ (!recursive || ListRecursively(path, recursive, follow_links, listing));
}
@@ -93,8 +95,20 @@
}
+static bool HandleLink(char* link_name,
+ PathBuffer* path,
+ DirectoryListing *listing) {
+ if (!path->Add(link_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleLink(path->data);
+}
+
+
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
if (!path->Add(File::PathSeparator())) {
PostError(listing, path->data);
@@ -125,6 +139,7 @@
success = HandleDir(entry.d_name,
path,
recursive,
+ follow_links,
listing) && success;
break;
case DT_REG:
@@ -133,6 +148,14 @@
listing) && success;
break;
case DT_LNK:
+ if (!follow_links) {
+ success = HandleLink(entry.d_name,
+ path,
+ listing) && success;
+ break;
+ }
+ // Else fall through to next case.
+ // Fall through.
case DT_UNKNOWN: {
// On some file systems the entry type is not determined by
// readdir_r. For those and for links we use stat to determine
@@ -143,7 +166,12 @@
success = false;
break;
}
- int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+ int stat_success;
+ if (follow_links) {
+ stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+ } else {
+ stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+ }
if (stat_success == -1) {
success = false;
PostError(listing, path->data);
@@ -154,13 +182,18 @@
success = HandleDir(entry.d_name,
path,
recursive,
+ follow_links,
listing) && success;
} else if (S_ISREG(entry_info.st_mode)) {
success = HandleFile(entry.d_name,
path,
listing) && success;
+ } else if (S_ISLNK(entry_info.st_mode)) {
+ ASSERT(!follow_links);
+ success = HandleLink(entry.d_name,
+ path,
+ listing) && success;
}
- ASSERT(!S_ISLNK(entry_info.st_mode));
break;
}
default:
@@ -283,13 +316,14 @@
bool Directory::List(const char* dir_name,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
PathBuffer path;
if (!path.Add(dir_name)) {
PostError(listing, dir_name);
return false;
}
- return ListRecursively(&path, recursive, listing);
+ return ListRecursively(&path, recursive, follow_links, listing);
}
diff --git a/runtime/bin/directory_macos.cc b/runtime/bin/directory_macos.cc
index 4685479..d66a809 100644
--- a/runtime/bin/directory_macos.cc
+++ b/runtime/bin/directory_macos.cc
@@ -57,6 +57,7 @@
// Forward declarations.
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing);
static bool DeleteRecursively(PathBuffer* path);
@@ -70,6 +71,7 @@
static bool HandleDir(char* dir_name,
PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
if (strcmp(dir_name, ".") == 0) return true;
if (strcmp(dir_name, "..") == 0) return true;
@@ -78,7 +80,7 @@
return false;
}
return listing->HandleDirectory(path->data) &&
- (!recursive || ListRecursively(path, recursive, listing));
+ (!recursive || ListRecursively(path, recursive, follow_links, listing));
}
@@ -93,8 +95,20 @@
}
+static bool HandleLink(char* link_name,
+ PathBuffer* path,
+ DirectoryListing *listing) {
+ if (!path->Add(link_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleLink(path->data);
+}
+
+
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
if (!path->Add(File::PathSeparator())) {
PostError(listing, path->data);
@@ -125,6 +139,7 @@
success = HandleDir(entry.d_name,
path,
recursive,
+ follow_links,
listing) && success;
break;
case DT_REG:
@@ -133,6 +148,14 @@
listing) && success;
break;
case DT_LNK:
+ if (!follow_links) {
+ success = HandleLink(entry.d_name,
+ path,
+ listing) && success;
+ break;
+ }
+ // Else fall through to next case.
+ // Fall through.
case DT_UNKNOWN: {
// On some file systems the entry type is not determined by
// readdir_r. For those and for links we use stat to determine
@@ -143,7 +166,12 @@
success = false;
break;
}
- int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+ int stat_success;
+ if (follow_links) {
+ stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+ } else {
+ stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+ }
if (stat_success == -1) {
success = false;
PostError(listing, path->data);
@@ -154,13 +182,18 @@
success = HandleDir(entry.d_name,
path,
recursive,
+ follow_links,
listing) && success;
} else if (S_ISREG(entry_info.st_mode)) {
success = HandleFile(entry.d_name,
path,
listing) && success;
+ } else if (S_ISLNK(entry_info.st_mode)) {
+ ASSERT(!follow_links);
+ success = HandleLink(entry.d_name,
+ path,
+ listing) && success;
}
- ASSERT(!S_ISLNK(entry_info.st_mode));
break;
}
default:
@@ -283,13 +316,14 @@
bool Directory::List(const char* dir_name,
bool recursive,
+ bool follow_links,
DirectoryListing *listing) {
PathBuffer path;
if (!path.Add(dir_name)) {
PostError(listing, dir_name);
return false;
}
- return ListRecursively(&path, recursive, listing);
+ return ListRecursively(&path, recursive, follow_links, listing);
}
diff --git a/runtime/bin/directory_patch.dart b/runtime/bin/directory_patch.dart
index cb844f7..4b6ce1f 100644
--- a/runtime/bin/directory_patch.dart
+++ b/runtime/bin/directory_patch.dart
@@ -11,7 +11,7 @@
native "Directory_Delete";
/* patch */ static _rename(String path, String newPath)
native "Directory_Rename";
- /* patch */ static List _list(String path, bool recursive)
+ /* patch */ static List _list(String path, bool recursive, bool followLinks)
native "Directory_List";
/* patch */ static SendPort _newServicePort()
native "Directory_NewServicePort";
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 97a2207..857739a 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -52,6 +52,7 @@
// Forward declarations.
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing);
static bool DeleteRecursively(PathBuffer* path);
@@ -67,6 +68,7 @@
static bool HandleDir(wchar_t* dir_name,
PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing) {
if (wcscmp(dir_name, L".") == 0) return true;
if (wcscmp(dir_name, L"..") == 0) return true;
@@ -77,7 +79,8 @@
char* utf8_path = StringUtils::WideToUtf8(path->data);
bool ok = listing->HandleDirectory(utf8_path);
free(utf8_path);
- return ok && (!recursive || ListRecursively(path, recursive, listing));
+ return ok &&
+ (!recursive || ListRecursively(path, recursive, follow_links, listing));
}
@@ -95,15 +98,33 @@
}
+static bool HandleLink(wchar_t* link_name,
+ PathBuffer* path,
+ DirectoryListing* listing) {
+ if (!path->Add(link_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ char* utf8_path = StringUtils::WideToUtf8(path->data);
+ bool ok = listing->HandleLink(utf8_path);
+ free(utf8_path);
+ return ok;
+}
+
+
static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data,
PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing) {
DWORD attributes = find_file_data->dwFileAttributes;
- if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ if (!follow_links && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+ return HandleLink(find_file_data->cFileName, path, listing);
+ } else if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
return HandleDir(find_file_data->cFileName,
path,
recursive,
+ follow_links,
listing);
} else {
return HandleFile(find_file_data->cFileName, path, listing);
@@ -113,6 +134,7 @@
static bool ListRecursively(PathBuffer* path,
bool recursive,
+ bool follow_links,
DirectoryListing* listing) {
if (!path->Add(L"\\*")) {
PostError(listing, path->data);
@@ -134,6 +156,7 @@
bool success = HandleEntry(&find_file_data,
path,
recursive,
+ follow_links,
listing);
while ((FindNextFileW(find_handle, &find_file_data) != 0)) {
@@ -141,6 +164,7 @@
success = HandleEntry(&find_file_data,
path,
recursive,
+ follow_links,
listing) && success;
}
@@ -250,6 +274,7 @@
bool Directory::List(const char* dir_name,
bool recursive,
+ bool follow_links,
DirectoryListing* listing) {
const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name);
PathBuffer path;
@@ -258,7 +283,7 @@
return false;
}
free(const_cast<wchar_t*>(system_name));
- return ListRecursively(&path, recursive, listing);
+ return ListRecursively(&path, recursive, follow_links, listing);
}
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index cb193a6..3ed6e3f 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -20,6 +20,8 @@
#include "platform/thread.h"
+static const int kBufferSize = 32 * 1024;
+
static const int kInfinityTimeout = -1;
static const int kTimeoutId = -1;
static const int kShutdownId = -2;
@@ -234,7 +236,7 @@
ScopedLock lock(this);
ASSERT(type_ != kListenSocket);
ASSERT(pending_read_ == NULL);
- IOBuffer* buffer = IOBuffer::AllocateReadBuffer(1024);
+ IOBuffer* buffer = IOBuffer::AllocateReadBuffer(kBufferSize);
if (SupportsOverlappedIO()) {
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
@@ -491,7 +493,7 @@
if (SupportsOverlappedIO()) {
if (pending_write_ != NULL) return 0;
if (completion_port_ == INVALID_HANDLE_VALUE) return 0;
- if (num_bytes > 4096) num_bytes = 4096;
+ if (num_bytes > kBufferSize) num_bytes = kBufferSize;
pending_write_ = IOBuffer::AllocateWriteBuffer(num_bytes);
pending_write_->Write(buffer, num_bytes);
if (!IssueWrite()) return -1;
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index f457dd9..5c54ed8 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -439,8 +439,32 @@
Dart_SetReturnValue(args, err);
}
} else {
- OSError os_error(-1, "Invalid argument", OSError::kUnknown);
- Dart_Handle err = DartUtils::NewDartOSError(&os_error);
+ Dart_Handle err = DartUtils::NewDartArgumentError(
+ "Non-string argument to Link.create");
+ if (Dart_IsError(err)) Dart_PropagateError(err);
+ Dart_SetReturnValue(args, err);
+ }
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(File_LinkTarget)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ if (Dart_IsString(Dart_GetNativeArgument(args, 0))) {
+ const char* name =
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+ char* target = File::LinkTarget(name);
+ if (target == NULL) {
+ Dart_Handle err = DartUtils::NewDartOSError();
+ if (Dart_IsError(err)) Dart_PropagateError(err);
+ Dart_SetReturnValue(args, err);
+ } else {
+ Dart_SetReturnValue(args, DartUtils::NewString(target));
+ free(target);
+ }
+ } else {
+ Dart_Handle err = DartUtils::NewDartArgumentError(
+ "Non-string argument to Link.target");
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
@@ -531,8 +555,34 @@
File::Type type = File::GetType(str, follow_links);
Dart_SetReturnValue(args, Dart_NewInteger(static_cast<int>(type)));
} else {
- OSError os_error(-1, "Invalid argument", OSError::kUnknown);
- Dart_Handle err = DartUtils::NewDartOSError(&os_error);
+ Dart_Handle err = DartUtils::NewDartArgumentError(
+ "Non-string argument to FileSystemEntity.type");
+ if (Dart_IsError(err)) Dart_PropagateError(err);
+ Dart_SetReturnValue(args, err);
+ }
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(File_AreIdentical)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ if (Dart_IsString(Dart_GetNativeArgument(args, 0)) &&
+ Dart_IsString(Dart_GetNativeArgument(args, 1))) {
+ const char* path_1 =
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+ const char* path_2 =
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
+ File::Identical result = File::AreIdentical(path_1, path_2);
+ if (result == File::kError) {
+ Dart_Handle err = DartUtils::NewDartOSError();
+ if (Dart_IsError(err)) Dart_PropagateError(err);
+ Dart_SetReturnValue(args, err);
+ } else {
+ Dart_SetReturnValue(args, Dart_NewBoolean(result == File::kIdentical));
+ }
+ } else {
+ Dart_Handle err = DartUtils::NewDartArgumentError(
+ "Non-string argument to FileSystemEntity.identical");
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index dab7a9c..a4c6d4b 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -43,6 +43,12 @@
kDoesNotExist = 3
};
+ enum Identical {
+ kIdentical = 0,
+ kDifferent = 1,
+ kError = 2
+ };
+
enum StdioHandleType {
kTerminal = 0,
kPipe = 1,
@@ -127,12 +133,14 @@
static bool Delete(const char* path);
static off_t LengthFromPath(const char* path);
static time_t LastModified(const char* path);
+ static char* LinkTarget(const char* pathname);
static bool IsAbsolutePath(const char* path);
static char* GetCanonicalPath(const char* path);
static char* GetContainingDirectory(char* path);
static const char* PathSeparator();
static const char* StringEscapedPathSeparator();
static Type GetType(const char* path, bool follow_links);
+ static Identical AreIdentical(const char* file_1, const char* file_2);
static StdioHandleType GetStdioHandleType(int fd);
static FileOpenMode DartModeToFileMode(DartFileOpenMode mode);
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index bdb8ac1..21dcaa9 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -192,6 +192,25 @@
}
+char* File::LinkTarget(const char* pathname) {
+ struct stat link_stats;
+ if (lstat(pathname, &link_stats) != 0) return NULL;
+ if (!S_ISLNK(link_stats.st_mode)) {
+ errno = ENOENT;
+ return NULL;
+ }
+ size_t target_size = link_stats.st_size;
+ char* target_name = reinterpret_cast<char*>(malloc(target_size + 1));
+ size_t read_size = readlink(pathname, target_name, target_size + 1);
+ if (read_size != target_size) {
+ free(target_name);
+ return NULL;
+ }
+ target_name[target_size] = '\0';
+ return target_name;
+}
+
+
bool File::IsAbsolutePath(const char* pathname) {
return (pathname != NULL && pathname[0] == '/');
}
@@ -268,4 +287,18 @@
return File::kDoesNotExist;
}
+
+File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
+ struct stat file_1_info;
+ struct stat file_2_info;
+ if (TEMP_FAILURE_RETRY(lstat(file_1, &file_1_info)) == -1 ||
+ TEMP_FAILURE_RETRY(lstat(file_2, &file_2_info)) == -1) {
+ return File::kError;
+ }
+ return (file_1_info.st_ino == file_2_info.st_ino &&
+ file_1_info.st_dev == file_2_info.st_dev) ?
+ File::kIdentical :
+ File::kDifferent;
+}
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index abbe9cc..ceac630 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -193,6 +193,25 @@
}
+char* File::LinkTarget(const char* pathname) {
+ struct stat link_stats;
+ if (lstat(pathname, &link_stats) != 0) return NULL;
+ if (!S_ISLNK(link_stats.st_mode)) {
+ errno = ENOENT;
+ return NULL;
+ }
+ size_t target_size = link_stats.st_size;
+ char* target_name = reinterpret_cast<char*>(malloc(target_size + 1));
+ size_t read_size = readlink(pathname, target_name, target_size + 1);
+ if (read_size != target_size) {
+ free(target_name);
+ return NULL;
+ }
+ target_name[target_size] = '\0';
+ return target_name;
+}
+
+
bool File::IsAbsolutePath(const char* pathname) {
return (pathname != NULL && pathname[0] == '/');
}
@@ -269,4 +288,18 @@
return File::kDoesNotExist;
}
+
+File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
+ struct stat file_1_info;
+ struct stat file_2_info;
+ if (TEMP_FAILURE_RETRY(lstat(file_1, &file_1_info)) == -1 ||
+ TEMP_FAILURE_RETRY(lstat(file_2, &file_2_info)) == -1) {
+ return File::kError;
+ }
+ return (file_1_info.st_ino == file_2_info.st_ino &&
+ file_1_info.st_dev == file_2_info.st_dev) ?
+ File::kIdentical :
+ File::kDifferent;
+}
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index 9d32457..301424b 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -195,6 +195,25 @@
}
+char* File::LinkTarget(const char* pathname) {
+ struct stat link_stats;
+ if (lstat(pathname, &link_stats) != 0) return NULL;
+ if (!S_ISLNK(link_stats.st_mode)) {
+ errno = ENOENT;
+ return NULL;
+ }
+ size_t target_size = link_stats.st_size;
+ char* target_name = reinterpret_cast<char*>(malloc(target_size + 1));
+ size_t read_size = readlink(pathname, target_name, target_size + 1);
+ if (read_size != target_size) {
+ free(target_name);
+ return NULL;
+ }
+ target_name[target_size] = '\0';
+ return target_name;
+}
+
+
bool File::IsAbsolutePath(const char* pathname) {
return (pathname != NULL && pathname[0] == '/');
}
@@ -277,4 +296,18 @@
return File::kDoesNotExist;
}
+
+File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
+ struct stat file_1_info;
+ struct stat file_2_info;
+ if (TEMP_FAILURE_RETRY(lstat(file_1, &file_1_info)) == -1 ||
+ TEMP_FAILURE_RETRY(lstat(file_2, &file_2_info)) == -1) {
+ return File::kError;
+ }
+ return (file_1_info.st_ino == file_2_info.st_ino &&
+ file_1_info.st_dev == file_2_info.st_dev) ?
+ File::kIdentical :
+ File::kDifferent;
+}
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 194813b..e1e1bfa 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -11,6 +11,7 @@
/* patch */ static _create(String path) native "File_Create";
/* patch */ static _createLink(String path, String target)
native "File_CreateLink";
+ /* patch */ static _linkTarget(String path) native "File_LinkTarget";
/* patch */ static _delete(String path) native "File_Delete";
/* patch */ static _directory(String path) native "File_Directory";
/* patch */ static _lengthFromPath(String path) native "File_LengthFromPath";
diff --git a/runtime/bin/file_system_entity_patch.dart b/runtime/bin/file_system_entity_patch.dart
index 267ab1b..2815ba6 100644
--- a/runtime/bin/file_system_entity_patch.dart
+++ b/runtime/bin/file_system_entity_patch.dart
@@ -5,4 +5,6 @@
patch class FileSystemEntity {
/* patch */ static int _getType(String path, bool followLinks)
native "File_GetType";
+ /* patch */ static bool _identical(String path1, String path2)
+ native "File_AreIdentical";
}
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index b23049d..8e618d3 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -167,6 +167,7 @@
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
+ ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
@@ -279,6 +280,103 @@
}
+char* File::LinkTarget(const char* pathname) {
+ const wchar_t* name = StringUtils::Utf8ToWide(pathname);
+ HANDLE dir_handle = CreateFileW(
+ name,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ free(const_cast<wchar_t*>(name));
+ if (dir_handle == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+
+ int buffer_size =
+ sizeof REPARSE_DATA_BUFFER + 2 * (MAX_PATH + 1) * sizeof WCHAR;
+ REPARSE_DATA_BUFFER* buffer =
+ static_cast<REPARSE_DATA_BUFFER*>(calloc(buffer_size, 1));
+ DWORD received_bytes; // Value is not used.
+ int result = DeviceIoControl(
+ dir_handle,
+ FSCTL_GET_REPARSE_POINT,
+ NULL,
+ 0,
+ buffer,
+ buffer_size,
+ &received_bytes,
+ NULL);
+ if (result == 0) {
+ DWORD error = GetLastError();
+ CloseHandle(dir_handle);
+ free(buffer);
+ SetLastError(error);
+ return NULL;
+ }
+ if (CloseHandle(dir_handle) == 0) {
+ DWORD error = GetLastError();
+ free(buffer);
+ SetLastError(error);
+ return NULL;
+ }
+
+ wchar_t* target;
+ size_t target_offset;
+ size_t target_length;
+ if (buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ target = buffer->MountPointReparseBuffer.PathBuffer;
+ target_offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
+ target_length = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ } else if (buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ target = buffer->SymbolicLinkReparseBuffer.PathBuffer;
+ target_offset = buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset;
+ target_length = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ } else { // Not a junction or a symbolic link.
+ free(buffer);
+ SetLastError(ERROR_NOT_A_REPARSE_POINT);
+ return NULL;
+ }
+
+ target_offset /= sizeof(wchar_t); // Offset and length are in bytes.
+ target_length /= sizeof(wchar_t);
+ target += target_offset;
+ // Remove "\??\" from beginning of target.
+ if (target_length > 4 && wcsncmp(L"\\??\\", target, 4) == 0) {
+ target += 4;
+ target_length -=4;
+ }
+ int utf8_length = WideCharToMultiByte(CP_UTF8,
+ 0,
+ target,
+ target_length,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ char* utf8_target = reinterpret_cast<char*>(malloc(utf8_length + 1));
+ if (0 == WideCharToMultiByte(CP_UTF8,
+ 0,
+ target,
+ target_length,
+ utf8_target,
+ utf8_length,
+ NULL,
+ NULL)) {
+ DWORD error = GetLastError();
+ free(buffer);
+ free(utf8_target);
+ SetLastError(error);
+ return NULL;
+ }
+ utf8_target[utf8_length] = '\0';
+ free(buffer);
+ return utf8_target;
+}
+
+
time_t File::LastModified(const char* name) {
struct _stat st;
const wchar_t* system_name = StringUtils::Utf8ToWide(name);
@@ -416,4 +514,45 @@
}
}
+
+File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
+ BY_HANDLE_FILE_INFORMATION file_info[2];
+ const char* file_names[2] = { file_1, file_2 };
+ for (int i = 0; i < 2; ++i) {
+ const wchar_t* wide_name = StringUtils::Utf8ToWide(file_names[i]);
+ HANDLE file_handle = CreateFileW(
+ wide_name,
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ if (file_handle == INVALID_HANDLE_VALUE) {
+ DWORD error = GetLastError();
+ free(const_cast<wchar_t*>(wide_name));
+ SetLastError(error);
+ return File::kError;
+ }
+ free(const_cast<wchar_t*>(wide_name));
+ int result = GetFileInformationByHandle(file_handle, &file_info[i]);
+ if (result == 0) {
+ DWORD error = GetLastError();
+ CloseHandle(file_handle);
+ SetLastError(error);
+ return File::kError;
+ }
+ if (CloseHandle(file_handle) == 0) {
+ return File::kError;
+ }
+ }
+ if (file_info[0].dwVolumeSerialNumber == file_info[1].dwVolumeSerialNumber &&
+ file_info[0].nFileIndexHigh == file_info[1].nFileIndexHigh &&
+ file_info[0].nFileIndexLow == file_info[1].nFileIndexLow) {
+ return kIdentical;
+ } else {
+ return kDifferent;
+ }
+}
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 091cb69..05833ba 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -335,7 +335,7 @@
if (Dart_IsError(source)) {
return source;
}
- return Dart_LoadScript(resolved_script_uri, source);
+ return Dart_LoadScript(resolved_script_uri, source, 0, 0);
}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 6f29afa..988f78a 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -29,7 +29,6 @@
// Global state that stores a pointer to the application script snapshot.
-static bool use_script_snapshot = false;
static bool generate_script_snapshot = false;
static File* snapshot_file = NULL;
@@ -154,25 +153,6 @@
}
-static bool ProcessUseScriptSnapshotOption(const char* filename) {
- if (filename != NULL && strlen(filename) != 0) {
- use_script_snapshot = true;
- if (generate_script_snapshot) {
- Log::PrintErr("Incompatible options specified --generate-script-snapshot "
- "and --use-script-snapshot\n");
- return false;
- }
- snapshot_file = File::Open(filename, File::kRead);
- if (snapshot_file == NULL) {
- Log::PrintErr("Unable to open file %s for reading the snapshot\n",
- filename);
- return false;
- }
- }
- return true;
-}
-
-
static bool ProcessVmStatsOption(const char* port) {
ASSERT(port != NULL);
if (*port == '\0') {
@@ -216,11 +196,6 @@
" dart\n");
return false;
}
- if (use_script_snapshot) {
- Log::PrintErr("Incompatible options specified --use-script-snapshot "
- "and --generate-script-snapshot\n");
- return false;
- }
snapshot_file = File::Open(filename, File::kWriteTruncate);
if (snapshot_file == NULL) {
Log::PrintErr("Unable to open file %s for writing the snapshot\n",
@@ -249,7 +224,6 @@
{ "--break_at=", ProcessBreakpointOption },
{ "--compile_all", ProcessCompileAllOption },
{ "--debug", ProcessDebugOption },
- { "--use-script-snapshot=", ProcessUseScriptSnapshotOption },
{ "--generate-script-snapshot=", ProcessGenScriptSnapshotOption },
{ "--stats-root=", ProcessVmStatsRootOption },
{ "--stats", ProcessVmStatsOption },
@@ -476,54 +450,23 @@
CHECK_RESULT(result);
// Load the specified application script into the newly created isolate.
- Dart_Handle library;
- if (use_script_snapshot) {
- if (snapshot_file == NULL) {
- use_script_snapshot = false;
- *error = strdup("Invalid script snapshot file name specified");
- Dart_ExitScope();
- Dart_ShutdownIsolate();
- return false;
- }
- size_t len = snapshot_file->Length();
- uint8_t* buffer = reinterpret_cast<uint8_t*>(malloc(len));
- if (buffer == NULL) {
- delete snapshot_file;
- snapshot_file = NULL;
- use_script_snapshot = false;
- *error = strdup("Unable to read contents of script snapshot file");
- Dart_ExitScope();
- Dart_ShutdownIsolate();
- return false;
- }
- // Prepare for script loading by setting up the 'print' and 'timer'
- // closures and setting up 'package root' for URI resolution.
- Dart_Handle builtin_lib =
- Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
- DartUtils::PrepareForScriptLoading(package_root, builtin_lib);
- snapshot_file->ReadFully(buffer, len);
- library = Dart_LoadScriptFromSnapshot(buffer);
- free(buffer);
- delete snapshot_file;
- snapshot_file = NULL;
- use_script_snapshot = false; // No further usage of script snapshots.
- } else {
- // Prepare builtin and its dependent libraries for use to resolve URIs.
- Dart_Handle uri_url = DartUtils::NewString(DartUtils::kUriLibURL);
- Dart_Handle uri_lib = Dart_LookupLibrary(uri_url);
- CHECK_RESULT(uri_lib);
- Dart_Handle builtin_lib =
- Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
- CHECK_RESULT(builtin_lib);
+ // Prepare builtin and its dependent libraries for use to resolve URIs.
+ // The builtin library is part of the core snapshot and would already be
+ // available here in the case of script snapshot loading.
+ Dart_Handle uri_url = DartUtils::NewString(DartUtils::kUriLibURL);
+ Dart_Handle uri_lib = Dart_LookupLibrary(uri_url);
+ CHECK_RESULT(uri_lib);
+ Dart_Handle builtin_lib =
+ Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
+ CHECK_RESULT(builtin_lib);
- // Prepare for script loading by setting up the 'print' and 'timer'
- // closures and setting up 'package root' for URI resolution.
- result = DartUtils::PrepareForScriptLoading(package_root, builtin_lib);
- CHECK_RESULT(result);
+ // Prepare for script loading by setting up the 'print' and 'timer'
+ // closures and setting up 'package root' for URI resolution.
+ result = DartUtils::PrepareForScriptLoading(package_root, builtin_lib);
+ CHECK_RESULT(result);
- library = DartUtils::LoadScript(script_uri, builtin_lib);
- }
+ Dart_Handle library = DartUtils::LoadScript(script_uri, builtin_lib);
CHECK_RESULT(library);
if (!Dart_IsLibrary(library)) {
char errbuf[256];
@@ -825,6 +768,9 @@
return kErrorExitCode; // Indicates we encountered an error.
}
+ // Write the magic number to indicate file is a script snapshot.
+ DartUtils::WriteMagicNumber(snapshot_file);
+
// Now write the snapshot out to specified file.
bool bytes_written = snapshot_file->WriteFully(buffer, size);
ASSERT(bytes_written);
diff --git a/runtime/embedders/openglui/common/vm_glue.cc b/runtime/embedders/openglui/common/vm_glue.cc
index b014d1d..1fde06c 100644
--- a/runtime/embedders/openglui/common/vm_glue.cc
+++ b/runtime/embedders/openglui/common/vm_glue.cc
@@ -191,7 +191,7 @@
Dart_Handle url = CheckError(Dart_NewStringFromCString(main_script_));
Dart_Handle source = LoadSourceFromFile(main_script_);
- CheckError(Dart_LoadScript(url, source));
+ CheckError(Dart_LoadScript(url, source, 0, 0));
Dart_ExitScope();
Dart_ExitIsolate();
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 96ca096..c9375ca 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -327,11 +327,14 @@
*
* Provided for convenience.
*/
-#define DART_CHECK_VALID(handle) \
- if (Dart_IsError((handle))) { \
- _Dart_ReportErrorHandle(__FILE__, __LINE__, \
- #handle, Dart_GetError(handle)); \
- }
+#define DART_CHECK_VALID(handle) \
+ { \
+ Dart_Handle __handle = handle; \
+ if (Dart_IsError((__handle))) { \
+ _Dart_ReportErrorHandle(__FILE__, __LINE__, \
+ #handle, Dart_GetError(__handle)); \
+ } \
+ } \
/**
@@ -2354,15 +2357,6 @@
DART_EXPORT Dart_Handle Dart_SetLibraryTagHandler(
Dart_LibraryTagHandler handler);
-
-/**
- * Loads the root script for the current isolate.
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle Dart_LoadScript(Dart_Handle url,
- Dart_Handle source);
-
/**
* Loads the root script for the current isolate. The script can be
* embedded in another file, for example in an html file.
@@ -2375,8 +2369,7 @@
* \col_offset is the number of characters before the first character
* in the first line of the Dart script.
*/
-DART_EXPORT Dart_Handle Dart_LoadEmbeddedScript(
- Dart_Handle url,
+DART_EXPORT Dart_Handle Dart_LoadScript(Dart_Handle url,
Dart_Handle source,
intptr_t line_offset,
intptr_t col_offset);
@@ -2385,11 +2378,13 @@
* Loads the root script for current isolate from a snapshot.
*
* \param buffer A buffer which contains a snapshot of the script.
+ * \param length Length of the passed in buffer.
*
* \return If no error occurs, the Library object corresponding to the root
* script is returned. Otherwise an error handle is returned.
*/
-DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer);
+DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer,
+ intptr_t buffer_len);
/**
* Gets the library for the root script for the current isolate.
diff --git a/runtime/lib/byte_array.cc b/runtime/lib/byte_array.cc
index 08e0bc8..4a806a6 100644
--- a/runtime/lib/byte_array.cc
+++ b/runtime/lib/byte_array.cc
@@ -252,12 +252,12 @@
DEFINE_NATIVE_ENTRY(ByteArray_getFloat32x4, 2) {
- UNALIGNED_GETTER(ByteArray, Float32x4, simd_value_t);
+ UNALIGNED_GETTER(ByteArray, Float32x4, simd128_value_t);
}
DEFINE_NATIVE_ENTRY(ByteArray_setFloat32x4, 3) {
- UNALIGNED_SETTER(ByteArray, Float32x4, value, simd_value_t);
+ UNALIGNED_SETTER(ByteArray, Float32x4, value, simd128_value_t);
}
@@ -621,7 +621,8 @@
GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(0));
intptr_t len = length.Value();
LengthCheck(len, Float32x4Array::kMaxElements);
- simd_value_t* bytes = OS::AllocateAlignedArray<simd_value_t>(len, kAlignment);
+ simd128_value_t* bytes =
+ OS::AllocateAlignedArray<simd128_value_t>(len, kAlignment);
const ExternalFloat32x4Array& obj =
ExternalFloat32x4Array::Handle(ExternalFloat32x4Array::New(bytes, len));
obj.AddFinalizer(bytes, PeerFinalizer);
@@ -630,12 +631,12 @@
DEFINE_NATIVE_ENTRY(Float32x4Array_getIndexed, 2) {
- GETTER(Float32x4Array, Float32x4, simd_value_t);
+ GETTER(Float32x4Array, Float32x4, simd128_value_t);
}
DEFINE_NATIVE_ENTRY(Float32x4Array_setIndexed, 3) {
- SETTER(Float32x4Array, Float32x4, value, simd_value_t);
+ SETTER(Float32x4Array, Float32x4, value, simd128_value_t);
}
@@ -816,12 +817,12 @@
// ExternalFloat32x4Array
DEFINE_NATIVE_ENTRY(ExternalFloat32x4Array_getIndexed, 2) {
- GETTER(ExternalFloat32x4Array, Float32x4, simd_value_t);
+ GETTER(ExternalFloat32x4Array, Float32x4, simd128_value_t);
}
DEFINE_NATIVE_ENTRY(ExternalFloat32x4Array_setIndexed, 3) {
- SETTER(ExternalFloat32x4Array, Float32x4, value, simd_value_t);
+ SETTER(ExternalFloat32x4Array, Float32x4, value, simd128_value_t);
}
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 081ba83..8e6d905 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -3,4 +3,4 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:math";
-import "dart:scalarlist";
+import "dart:typeddata";
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index a521a63..144e9c9 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -2,6 +2,63 @@
// 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.
+class _CloseToken {
+ /// This token is sent from [IsolateSink]s to [IsolateStream]s to ask them to
+ /// close themselves.
+ const _CloseToken();
+}
+
+patch bool _isCloseToken(var object) {
+ // TODO(floitsch): can we compare against const _CloseToken()?
+ return object is _CloseToken;
+}
+
+patch class MessageBox {
+ /* patch */ MessageBox.oneShot() : this._oneShot(new ReceivePort());
+ MessageBox._oneShot(ReceivePort receivePort)
+ : stream = new IsolateStream._fromOriginalReceivePortOneShot(receivePort),
+ sink = new _IsolateSink._fromPort(receivePort.toSendPort());
+
+ /* patch */ MessageBox() : this._(new ReceivePort());
+ MessageBox._(ReceivePort receivePort)
+ : stream = new IsolateStream._fromOriginalReceivePort(receivePort),
+ sink = new _IsolateSink._fromPort(receivePort.toSendPort());
+}
+
+class _IsolateSink implements IsolateSink {
+ bool _isClosed = false;
+ final SendPort _port;
+ _IsolateSink._fromPort(this._port);
+
+ void add(dynamic message) {
+ _port.send(message);
+ }
+
+ void addError(AsyncError errorEvent) {
+ throw new UnimplementedError("signalError on isolate streams");
+ }
+
+ void close() {
+ if (_isClosed) return;
+ add(const _CloseToken());
+ _isClosed = true;
+ }
+
+ bool operator==(var other) {
+ return other is IsolateSink && _port == other._port;
+ }
+
+ int get hashCode => _port.hashCode + 499;
+}
+
+patch IsolateSink streamSpawnFunction(
+ void topLevelFunction(),
+ [bool unhandledExceptionCallback(IsolateUnhandledException e)]) {
+ SendPort sendPort = spawnFunction(topLevelFunction,
+ unhandledExceptionCallback);
+ return new _IsolateSink._fromPort(sendPort);
+}
+
patch class ReceivePort {
/* patch */ factory ReceivePort() {
return new _ReceivePortImpl();
@@ -131,7 +188,7 @@
}
/* patch */ static spawnFunction(void topLevelFunction(),
- [bool UnhandledExceptionCallback(IsolateUnhandledException e)])
+ [bool unhandledExceptionCallback(IsolateUnhandledException e)])
native "isolate_spawnFunction";
/* patch */ static spawnUri(String uri) native "isolate_spawnUri";
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index c01084b..d17d82e 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -2,7 +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:scalarlist";
+import "dart:typeddata";
// A VM patch of the dart:math library.
patch num pow(num x, num exponent) {
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index c282b7a..9a06b24 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -215,8 +215,7 @@
DEFINE_NATIVE_ENTRY(StringBuffer_createStringFromUint16Array, 3) {
- GET_NON_NULL_NATIVE_ARGUMENT(Uint16Array, codeUnits,
- arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(TypedData, codeUnits, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(Bool, isLatin1, arguments->NativeArgAt(2));
intptr_t array_length = codeUnits.Length();
@@ -231,7 +230,7 @@
: String::Handle(TwoByteString::New(length_value, Heap::kNew));
NoGCScope no_gc;
- uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.ByteAddr(0));
+ uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0));
String::Copy(result, 0, data_position, length_value);
return result.raw();
}
diff --git a/runtime/lib/typeddata.dart b/runtime/lib/typeddata.dart
index cf049d7..ab40008 100644
--- a/runtime/lib/typeddata.dart
+++ b/runtime/lib/typeddata.dart
@@ -228,12 +228,12 @@
patch class ByteData {
/* patch */ factory ByteData(int length) {
var list = new _Uint8Array(length);
- return new _ByteDataView(list.buffer);
+ return new _ByteDataView(list.buffer, 0, length);
}
/* patch */ factory ByteData.transferable(int length) {
var list = new _Uint8Array.transferable(length);
- return new _ByteDataView(list.buffer);
+ return new _ByteDataView(list.buffer, 0, length);
}
/* patch */ factory ByteData.view(ByteBuffer buffer,
diff --git a/runtime/platform/assert.h b/runtime/platform/assert.h
index d92897d..3b5f32e 100644
--- a/runtime/platform/assert.h
+++ b/runtime/platform/assert.h
@@ -267,6 +267,9 @@
#define DEBUG_ASSERT(cond)
+#endif // if defined(DEBUG)
+
+
// The COMPILE_ASSERT macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the
// size of a static array:
@@ -290,8 +293,6 @@
typedef CompileAssert<(static_cast<bool>(expr))> \
msg[static_cast<bool>(expr) ? 1 : -1]
-#endif // if defined(DEBUG)
-
#if defined(TESTING)
#define EXPECT(condition) \
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index f06f04c..2d566bb 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -72,6 +72,45 @@
#error Automatic target os detection failed.
#endif
+struct simd128_value_t {
+ float storage[4];
+ simd128_value_t& readFrom(const float* v) {
+ storage[0] = v[0];
+ storage[1] = v[1];
+ storage[2] = v[2];
+ storage[3] = v[3];
+ return *this;
+ }
+ simd128_value_t& readFrom(const uint32_t* v) {
+ const float* vv = reinterpret_cast<const float*>(v);
+ storage[0] = vv[0];
+ storage[1] = vv[1];
+ storage[2] = vv[2];
+ storage[3] = vv[3];
+ return *this;
+ }
+ simd128_value_t& readFrom(const simd128_value_t* v) {
+ *this = *v;
+ return *this;
+ }
+ void writeTo(float* v) {
+ v[0] = storage[0];
+ v[1] = storage[1];
+ v[2] = storage[2];
+ v[3] = storage[3];
+ }
+ void writeTo(uint32_t* v) {
+ float* vv = reinterpret_cast<float*>(v);
+ vv[0] = storage[0];
+ vv[1] = storage[1];
+ vv[2] = storage[2];
+ vv[3] = storage[3];
+ }
+ void writeTo(simd128_value_t* v) {
+ *v = *this;
+ }
+};
+
// Processor architecture detection. For more info on what's defined, see:
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
// http://www.agner.org/optimize/calling_conventions.pdf
@@ -79,47 +118,23 @@
#if defined(_M_X64) || defined(__x86_64__)
#define HOST_ARCH_X64 1
#define ARCH_IS_64_BIT 1
-#include <xmmintrin.h> // NOLINT
#define kFpuRegisterSize 16
-typedef __m128 fpu_register_t;
-typedef __m128 simd_value_t;
-// Unaligned load.
-#define simd_value_safe_load(addr) \
- _mm_loadu_ps(reinterpret_cast<const float*>(addr))
-// Unaligned store.
-#define simd_value_safe_store(addr, value) \
- _mm_storeu_ps(reinterpret_cast<float*>(addr), value)
+typedef simd128_value_t fpu_register_t;
#elif defined(_M_IX86) || defined(__i386__)
#define HOST_ARCH_IA32 1
#define ARCH_IS_32_BIT 1
-#include <xmmintrin.h> // NOLINT
#define kFpuRegisterSize 16
-typedef __m128 fpu_register_t;
-typedef __m128 simd_value_t;
-// Unaligned load.
-#define simd_value_safe_load(addr) \
- _mm_loadu_ps(reinterpret_cast<const float*>(addr))
-// Unaligned store.
-#define simd_value_safe_store(addr, value) \
- _mm_storeu_ps(reinterpret_cast<float*>(addr), value)
+typedef simd128_value_t fpu_register_t;
#elif defined(__ARMEL__)
#define HOST_ARCH_ARM 1
#define ARCH_IS_32_BIT 1
#define kFpuRegisterSize 8
typedef double fpu_register_t;
-// TODO(johnmccutchan): ARM simd type.
-typedef struct {
- uint32_t data_[4];
-} simd_value_t;
#elif defined(__MIPSEL__)
#define HOST_ARCH_MIPS 1
#define ARCH_IS_32_BIT 1
#define kFpuRegisterSize 8
typedef double fpu_register_t;
-// TODO(johnmccutchan): MIPS simd type.
-typedef struct {
- uint32_t data_[4];
-} simd_value_t;
#else
#error Architecture was not detected as supported by Dart.
#endif
@@ -215,7 +230,7 @@
const int kWordSize = sizeof(word);
const int kDoubleSize = sizeof(double); // NOLINT
const int kFloatSize = sizeof(float); // NOLINT
-const int kSimd128Size = 16;
+const int kSimd128Size = sizeof(simd128_value_t); // NOLINT
#ifdef ARCH_IS_32_BIT
const int kWordSizeLog2 = 2;
const uword kUwordMax = kMaxUint32;
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index acd74eb..a86de87 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -2,11 +2,6 @@
# 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.
-cc/New: Crash # Issue 6958.
-cc/TypeVariableReflection: Crash # Issue 6958.
-cc/LibraryGetClassNames: Fail # Issue 6958.
-cc/ImportLibrary5: Fail # Issue 6958.
-
# These tests are expected to crash on all platforms.
cc/ArrayNew_Overflow_Crash: Crash
cc/AllocGeneric_Overflow: Crash
@@ -74,6 +69,7 @@
# Tests needing type check support.
cc/DartStaticResolve: Crash
cc/DartDynamicResolve: Crash
+cc/FindCodeObject: Crash
[ $arch == mips ]
*: Skip
diff --git a/runtime/tools/gyp/find_mac_sdk.py b/runtime/tools/gyp/find_mac_sdk.py
new file mode 100755
index 0000000..baf6279
--- /dev/null
+++ b/runtime/tools/gyp/find_mac_sdk.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# 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 file is a copy of Chromium's src/build/mac/find_sdk.py.
+# Revision 180337.
+
+import os
+import re
+import subprocess
+import sys
+
+"""Prints the lowest locally available SDK version greater than or equal to a
+given minimum sdk version to standard output.
+
+Usage:
+ python find_sdk.py 10.6 # Ignores SDKs < 10.6
+"""
+
+from optparse import OptionParser
+
+
+def parse_version(version_str):
+ """'10.6' => [10, 6]"""
+ return map(int, re.findall(r'(\d+)', version_str))
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option("--verify",
+ action="store_true", dest="verify", default=False,
+ help="return the sdk argument and warn if it doesn't exist")
+ parser.add_option("--sdk_path",
+ action="store", type="string", dest="sdk_path", default="",
+ help="user-specified SDK path; bypasses verification")
+ (options, args) = parser.parse_args()
+ min_sdk_version = args[0]
+
+ job = subprocess.Popen(['xcode-select', '-print-path'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, err = job.communicate()
+ if job.returncode != 0:
+ print >>sys.stderr, out
+ print >>sys.stderr, err
+ raise Exception(('Error %d running xcode-select, you might have to run '
+ '|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
+ 'if you are using Xcode 4.') % job.returncode)
+ # The Developer folder moved in Xcode 4.3.
+ xcode43_sdk_path = os.path.join(
+ out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs')
+ if os.path.isdir(xcode43_sdk_path):
+ sdk_dir = xcode43_sdk_path
+ else:
+ sdk_dir = os.path.join(out.rstrip(), 'SDKs')
+ sdks = [re.findall('^MacOSX(10\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)]
+ sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6']
+ sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6']
+ if parse_version(s) >= parse_version(min_sdk_version)]
+ if not sdks:
+ raise Exception('No %s+ SDK found' % min_sdk_version)
+ best_sdk = sorted(sdks, key=parse_version)[0]
+
+ if options.verify and best_sdk != min_sdk_version and not options.sdk_path:
+ print >>sys.stderr, ''
+ print >>sys.stderr, ' vvvvvvv'
+ print >>sys.stderr, ''
+ print >>sys.stderr, \
+ 'This build requires the %s SDK, but it was not found on your system.' \
+ % min_sdk_version
+ print >>sys.stderr, \
+ 'Either install it, or explicitly set mac_sdk in your GYP_DEFINES.'
+ print >>sys.stderr, ''
+ print >>sys.stderr, ' ^^^^^^^'
+ print >>sys.stderr, ''
+ return min_sdk_version
+
+ return best_sdk
+
+
+if __name__ == '__main__':
+ if sys.platform != 'darwin':
+ raise Exception("This script only runs on Mac")
+ print main()
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index af41d08..023a05a 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1262,6 +1262,9 @@
void Assembler::LoadObject(Register rd, const Object& object) {
+ // Since objects in the VM heap are never relocated, test instead
+ // if (object.IsSmi() || object.InVMHeap()) {
+ // and modify the decoding code in CallPattern to understand movt, movw.
if (object.IsNull() ||
object.IsSmi() ||
(object.raw() == Bool::True().raw()) ||
@@ -1282,6 +1285,13 @@
}
+void Assembler::CompareObject(Register rn, const Object& object) {
+ ASSERT(rn != IP);
+ LoadObject(IP, object);
+ cmp(rn, ShifterOperand(IP));
+}
+
+
void Assembler::Bind(Label* label) {
ASSERT(!label->IsBound());
int bound_pc = buffer_.Size();
@@ -1919,6 +1929,8 @@
int32_t Assembler::AddObject(const Object& obj) {
+ ASSERT(obj.IsNotTemporaryScopedHandle());
+ ASSERT(obj.IsOld());
if (object_pool_.IsNull()) {
// The object pool cannot be used in the vm isolate.
ASSERT(Isolate::Current() != Dart::vm_isolate());
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 67e385a..199b80c 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -555,6 +555,7 @@
void Drop(intptr_t stack_elements);
void LoadObject(Register rd, const Object& object);
void PushObject(const Object& object);
+ void CompareObject(Register rn, const Object& object);
void LoadWordFromPoolOffset(Register rd, int32_t offset);
void LoadFromOffset(LoadOperandType type,
Register reg,
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 2acf8ce..8d0221c 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -1850,6 +1850,26 @@
// Destroys the value register.
+void Assembler::StoreIntoObjectFilterNoSmi(Register object,
+ Register value,
+ Label* no_update) {
+ COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) &&
+ (kOldObjectAlignmentOffset == 0), young_alignment);
+
+ // Write-barrier triggers if the value is in the new space (has bit set) and
+ // the object is in the old space (has bit cleared).
+ // To check that we could compute value & ~object and skip the write barrier
+ // if the bit is not set. However we can't destroy the object.
+ // However to preserve the object we compute negated expression
+ // ~value | object instead and skip the write barrier if the bit is set.
+ notl(value);
+ orl(value, object);
+ testl(value, Immediate(kNewObjectAlignmentOffset));
+ j(NOT_ZERO, no_update, Assembler::kNearJump);
+}
+
+
+// Destroys the value register.
void Assembler::StoreIntoObjectFilter(Register object,
Register value,
Label* no_update) {
@@ -1872,12 +1892,17 @@
void Assembler::StoreIntoObject(Register object,
const Address& dest,
- Register value) {
+ Register value,
+ bool can_value_be_smi) {
ASSERT(object != value);
TraceStoreIntoObject(object, dest, value);
movl(dest, value);
Label done;
- StoreIntoObjectFilter(object, value, &done);
+ if (can_value_be_smi) {
+ StoreIntoObjectFilter(object, value, &done);
+ } else {
+ StoreIntoObjectFilterNoSmi(object, value, &done);
+ }
// A store buffer update is required.
if (value != EAX) pushl(EAX); // Preserve EAX.
leal(EAX, dest);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 07088a4..d147296 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -611,7 +611,8 @@
void StoreIntoObject(Register object, // Object we are storing into.
const Address& dest, // Where we are storing into.
- Register value); // Value we are storing.
+ Register value, // Value we are storing.
+ bool can_value_be_smi = true);
void StoreIntoObjectNoBarrier(Register object,
const Address& dest,
@@ -790,6 +791,11 @@
void StoreIntoObjectFilter(Register object, Register value, Label* no_update);
+ // Shorter filtering sequence that assumes that value is not a smi.
+ void StoreIntoObjectFilterNoSmi(Register object,
+ Register value,
+ Label* no_update);
+
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler);
};
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index f74e06e..88bd937 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -22,6 +22,40 @@
}
}
+
+void Assembler::Bind(Label* label) {
+ ASSERT(!label->IsBound());
+ int bound_pc = buffer_.Size();
+ while (label->IsLinked()) {
+ int32_t position = label->Position();
+ int32_t next = buffer_.Load<int32_t>(position);
+ // Reletive destination from an instruction after the branch.
+ int32_t dest = bound_pc - (position + Instr::kInstrSize);
+ int32_t encoded = Assembler::EncodeBranchOffset(dest, next);
+ buffer_.Store<int32_t>(position, encoded);
+ label->position_ = Assembler::DecodeBranchOffset(next);
+ }
+ label->BindTo(bound_pc);
+ delay_slot_available_ = false;
+}
+
+
+int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t instr) {
+ ASSERT(Utils::IsAligned(offset, 4));
+ ASSERT(Utils::IsInt(18, offset));
+
+ // Properly preserve only the bits supported in the instruction.
+ offset >>= 2;
+ offset &= kBranchOffsetMask;
+ return (instr & ~kBranchOffsetMask) | offset;
+}
+
+
+int Assembler::DecodeBranchOffset(int32_t instr) {
+ // Sign-extend, left-shift by 2.
+ return (((instr & kBranchOffsetMask) << 16) >> 14);
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 67ad01f..ed85493 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -147,9 +147,7 @@
UNIMPLEMENTED();
}
- void Bind(Label* label) {
- UNIMPLEMENTED();
- }
+ void Bind(Label* label);
// Misc. functionality
int CodeSize() const { return buffer_.Size(); }
@@ -224,7 +222,7 @@
return this;
}
- // CPU instructions.
+ // CPU instructions in alphabetical order.
void addiu(Register rt, Register rs, const Immediate& imm) {
ASSERT(Utils::IsInt(16, imm.value()));
uint16_t imm_value = static_cast<uint16_t>(imm.value());
@@ -245,6 +243,101 @@
EmitIType(ANDI, rs, rt, imm_value);
}
+ // Unconditional branch.
+ void b(Label* l) {
+ beq(R0, R0, l);
+ }
+
+ // Branch if equal.
+ void beq(Register rs, Register rt, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitBranch(BEQ, rs, rt, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if equal, likely taken.
+ // Delay slot executed only when branch taken.
+ void beql(Register rs, Register rt, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitBranch(BEQL, rs, rt, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs >= 0.
+ void bgez(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitRegImmBranch(BGEZ, rs, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs >= 0, likely taken.
+ // Delay slot executed only when branch taken.
+ void bgezl(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitRegImmBranch(BGEZL, rs, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs > 0.
+ void bgtz(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitBranch(BGTZ, rs, R0, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs > 0, likely taken.
+ // Delay slot executed only when branch taken.
+ void bgtzl(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitBranch(BGTZL, rs, R0, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs <= 0.
+ void blez(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitBranch(BLEZ, rs, R0, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs <= 0, likely taken.
+ // Delay slot executed only when branch taken.
+ void blezl(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitBranch(BLEZL, rs, R0, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs < 0.
+ void bltz(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitRegImmBranch(BLTZ, rs, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if rs < 0, likely taken.
+ // Delay slot executed only when branch taken.
+ void bltzl(Register rs, Label* l) {
+ ASSERT(!in_delay_slot_);
+ EmitRegImmBranch(BLTZL, rs, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if not equal.
+ void bne(Register rs, Register rt, Label* l) {
+ ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
+ EmitBranch(BNE, rs, rt, l);
+ EmitBranchDelayNop();
+ }
+
+ // Branch if not equal, likely taken.
+ // Delay slot executed only when branch taken.
+ void bnel(Register rs, Register rt, Label* l) {
+ ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
+ EmitBranch(BNEL, rs, rt, l);
+ EmitBranchDelayNop();
+ }
+
void break_(int32_t code) {
ASSERT(Utils::IsUint(20, code));
Emit(SPECIAL << kOpcodeShift |
@@ -268,6 +361,18 @@
EmitRType(SPECIAL, rs, rt, R0, 0, DIVU);
}
+ void jalr(Register rs, Register rd = RA) {
+ ASSERT(rs != rd);
+ ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
+ EmitRType(SPECIAL, rs, R0, rd, 0, JALR);
+ EmitBranchDelayNop();
+ }
+
+ void jr(Register rs) {
+ ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
+ EmitRType(SPECIAL, rs, R0, R0, 0, JR);
+ EmitBranchDelayNop();
+ }
void lb(Register rt, const Address& addr) {
EmitLoadStore(LB, rt, addr);
@@ -303,19 +408,44 @@
EmitRType(SPECIAL, R0, R0, rd, 0, MFLO);
}
+ void mov(Register rd, Register rs) {
+ or_(rd, rs, ZR);
+ }
+
+ void movn(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, MOVN);
+ }
+
+ void movz(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, MOVZ);
+ }
+
+ void mult(Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, R0, 0, MULT);
+ }
+
+ void multu(Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, R0, 0, MULTU);
+ }
+
+ void nop() {
+ Emit(Instr::kNopInstruction);
+ }
+
+ void nor(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, NOR);
+ }
+
+ void or_(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, OR);
+ }
+
void ori(Register rt, Register rs, const Immediate& imm) {
ASSERT(Utils::IsUint(16, imm.value()));
uint16_t imm_value = static_cast<uint16_t>(imm.value());
EmitIType(ORI, rs, rt, imm_value);
}
- void jr(Register rs) {
- ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported.
- EmitRType(SPECIAL, rs, R0, R0, 0, JR);
- Emit(Instr::kNopInstruction); // Branch delay NOP.
- delay_slot_available_ = true;
- }
-
void sb(Register rt, const Address& addr) {
EmitLoadStore(SB, rt, addr);
}
@@ -324,18 +454,62 @@
EmitLoadStore(SH, rt, addr);
}
- void sw(Register rt, const Address& addr) {
- EmitLoadStore(SW, rt, addr);
- }
-
void sll(Register rd, Register rt, int sa) {
EmitRType(SPECIAL, R0, rt, rd, sa, SLL);
}
- // Macros.
+ void sllv(Register rd, Register rt, Register rs) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, SLLV);
+ }
+
+ void slt(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, SLT);
+ }
+
+ void sltu(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, SLTU);
+ }
+
+ void sra(Register rd, Register rt, int sa) {
+ EmitRType(SPECIAL, R0, rt, rd, sa, SRA);
+ }
+
+ void srav(Register rd, Register rt, Register rs) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, SRAV);
+ }
+
+ void srl(Register rd, Register rt, int sa) {
+ EmitRType(SPECIAL, R0, rt, rd, sa, SRL);
+ }
+
+ void srlv(Register rd, Register rt, Register rs) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, SRLV);
+ }
+
+ void sub(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, SUB);
+ }
+
+ void subu(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, SUBU);
+ }
+
+ void sw(Register rt, const Address& addr) {
+ EmitLoadStore(SW, rt, addr);
+ }
+
+ void xor_(Register rd, Register rs, Register rt) {
+ EmitRType(SPECIAL, rs, rt, rd, 0, XOR);
+ }
+
+ // Macros in alphabetical order.
void LoadImmediate(Register rd, int32_t value) {
- lui(rd, Immediate((value >> 16) & 0xffff));
- ori(rd, rd, Immediate(value & 0xffff));
+ if (Utils::IsInt(16, value)) {
+ addiu(rd, ZR, Immediate(value));
+ } else {
+ lui(rd, Immediate((value >> 16) & 0xffff));
+ ori(rd, rd, Immediate(value & 0xffff));
+ }
}
private:
@@ -419,6 +593,40 @@
func << kFunctionShift);
}
+ void EmitBranch(Opcode b, Register rs, Register rt, Label* label) {
+ if (label->IsBound()) {
+ // Reletive destination from an instruction after the branch.
+ int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize);
+ uint16_t dest_off = EncodeBranchOffset(dest, 0);
+ EmitIType(b, rs, rt, dest_off);
+ } else {
+ int position = buffer_.Size();
+ EmitIType(b, rs, rt, label->position_);
+ label->LinkTo(position);
+ }
+ }
+
+ void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) {
+ if (label->IsBound()) {
+ // Reletive destination from an instruction after the branch.
+ int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize);
+ uint16_t dest_off = EncodeBranchOffset(dest, 0);
+ EmitRegImmType(REGIMM, rs, b, dest_off);
+ } else {
+ int position = buffer_.Size();
+ EmitRegImmType(REGIMM, rs, b, label->position_);
+ label->LinkTo(position);
+ }
+ }
+
+ static int32_t EncodeBranchOffset(int32_t offset, int32_t instr);
+ static int DecodeBranchOffset(int32_t instr);
+
+ void EmitBranchDelayNop() {
+ Emit(Instr::kNopInstruction); // Branch delay NOP.
+ delay_slot_available_ = true;
+ }
+
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler);
};
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index 82287ff..cf122b4 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -14,6 +14,17 @@
#define __ assembler->
+ASSEMBLER_TEST_GENERATE(Simple, assembler) {
+ __ LoadImmediate(V0, 42);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Simple, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
ASSEMBLER_TEST_GENERATE(Addiu, assembler) {
__ addiu(V0, ZR, Immediate(42));
@@ -322,13 +333,670 @@
}
-ASSEMBLER_TEST_GENERATE(Simple, assembler) {
+ASSEMBLER_TEST_GENERATE(Sll, assembler) {
+ __ LoadImmediate(R1, 21);
+ __ sll(V0, R1, 1);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Sll, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Srl, assembler) {
+ __ LoadImmediate(R1, 84);
+ __ srl(V0, R1, 1);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Srl, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LShifting, assembler) {
+ __ LoadImmediate(R1, 1);
+ __ sll(R1, R1, 31);
+ __ srl(V0, R1, 31);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(LShifting, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(RShifting, assembler) {
+ __ LoadImmediate(R1, 1);
+ __ sll(R1, R1, 31);
+ __ sra(V0, R1, 31);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(RShifting, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Sllv, assembler) {
+ __ LoadImmediate(R1, 21);
+ __ LoadImmediate(R2, 1);
+ __ sllv(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Sllv, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Srlv, assembler) {
+ __ LoadImmediate(R1, 84);
+ __ LoadImmediate(R2, 1);
+ __ srlv(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Srlv, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LShiftingV, assembler) {
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R2, 31);
+ __ sllv(R1, R1, R2);
+ __ srlv(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(LShiftingV, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(RShiftingV, assembler) {
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R2, 31);
+ __ sllv(R1, R1, R2);
+ __ srav(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(RShiftingV, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Mult_pos, assembler) {
+ __ LoadImmediate(R1, 6);
+ __ LoadImmediate(R2, 7);
+ __ mult(R1, R2);
+ __ mflo(V0);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Mult_pos, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Mult_neg, assembler) {
+ __ LoadImmediate(R1, -6);
+ __ LoadImmediate(R2, 7);
+ __ mult(R1, R2);
+ __ mflo(V0);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Mult_neg, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Mult_neg_hi, assembler) {
+ __ LoadImmediate(R1, -6);
+ __ LoadImmediate(R2, 7);
+ __ mult(R1, R2);
+ __ mfhi(V0);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Mult_neg_hi, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Multu_lo, assembler) {
+ __ LoadImmediate(R1, 6);
+ __ LoadImmediate(R2, 7);
+ __ multu(R1, R2);
+ __ mflo(V0);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Multu_lo, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Multu_hi, assembler) {
+ __ LoadImmediate(R1, 65536);
+ __ LoadImmediate(R2, 65536);
+ __ multu(R1, R2);
+ __ mfhi(V0);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Multu_hi, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Subu, assembler) {
+ __ LoadImmediate(R1, 737);
+ __ LoadImmediate(R2, 695);
+ __ subu(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Subu, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Or, assembler) {
+ __ LoadImmediate(R1, 34);
+ __ LoadImmediate(R2, 8);
+ __ or_(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Or, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Nor, assembler) {
+ __ LoadImmediate(R1, -47);
+ __ LoadImmediate(R2, -60);
+ __ nor(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Nor, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Xor, assembler) {
+ __ LoadImmediate(R1, 51);
+ __ LoadImmediate(R2, 25);
+ __ xor_(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Xor, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Slt, assembler) {
+ __ LoadImmediate(R1, -1);
+ __ LoadImmediate(R2, 0);
+ __ slt(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Slt, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Sltu, assembler) {
+ __ LoadImmediate(R1, -1);
+ __ LoadImmediate(R2, 0);
+ __ sltu(V0, R1, R2);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Sltu, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Movz, assembler) {
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 23);
+ __ slt(R3, R1, R2);
+ __ movz(V0, R1, R3);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Movz, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Movn, assembler) {
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 23);
+ __ slt(R3, R2, R1);
+ __ movn(V0, R1, R3);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Movn, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Jr_delay, assembler) {
__ jr(RA);
__ delay_slot()->ori(V0, ZR, Immediate(42));
}
-ASSEMBLER_TEST_RUN(Simple, test) {
+ASSEMBLER_TEST_RUN(Jr_delay, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beq_backward, assembler) {
+ Label l;
+
+ __ LoadImmediate(R1, 0);
+ __ LoadImmediate(R2, 1);
+ __ Bind(&l);
+ __ addiu(R1, R1, Immediate(1));
+ __ beq(R1, R2, &l);
+ __ ori(V0, R1, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beq_backward, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(2, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beq_backward_delay, assembler) {
+ Label l;
+
+ __ LoadImmediate(R1, 0);
+ __ LoadImmediate(R2, 1);
+ __ Bind(&l);
+ __ addiu(R1, R1, Immediate(1));
+ __ beq(R1, R2, &l);
+ __ delay_slot()->addiu(R1, R1, Immediate(1));
+ __ ori(V0, R1, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beq_backward_delay, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beq_forward_taken, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 1);
+ __ LoadImmediate(R6, 1);
+
+ __ LoadImmediate(V0, 42);
+ __ beq(R5, R6, &l);
+ __ LoadImmediate(V0, 0);
+ __ Bind(&l);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beq_forward_taken, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beq_forward_not_taken, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 0);
+ __ LoadImmediate(R6, 1);
+
+ __ LoadImmediate(V0, 42);
+ __ beq(R5, R6, &l);
+ __ LoadImmediate(V0, 0);
+ __ Bind(&l);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beq_forward_not_taken, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beq_forward_taken2, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 1);
+ __ LoadImmediate(R6, 1);
+
+ __ LoadImmediate(V0, 42);
+ __ beq(R5, R6, &l);
+ __ nop();
+ __ nop();
+ __ LoadImmediate(V0, 0);
+ __ Bind(&l);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beq_forward_taken2, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beq_forward_taken_delay, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 1);
+ __ LoadImmediate(R6, 1);
+
+ __ LoadImmediate(V0, 42);
+ __ beq(R5, R6, &l);
+ __ delay_slot()->ori(V0, V0, Immediate(1));
+ __ LoadImmediate(V0, 0);
+ __ Bind(&l);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beq_forward_taken_delay, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(43, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beq_forward_not_taken_delay, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 0);
+ __ LoadImmediate(R6, 1);
+
+ __ LoadImmediate(V0, 42);
+ __ beq(R5, R6, &l);
+ __ delay_slot()->ori(V0, V0, Immediate(1));
+ __ addiu(V0, V0, Immediate(1));
+ __ Bind(&l);
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beq_forward_not_taken_delay, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(44, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Beql_backward_delay, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 0);
+ __ LoadImmediate(R6, 1);
+ __ Bind(&l);
+ __ addiu(R5, R5, Immediate(1));
+ __ beql(R5, R6, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Beql_backward_delay, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bgez, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 3);
+ __ Bind(&l);
+ __ bgez(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(-1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bgez, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bgezl, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 3);
+ __ Bind(&l);
+ __ bgezl(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(-1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bgezl, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Blez, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, -3);
+ __ Bind(&l);
+ __ blez(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Blez, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(2, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Blezl, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, -3);
+ __ Bind(&l);
+ __ blezl(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Blezl, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bgtz, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 3);
+ __ Bind(&l);
+ __ bgtz(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(-1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bgtz, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bgtzl, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 3);
+ __ Bind(&l);
+ __ bgtzl(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(-1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bgtzl, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bltz, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, -3);
+ __ Bind(&l);
+ __ bltz(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bltz, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bltzl, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, -3);
+ __ Bind(&l);
+ __ bltzl(R5, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bltzl, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bne, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 3);
+ __ Bind(&l);
+ __ bne(R5, R0, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(-1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bne, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Bnel, assembler) {
+ Label l;
+
+ __ LoadImmediate(R5, 3);
+ __ Bind(&l);
+ __ bnel(R5, R0, &l);
+ __ delay_slot()->addiu(R5, R5, Immediate(-1));
+ __ ori(V0, R5, Immediate(0));
+ __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(Bnel, test) {
+ typedef int (*SimpleCode)();
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Jalr_delay, assembler) {
+ __ mov(R2, RA);
+ __ jalr(R2, RA);
+ __ delay_slot()->ori(V0, ZR, Immediate(42));
+}
+
+
+ASSEMBLER_TEST_RUN(Jalr_delay, test) {
typedef int (*SimpleCode)();
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
}
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 0d621b1..49acf4a 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -1690,6 +1690,14 @@
}
+void Assembler::notl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitRegisterREX(reg, REX_NONE);
+ EmitUint8(0xF7);
+ EmitUint8(0xD0 | (reg & 7));
+}
+
+
void Assembler::notq(Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(reg, REX_W);
@@ -2008,6 +2016,26 @@
// Destroys the value register.
+void Assembler::StoreIntoObjectFilterNoSmi(Register object,
+ Register value,
+ Label* no_update) {
+ COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) &&
+ (kOldObjectAlignmentOffset == 0), young_alignment);
+
+ // Write-barrier triggers if the value is in the new space (has bit set) and
+ // the object is in the old space (has bit cleared).
+ // To check that we could compute value & ~object and skip the write barrier
+ // if the bit is not set. However we can't destroy the object.
+ // However to preserve the object we compute negated expression
+ // ~value | object instead and skip the write barrier if the bit is set.
+ notl(value);
+ orl(value, object);
+ testl(value, Immediate(kNewObjectAlignmentOffset));
+ j(NOT_ZERO, no_update, Assembler::kNearJump);
+}
+
+
+// Destroys the value register.
void Assembler::StoreIntoObjectFilter(Register object,
Register value,
Label* no_update) {
@@ -2030,11 +2058,16 @@
void Assembler::StoreIntoObject(Register object,
const Address& dest,
- Register value) {
+ Register value,
+ bool can_value_be_smi) {
ASSERT(object != value);
movq(dest, value);
Label done;
- StoreIntoObjectFilter(object, value, &done);
+ if (can_value_be_smi) {
+ StoreIntoObjectFilter(object, value, &done);
+ } else {
+ StoreIntoObjectFilterNoSmi(object, value, &done);
+ }
// A store buffer update is required.
if (value != RAX) pushq(RAX);
leaq(RAX, dest);
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index aa6c21b..d14c02d 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -533,6 +533,7 @@
void negl(Register reg);
void negq(Register reg);
+ void notl(Register reg);
void notq(Register reg);
void enter(const Immediate& imm);
@@ -632,7 +633,8 @@
// Destroys value.
void StoreIntoObject(Register object, // Object we are storing into.
const Address& dest, // Where we are storing into.
- Register value); // Value we are storing.
+ Register value, // Value we are storing.
+ bool can_value_be_smi = true);
void StoreIntoObjectNoBarrier(Register object,
const Address& dest,
@@ -821,6 +823,11 @@
void StoreIntoObjectFilter(Register object, Register value, Label* no_update);
+ // Shorter filtering sequence that assumes that value is not a smi.
+ void StoreIntoObjectFilterNoSmi(Register object,
+ Register value,
+ Label* no_update);
+
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler);
};
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index ba99591..1287571 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -2025,6 +2025,20 @@
}
+ASSEMBLER_TEST_GENERATE(TestNotInt32, assembler) {
+ __ movq(RAX, Immediate(0x0));
+ __ notl(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(TestNotInt32, test) {
+ typedef int (*TestNot)();
+ unsigned int res = reinterpret_cast<TestNot>(test->entry())();
+ EXPECT_EQ(0xFFFFFFFF, res);
+}
+
+
ASSEMBLER_TEST_GENERATE(XorpdZeroing, assembler) {
__ pushq(RAX);
__ movsd(Address(RSP, 0), XMM0);
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 48faa6b..400f1fa 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1372,6 +1372,7 @@
void ClassFinalizer::FinalizeClass(const Class& cls) {
+ HANDLESCOPE(Isolate::Current());
if (cls.is_finalized()) {
return;
}
@@ -1445,6 +1446,32 @@
interface_type ^= interface_types.At(i);
interface_type = FinalizeType(cls, interface_type, kCanonicalizeWellFormed);
interface_types.SetAt(i, interface_type);
+
+ // Check whether the interface is duplicated. We need to wait with
+ // this check until the super type and interface types are finalized,
+ // so that we can use Type::Equals() for the test.
+ ASSERT(interface_type.IsFinalized());
+ ASSERT(super_type.IsFinalized());
+ if (interface_type.Equals(super_type)) {
+ const Script& script = Script::Handle(cls.script());
+ ReportError(script, cls.token_pos(),
+ "super type '%s' may not be listed in "
+ "implements clause of class '%s'",
+ String::Handle(super_type.Name()).ToCString(),
+ String::Handle(cls.Name()).ToCString());
+ }
+ AbstractType& seen_interf = AbstractType::Handle();
+ for (intptr_t j = 0; j < i; j++) {
+ seen_interf ^= interface_types.At(j);
+ if (interface_type.Equals(seen_interf)) {
+ const Script& script = Script::Handle(cls.script());
+ ReportError(script, cls.token_pos(),
+ "interface '%s' appears twice in "
+ "implements clause of class '%s'",
+ String::Handle(interface_type.Name()).ToCString(),
+ String::Handle(cls.Name()).ToCString());
+ }
+ }
}
// Mark as finalized before resolving type parameter upper bounds and member
// types in order to break cycles.
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index b1f11df..daafa597 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1380,7 +1380,8 @@
}
-static void DeoptimizeAt(const Code& optimized_code, uword pc) {
+void DeoptimizeAt(const Code& optimized_code, uword pc) {
+ ASSERT(optimized_code.is_optimized());
intptr_t deopt_reason = kDeoptUnknown;
const DeoptInfo& deopt_info =
DeoptInfo::Handle(optimized_code.GetDeoptInfoAtPc(pc, &deopt_reason));
@@ -1449,11 +1450,13 @@
// Copy saved registers into the isolate buffer.
static void CopySavedRegisters(uword saved_registers_address) {
- double* fpu_registers_copy = new double[kNumberOfFpuRegisters];
+ fpu_register_t* fpu_registers_copy =
+ new fpu_register_t[kNumberOfFpuRegisters];
ASSERT(fpu_registers_copy != NULL);
for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
- fpu_registers_copy[i] = *reinterpret_cast<double*>(saved_registers_address);
- saved_registers_address += kDoubleSize;
+ fpu_registers_copy[i] =
+ *reinterpret_cast<fpu_register_t*>(saved_registers_address);
+ saved_registers_address += kFpuRegisterSize;
}
Isolate::Current()->set_deopt_fpu_registers_copy(fpu_registers_copy);
@@ -1505,7 +1508,8 @@
// All registers have been saved below last-fp.
const uword last_fp = saved_registers_address +
- kNumberOfCpuRegisters * kWordSize + kNumberOfFpuRegisters * kDoubleSize;
+ kNumberOfCpuRegisters * kWordSize +
+ kNumberOfFpuRegisters * kFpuRegisterSize;
CopySavedRegisters(saved_registers_address);
// Get optimized code and frame that need to be deoptimized.
@@ -1607,7 +1611,7 @@
intptr_t* frame_copy = isolate->deopt_frame_copy();
intptr_t* cpu_registers_copy = isolate->deopt_cpu_registers_copy();
- double* fpu_registers_copy = isolate->deopt_fpu_registers_copy();
+ fpu_register_t* fpu_registers_copy = isolate->deopt_fpu_registers_copy();
intptr_t deopt_reason = kDeoptUnknown;
const DeoptInfo& deopt_info = DeoptInfo::Handle(
@@ -1633,42 +1637,17 @@
// This is the last step in the deoptimization, GC can occur.
DEFINE_RUNTIME_ENTRY(DeoptimizeMaterializeDoubles, 0) {
- DeferredDouble* deferred_double = Isolate::Current()->DetachDeferredDoubles();
+ DeferredObject* deferred_object = Isolate::Current()->DetachDeferredObjects();
- while (deferred_double != NULL) {
- DeferredDouble* current = deferred_double;
- deferred_double = deferred_double->next();
+ while (deferred_object != NULL) {
+ DeferredObject* current = deferred_object;
+ deferred_object = deferred_object->next();
- RawDouble** slot = current->slot();
- *slot = Double::New(current->value());
-
- if (FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("materializing double at %"Px": %g\n",
- reinterpret_cast<uword>(current->slot()),
- current->value());
- }
+ current->Materialize();
delete current;
}
- DeferredMint* deferred_mint = Isolate::Current()->DetachDeferredMints();
-
- while (deferred_mint != NULL) {
- DeferredMint* current = deferred_mint;
- deferred_mint = deferred_mint->next();
-
- RawMint** slot = current->slot();
- ASSERT(!Smi::IsValid64(current->value()));
- *slot = Mint::New(current->value());
-
- if (FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("materializing mint at %"Px": %"Pd64"\n",
- reinterpret_cast<uword>(current->slot()),
- current->value());
- }
-
- delete current;
- }
// Since this is the only step where GC can occur during deoptimization,
// use it to report the source line where deoptimization occured.
if (FLAG_trace_deoptimization) {
@@ -1733,4 +1712,17 @@
return remainder;
}
+
+// Update global type feedback recorded for a field recording the assignment
+// of the given value.
+// Arg0: Field object;
+// Arg1: Value that is being stored.
+DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) {
+ ASSERT(arguments.ArgCount() == kUpdateFieldCidRuntimeEntry.argument_count());
+ const Field& field = Field::CheckedHandle(arguments.ArgAt(0));
+ const Object& value = Object::Handle(arguments.ArgAt(1));
+
+ field.UpdateCid(Class::Handle(value.clazz()).id());
+}
+
} // namespace dart
diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h
index 7946dc2..82ecc2d 100644
--- a/runtime/vm/code_generator.h
+++ b/runtime/vm/code_generator.h
@@ -50,6 +50,8 @@
DECLARE_RUNTIME_ENTRY(TraceFunctionExit);
DECLARE_RUNTIME_ENTRY(DeoptimizeMaterializeDoubles);
DECLARE_RUNTIME_ENTRY(UpdateICDataTwoArgs);
+DECLARE_RUNTIME_ENTRY(UpdateFieldCid);
+
#define DEOPT_REASONS(V) \
V(Unknown) \
@@ -75,6 +77,7 @@
V(DoubleToSmi) \
V(Int32Load) \
V(Uint32Load) \
+ V(GuardField) \
V(NumReasons) \
enum DeoptReasonId {
@@ -92,6 +95,7 @@
const ICData& ic_data,
const Array& arguments_descriptor);
+void DeoptimizeAt(const Code& optimized_code, uword pc);
void DeoptimizeAll();
void DeoptimizeIfOwner(const GrowableArray<intptr_t>& classes);
diff --git a/runtime/vm/code_patcher.cc b/runtime/vm/code_patcher.cc
index c353cac..986ade4 100644
--- a/runtime/vm/code_patcher.cc
+++ b/runtime/vm/code_patcher.cc
@@ -28,6 +28,7 @@
void CodePatcher::PatchEntry(const Code& code) {
const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
PcDescriptors::kEntryPatch);
+ ASSERT(patch_addr != 0);
JumpPattern jmp_entry(patch_addr);
ASSERT(!jmp_entry.IsValid());
const uword patch_buffer = code.GetPatchCodePc();
@@ -47,6 +48,7 @@
void CodePatcher::RestoreEntry(const Code& code) {
const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
PcDescriptors::kEntryPatch);
+ ASSERT(patch_addr != 0);
JumpPattern jmp_entry(patch_addr);
ASSERT(jmp_entry.IsValid());
const uword jump_target = jmp_entry.TargetAddress();
diff --git a/runtime/vm/code_patcher_ia32.cc b/runtime/vm/code_patcher_ia32.cc
index cd21ef2..2bd3f1b 100644
--- a/runtime/vm/code_patcher_ia32.cc
+++ b/runtime/vm/code_patcher_ia32.cc
@@ -93,7 +93,7 @@
// The expected pattern of a dart static call:
-// mov EDX, arguments_descriptor_array
+// mov EDX, arguments_descriptor_array (optional in polymorphic calls)
// call target_address
// <- return address
class StaticCall : public ValueObject {
@@ -108,8 +108,7 @@
uint8_t* code_bytes =
reinterpret_cast<uint8_t*>(
return_address - (kNumInstructions * kInstructionSize));
- return (code_bytes[0] == 0xBA) &&
- (code_bytes[1 * kInstructionSize] == 0xE8);
+ return (code_bytes[0] == 0xE8);
}
uword target() const {
@@ -124,7 +123,7 @@
CPU::FlushICache(call_address(), kInstructionSize);
}
- static const int kNumInstructions = 2;
+ static const int kNumInstructions = 1;
static const int kInstructionSize = 5; // All instructions have same length.
private:
@@ -133,7 +132,7 @@
}
uword call_address() const {
- return start_ + 1 * kInstructionSize;
+ return start_;
}
uword start_;
diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
index 5be92be..1f2cebe 100644
--- a/runtime/vm/code_patcher_x64.cc
+++ b/runtime/vm/code_patcher_x64.cc
@@ -86,7 +86,7 @@
// The expected pattern of a dart static call:
-// mov R10, arguments_descriptor_array (10 bytes)
+// mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls)
// mov R11, target_address (10 bytes)
// call R11 (3 bytes)
// <- return address
@@ -95,28 +95,27 @@
explicit StaticCall(uword return_address)
: start_(return_address - kCallPatternSize) {
ASSERT(IsValid(return_address));
- ASSERT((kCallPatternSize - 10) == Assembler::kCallExternalLabelSize);
+ ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize);
}
- static const int kCallPatternSize = 23;
+ static const int kCallPatternSize = 13;
static bool IsValid(uword return_address) {
uint8_t* code_bytes =
reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
- return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) &&
- (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) &&
- (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) &&
- (code_bytes[22] == 0xD3);
+ return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBB) &&
+ (code_bytes[10] == 0x41) && (code_bytes[11] == 0xFF) &&
+ (code_bytes[12] == 0xD3);
}
uword target() const {
- return *reinterpret_cast<uword*>(start_ + 10 + 2);
+ return *reinterpret_cast<uword*>(start_ + 2);
}
void set_target(uword target) const {
- uword* target_addr = reinterpret_cast<uword*>(start_ + 10 + 2);
+ uword* target_addr = reinterpret_cast<uword*>(start_ + 2);
*target_addr = target;
- CPU::FlushICache(start_ + 10, 2 + 8);
+ CPU::FlushICache(start_, 2 + 8);
}
private:
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index d993415..a0e412e 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -167,6 +167,8 @@
FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph);
}
+ const ZoneGrowableArray<Field*>* guarded_fields = NULL;
+
if (optimized) {
TimerScope timer(FLAG_compiler_stats,
&CompilerStats::graphoptimizer_timer,
@@ -193,6 +195,8 @@
DEBUG_ASSERT(flow_graph->VerifyUseLists());
}
+ guarded_fields = flow_graph->FieldDependencies();
+
// Propagate types and eliminate more type tests.
if (FLAG_propagate_types) {
FlowGraphTypePropagator propagator(flow_graph);
@@ -221,6 +225,8 @@
// Propagate types and eliminate even more type tests.
if (FLAG_propagate_types) {
+ // Recompute types after constant propagation to infer more precise
+ // types for uses that were previously reached by now eliminated phis.
FlowGraphTypePropagator propagator(flow_graph);
propagator.Propagate();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -303,6 +309,7 @@
graph_compiler.FinalizeExceptionHandlers(code);
graph_compiler.FinalizeComments(code);
graph_compiler.FinalizeStaticCallTargetsTable(code);
+
if (optimized) {
CodePatcher::PatchEntry(Code::Handle(function.CurrentCode()));
function.SetCode(code);
@@ -310,6 +317,11 @@
OS::Print("--> patching entry %#"Px"\n",
Code::Handle(function.unoptimized_code()).EntryPoint());
}
+
+ for (intptr_t i = 0; i < guarded_fields->length(); i++) {
+ const Field& field = *(*guarded_fields)[i];
+ field.RegisterDependentCode(code);
+ }
} else {
function.set_unoptimized_code(code);
function.SetCode(code);
diff --git a/runtime/vm/constants_mips.h b/runtime/vm/constants_mips.h
index aba778d..95a0799 100644
--- a/runtime/vm/constants_mips.h
+++ b/runtime/vm/constants_mips.h
@@ -174,6 +174,8 @@
kInstrBits = 26,
kBreakCodeShift = 5,
kBreakCodeBits = 20,
+
+ kBranchOffsetMask = 0x0000ffff,
};
@@ -253,7 +255,7 @@
MFLO = 18,
MTLO = 19,
MULT = 24,
- MUTLU = 25,
+ MULTU = 25,
DIV = 26,
DIVU = 27,
ADD = 32,
@@ -366,6 +368,10 @@
return static_cast<SpecialFunction>(Bits(kFunctionShift, kFunctionBits));
}
+ inline RtRegImm RegImmFnField() const {
+ return static_cast<RtRegImm>(Bits(kRtShift, kRtBits));
+ }
+
inline bool IsBreakPoint() {
return (OpcodeField() == SPECIAL) && (FunctionField() == BREAK);
}
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4ed5a7d..2333523 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2074,8 +2074,7 @@
Isolate* isolate = Isolate::Current();
// Lookup the class ArgumentError in dart:core.
const String& lib_url = String::Handle(String::New("dart:core"));
- const String& class_name =
- String::Handle(String::New("ArgumentError"));
+ const String& class_name = String::Handle(String::New("ArgumentError"));
const Library& lib =
Library::Handle(isolate, Library::LookupLibrary(lib_url));
if (lib.IsNull()) {
@@ -2093,9 +2092,10 @@
lib_url.ToCString()));
return ApiError::New(message);
}
- String& dot_name = String::Handle(String::New("."));
Object& result = Object::Handle(isolate);
- result = ResolveConstructor(CURRENT_FUNC, cls, class_name, dot_name, 1);
+ String& dot_name = String::Handle(String::New("."));
+ String& constr_name = String::Handle(String::Concat(class_name, dot_name));
+ result = ResolveConstructor(CURRENT_FUNC, cls, class_name, constr_name, 1);
if (result.IsError()) return result.raw();
ASSERT(result.IsFunction());
Function& constructor = Function::Handle(isolate);
@@ -2329,9 +2329,6 @@
static Dart_TypedData_Type GetType(intptr_t class_id) {
Dart_TypedData_Type type;
switch (class_id) {
- case kByteArrayCid :
- type = kByteData;
- break;
case kTypedDataInt8ArrayCid :
case kExternalTypedDataInt8ArrayCid :
type = kInt8;
@@ -2386,20 +2383,77 @@
DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object) {
intptr_t class_id = Api::ClassId(object);
- if (!RawObject::IsTypedDataClassId(class_id)) {
- return kInvalid;
+ if (RawObject::IsTypedDataClassId(class_id)) {
+ return GetType(class_id);
}
- return GetType(class_id);
+ Isolate* isolate = Isolate::Current();
+ const Library& lib =
+ Library::Handle(isolate->object_store()->typeddata_library());
+ const Class& cls =
+ Class::Handle(isolate,
+ lib.LookupClassAllowPrivate(Symbols::_ByteDataView()));
+ if (isolate->class_table()->At(class_id) == cls.raw()) {
+ return kByteData;
+ }
+ return kInvalid;
}
DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfExternalTypedData(
Dart_Handle object) {
intptr_t class_id = Api::ClassId(object);
- if (!RawObject::IsExternalTypedDataClassId(class_id)) {
- return kInvalid;
+ if (RawObject::IsExternalTypedDataClassId(class_id)) {
+ return GetType(class_id);
}
- return GetType(class_id);
+ Isolate* isolate = Isolate::Current();
+ const Library& lib =
+ Library::Handle(isolate->object_store()->typeddata_library());
+ const Class& cls =
+ Class::Handle(isolate,
+ lib.LookupClassAllowPrivate(Symbols::_ByteDataView()));
+ if (isolate->class_table()->At(class_id) == cls.raw()) {
+ return kByteData;
+ }
+ return kInvalid;
+}
+
+
+static RawObject* GetByteDataConstructor(Isolate* isolate,
+ const String& constructor_name,
+ intptr_t num_args) {
+ const Library& lib =
+ Library::Handle(isolate->object_store()->typeddata_library());
+ ASSERT(!lib.IsNull());
+ const Class& cls =
+ Class::Handle(isolate, lib.LookupClassAllowPrivate(Symbols::ByteData()));
+ ASSERT(!cls.IsNull());
+ return ResolveConstructor(CURRENT_FUNC,
+ cls,
+ Symbols::ByteData(),
+ constructor_name,
+ num_args);
+}
+
+
+static Dart_Handle NewByteData(Isolate* isolate, intptr_t length) {
+ CHECK_LENGTH(length, TypedData::MaxElements(kTypedDataInt8ArrayCid));
+ Object& result = Object::Handle(isolate);
+ result = GetByteDataConstructor(isolate, Symbols::ByteDataDot(), 1);
+ ASSERT(!result.IsNull());
+ ASSERT(result.IsFunction());
+ const Function& factory = Function::Cast(result);
+ ASSERT(!factory.IsConstructor());
+
+ // Create the argument list.
+ const Array& args = Array::Handle(isolate, Array::New(2));
+ // Factories get type arguments.
+ args.SetAt(0, TypeArguments::Handle(isolate));
+ args.SetAt(1, Smi::Handle(isolate, Smi::New(length)));
+
+ // Invoke the constructor and return the new object.
+ result = DartEntry::InvokeFunction(factory, args);
+ ASSERT(result.IsInstance() || result.IsNull() || result.IsError());
+ return Api::NewHandle(isolate, result.raw());
}
@@ -2426,6 +2480,47 @@
}
+static Dart_Handle NewExternalByteData(Isolate* isolate,
+ void* data,
+ intptr_t length,
+ void* peer,
+ Dart_WeakPersistentHandleFinalizer cb) {
+ Dart_Handle ext_data = NewExternalTypedData(kExternalTypedDataUint8ArrayCid,
+ data,
+ length,
+ peer,
+ cb);
+ if (::Dart_IsError(ext_data)) {
+ return ext_data;
+ }
+ Object& result = Object::Handle(isolate);
+ result = GetByteDataConstructor(isolate, Symbols::ByteDataDotview(), 3);
+ ASSERT(!result.IsNull());
+ ASSERT(result.IsFunction());
+ const Function& factory = Function::Cast(result);
+ ASSERT(!factory.IsConstructor());
+
+ // Create the argument list.
+ const intptr_t num_args = 3;
+ const Array& args = Array::Handle(isolate, Array::New(num_args + 1));
+ // Factories get type arguments.
+ args.SetAt(0, TypeArguments::Handle(isolate));
+ const ExternalTypedData& array =
+ Api::UnwrapExternalTypedDataHandle(isolate, ext_data);
+ args.SetAt(1, array);
+ Smi& smi = Smi::Handle(isolate);
+ smi = Smi::New(0);
+ args.SetAt(2, smi);
+ smi = Smi::New(length);
+ args.SetAt(3, smi);
+
+ // Invoke the constructor and return the new object.
+ result = DartEntry::InvokeFunction(factory, args);
+ ASSERT(result.IsNull() || result.IsInstance() || result.IsError());
+ return Api::NewHandle(isolate, result.raw());
+}
+
+
DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type,
intptr_t length) {
Isolate* isolate = Isolate::Current();
@@ -2433,8 +2528,7 @@
CHECK_CALLBACK_STATE(isolate);
switch (type) {
case kByteData :
- // TODO(asiva): Add a new ByteArray::New() method.
- break;
+ return NewByteData(isolate, length);
case kInt8 :
return NewTypedData(isolate, kTypedDataInt8ArrayCid, length);
case kUint8 :
@@ -2480,8 +2574,7 @@
CHECK_CALLBACK_STATE(isolate);
switch (type) {
case kByteData :
- // TODO(asiva): Allocate external ByteData object.
- break;
+ return NewExternalByteData(isolate, data, length, peer, callback);
case kInt8 :
return NewExternalTypedData(kExternalTypedDataInt8ArrayCid,
data,
@@ -3462,10 +3555,9 @@
static RawObject* ResolveConstructor(const char* current_func,
const Class& cls,
const String& class_name,
- const String& dotted_name,
+ const String& constr_name,
int num_args) {
// The constructor must be present in the interface.
- String& constr_name = String::Handle(String::Concat(class_name, dotted_name));
const Function& constructor =
Function::Handle(cls.LookupFunctionAllowPrivate(constr_name));
if (constructor.IsNull() ||
@@ -3550,17 +3642,26 @@
}
// Resolve the constructor.
- result = ResolveConstructor(
- "Dart_New", cls, base_constructor_name, dot_name, number_of_arguments);
+ String& constr_name =
+ String::Handle(String::Concat(base_constructor_name, dot_name));
+ result = ResolveConstructor("Dart_New",
+ cls,
+ base_constructor_name,
+ constr_name,
+ number_of_arguments);
if (result.IsError()) {
return Api::NewHandle(isolate, result.raw());
}
- // TODO(turnidge): Support redirecting factories.
ASSERT(result.IsFunction());
Function& constructor = Function::Handle(isolate);
constructor ^= result.raw();
Instance& new_object = Instance::Handle(isolate);
+ if (constructor.IsRedirectingFactory()) {
+ Type& type = Type::Handle(constructor.RedirectionType());
+ cls = type.type_class();
+ constructor = constructor.RedirectionTarget();
+ }
if (constructor.IsConstructor()) {
// Create the new object.
new_object = Instance::New(cls);
@@ -4247,44 +4348,9 @@
DART_EXPORT Dart_Handle Dart_LoadScript(Dart_Handle url,
- Dart_Handle source) {
- TIMERSCOPE(time_script_loading);
- Isolate* isolate = Isolate::Current();
- DARTSCOPE(isolate);
- const String& url_str = Api::UnwrapStringHandle(isolate, url);
- if (url_str.IsNull()) {
- RETURN_TYPE_ERROR(isolate, url, String);
- }
- const String& source_str = Api::UnwrapStringHandle(isolate, source);
- if (source_str.IsNull()) {
- RETURN_TYPE_ERROR(isolate, source, String);
- }
- Library& library =
- Library::Handle(isolate, isolate->object_store()->root_library());
- if (!library.IsNull()) {
- const String& library_url = String::Handle(isolate, library.url());
- return Api::NewError("%s: A script has already been loaded from '%s'.",
- CURRENT_FUNC, library_url.ToCString());
- }
- CHECK_CALLBACK_STATE(isolate);
-
- library = Library::New(url_str);
- library.set_debuggable(true);
- library.Register();
- isolate->object_store()->set_root_library(library);
-
- const Script& script = Script::Handle(
- isolate, Script::New(url_str, source_str, RawScript::kScriptTag));
- Dart_Handle result;
- CompileSource(isolate, library, script, &result);
- return result;
-}
-
-
-DART_EXPORT Dart_Handle Dart_LoadEmbeddedScript(Dart_Handle url,
- Dart_Handle source,
- intptr_t line_offset,
- intptr_t col_offset) {
+ Dart_Handle source,
+ intptr_t line_offset,
+ intptr_t col_offset) {
TIMERSCOPE(time_script_loading);
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
@@ -4327,7 +4393,8 @@
}
-DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer) {
+DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer,
+ intptr_t buffer_len) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
TIMERSCOPE(time_script_loading);
@@ -4339,6 +4406,11 @@
return Api::NewError("%s expects parameter 'buffer' to be a script type"
" snapshot.", CURRENT_FUNC);
}
+ if (snapshot->length() != buffer_len) {
+ return Api::NewError("%s: 'buffer_len' of %"Pd" is not equal to %d which"
+ " is the expected length in the snapshot.",
+ CURRENT_FUNC, buffer_len, snapshot->length());
+ }
Library& library =
Library::Handle(isolate, isolate->object_store()->root_library());
if (!library.IsNull()) {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index efca65a..b86ab17 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -885,6 +885,117 @@
}
+static int kLength = 16;
+
+static void ByteDataNativeFunction(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle byte_data = Dart_NewTypedData(kByteData, kLength);
+ EXPECT_VALID(byte_data);
+ EXPECT_EQ(kByteData, Dart_GetTypeOfTypedData(byte_data));
+ Dart_SetReturnValue(args, byte_data);
+ Dart_ExitScope();
+}
+
+
+static Dart_NativeFunction ByteDataNativeResolver(Dart_Handle name,
+ int arg_count) {
+ return &ByteDataNativeFunction;
+}
+
+
+TEST_CASE(ByteDataAccess) {
+ const char* kScriptChars =
+ "import 'dart:typeddata';\n"
+ "ByteData createByteData() native 'CreateByteData';"
+ "ByteData main() {"
+ " var length = 16;"
+ " var a = createByteData();"
+ " Expect.equals(length, a.lengthInBytes);"
+ " for (int i = 0; i < length; i+=1) {"
+ " a.setInt8(i, 0x42);"
+ " }"
+ " for (int i = 0; i < length; i+=2) {"
+ " Expect.equals(0x4242, a.getInt16(i));"
+ " }"
+ " return a;"
+ "}\n";
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+
+ Dart_Handle result = Dart_SetNativeResolver(lib, &ByteDataNativeResolver);
+ EXPECT_VALID(result);
+
+ // Invoke 'main' function.
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+}
+
+
+static const intptr_t kExtLength = 16;
+static int8_t data[kExtLength] = { 0x41, 0x42, 0x41, 0x42,
+ 0x41, 0x42, 0x41, 0x42,
+ 0x41, 0x42, 0x41, 0x42,
+ 0x41, 0x42, 0x41, 0x42, };
+
+static void ExternalByteDataNativeFunction(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle external_byte_data = Dart_NewExternalTypedData(kByteData,
+ data,
+ 16,
+ NULL, NULL);
+ EXPECT_VALID(external_byte_data);
+ EXPECT_EQ(kByteData, Dart_GetTypeOfTypedData(external_byte_data));
+ Dart_SetReturnValue(args, external_byte_data);
+ Dart_ExitScope();
+}
+
+
+static Dart_NativeFunction ExternalByteDataNativeResolver(Dart_Handle name,
+ int arg_count) {
+ return &ExternalByteDataNativeFunction;
+}
+
+
+TEST_CASE(ExternalByteDataAccess) {
+ // TODO(asiva): Once we have getInt16LE and getInt16BE support use the
+ // appropriate getter instead of the host endian format used now.
+ const char* kScriptChars =
+ "import 'dart:typeddata';\n"
+ "ByteData createExternalByteData() native 'CreateExternalByteData';"
+ "ByteData main() {"
+ " var length = 16;"
+ " var a = createExternalByteData();"
+ " Expect.equals(length, a.lengthInBytes);"
+ " for (int i = 0; i < length; i+=2) {"
+ " Expect.equals(0x4241, a.getInt16(i));"
+ " }"
+ " for (int i = 0; i < length; i+=2) {"
+ " a.setInt8(i, 0x24);"
+ " a.setInt8(i + 1, 0x28);"
+ " }"
+ " for (int i = 0; i < length; i+=2) {"
+ " Expect.equals(0x2824, a.getInt16(i));"
+ " }"
+ " return a;"
+ "}\n";
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+
+ Dart_Handle result = Dart_SetNativeResolver(lib,
+ &ExternalByteDataNativeResolver);
+ EXPECT_VALID(result);
+
+ // Invoke 'main' function.
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ for (intptr_t i = 0; i < kExtLength; i+=2) {
+ EXPECT_EQ(0x24, data[i]);
+ EXPECT_EQ(0x28, data[i+1]);
+ }
+}
+
+
TEST_CASE(TypedDataDirectAccess) {
Dart_Handle str = Dart_NewStringFromCString("junk");
Dart_Handle byte_array = Dart_NewTypedData(kUint8, 10);
@@ -3281,7 +3392,7 @@
TEST_CASE(New) {
const char* kScriptChars =
- "class MyClass implements MyInterface {\n"
+ "class MyClass {\n"
" MyClass() : foo = 7 {}\n"
" MyClass.named(value) : foo = value {}\n"
" MyClass._hidden(value) : foo = -value {}\n"
@@ -3294,43 +3405,24 @@
" factory MyClass.nullo() {\n"
" return null;\n"
" }\n"
- " factory MyInterface.multiply(value) { // won't get called.\n"
- " return new MyClass.named(value * 1000);\n"
- " }\n"
- " factory MyInterface2.unused(value) {\n"
- " return new MyClass2(-value);\n"
- " }\n"
- " factory MyInterface2.multiply(value) {\n"
- " return new MyClass2(value * 10000);\n"
- " }\n"
" var foo;\n"
"}\n"
"\n"
- "class MyClass2 implements MyInterface2 {\n"
- " MyClass2(value) : bar = value {}\n"
- " var bar;\n"
+ "abstract class MyExtraHop {\n"
+ " factory MyExtraHop.hop(value) = MyClass.named;\n"
"}\n"
"\n"
- "interface MyInterface default MyClass {\n"
- " MyInterface.named(value);\n"
- " MyInterface.multiply(value);\n"
+ "abstract class MyInterface {\n"
+ " factory MyInterface.named(value) = MyExtraHop.hop;\n"
+ " factory MyInterface.multiply(value) = MyClass.multiply;\n"
" MyInterface.notfound(value);\n"
- "}\n"
- "\n"
- "interface MyInterface2 default MyClass {\n"
- " MyInterface2.multiply(value);\n"
- " MyInterface2.notfound(value);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, NewString("MyClass"));
EXPECT_VALID(cls);
- Dart_Handle cls2 = Dart_GetClass(lib, NewString("MyClass2"));
- EXPECT_VALID(cls2);
Dart_Handle intf = Dart_GetClass(lib, NewString("MyInterface"));
EXPECT_VALID(intf);
- Dart_Handle intf2 = Dart_GetClass(lib, NewString("MyInterface2"));
- EXPECT_VALID(intf2);
Dart_Handle args[1];
args[0] = Dart_NewInteger(11);
Dart_Handle bad_args[1];
@@ -3433,19 +3525,7 @@
result = Dart_New(cls, NewString("exception"), 1, args);
EXPECT_ERROR(result, "ConstructorDeath");
- // MyInterface has default class MyClass.
- //
- // MyClass *implements* MyInterface.
- //
- // Therefore the constructor call:
- //
- // MyInterface.foo()
- //
- // Becomes:
- //
- // MyClass.foo() from the class MyClass.
-
- // Invoke an interface constructor.
+ // Invoke two-hop redirecting factory constructor.
result = Dart_New(intf, NewString("named"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
@@ -3455,8 +3535,7 @@
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(11, int_value);
- // Invoke an interface constructor which in turn calls a factory
- // constructor.
+ // Invoke one-hop redirecting factory constructor.
result = Dart_New(intf, NewString("multiply"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
@@ -3466,53 +3545,16 @@
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(1100, int_value);
- // Invoke a constructor that is missing in the interface but present
- // in the default class.
+ // Invoke a constructor that is missing in the interface.
result = Dart_New(intf, Dart_Null(), 0, NULL);
EXPECT_ERROR(result,
"Dart_New: could not find constructor 'MyInterface.'.");
- // Invoke a constructor that is present in the interface but missing
- // in the default class.
+ // Invoke abstract constructor that is present in the interface.
result = Dart_New(intf, NewString("notfound"), 1, args);
- EXPECT_ERROR(result,
- "Dart_New: could not find constructor 'MyClass.notfound'.");
-
- // MyInterface2 has default class MyClass.
- //
- // MyClass *does not implement* MyInterface2.
- //
- // Therefore the constructor call:
- //
- // new MyInterface2.foo()
- //
- // Becomes:
- //
- // new MyInterface2.foo() from the class MyClass.
-
- // Invoke an interface constructor which in turn calls a factory
- // constructor.
- result = Dart_New(intf2, NewString("multiply"), 1, args);
EXPECT_VALID(result);
- EXPECT_VALID(Dart_ObjectIsType(result, cls2, &instanceof));
- EXPECT(instanceof);
- int_value = 0;
- Dart_Handle bar = Dart_GetField(result, NewString("bar"));
- EXPECT_VALID(Dart_IntegerToInt64(bar, &int_value));
- EXPECT_EQ(110000, int_value);
-
- // Invoke a constructor that is missing in the interface but present
- // in the default class.
- result = Dart_New(intf2, NewString("unused"), 1, args);
- EXPECT_ERROR(result,
- "Dart_New: could not find constructor 'MyInterface2.unused'.");
-
- // Invoke a constructor that is present in the interface but missing
- // in the default class.
- result = Dart_New(intf2, NewString("notfound"), 1, args);
- EXPECT_ERROR(result,
- "Dart_New: could not find factory 'MyInterface2.notfound' "
- "in class 'MyClass'.");
+ EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
+ EXPECT(!instanceof);
}
@@ -4769,7 +4811,7 @@
TEST_CASE(TypeVariableReflection) {
const char* kScriptChars =
- "interface UpperBound {}\n"
+ "abstract class UpperBound {}\n"
"class GenericClass<U, T extends UpperBound> {\n"
" T func1() { return null; }\n"
" U func2() { return null; }\n"
@@ -4915,37 +4957,37 @@
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- result = Dart_LoadScript(Dart_Null(), source);
+ result = Dart_LoadScript(Dart_Null(), source, 0, 0);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'url' to be non-null.",
Dart_GetError(result));
- result = Dart_LoadScript(Dart_True(), source);
+ result = Dart_LoadScript(Dart_True(), source, 0, 0);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'url' to be of type String.",
Dart_GetError(result));
- result = Dart_LoadScript(error, source);
+ result = Dart_LoadScript(error, source, 0, 0);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
- result = Dart_LoadScript(url, Dart_Null());
+ result = Dart_LoadScript(url, Dart_Null(), 0, 0);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'source' to be non-null.",
Dart_GetError(result));
- result = Dart_LoadScript(url, Dart_True());
+ result = Dart_LoadScript(url, Dart_True(), 0, 0);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadScript expects argument 'source' to be of type String.",
Dart_GetError(result));
- result = Dart_LoadScript(url, error);
+ result = Dart_LoadScript(url, error, 0, 0);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
// Load a script successfully.
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(result);
result = Dart_Invoke(result, NewString("main"), 0, NULL);
@@ -4956,7 +4998,7 @@
EXPECT_EQ(12345, value);
// Further calls to LoadScript are errors.
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript: "
"A script has already been loaded from 'dart:test-lib'.",
@@ -4977,7 +5019,7 @@
// Load a script.
Dart_Handle url = NewString(TestCase::url());
Dart_Handle source = NewString(kScriptChars);
- EXPECT_VALID(Dart_LoadScript(url, source));
+ EXPECT_VALID(Dart_LoadScript(url, source, 0, 0));
root_lib = Dart_RootLibrary();
Dart_Handle lib_name = Dart_LibraryName(root_lib);
@@ -5033,7 +5075,7 @@
Dart_Handle source = NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(import_library_handler);
EXPECT_VALID(result);
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result), "unexpected token ')'"));
}
@@ -5052,7 +5094,7 @@
Dart_Handle source = NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(result);
url = NewString("library1_dart");
@@ -5158,10 +5200,10 @@
"\n"
"class A {}\n"
"class B {}\n"
- "interface C {}\n"
+ "abstract class C {}\n"
"class _A {}\n"
"class _B {}\n"
- "interface _C {}\n"
+ "abstract class _C {}\n"
"\n"
"_compare(String a, String b) => a.compareTo(b);\n"
"sort(list) => list.sort(_compare);\n";
@@ -5750,7 +5792,7 @@
Dart_Handle script_url = NewString("theScript");
source = NewString(kScriptChars);
- Dart_Handle test_script = Dart_LoadScript(script_url, source);
+ Dart_Handle test_script = Dart_LoadScript(script_url, source, 0, 0);
EXPECT_VALID(test_script);
// Make sure that we can compile all of the patched code.
@@ -5842,7 +5884,7 @@
Dart_Handle source = NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- Dart_Handle lib = Dart_LoadScript(url, source);
+ Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
Dart_Handle cls = Dart_GetClass(lib, NewString("Test"));
@@ -5925,7 +5967,7 @@
Dart_Handle source = NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
url = NewString("library1_dart");
source = NewString(kLibrary1Chars);
@@ -5961,7 +6003,7 @@
Dart_Handle source = NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(result);
url = NewString("library2_dart");
@@ -5998,7 +6040,7 @@
Dart_Handle source = NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(result);
url = NewString("library2_dart");
@@ -6017,13 +6059,13 @@
TEST_CASE(ImportLibrary5) {
const char* kScriptChars =
"import 'lib.dart';\n"
- "interface Y {\n"
+ "abstract class Y {\n"
" void set handler(void callback(List<int> x));\n"
"}\n"
"void main() {}\n";
const char* kLibraryChars =
"library lib.dart;\n"
- "interface X {\n"
+ "abstract class X {\n"
" void set handler(void callback(List<int> x));\n"
"}\n";
Dart_Handle result;
@@ -6033,7 +6075,7 @@
Dart_Handle source = NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- result = Dart_LoadScript(url, source);
+ result = Dart_LoadScript(url, source, 0, 0);
url = NewString("lib.dart");
source = NewString(kLibraryChars);
@@ -6169,7 +6211,7 @@
Dart_Handle source = NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(TestCase::library_handler);
EXPECT_VALID(result);
- Dart_Handle lib = Dart_LoadScript(url, source);
+ Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
Dart_ExitScope();
return true;
@@ -6302,7 +6344,7 @@
Dart_Handle source = NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(TestCase::library_handler);
EXPECT_VALID(result);
- lib = Dart_LoadScript(url, source);
+ lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
result = Dart_SetNativeResolver(lib, &IsolateInterruptTestNativeLookup);
DART_CHECK_VALID(result);
@@ -6570,7 +6612,7 @@
Dart_Handle source = NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- Dart_Handle lib = Dart_LoadScript(url, source);
+ Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
result = Dart_SetNativeResolver(lib, &MyNativeClosureResolver);
@@ -6708,7 +6750,7 @@
Dart_Handle source = NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
- Dart_Handle lib = Dart_LoadScript(url, source);
+ Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
result = Dart_SetNativeResolver(lib, &MyStaticNativeClosureResolver);
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 180a43c..ab1e060 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -267,7 +267,10 @@
// Reading of regular dart instances is not supported.
if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) {
- return AllocateDartCObjectUnsupported();
+ intptr_t object_id = SerializedHeaderData::decode(value);
+ Dart_CObject* object = AllocateDartCObjectUnsupported();
+ AddBackRef(object_id, object, kIsNotDeserialized);
+ return object;
}
ASSERT((class_header & kSmiTagMask) != 0);
intptr_t object_id = SerializedHeaderData::decode(value);
@@ -310,7 +313,9 @@
intptr_t object_id) {
switch (class_id) {
case kClassCid: {
- return AllocateDartCObjectUnsupported();
+ Dart_CObject* object = AllocateDartCObjectUnsupported();
+ AddBackRef(object_id, object, kIsDeserialized);
+ return object;
}
case kTypeArgumentsCid: {
// TODO(sjesse): Remove this when message serialization format is
@@ -467,7 +472,9 @@
}
default:
// Everything else not supported.
- return AllocateDartCObjectUnsupported();
+ Dart_CObject* value = AllocateDartCObjectUnsupported();
+ AddBackRef(object_id, value, kIsDeserialized);
+ return value;
}
}
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index dd814b7..652d942 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -29,6 +29,12 @@
current_(buffer),
end_(buffer + size) {}
+ void SetStream(const uint8_t* buffer, intptr_t size) {
+ buffer_ = buffer;
+ current_ = buffer;
+ end_ = buffer + size;
+ }
+
template<int N, typename T>
class Raw { };
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 9b6d5e3..3d61b7b 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1050,7 +1050,7 @@
// Load a script.
Dart_Handle url = NewString(TestCase::url());
Dart_Handle source = NewString(kScriptChars);
- EXPECT_VALID(Dart_LoadScript(url, source));
+ EXPECT_VALID(Dart_LoadScript(url, source, 0, 0));
lib_list = Dart_GetLibraryURLs();
EXPECT_VALID(lib_list);
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index b153b8c..f505590 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -170,6 +170,78 @@
};
+class DeoptFloat32x4StackSlotInstr : public DeoptInstr {
+ public:
+ explicit DeoptFloat32x4StackSlotInstr(intptr_t from_index)
+ : stack_slot_index_(from_index) {
+ ASSERT(stack_slot_index_ >= 0);
+ }
+
+ virtual intptr_t from_index() const { return stack_slot_index_; }
+ virtual DeoptInstr::Kind kind() const { return kFloat32x4StackSlot; }
+
+ virtual const char* ToCString() const {
+ const char* format = "f32x4s%"Pd"";
+ intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_);
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(chars, len + 1, format, stack_slot_index_);
+ return chars;
+ }
+
+ void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+ intptr_t from_index =
+ deopt_context->from_frame_size() - stack_slot_index_ - 1;
+ simd128_value_t* from_addr = reinterpret_cast<simd128_value_t*>(
+ deopt_context->GetFromFrameAddressAt(from_index));
+ intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
+ *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
+ Isolate::Current()->DeferFloat32x4Materialization(
+ *from_addr, reinterpret_cast<RawFloat32x4**>(to_addr));
+ }
+
+ private:
+ const intptr_t stack_slot_index_; // First argument is 0, always >= 0.
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptFloat32x4StackSlotInstr);
+};
+
+
+class DeoptUint32x4StackSlotInstr : public DeoptInstr {
+ public:
+ explicit DeoptUint32x4StackSlotInstr(intptr_t from_index)
+ : stack_slot_index_(from_index) {
+ ASSERT(stack_slot_index_ >= 0);
+ }
+
+ virtual intptr_t from_index() const { return stack_slot_index_; }
+ virtual DeoptInstr::Kind kind() const { return kUint32x4StackSlot; }
+
+ virtual const char* ToCString() const {
+ const char* format = "ui32x4s%"Pd"";
+ intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_);
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(chars, len + 1, format, stack_slot_index_);
+ return chars;
+ }
+
+ void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+ intptr_t from_index =
+ deopt_context->from_frame_size() - stack_slot_index_ - 1;
+ simd128_value_t* from_addr = reinterpret_cast<simd128_value_t*>(
+ deopt_context->GetFromFrameAddressAt(from_index));
+ intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
+ *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
+ Isolate::Current()->DeferUint32x4Materialization(
+ *from_addr, reinterpret_cast<RawUint32x4**>(to_addr));
+ }
+
+ private:
+ const intptr_t stack_slot_index_; // First argument is 0, always >= 0.
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptUint32x4StackSlotInstr);
+};
+
+
// Deoptimization instruction creating return address using function and
// deopt-id stored at 'object_table_index'. Uses the deopt-after
// continuation point.
@@ -205,7 +277,9 @@
function ^= deopt_context->ObjectAt(object_table_index_);
const Code& code =
Code::Handle(deopt_context->isolate(), function.unoptimized_code());
+ ASSERT(!code.IsNull());
uword continue_at_pc = code.GetDeoptAfterPcAtDeoptId(deopt_id_);
+ ASSERT(continue_at_pc != 0);
intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
*to_addr = continue_at_pc;
}
@@ -260,7 +334,9 @@
function ^= deopt_context->ObjectAt(object_table_index_);
const Code& code =
Code::Handle(deopt_context->isolate(), function.unoptimized_code());
+ ASSERT(!code.IsNull());
uword continue_at_pc = code.GetDeoptBeforePcAtDeoptId(deopt_id_);
+ ASSERT(continue_at_pc != 0);
intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
*to_addr = continue_at_pc;
@@ -413,6 +489,72 @@
};
+// Deoptimization instruction moving an XMM register.
+class DeoptFloat32x4FpuRegisterInstr: public DeoptInstr {
+ public:
+ explicit DeoptFloat32x4FpuRegisterInstr(intptr_t reg_as_int)
+ : reg_(static_cast<FpuRegister>(reg_as_int)) {}
+
+ virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); }
+ virtual DeoptInstr::Kind kind() const { return kFloat32x4FpuRegister; }
+
+ virtual const char* ToCString() const {
+ const char* format = "%s(f32x4)";
+ intptr_t len =
+ OS::SNPrint(NULL, 0, format, Assembler::FpuRegisterName(reg_));
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(chars, len + 1, format, Assembler::FpuRegisterName(reg_));
+ return chars;
+ }
+
+ void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+ simd128_value_t value = deopt_context->FpuRegisterValueAsSimd128(reg_);
+ intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
+ *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
+ Isolate::Current()->DeferFloat32x4Materialization(
+ value, reinterpret_cast<RawFloat32x4**>(to_addr));
+ }
+
+ private:
+ const FpuRegister reg_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptFloat32x4FpuRegisterInstr);
+};
+
+
+// Deoptimization instruction moving an XMM register.
+class DeoptUint32x4FpuRegisterInstr: public DeoptInstr {
+ public:
+ explicit DeoptUint32x4FpuRegisterInstr(intptr_t reg_as_int)
+ : reg_(static_cast<FpuRegister>(reg_as_int)) {}
+
+ virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); }
+ virtual DeoptInstr::Kind kind() const { return kFloat32x4FpuRegister; }
+
+ virtual const char* ToCString() const {
+ const char* format = "%s(f32x4)";
+ intptr_t len =
+ OS::SNPrint(NULL, 0, format, Assembler::FpuRegisterName(reg_));
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(chars, len + 1, format, Assembler::FpuRegisterName(reg_));
+ return chars;
+ }
+
+ void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+ simd128_value_t value = deopt_context->FpuRegisterValueAsSimd128(reg_);
+ intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
+ *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
+ Isolate::Current()->DeferUint32x4Materialization(
+ value, reinterpret_cast<RawUint32x4**>(to_addr));
+ }
+
+ private:
+ const FpuRegister reg_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptUint32x4FpuRegisterInstr);
+};
+
+
// Deoptimization instruction creating a PC marker for the code of
// function at 'object_table_index'.
class DeoptPcMarkerInstr : public DeoptInstr {
@@ -447,7 +589,7 @@
// function occurring in the optimized frame.
function.set_deoptimization_counter(function.deoptimization_counter() + 1);
if (FLAG_trace_deoptimization) {
- OS::PrintErr("Deoptimizing inlined %s (count %d)\n",
+ OS::PrintErr("Deoptimizing %s (count %d)\n",
function.ToFullyQualifiedCString(),
function.deoptimization_counter());
}
@@ -581,7 +723,10 @@
ASSERT(func != NULL);
*func ^= object_table.At(ret_after_instr->object_table_index());
const Code& code = Code::Handle(func->unoptimized_code());
- return code.GetDeoptAfterPcAtDeoptId(ret_after_instr->deopt_id());
+ ASSERT(!code.IsNull());
+ uword res = code.GetDeoptAfterPcAtDeoptId(ret_after_instr->deopt_id());
+ ASSERT(res != 0);
+ return res;
}
@@ -591,12 +736,20 @@
case kStackSlot: return new DeoptStackSlotInstr(from_index);
case kDoubleStackSlot: return new DeoptDoubleStackSlotInstr(from_index);
case kInt64StackSlot: return new DeoptInt64StackSlotInstr(from_index);
+ case kFloat32x4StackSlot:
+ return new DeoptFloat32x4StackSlotInstr(from_index);
+ case kUint32x4StackSlot:
+ return new DeoptUint32x4StackSlotInstr(from_index);
case kRetAfterAddress: return new DeoptRetAfterAddressInstr(from_index);
case kRetBeforeAddress: return new DeoptRetBeforeAddressInstr(from_index);
case kConstant: return new DeoptConstantInstr(from_index);
case kRegister: return new DeoptRegisterInstr(from_index);
case kFpuRegister: return new DeoptFpuRegisterInstr(from_index);
case kInt64FpuRegister: return new DeoptInt64FpuRegisterInstr(from_index);
+ case kFloat32x4FpuRegister:
+ return new DeoptFloat32x4FpuRegisterInstr(from_index);
+ case kUint32x4FpuRegister:
+ return new DeoptUint32x4FpuRegisterInstr(from_index);
case kPcMarker: return new DeoptPcMarkerInstr(from_index);
case kCallerFp: return new DeoptCallerFpInstr();
case kCallerPc: return new DeoptCallerPcInstr();
@@ -664,6 +817,9 @@
void DeoptInfoBuilder::AddReturnAddressBefore(const Function& function,
intptr_t deopt_id,
intptr_t to_index) {
+ // Check that deopt_id exists.
+ ASSERT(Code::Handle(function.unoptimized_code()).
+ GetDeoptBeforePcAtDeoptId(deopt_id) != 0);
const intptr_t object_table_index = FindOrAddObjectInTable(function);
ASSERT(to_index == instructions_.length());
instructions_.Add(new DeoptRetBeforeAddressInstr(object_table_index,
@@ -691,22 +847,23 @@
void DeoptInfoBuilder::AddCopy(const Location& from_loc,
- const Value& from_value,
const intptr_t to_index) {
DeoptInstr* deopt_instr = NULL;
if (from_loc.IsConstant()) {
intptr_t object_table_index = FindOrAddObjectInTable(from_loc.constant());
deopt_instr = new DeoptConstantInstr(object_table_index);
} else if (from_loc.IsRegister()) {
+ ASSERT(from_loc.representation() == kTagged);
deopt_instr = new DeoptRegisterInstr(from_loc.reg());
} else if (from_loc.IsFpuRegister()) {
- if (from_loc.representation() == Location::kDouble) {
+ if (from_loc.representation() == kUnboxedDouble) {
deopt_instr = new DeoptFpuRegisterInstr(from_loc.fpu_reg());
} else {
- ASSERT(from_loc.representation() == Location::kMint);
+ ASSERT(from_loc.representation() == kUnboxedMint);
deopt_instr = new DeoptInt64FpuRegisterInstr(from_loc.fpu_reg());
}
} else if (from_loc.IsStackSlot()) {
+ ASSERT(from_loc.representation() == kTagged);
intptr_t from_index = (from_loc.stack_index() < 0) ?
from_loc.stack_index() + num_args_ :
from_loc.stack_index() + num_args_ - kFirstLocalSlotIndex + 1;
@@ -715,16 +872,17 @@
intptr_t from_index = (from_loc.stack_index() < 0) ?
from_loc.stack_index() + num_args_ :
from_loc.stack_index() + num_args_ - kFirstLocalSlotIndex + 1;
- if (from_loc.representation() == Location::kDouble) {
+ if (from_loc.representation() == kUnboxedDouble) {
deopt_instr = new DeoptDoubleStackSlotInstr(from_index);
} else {
- ASSERT(from_loc.representation() == Location::kMint);
+ ASSERT(from_loc.representation() == kUnboxedMint);
deopt_instr = new DeoptInt64StackSlotInstr(from_index);
}
} else {
UNREACHABLE();
}
ASSERT(to_index == instructions_.length());
+ ASSERT(deopt_instr != NULL);
instructions_.Add(deopt_instr);
}
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 134d33d..7967aa9 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -53,11 +53,16 @@
}
double FpuRegisterValue(FpuRegister reg) const {
- return fpu_registers_copy_[reg];
+ return *reinterpret_cast<double*>(&fpu_registers_copy_[reg]);
}
int64_t FpuRegisterValueAsInt64(FpuRegister reg) const {
- return (reinterpret_cast<int64_t*>(fpu_registers_copy_))[reg];
+ return *reinterpret_cast<int64_t*>(&fpu_registers_copy_[reg]);
+ }
+
+ simd128_value_t FpuRegisterValueAsSimd128(FpuRegister reg) const {
+ const float* address = reinterpret_cast<float*>(&fpu_registers_copy_[reg]);
+ return simd128_value_t().readFrom(address);
}
Isolate* isolate() const { return isolate_; }
@@ -73,7 +78,7 @@
intptr_t* from_frame_;
intptr_t from_frame_size_;
intptr_t* registers_copy_;
- double* fpu_registers_copy_;
+ fpu_register_t* fpu_registers_copy_;
const intptr_t num_args_;
const DeoptReasonId deopt_reason_;
intptr_t caller_fp_;
@@ -96,9 +101,13 @@
kRegister,
kFpuRegister,
kInt64FpuRegister,
+ kFloat32x4FpuRegister,
+ kUint32x4FpuRegister,
kStackSlot,
kDoubleStackSlot,
kInt64StackSlot,
+ kFloat32x4StackSlot,
+ kUint32x4StackSlot,
kPcMarker,
kCallerFp,
kCallerPc,
@@ -165,9 +174,7 @@
intptr_t to_index);
// Copy from optimized frame to unoptimized.
- void AddCopy(const Location& from_loc,
- const Value& from_value,
- intptr_t to_index);
+ void AddCopy(const Location& from_loc, intptr_t to_index);
void AddPcMarker(const Function& function, intptr_t to_index);
void AddCallerFp(intptr_t to_index);
void AddCallerPc(intptr_t to_index);
diff --git a/runtime/vm/disassembler.h b/runtime/vm/disassembler.h
index 9958b20..1f2a22c 100644
--- a/runtime/vm/disassembler.h
+++ b/runtime/vm/disassembler.h
@@ -60,51 +60,50 @@
// Disassemble instructions between start and end.
// (The assumption is that start is at a valid instruction).
// Return true if all instructions were successfully decoded, false otherwise.
- static bool Disassemble(uword start,
+ static void Disassemble(uword start,
uword end,
DisassemblyFormatter* formatter,
const Code::Comments& comments);
- static bool Disassemble(uword start,
+ static void Disassemble(uword start,
uword end,
DisassemblyFormatter* formatter) {
- return Disassemble(start, end, formatter, Code::Comments::New(0));
+ Disassemble(start, end, formatter, Code::Comments::New(0));
}
- static bool Disassemble(uword start,
+ static void Disassemble(uword start,
uword end,
const Code::Comments& comments) {
DisassembleToStdout stdout_formatter;
- return Disassemble(start, end, &stdout_formatter, comments);
+ Disassemble(start, end, &stdout_formatter, comments);
}
- static bool Disassemble(uword start, uword end) {
+ static void Disassemble(uword start, uword end) {
DisassembleToStdout stdout_formatter;
- return Disassemble(start, end, &stdout_formatter);
+ Disassemble(start, end, &stdout_formatter);
}
// Disassemble instructions in a memory region.
- static bool DisassembleMemoryRegion(const MemoryRegion& instructions,
+ static void DisassembleMemoryRegion(const MemoryRegion& instructions,
DisassemblyFormatter* formatter) {
uword start = instructions.start();
uword end = instructions.end();
- return Disassemble(start, end, formatter);
+ Disassemble(start, end, formatter);
}
- static bool DisassembleMemoryRegion(const MemoryRegion& instructions) {
+ static void DisassembleMemoryRegion(const MemoryRegion& instructions) {
uword start = instructions.start();
uword end = instructions.end();
- return Disassemble(start, end);
+ Disassemble(start, end);
}
// Decodes one instruction.
// Writes a hexadecimal representation into the hex_buffer and a
// human-readable representation into the human_buffer.
// Writes the length of the decoded instruction in bytes in out_instr_len.
- // Returns false if the instruction could not be decoded.
- static bool DecodeInstruction(char* hex_buffer, intptr_t hex_size,
+ static void DecodeInstruction(char* hex_buffer, intptr_t hex_size,
char* human_buffer, intptr_t human_size,
- int *out_instr_len, uword pc);
+ int* out_instr_len, uword pc);
private:
static const int kHexadecimalBufferSize = 32;
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 6cecb45..067f069 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -15,8 +15,7 @@
ARMDecoder(char* buffer, size_t buffer_size)
: buffer_(buffer),
buffer_size_(buffer_size),
- buffer_pos_(0),
- decode_failure_(false) {
+ buffer_pos_(0) {
buffer_[buffer_pos_] = '\0';
}
@@ -26,9 +25,6 @@
// Returns true if the instruction was successfully decoded, false otherwise.
void InstructionDecode(uword pc);
- void set_decode_failure(bool b) { decode_failure_ = b; }
- bool decode_failure() const { return decode_failure_; }
-
private:
// Bottleneck functions to print into the out_buffer.
void Print(const char* str);
@@ -71,8 +67,6 @@
size_t buffer_size_; // The size of the character buffer.
size_t buffer_pos_; // Current character position in buffer.
- bool decode_failure_; // Set to true when a failure to decode is detected.
-
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(ARMDecoder);
};
@@ -579,7 +573,6 @@
// which will just print "unknown" of the instruction bits.
void ARMDecoder::Unknown(Instr* instr) {
Format(instr, "unknown");
- set_decode_failure(true);
}
@@ -1267,9 +1260,9 @@
}
-bool Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
- char* human_buffer, intptr_t human_size,
- int* out_instr_size, uword pc) {
+void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
+ char* human_buffer, intptr_t human_size,
+ int* out_instr_size, uword pc) {
ARMDecoder decoder(human_buffer, human_size);
decoder.InstructionDecode(pc);
int32_t instruction_bits = Instr::At(pc)->InstructionBits();
@@ -1277,16 +1270,14 @@
if (out_instr_size) {
*out_instr_size = Instr::kInstrSize;
}
- return !decoder.decode_failure();
}
-bool Disassembler::Disassemble(uword start,
+void Disassembler::Disassemble(uword start,
uword end,
DisassemblyFormatter* formatter,
const Code::Comments& comments) {
ASSERT(formatter != NULL);
- bool success = true;
char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form.
char human_buffer[kUserReadableBufferSize]; // Human-readable instruction.
uword pc = start;
@@ -1301,12 +1292,10 @@
comment_finger++;
}
int instruction_length;
- bool res = DecodeInstruction(hex_buffer, sizeof(hex_buffer),
- human_buffer, sizeof(human_buffer),
- &instruction_length, pc);
- if (!res) {
- success = false;
- }
+ DecodeInstruction(hex_buffer, sizeof(hex_buffer),
+ human_buffer, sizeof(human_buffer),
+ &instruction_length, pc);
+
formatter->ConsumeInstruction(hex_buffer,
sizeof(hex_buffer),
human_buffer,
@@ -1314,8 +1303,6 @@
pc);
pc += instruction_length;
}
-
- return success;
}
} // namespace dart
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 9aa3a49..f17d0c7 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -1744,9 +1744,9 @@
}
-bool Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
- char* human_buffer, intptr_t human_size,
- int* out_instr_len, uword pc) {
+void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
+ char* human_buffer, intptr_t human_size,
+ int* out_instr_len, uword pc) {
ASSERT(hex_size > 0);
ASSERT(human_size > 0);
X86Decoder decoder(human_buffer, human_size);
@@ -1763,11 +1763,10 @@
if (out_instr_len) {
*out_instr_len = instruction_length;
}
- return true;
}
-bool Disassembler::Disassemble(uword start,
+void Disassembler::Disassemble(uword start,
uword end,
DisassemblyFormatter* formatter,
const Code::Comments& comments) {
@@ -1799,7 +1798,7 @@
pc += instruction_length;
}
- return true;
+ return;
}
} // namespace dart
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index d7a83c0..ff74333 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -15,8 +15,7 @@
MIPSDecoder(char* buffer, size_t buffer_size)
: buffer_(buffer),
buffer_size_(buffer_size),
- buffer_pos_(0),
- decode_failure_(false) {
+ buffer_pos_(0) {
buffer_[buffer_pos_] = '\0';
}
@@ -26,9 +25,6 @@
// Returns true if the instruction was successfully decoded, false otherwise.
void InstructionDecode(Instr* instr);
- void set_decode_failure(bool b) { decode_failure_ = b; }
- bool decode_failure() const { return decode_failure_; }
-
private:
// Bottleneck functions to print into the out_buffer.
void Print(const char* str);
@@ -43,6 +39,7 @@
void DecodeSpecial(Instr* instr);
void DecodeSpecial2(Instr* instr);
+ void DecodeRegImm(Instr* instr);
// Convenience functions.
char* get_buffer() const { return buffer_; }
@@ -53,8 +50,6 @@
size_t buffer_size_; // The size of the character buffer.
size_t buffer_pos_; // Current character position in buffer.
- bool decode_failure_; // Set to true when a failure to decode is detected.
-
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(MIPSDecoder);
};
@@ -143,6 +138,16 @@
}
return 4;
}
+ case 'd': {
+ ASSERT(STRING_STARTS_WITH(format, "dest"));
+ int off = instr->SImmField() << 2;
+ uword destination = reinterpret_cast<uword>(instr) + off;
+ buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+ remaining_size_in_buffer(),
+ "%#"Px"",
+ destination);
+ return 4;
+ }
case 'i': {
ASSERT(STRING_STARTS_WITH(format, "imm"));
if (format[3] == 'u') {
@@ -202,7 +207,6 @@
// which will just print "unknown" of the instruction bits.
void MIPSDecoder::Unknown(Instr* instr) {
Format(instr, "unknown");
- set_decode_failure(true);
}
@@ -229,6 +233,14 @@
Format(instr, "divu 'rs, 'rt");
break;
}
+ case JALR: {
+ Format(instr, "jalr'hint 'rd, 'rs");
+ break;
+ }
+ case JR: {
+ Format(instr, "jr'hint 'rs");
+ break;
+ }
case MFHI: {
Format(instr, "mfhi 'rd");
break;
@@ -237,6 +249,38 @@