Version 1.15.0-dev.0.0
Merge commit '6a4903f20174697d732b6b6afbfd87c04fde47f8' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3fffad..7702384 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.15.0
+
+### Core library changes
+ * Added `Uri.queryParametersAll` to handle multiple query parameters with
+ the same name.
+
## 1.14.0
### Core library changes
@@ -10,8 +16,10 @@
* `dart:core`
* Added `current` getter to `StackTrace` class.
- * Added `Uri.data` getter for `data:` URIs, and `UriData` class for the
- return type.
+ * `Uri` class added support for data URIs
+ * Added two new constructors: `dataFromBytes` and `dataFromString`.
+ * Added a `data` getter for `data:` URIs with a new `UriData` class for
+ the return type.
* Added `growable` parameter to `List.filled` constructor.
* Added microsecond support to `DateTime`: `DateTime.microsecond`,
`DateTime.microsecondsSinceEpoch`, and
@@ -23,14 +31,25 @@
embedder for every generated random value.
* `dart:io`
- * `Platform` added an `isIOS` getter and `Platform.operatingSystem` may now
- return `ios`.
- * Added support for WebSocket compression as standardized in RFC 7692. By
- default compression is turned on for all WebSocket connections. The
- optionally named parameter `compression` on the methods `WebSocket.connect`,
- `WebSocket.fromUpgradedSocket`, and `WebSocketTransformer.upgrade` and on
- the `WebSocketTransformer` constructor is used to select the compression
- options.
+ * `Platform` added a static `isIOS` getter and `Platform.operatingSystem` may
+ now return `ios`.
+ * `Platform` added a static `packageConfig` getter.
+ * Added support for WebSocket compression as standardized in RFC 7692.
+ * Compression is enabled by default for all WebSocket connections.
+ * The optionally named parameter `compression` on the methods
+ `WebSocket.connect`, `WebSocket.fromUpgradedSocket`, and
+ `WebSocketTransformer.upgrade` and the `WebSocketTransformer`
+ constructor can be used to modify or disable compression using the new
+ `CompressionOptions` class.
+
+* `dart:isolate`
+ * Added **_experimental_** support for [Package Resolution Configuration].
+ * Added `packageConfig` and `packageRoot` instance getters to `Isolate`.
+ * Added a `resolvePackageUri` method to `Isolate`.
+ * Added named arguments `packageConfig` and `automaticPackageResolution` to
+ the `Isolate.spawnUri` constructor.
+
+[Package Resolution Configuration File]: https://github.com/dart-lang/dart_enhancement_proposals/blob/master/Accepted/0005%20-%20Package%20Specification/DEP-pkgspec.md
### Tool changes
diff --git a/DEPS b/DEPS
index fbe59dc..fdb11dc 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
"dart2js_info_rev" : "@0a221eaf16aec3879c45719de656680ccb80d8a1",
"dartdoc_tag" : "@v0.8.5",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
- "dart_style_tag": "@0.2.2",
+ "dart_style_tag": "@0.2.4",
"dev_compiler_rev": "@0.1.9",
"glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
"html_tag" : "@0.12.1+1",
@@ -86,7 +86,6 @@
"test_tag": "@0.12.6+1",
"test_reflective_loader_tag": "@0.0.3",
"utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
- "unittest_tag": "@0.11.6",
"usage_rev": "@b5080dac0d26a5609b266f8fdb0d053bc4c1c638",
"watcher_tag": "@0.9.7",
"when_tag": "@0.2.0+2",
@@ -256,8 +255,6 @@
Var("dart_root") + "/third_party/pkg/test_reflective_loader":
(Var("github_mirror") % "test_reflective_loader") +
Var("test_reflective_loader_tag"),
- Var("dart_root") + "/third_party/pkg/unittest":
- (Var("github_mirror") % "test") + Var("unittest_tag"),
Var("dart_root") + "/third_party/pkg/usage":
(Var("github_mirror") % "usage") + Var("usage_rev"),
Var("dart_root") + "/third_party/pkg/utf":
@@ -384,6 +381,22 @@
],
},
{
+ "name": "unittest",
+ # Unittest is an early version, 0.11.6, of the package "test"
+ # Do not use it in any new tests.
+ "pattern": ".",
+ "action": [
+ "download_from_google_storage",
+ "--no_auth",
+ "--no_resume",
+ "--bucket",
+ "dart-dependencies",
+ "--extract",
+ "-s",
+ Var('dart_root') + "/third_party/pkg/unittest.tar.gz.sha1",
+ ],
+ },
+ {
"name": "7zip",
"pattern": ".",
"action": [
diff --git a/dart.gyp b/dart.gyp
index 3e73877..a0c5a85 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -25,7 +25,7 @@
'type': 'none',
'dependencies': [
'runtime/dart-runtime.gyp:dart',
- 'runtime/dart-runtime.gyp:dart_precompiled',
+ 'runtime/dart-runtime.gyp:dart_precompiled_runtime',
'runtime/dart-runtime.gyp:dart_no_snapshot',
'runtime/dart-runtime.gyp:run_vm_tests',
'runtime/dart-runtime.gyp:process_test',
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index fb3a9e4..25a0c0d 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -1547,7 +1547,7 @@
Any expression that appears within the initializer list of a constant constructor must be a potentially constant expression, or a compile-time error occurs.
\LMHash{}
-A {\em potentially constant expression} is an expression $e$ that would be a valid constant expression if all formal parameters of $e$'s immediately enclosing constant constructor were treated as compile-time constants that were guaranteed to evaluate to an integer, boolean or string value as required by their immediately enclosing superexpression.
+A {\em potentially constant expression} is an expression $e$ that would be a valid constant expression if all formal parameters of $e$'s immediately enclosing constant constructor were treated as compile-time constants that were guaranteed to evaluate to an integer, boolean or string value as required by their immediately enclosing superexpression, <em>and</em> where $e$ is also a valid expression if all the formal parameters are treated as non-constant variables.
\commentary{
Note that a parameter that is not used in a superexpression that is restricted to certain types can be a constant of any type. For example}
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
index 2da3812..863ced0 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
@@ -61,7 +61,7 @@
return Assist.EMPTY_LIST;
}
CompilationUnit unit =
- analysisContext.resolveCompilationUnit2(source, libraries[0]);
+ analysisContext.getResolvedCompilationUnit2(source, libraries[0]);
if (unit == null) {
return Assist.EMPTY_LIST;
}
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index e8f7104..6ef1bed 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -44,7 +44,7 @@
return Fix.EMPTY_LIST;
}
CompilationUnit unit =
- analysisContext.resolveCompilationUnit2(source, libraries[0]);
+ analysisContext.getResolvedCompilationUnit2(source, libraries[0]);
if (unit == null) {
return Fix.EMPTY_LIST;
}
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 45467ca..02c4f70 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/plugin/protocol/protocol.dart'
show HoverInformation;
+import 'package:analysis_server/src/computer/computer_overrides.dart';
import 'package:analysis_server/src/utilities/documentation.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/ast.dart';
@@ -69,7 +70,6 @@
hover.containingLibraryPath = library.source.fullName;
}
}
-
// documentation
hover.dartdoc = _computeDocumentation(element);
}
@@ -91,7 +91,23 @@
if (element is ParameterElement) {
element = element.enclosingElement;
}
- return removeDartDocDelimiters(element.documentationComment);
+ // The documentation of the element itself.
+ if (element.documentationComment != null) {
+ return removeDartDocDelimiters(element.documentationComment);
+ }
+ // Look for documentation comments of overridden members.
+ OverriddenElements overridden = findOverriddenElements(element);
+ for (Element superElement in []
+ ..addAll(overridden.superElements)
+ ..addAll(overridden.interfaceElements)) {
+ String rawDoc = superElement.documentationComment;
+ if (rawDoc != null) {
+ Element interfaceClass = superElement.enclosingElement;
+ return removeDartDocDelimiters(rawDoc) +
+ '\n\nCopied from `${interfaceClass.displayName}`.';
+ }
+ }
+ return null;
}
static _safeToString(obj) => obj != null ? obj.toString() : null;
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index 4e2e00b..4eb93d1 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -5,15 +5,106 @@
library computer.overrides;
import 'package:analysis_server/src/collections.dart';
-import 'package:analysis_server/src/protocol_server.dart';
-import 'package:analyzer/dart/element/element.dart' as engine;
-import 'package:analyzer/dart/element/type.dart' as engine;
+import 'package:analysis_server/src/protocol_server.dart' as proto;
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/generated/ast.dart';
/**
+ * Return the elements that the given [element] overrides.
+ */
+OverriddenElements findOverriddenElements(Element element) {
+ if (element?.enclosingElement is ClassElement) {
+ return new _OverriddenElementsFinder(element).find();
+ }
+ return new OverriddenElements(element, <Element>[], <Element>[]);
+}
+
+/**
* A computer for class member overrides in a Dart [CompilationUnit].
*/
class DartUnitOverridesComputer {
+ final CompilationUnit _unit;
+ final List<proto.Override> _overrides = <proto.Override>[];
+
+ DartUnitOverridesComputer(this._unit);
+
+ /**
+ * Returns the computed occurrences, not `null`.
+ */
+ List<proto.Override> compute() {
+ for (CompilationUnitMember unitMember in _unit.declarations) {
+ if (unitMember is ClassDeclaration) {
+ for (ClassMember classMember in unitMember.members) {
+ if (classMember is MethodDeclaration) {
+ if (classMember.isStatic) {
+ continue;
+ }
+ _addOverride(classMember.name);
+ }
+ if (classMember is FieldDeclaration) {
+ if (classMember.isStatic) {
+ continue;
+ }
+ List<VariableDeclaration> fields = classMember.fields.variables;
+ for (VariableDeclaration field in fields) {
+ _addOverride(field.name);
+ }
+ }
+ }
+ }
+ }
+ return _overrides;
+ }
+
+ /**
+ * Add a new [Override] for the declaration with the given name [node].
+ */
+ void _addOverride(SimpleIdentifier node) {
+ Element element = node.staticElement;
+ OverriddenElements overridesResult =
+ new _OverriddenElementsFinder(element).find();
+ List<Element> superElements = overridesResult.superElements;
+ List<Element> interfaceElements = overridesResult.interfaceElements;
+ if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
+ proto.OverriddenMember superMember = superElements.isNotEmpty
+ ? proto.newOverriddenMember_fromEngine(superElements.first)
+ : null;
+ List<proto.OverriddenMember> interfaceMembers = interfaceElements
+ .map((member) => proto.newOverriddenMember_fromEngine(member))
+ .toList();
+ _overrides.add(new proto.Override(node.offset, node.length,
+ superclassMember: superMember,
+ interfaceMembers: nullIfEmpty(interfaceMembers)));
+ }
+ }
+}
+
+/**
+ * The container with elements that a class member overrides.
+ */
+class OverriddenElements {
+ /**
+ * The element that overrides other class members.
+ */
+ final Element element;
+
+ /**
+ * The elements that [element] overrides and which is defined in a class that
+ * is a superclass of the class that defines [element].
+ */
+ final List<Element> superElements;
+
+ /**
+ * The elements that [element] overrides and which is defined in a class that
+ * which is implemented by the class that defines [element].
+ */
+ final List<Element> interfaceElements;
+
+ OverriddenElements(this.element, this.superElements, this.interfaceElements);
+}
+
+class _OverriddenElementsFinder {
static const List<ElementKind> FIELD_KINDS = const <ElementKind>[
ElementKind.FIELD,
ElementKind.GETTER,
@@ -34,138 +125,102 @@
ElementKind.SETTER
];
- final CompilationUnit _unit;
+ Element _seed;
+ LibraryElement _library;
+ ClassElement _class;
+ String _name;
+ List<ElementKind> _kinds;
- final List<Override> _overrides = <Override>[];
- engine.ClassElement _currentClass;
+ List<Element> _superElements = <Element>[];
+ List<Element> _interfaceElements = <Element>[];
+ Set<InterfaceType> _visited = new Set<InterfaceType>();
- DartUnitOverridesComputer(this._unit);
-
- /**
- * Returns the computed occurrences, not `null`.
- */
- List<Override> compute() {
- for (CompilationUnitMember unitMember in _unit.declarations) {
- if (unitMember is ClassDeclaration) {
- _currentClass = unitMember.element;
- for (ClassMember classMember in unitMember.members) {
- if (classMember is MethodDeclaration) {
- if (classMember.isStatic) {
- continue;
- }
- SimpleIdentifier nameNode = classMember.name;
- List<ElementKind> kinds;
- if (classMember.isGetter) {
- kinds = GETTER_KINDS;
- } else if (classMember.isSetter) {
- kinds = SETTER_KINDS;
- } else {
- kinds = METHOD_KINDS;
- }
- _addOverride(
- nameNode.offset, nameNode.length, nameNode.name, kinds);
- }
- if (classMember is FieldDeclaration) {
- if (classMember.isStatic) {
- continue;
- }
- List<VariableDeclaration> fields = classMember.fields.variables;
- for (VariableDeclaration field in fields) {
- SimpleIdentifier nameNode = field.name;
- _addOverride(
- nameNode.offset, nameNode.length, nameNode.name, FIELD_KINDS);
- }
- }
- }
- }
+ _OverriddenElementsFinder(Element seed) {
+ _seed = seed;
+ _class = seed.enclosingElement;
+ _library = _class.library;
+ _name = seed.displayName;
+ if (seed is MethodElement) {
+ _kinds = METHOD_KINDS;
+ } else if (seed is PropertyAccessorElement) {
+ _kinds = seed.isGetter ? GETTER_KINDS : SETTER_KINDS;
+ } else {
+ _kinds = FIELD_KINDS;
}
- return _overrides;
}
- void _addInterfaceOverrides(
- Set<engine.Element> elements,
- String name,
- List<ElementKind> kinds,
- engine.InterfaceType type,
- bool checkType,
- Set<engine.InterfaceType> visited) {
+ /**
+ * Add the [OverriddenElements] for this element.
+ */
+ OverriddenElements find() {
+ _visited.clear();
+ _addSuperOverrides(_class.supertype);
+ _visited.clear();
+ _addInterfaceOverrides(_class.type, false);
+ _superElements.forEach(_interfaceElements.remove);
+ return new OverriddenElements(_seed, _superElements, _interfaceElements);
+ }
+
+ void _addInterfaceOverrides(InterfaceType type, bool checkType) {
if (type == null) {
return;
}
- if (!visited.add(type)) {
+ if (!_visited.add(type)) {
return;
}
- // check type
+ // this type
if (checkType) {
- engine.Element element = _lookupMember(type.element, name, kinds);
- if (element != null) {
- elements.add(element);
- return;
- }
- }
- // check interfaces
- for (engine.InterfaceType interfaceType in type.interfaces) {
- _addInterfaceOverrides(
- elements, name, kinds, interfaceType, true, visited);
- }
- // check super
- _addInterfaceOverrides(
- elements, name, kinds, type.superclass, checkType, visited);
- }
-
- void _addOverride(
- int offset, int length, String name, List<ElementKind> kinds) {
- // super
- engine.Element superEngineElement;
- {
- engine.InterfaceType superType = _currentClass.supertype;
- if (superType != null) {
- superEngineElement = _lookupMember(superType.element, name, kinds);
+ Element element = _lookupMember(type.element);
+ if (element != null && !_interfaceElements.contains(element)) {
+ _interfaceElements.add(element);
}
}
// interfaces
- Set<engine.Element> interfaceEngineElements = new Set<engine.Element>();
- _addInterfaceOverrides(interfaceEngineElements, name, kinds,
- _currentClass.type, false, new Set<engine.InterfaceType>());
- interfaceEngineElements.remove(superEngineElement);
- // is there any override?
- if (superEngineElement != null || interfaceEngineElements.isNotEmpty) {
- OverriddenMember superMember = superEngineElement != null
- ? newOverriddenMember_fromEngine(superEngineElement)
- : null;
- List<OverriddenMember> interfaceMembers = interfaceEngineElements
- .map((member) => newOverriddenMember_fromEngine(member))
- .toList();
- _overrides.add(new Override(offset, length,
- superclassMember: superMember,
- interfaceMembers: nullIfEmpty(interfaceMembers)));
+ for (InterfaceType interfaceType in type.interfaces) {
+ _addInterfaceOverrides(interfaceType, true);
}
+ // super
+ _addInterfaceOverrides(type.superclass, checkType);
}
- static engine.Element _lookupMember(
- engine.ClassElement classElement, String name, List<ElementKind> kinds) {
+ void _addSuperOverrides(InterfaceType type) {
+ if (type == null) {
+ return;
+ }
+ if (!_visited.add(type)) {
+ return;
+ }
+ // this type
+ Element element = _lookupMember(type.element);
+ if (element != null && !_superElements.contains(element)) {
+ _superElements.add(element);
+ }
+ // super
+ _addSuperOverrides(type.superclass);
+ }
+
+ Element _lookupMember(ClassElement classElement) {
if (classElement == null) {
return null;
}
- engine.LibraryElement library = classElement.library;
- engine.Element member;
+ Element member;
// method
- if (kinds.contains(ElementKind.METHOD)) {
- member = classElement.lookUpMethod(name, library);
+ if (_kinds.contains(ElementKind.METHOD)) {
+ member = classElement.lookUpMethod(_name, _library);
if (member != null) {
return member;
}
}
// getter
- if (kinds.contains(ElementKind.GETTER)) {
- member = classElement.lookUpGetter(name, library);
+ if (_kinds.contains(ElementKind.GETTER)) {
+ member = classElement.lookUpGetter(_name, _library);
if (member != null) {
return member;
}
}
// setter
- if (kinds.contains(ElementKind.SETTER)) {
- member = classElement.lookUpSetter(name + '=', library);
+ if (_kinds.contains(ElementKind.SETTER)) {
+ member = classElement.lookUpSetter(_name + '=', _library);
if (member != null) {
return member;
}
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index 5391d5e..42e7213 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -57,21 +57,23 @@
if (element.isSynthetic || _isStatic(element)) {
return;
}
- String name = element.displayName;
- if (name != null && _hasOverride(name)) {
+ if (_hasOverride(element)) {
_addImplementedMember(element);
}
}
- bool _hasOverride(String name) {
+ bool _hasOverride(Element element) {
+ String name = element.displayName;
+ LibraryElement library = element.library;
for (ClassElement subtype in subtypes) {
- MethodElement method = subtype.getMethod(name);
- if (method != null) {
- return !method.isStatic;
+ ClassMemberElement subElement = subtype.getMethod(name);
+ if (subElement == null) {
+ subElement = subtype.getField(name);
}
- FieldElement field = subtype.getField(name);
- if (field != null) {
- return !field.isStatic;
+ if (subElement != null &&
+ !subElement.isStatic &&
+ subElement.isAccessibleIn(library)) {
+ return true;
}
}
return false;
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index 793e471..e723722 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -175,7 +175,7 @@
result = clazz.getSetter(_pivotName);
}
}
- if (result != null) {
+ if (result != null && result.isAccessibleIn(_pivotLibrary)) {
return result;
}
// try to find in the class mixin
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 5833af4..664ab74 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -46,8 +46,9 @@
// create logger
if (spec == 'console') {
logger = new StringSinkLogger(stdout);
- }
- if (spec.startsWith('file:')) {
+ } else if (spec == 'stderr') {
+ logger = new StringSinkLogger(stderr);
+ } else if (spec.startsWith('file:')) {
String fileName = spec.substring('file:'.length);
File file = new File(fileName);
IOSink sink = file.openWrite();
@@ -485,7 +486,7 @@
defaultsTo: false,
negatable: false);
parser.addOption(INCREMENTAL_RESOLUTION_LOG,
- help: "the description of the incremental resolution log");
+ help: "set a destination for the incremental resolver's log");
parser.addFlag(INCREMENTAL_RESOLUTION_VALIDATION,
help: "enable validation of incremental resolution results (slow)",
defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index a683638..13714ae 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -1092,17 +1092,15 @@
Block targetBlock;
{
Statement statement = node.getAncestor((n) => n is Statement);
- prefix = utils.getNodePrefix(statement);
if (statement is IfStatement && statement.thenStatement is Block) {
targetBlock = statement.thenStatement;
- }
- if (statement is WhileStatement && statement.body is Block) {
+ } else if (statement is WhileStatement && statement.body is Block) {
targetBlock = statement.body;
+ } else {
+ _coverageMarker();
+ return;
}
- }
- if (targetBlock == null) {
- _coverageMarker();
- return;
+ prefix = utils.getNodePrefix(statement);
}
// prepare location
int offset;
diff --git a/pkg/analysis_server/lib/src/services/correction/strings.dart b/pkg/analysis_server/lib/src/services/correction/strings.dart
index 1689c7c..4a0ff76 100644
--- a/pkg/analysis_server/lib/src/services/correction/strings.dart
+++ b/pkg/analysis_server/lib/src/services/correction/strings.dart
@@ -201,6 +201,10 @@
return str == null || str.isEmpty;
}
+bool isEOL(int c) {
+ return c == 0x0D || c == 0x0A;
+}
+
bool isLetter(int c) {
return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A);
}
@@ -220,7 +224,7 @@
}
bool isWhitespace(int c) {
- return isSpace(c) || c == 0x0D || c == 0x0A;
+ return isSpace(c) || isEOL(c);
}
String remove(String str, String remove) {
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 33a3105..63aefd9 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -396,17 +396,14 @@
*/
Expression getNodeQualifier(SimpleIdentifier node) {
AstNode parent = node.parent;
- if (parent is PropertyAccess) {
- PropertyAccess propertyAccess = parent;
- if (identical(propertyAccess.propertyName, node)) {
- return propertyAccess.target;
- }
+ if (parent is MethodInvocation && identical(parent.methodName, node)) {
+ return parent.target;
}
- if (parent is PrefixedIdentifier) {
- PrefixedIdentifier prefixed = parent;
- if (identical(prefixed.identifier, node)) {
- return prefixed.prefix;
- }
+ if (parent is PropertyAccess && identical(parent.propertyName, node)) {
+ return parent.target;
+ }
+ if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
+ return parent.prefix;
}
return null;
}
@@ -667,7 +664,8 @@
AstNode enclosingNode = findNode(offset);
Block enclosingBlock = enclosingNode.getAncestor((node) => node is Block);
if (enclosingBlock != null) {
- _CollectReferencedUnprefixedNames visitor = new _CollectReferencedUnprefixedNames();
+ _CollectReferencedUnprefixedNames visitor =
+ new _CollectReferencedUnprefixedNames();
enclosingBlock.accept(visitor);
return visitor.names;
}
@@ -906,10 +904,14 @@
* Returns a [SourceRange] that covers [range] and extends (if possible) to
* cover whole lines.
*/
- SourceRange getLinesRange(SourceRange range) {
+ SourceRange getLinesRange(SourceRange range,
+ {bool skipLeadingEmptyLines: false}) {
// start
int startOffset = range.offset;
int startLineOffset = getLineContentStart(startOffset);
+ if (skipLeadingEmptyLines) {
+ startLineOffset = skipEmptyLinesLeft(startLineOffset);
+ }
// end
int endOffset = range.end;
int afterEndLineOffset = getLineContentEnd(endOffset);
@@ -1224,6 +1226,27 @@
}
/**
+ * Skip spaces, tabs and EOLs on the left from [index].
+ *
+ * If [index] is the start of a method, then in the most cases return the end
+ * of the previous not-whitespace line.
+ */
+ int skipEmptyLinesLeft(int index) {
+ int lastLine = index;
+ while (index > 0) {
+ int c = _buffer.codeUnitAt(index - 1);
+ if (!isWhitespace(c)) {
+ return lastLine;
+ }
+ if (isEOL(c)) {
+ lastLine = index;
+ }
+ index--;
+ }
+ return 0;
+ }
+
+ /**
* @return the [ImportElement] used to import given [Element] into [library].
* May be `null` if was not imported, i.e. declared in the same library.
*/
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index 3b3c786..125c7ba 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -102,7 +102,7 @@
}
});
// replace static field "qualifier" with invocation target
- part._staticFieldOffsets.forEach((String className, List<int> offsets) {
+ part._implicitClassNameOffsets.forEach((String className, List<int> offsets) {
for (int offset in offsets) {
// edits.add(newSourceEdit_range(range, className + '.'));
edits.add(new SourceEdit(offset, 0, className + '.'));
@@ -263,7 +263,8 @@
// delete method
if (deleteSource && inlineAll) {
SourceRange methodRange = rangeNode(_methodNode);
- SourceRange linesRange = _methodUtils.getLinesRange(methodRange);
+ SourceRange linesRange =
+ _methodUtils.getLinesRange(methodRange, skipLeadingEmptyLines: true);
doSourceChange_addElementEdit(
change, _methodElement, newSourceEdit_range(linesRange, ''));
}
@@ -682,9 +683,9 @@
final List<int> _implicitThisOffsets = [];
/**
- * The offsets of the implicit class references in static field references.
+ * The offsets of the implicit class references in static member references.
*/
- final Map<String, List<int>> _staticFieldOffsets = {};
+ final Map<String, List<int>> _implicitClassNameOffsets = {};
_SourcePart(this._base, this._source, this._prefix);
@@ -692,6 +693,15 @@
_explicitThisOffsets.add(offset - _base);
}
+ void addImplicitClassNameOffset(String className, int offset) {
+ List<int> offsets = _implicitClassNameOffsets[className];
+ if (offsets == null) {
+ offsets = [];
+ _implicitClassNameOffsets[className] = offsets;
+ }
+ offsets.add(offset - _base);
+ }
+
void addImplicitThisOffset(int offset) {
_implicitThisOffsets.add(offset - _base);
}
@@ -709,15 +719,6 @@
}
}
- void addStaticFieldOffset(String className, int offset) {
- List<int> offsets = _staticFieldOffsets[className];
- if (offsets == null) {
- offsets = [];
- _staticFieldOffsets[className] = offsets;
- }
- offsets.add(offset - _base);
- }
-
void addVariable(VariableElement element, SourceRange range) {
List<SourceRange> ranges = _variables[element];
if (ranges == null) {
@@ -765,7 +766,7 @@
visitSimpleIdentifier(SimpleIdentifier node) {
SourceRange nodeRange = rangeNode(node);
if (bodyRange.covers(nodeRange)) {
- _addInstanceFieldQualifier(node);
+ _addMemberQualifier(node);
_addParameter(node);
_addVariable(node);
}
@@ -779,19 +780,28 @@
}
}
- void _addInstanceFieldQualifier(SimpleIdentifier node) {
- PropertyAccessorElement accessor = getPropertyAccessorElement(node);
- if (isFieldAccessorElement(accessor)) {
- AstNode qualifier = getNodeQualifier(node);
- if (qualifier == null) {
- int offset = node.offset;
- if (accessor.isStatic) {
- String className = accessor.enclosingElement.displayName;
- result.addStaticFieldOffset(className, offset);
- } else {
- result.addImplicitThisOffset(offset);
- }
- }
+ void _addMemberQualifier(SimpleIdentifier node) {
+ // should be unqualified
+ AstNode qualifier = getNodeQualifier(node);
+ if (qualifier != null) {
+ return;
+ }
+ // should be a method or field reference
+ Element element = node.staticElement;
+ if (!(element is MethodElement || element is PropertyAccessorElement)) {
+ return;
+ }
+ if (element.enclosingElement is! ClassElement) {
+ return;
+ }
+ // record the implicit static or instance reference
+ ExecutableElement member = element;
+ int offset = node.offset;
+ if (member.isStatic) {
+ String className = member.enclosingElement.displayName;
+ result.addImplicitClassNameOffset(className, offset);
+ } else {
+ result.addImplicitThisOffset(offset);
}
}
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 7260013..b20d642 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -65,10 +65,10 @@
int totalDocSpan = 0;
void visit(Element element) {
- SourceRange docRange = element.docRange;
- if (docRange != null) {
+ String comment = element.documentationComment;
+ if (comment != null) {
++elementsWithDocs;
- totalDocSpan += docRange.length;
+ totalDocSpan += comment.length;
}
Type type = element.runtimeType;
@@ -639,8 +639,16 @@
Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
Map<String, int> sourceTypeCounts = new HashMap<String, int>();
Map<String, int> typeCounts = new HashMap<String, int>();
+ int explicitSourceCount = 0;
+ int explicitLineInfoCount = 0;
+ int explicitLineCount = 0;
+ int implicitSourceCount = 0;
+ int implicitLineInfoCount = 0;
+ int implicitLineCount = 0;
analysisServer.folderMap
.forEach((Folder folder, InternalAnalysisContext context) {
+ Set<Source> explicitSources = new HashSet<Source>();
+ Set<Source> implicitSources = new HashSet<Source>();
AnalysisCache cache = context.analysisCache;
MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
while (iterator.moveNext()) {
@@ -651,8 +659,10 @@
String sourceName;
if (AnalysisEngine.isDartFileName(name)) {
if (iterator.value.explicitlyAdded) {
+ explicitSources.add(target);
sourceName = 'Dart file (explicit)';
} else {
+ implicitSources.add(target);
sourceName = 'Dart file (implicit)';
}
} else if (AnalysisEngine.isHtmlFileName(name)) {
@@ -677,6 +687,26 @@
}
}
}
+
+ int lineCount(Set<Source> sources, bool explicit) {
+ return sources.fold(0, (int previousTotal, Source source) {
+ LineInfo lineInfo = context.getLineInfo(source);
+ if (lineInfo is LineInfoWithCount) {
+ if (explicit) {
+ explicitLineInfoCount++;
+ } else {
+ implicitLineInfoCount++;
+ }
+ return previousTotal + lineInfo.lineCount;
+ } else {
+ return previousTotal;
+ }
+ });
+ }
+ explicitSourceCount += explicitSources.length;
+ explicitLineCount += lineCount(explicitSources, true);
+ implicitSourceCount += implicitSources.length;
+ implicitLineCount += lineCount(implicitSources, false);
});
List<String> sourceTypeNames = sourceTypeCounts.keys.toList();
sourceTypeNames.sort();
@@ -697,6 +727,37 @@
classes: [null, "right"]);
}
buffer.write('</table>');
+
+ buffer.write('<p><b>Line counts</b></p>');
+ buffer.write(
+ '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+ _writeRow(buffer, ['Kind', 'Lines of Code', 'Source Counts'],
+ header: true);
+ _writeRow(buffer, [
+ 'Explicit',
+ explicitLineCount.toString(),
+ '$explicitLineInfoCount / $explicitSourceCount'
+ ], classes: [
+ null,
+ "right"
+ ]);
+ _writeRow(buffer, [
+ 'Implicit',
+ implicitLineCount.toString(),
+ '$implicitLineInfoCount / $implicitSourceCount'
+ ], classes: [
+ null,
+ "right"
+ ]);
+ _writeRow(buffer, [
+ 'Total',
+ (explicitLineCount + implicitLineCount).toString(),
+ '${explicitLineInfoCount + implicitLineInfoCount} / ${explicitSourceCount + implicitSourceCount}'
+ ], classes: [
+ null,
+ "right"
+ ]);
+ buffer.write('</table>');
}, (StringBuffer buffer) {
//
// Write task model timing information.
@@ -1293,9 +1354,16 @@
buffer.write('<p><b>Error Processor count</b>: $processorCount</p>');
});
- _writeFiles(buffer, 'Priority Files', priorityNames);
- _writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames);
- _writeFiles(buffer, 'Implicitly Analyzed Files', implicitNames);
+ _writeFiles(
+ buffer, 'Priority Files (${priorityNames.length})', priorityNames);
+ _writeFiles(
+ buffer,
+ 'Explicitly Analyzed Files (${explicitNames.length})',
+ explicitNames);
+ _writeFiles(
+ buffer,
+ 'Implicitly Analyzed Files (${implicitNames.length})',
+ implicitNames);
buffer.write('<h3>Exceptions</h3>');
if (exceptions.isEmpty) {
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index cc1a4e4..672e9f2 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -96,6 +96,71 @@
expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
}
+ test_dartdoc_inherited_methodByMethod_fromInterface() async {
+ addTestFile('''
+class A {
+ /// my doc
+ m() {} // in A
+}
+
+class B implements A {
+ m() {} // in B
+}
+''');
+ HoverInformation hover = await prepareHover('m() {} // in B');
+ expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+ }
+
+ test_dartdoc_inherited_methodByMethod_fromSuper_direct() async {
+ addTestFile('''
+class A {
+ /// my doc
+ m() {} // in A
+}
+
+class B extends A {
+ m() {} // in B
+}
+''');
+ HoverInformation hover = await prepareHover('m() {} // in B');
+ expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+ }
+
+ test_dartdoc_inherited_methodByMethod_fromSuper_indirect() async {
+ addTestFile('''
+class A {
+ /// my doc
+ m() {}
+}
+class B extends A {
+ m() {}
+}
+class C extends B {
+ m() {} // in C
+}''');
+ HoverInformation hover = await prepareHover('m() {} // in C');
+ expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+ }
+
+ test_dartdoc_inherited_methodByMethod_preferSuper() async {
+ addTestFile('''
+class A {
+ /// my doc
+ m() {}
+}
+class B extends A {
+}
+class I {
+ // wrong doc
+ m() {}
+}
+class C extends B implements I {
+ m() {} // in C
+}''');
+ HoverInformation hover = await prepareHover('m() {} // in C');
+ expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+ }
+
test_enum() async {
addTestFile('''
enum MyEnum {AAA, BBB, CCC}
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index d5cde86..ab0e0c1 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -276,6 +276,38 @@
assertHasImplementedMember('m() {} // A');
}
+ test_method_withMethod_private_differentLib() async {
+ addFile(
+ '$testFolder/lib.dart',
+ r'''
+import 'test.dart';
+class B extends A {
+ void _m() {}
+}
+''');
+ addTestFile('''
+class A {
+ _m() {} // A
+}
+''');
+ await prepareImplementedElements();
+ assertNoImplementedMember('_m() {} // A');
+ }
+
+ test_method_withMethod_private_sameLibrary() async {
+ addTestFile('''
+class A {
+ _m() {} // A
+}
+class B extends A {
+ _m() {} // B
+}
+''');
+ await prepareImplementedElements();
+ assertHasImplementedMember('_m() {} // A');
+ assertNoImplementedMember('_m() {} // B');
+ }
+
test_method_withMethod_wasAbstract() async {
addTestFile('''
abstract class A {
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index ae7551e..61db513 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -229,6 +229,24 @@
assertNoOverride('fff(x) {} // B');
}
+ test_BAD_privateByPrivate_inDifferentLib() async {
+ addFile(
+ '$testFolder/lib.dart',
+ r'''
+class A {
+ void _m() {}
+}
+''');
+ addTestFile('''
+import 'lib.dart';
+class B extends A {
+ void _m() {} // in B
+}
+''');
+ await prepareOverrides();
+ assertNoOverride('_m() {} // in B');
+ }
+
test_BAD_setterByGetter() async {
addTestFile('''
class A {
@@ -352,7 +370,7 @@
''');
await prepareOverrides();
assertHasOverride('m() {} // in C');
- expect(override.interfaceMembers, hasLength(1));
+ expect(override.interfaceMembers, hasLength(2));
assertHasInterfaceMember('m() {} // in B');
}
@@ -514,6 +532,21 @@
assertNoInterfaceMembers();
}
+ test_super_method_privateByPrivate() async {
+ addTestFile('''
+class A {
+ _m() {} // in A
+}
+class B extends A {
+ _m() {} // in B
+}
+''');
+ await prepareOverrides();
+ assertHasOverride('_m() {} // in B');
+ assertHasSuperElement('_m() {} // in A');
+ assertNoInterfaceMembers();
+ }
+
test_super_method_superTypeCycle() async {
addTestFile('''
class A extends B {
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index 5c0616e..4faf108 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -32,7 +32,8 @@
int c = search.codeUnitAt(length);
if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
- c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
+ c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0) ||
+ c == '_'.codeUnitAt(0))) {
break;
}
length++;
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index f6eff47..c332aa9 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -14,6 +14,7 @@
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/services/lint.dart';
@@ -366,7 +367,8 @@
// Sanity check embedder libs.
var source = context.sourceFactory.forUri('dart:foobar');
expect(source, isNotNull);
- expect(source.fullName, '/my/proj/sdk_ext/entry.dart');
+ expect(source.fullName,
+ '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
}
test_embedder_packagespec() async {
@@ -403,7 +405,8 @@
var context = contexts[0];
var source = context.sourceFactory.forUri('dart:foobar');
expect(source, isNotNull);
- expect(source.fullName, equals('/my/proj/sdk_ext/entry.dart'));
+ expect(source.fullName,
+ '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
// We can't find dart:core because we didn't list it in our
// embedder_libs map.
expect(context.sourceFactory.forUri('dart:core'), isNull);
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index f234463..e0a6867 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -71,14 +71,15 @@
var request = new DiagnosticGetDiagnosticsParams().toRequest('0');
var response = handler.handleRequest(request);
- int fileCount = MockSdk.LIBRARIES.length + 1 /* test.dart */;
+ int fileCount = 1 /* test.dart */;
var json = response.toJson()[Response.RESULT];
expect(json['contexts'], hasLength(1));
var context = json['contexts'][0];
expect(context['name'], '/project');
expect(context['explicitFileCount'], fileCount);
- expect(context['implicitFileCount'], 0);
+ // dart:core dart:async dart:math dart:_internal
+ expect(context['implicitFileCount'], 4);
expect(context['workItemQueueLength'], isNotNull);
});
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 1fbb426..c43ef63 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -222,12 +222,6 @@
_analysisContext = new SdkAnalysisContext();
SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
_analysisContext.sourceFactory = factory;
- ChangeSet changeSet = new ChangeSet();
- for (String uri in uris) {
- Source source = factory.forUri(uri);
- changeSet.addedSource(source);
- }
- _analysisContext.applyChanges(changeSet);
}
return _analysisContext;
}
diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart
index 1d6ddf9a..c8b62dd 100644
--- a/pkg/analysis_server/test/search/type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart
@@ -186,8 +186,9 @@
class C extends A {}
''');
// configure roots
- Request request = new AnalysisSetAnalysisRootsParams(
- [projectPath, '/packages/pkgA'], []).toRequest('0');
+ Request request =
+ new AnalysisSetAnalysisRootsParams([projectPath, '/packages/pkgA'], [])
+ .toRequest('0');
handleSuccessfulRequest(request);
// test A type hierarchy
List<TypeHierarchyItem> items = await _getTypeHierarchy('A {}');
@@ -699,6 +700,66 @@
itemD.memberElement.location.offset, findOffset('test() {} // in D'));
}
+ test_member_method_private_differentLib() async {
+ addFile(
+ '$testFolder/lib.dart',
+ r'''
+import 'test.dart';
+class A {
+ void _m() {}
+}
+class C extends B {
+ void _m() {}
+}
+''');
+ addTestFile('''
+import 'lib.dart';
+class B extends A {
+ _m() {} // in B
+}
+class D extends C {
+ _m() {} // in D
+}
+''');
+ List<TypeHierarchyItem> items = await _getTypeHierarchy('_m() {} // in B');
+ var itemB = items[0];
+ var itemA = items[itemB.superclass];
+ var itemC = items[itemB.subclasses[0]];
+ var itemD = items[itemC.subclasses[0]];
+ expect(itemB.classElement.name, 'B');
+ expect(itemA.classElement.name, 'A');
+ expect(itemC.classElement.name, 'C');
+ expect(itemD.classElement.name, 'D');
+ expect(itemA.memberElement, isNull);
+ expect(itemC.memberElement, isNull);
+ expect(itemB.memberElement, isNotNull);
+ expect(itemD.memberElement, isNotNull);
+ }
+
+ test_member_method_private_sameLib() async {
+ addTestFile('''
+class A {
+ _m() {} // in A
+}
+class B extends A {
+ _m() {} // in B
+}
+class C extends B {
+ _m() {} // in C
+}
+''');
+ List<TypeHierarchyItem> items = await _getTypeHierarchy('_m() {} // in B');
+ var itemB = items[0];
+ var itemA = items[itemB.superclass];
+ var itemC = items[itemB.subclasses[0]];
+ expect(itemA.classElement.name, 'A');
+ expect(itemB.classElement.name, 'B');
+ expect(itemC.classElement.name, 'C');
+ expect(itemA.memberElement.location.offset, findOffset('_m() {} // in A'));
+ expect(itemB.memberElement.location.offset, findOffset('_m() {} // in B'));
+ expect(itemC.memberElement.location.offset, findOffset('_m() {} // in C'));
+ }
+
test_member_ofMixin2_method() async {
addTestFile('''
class M1 {
@@ -963,8 +1024,9 @@
test_superOnly_fileDoesNotExist() async {
Request request = new SearchGetTypeHierarchyParams(
- '/does/not/exist.dart', 0,
- superOnly: true).toRequest(requestId);
+ '/does/not/exist.dart', 0,
+ superOnly: true)
+ .toRequest(requestId);
Response response = await serverChannel.sendRequest(request);
List<TypeHierarchyItem> items =
new SearchGetTypeHierarchyResult.fromResponse(response).hierarchyItems;
@@ -973,7 +1035,8 @@
Request _createGetTypeHierarchyRequest(String search, {bool superOnly}) {
return new SearchGetTypeHierarchyParams(testFile, findOffset(search),
- superOnly: superOnly).toRequest(requestId);
+ superOnly: superOnly)
+ .toRequest(requestId);
}
Future<List<TypeHierarchyItem>> _getTypeHierarchy(String search,
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index ed3d7d3..859f248 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -2379,6 +2379,15 @@
await assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
}
+ test_introduceLocalTestedType_BAD_notStatement() async {
+ resolveTestUnit('''
+class C {
+ bool b;
+ C(v) : b = v is int;
+}''');
+ await assertNoAssistAt('is int', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
+ }
+
test_introduceLocalTestedType_OK_if_is() async {
resolveTestUnit('''
class MyTypeName {}
diff --git a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
index 8ff6c84..3433f1e 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -917,6 +917,81 @@
''');
}
+ test_method_methodInstance() {
+ indexTestUnit(r'''
+class A {
+ ma() {}
+}
+class B extends A {
+ test() {
+ ma();
+ mb();
+ }
+ mb() {}
+}
+main(B b) {
+ b.test();
+}
+''');
+ _createRefactoring('test();');
+ // validate change
+ return _assertSuccessfulRefactoring(r'''
+class A {
+ ma() {}
+}
+class B extends A {
+ test() {
+ ma();
+ mb();
+ }
+ mb() {}
+}
+main(B b) {
+ b.ma();
+ b.mb();
+}
+''');
+ }
+
+ test_method_methodStatic() {
+ indexTestUnit(r'''
+class A {
+ static ma() {}
+}
+class B extends A {
+ static mb() {}
+ test() {
+ mb();
+ A.ma();
+ B.mb();
+ }
+}
+main(B b) {
+ b.test();
+}
+''');
+ _createRefactoring('test();');
+ // validate change
+ return _assertSuccessfulRefactoring(r'''
+class A {
+ static ma() {}
+}
+class B extends A {
+ static mb() {}
+ test() {
+ mb();
+ A.ma();
+ B.mb();
+ }
+}
+main(B b) {
+ B.mb();
+ A.ma();
+ B.mb();
+}
+''');
+ }
+
test_method_singleStatement() {
indexTestUnit(r'''
class A {
@@ -973,7 +1048,7 @@
''');
}
- test_method_unqualifiedUnvocation() {
+ test_method_unqualifiedInvocation() {
indexTestUnit(r'''
class A {
test(a, b) {
@@ -1198,6 +1273,36 @@
''');
}
+ test_removeEmptyLinesBefore_method() {
+ indexTestUnit(r'''
+class A {
+ before() {
+ }
+
+
+ test() {
+ print(0);
+ }
+
+ foo() {
+ test();
+ }
+}
+''');
+ _createRefactoring('test() {');
+ // validate change
+ return _assertSuccessfulRefactoring(r'''
+class A {
+ before() {
+ }
+
+ foo() {
+ print(0);
+ }
+}
+''');
+ }
+
test_setter_classMember_instance() {
indexTestUnit(r'''
class A {
@@ -1361,7 +1466,7 @@
''');
}
- test_singleExpression_wrapIntoParenthesized_bools() {
+ test_singleExpression_wrapIntoParenthesized_bool() {
indexTestUnit(r'''
test(bool a, bool b) {
return a || b;
diff --git a/pkg/analyzer/example/parser_driver.dart b/pkg/analyzer/example/parser_driver.dart
index 8fdf1a9..2e082b7 100644
--- a/pkg/analyzer/example/parser_driver.dart
+++ b/pkg/analyzer/example/parser_driver.dart
@@ -5,7 +5,8 @@
import 'dart:io';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analyzer/example/resolver_driver.dart b/pkg/analyzer/example/resolver_driver.dart
index 74ed79c..fa2af7f 100755
--- a/pkg/analyzer/example/resolver_driver.dart
+++ b/pkg/analyzer/example/resolver_driver.dart
@@ -5,8 +5,9 @@
import 'dart:io';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
diff --git a/pkg/analyzer/lib/analyzer.dart b/pkg/analyzer/lib/analyzer.dart
index d0fdc65..78de42e 100644
--- a/pkg/analyzer/lib/analyzer.dart
+++ b/pkg/analyzer/lib/analyzer.dart
@@ -6,8 +6,8 @@
import 'dart:io';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/error.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/scanner.dart';
@@ -15,8 +15,10 @@
import 'package:analyzer/src/string_source.dart';
import 'package:path/path.dart' as pathos;
+export 'package:analyzer/dart/ast/ast.dart';
+export 'package:analyzer/dart/ast/visitor.dart';
+export 'package:analyzer/src/dart/ast/utilities.dart';
export 'package:analyzer/src/error.dart';
-export 'package:analyzer/src/generated/ast.dart';
export 'package:analyzer/src/generated/error.dart';
export 'package:analyzer/src/generated/utilities_dart.dart';
@@ -63,22 +65,6 @@
suppressErrors: suppressErrors, parseFunctionBodies: parseFunctionBodies);
}
-CompilationUnit _parseSource(String contents, Source source,
- {bool suppressErrors: false, bool parseFunctionBodies: true}) {
- var reader = new CharSequenceReader(contents);
- var errorCollector = new _ErrorCollector();
- var scanner = new Scanner(source, reader, errorCollector);
- var token = scanner.tokenize();
- var parser = new Parser(source, errorCollector)
- ..parseFunctionBodies = parseFunctionBodies;
- var unit = parser.parseCompilationUnit(token)
- ..lineInfo = new LineInfo(scanner.lineStarts);
-
- if (errorCollector.hasErrors && !suppressErrors) throw errorCollector.group;
-
- return unit;
-}
-
/// Parses the script tag and directives in a string of Dart code into an AST.
///
/// Stops parsing when the first non-directive is encountered. The rest of the
@@ -111,6 +97,22 @@
return literal.stringValue;
}
+CompilationUnit _parseSource(String contents, Source source,
+ {bool suppressErrors: false, bool parseFunctionBodies: true}) {
+ var reader = new CharSequenceReader(contents);
+ var errorCollector = new _ErrorCollector();
+ var scanner = new Scanner(source, reader, errorCollector);
+ var token = scanner.tokenize();
+ var parser = new Parser(source, errorCollector)
+ ..parseFunctionBodies = parseFunctionBodies;
+ var unit = parser.parseCompilationUnit(token)
+ ..lineInfo = new LineInfo(scanner.lineStarts);
+
+ if (errorCollector.hasErrors && !suppressErrors) throw errorCollector.group;
+
+ return unit;
+}
+
/// A simple error listener that collects errors into an [AnalysisErrorGroup].
class _ErrorCollector extends AnalysisErrorListener {
final _errors = <AnalysisError>[];
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
new file mode 100644
index 0000000..1237fd1
--- /dev/null
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -0,0 +1,7988 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.dart.ast.ast;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart' show AuxiliaryElements;
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Two or more string literals that are implicitly concatenated because of being
+ * adjacent (separated only by whitespace).
+ *
+ * While the grammar only allows adjacent strings when all of the strings are of
+ * the same kind (single line or multi-line), this class doesn't enforce that
+ * restriction.
+ *
+ * > adjacentStrings ::=
+ * > [StringLiteral] [StringLiteral]+
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AdjacentStrings extends StringLiteral {
+ /**
+ * Initialize a newly created list of adjacent strings. To be syntactically
+ * valid, the list of [strings] must contain at least two elements.
+ */
+ factory AdjacentStrings(List<StringLiteral> strings) = AdjacentStringsImpl;
+
+ /**
+ * Return the strings that are implicitly concatenated.
+ */
+ NodeList<StringLiteral> get strings;
+}
+
+/**
+ * An AST node that can be annotated with both a documentation comment and a
+ * list of annotations.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AnnotatedNode extends AstNode {
+ /**
+ * Return the documentation comment associated with this node, or `null` if
+ * this node does not have a documentation comment associated with it.
+ */
+ Comment get documentationComment;
+
+ /**
+ * Set the documentation comment associated with this node to the given
+ * [comment].
+ */
+ void set documentationComment(Comment comment);
+
+ /**
+ * Return the first token following the comment and metadata.
+ */
+ Token get firstTokenAfterCommentAndMetadata;
+
+ /**
+ * Return the annotations associated with this node.
+ */
+ NodeList<Annotation> get metadata;
+
+ /**
+ * Return a list containing the comment and annotations associated with this
+ * node, sorted in lexical order.
+ */
+ List<AstNode> get sortedCommentAndAnnotations;
+}
+
+/**
+ * An annotation that can be associated with an AST node.
+ *
+ * > metadata ::=
+ * > annotation*
+ * >
+ * > annotation ::=
+ * > '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Annotation extends AstNode {
+ /**
+ * Initialize a newly created annotation. Both the [period] and the
+ * [constructorName] can be `null` if the annotation is not referencing a
+ * named constructor. The [arguments] can be `null` if the annotation is not
+ * referencing a constructor.
+ */
+ factory Annotation(
+ Token atSign,
+ Identifier name,
+ Token period,
+ SimpleIdentifier constructorName,
+ ArgumentList arguments) = AnnotationImpl;
+
+ /**
+ * Return the arguments to the constructor being invoked, or `null` if this
+ * annotation is not the invocation of a constructor.
+ */
+ ArgumentList get arguments;
+
+ /**
+ * Set the arguments to the constructor being invoked to the given [arguments].
+ */
+ void set arguments(ArgumentList arguments);
+
+ /**
+ * Return the at sign that introduced the annotation.
+ */
+ Token get atSign;
+
+ /**
+ * Set the at sign that introduced the annotation to the given [token].
+ */
+ void set atSign(Token token);
+
+ /**
+ * Return the name of the constructor being invoked, or `null` if this
+ * annotation is not the invocation of a named constructor.
+ */
+ SimpleIdentifier get constructorName;
+
+ /**
+ * Set the name of the constructor being invoked to the given [name].
+ */
+ void set constructorName(SimpleIdentifier name);
+
+ /**
+ * Return the element associated with this annotation, or `null` if the AST
+ * structure has not been resolved or if this annotation could not be
+ * resolved.
+ */
+ Element get element;
+
+ /**
+ * Set the element associated with this annotation to the given [element].
+ */
+ void set element(Element element);
+
+ /**
+ * Return the element annotation representing this annotation in the element model.
+ */
+ ElementAnnotation get elementAnnotation;
+
+ /**
+ * Set the element annotation representing this annotation in the element
+ * model to the given [annotation].
+ */
+ void set elementAnnotation(ElementAnnotation annotation);
+
+ /**
+ * Return the name of the class defining the constructor that is being invoked
+ * or the name of the field that is being referenced.
+ */
+ Identifier get name;
+
+ /**
+ * Set the name of the class defining the constructor that is being invoked or
+ * the name of the field that is being referenced to the given [name].
+ */
+ void set name(Identifier name);
+
+ /**
+ * Return the period before the constructor name, or `null` if this annotation
+ * is not the invocation of a named constructor.
+ */
+ Token get period;
+
+ /**
+ * Set the period before the constructor name to the given [token].
+ */
+ void set period(Token token);
+}
+
+/**
+ * A list of arguments in the invocation of an executable element (that is, a
+ * function, method, or constructor).
+ *
+ * > argumentList ::=
+ * > '(' arguments? ')'
+ * >
+ * > arguments ::=
+ * > [NamedExpression] (',' [NamedExpression])*
+ * > | [Expression] (',' [Expression])* (',' [NamedExpression])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ArgumentList extends AstNode {
+ /**
+ * Initialize a newly created list of arguments. The list of [arguments] can
+ * be `null` if there are no arguments.
+ */
+ factory ArgumentList(Token leftParenthesis, List<Expression> arguments,
+ Token rightParenthesis) = ArgumentListImpl;
+
+ /**
+ * Return the expressions producing the values of the arguments. Although the
+ * language requires that positional arguments appear before named arguments,
+ * this class allows them to be intermixed.
+ */
+ NodeList<Expression> get arguments;
+
+ /**
+ * Set the parameter elements corresponding to each of the arguments in this
+ * list to the given list of [parameters]. The list of parameters must be the
+ * same length as the number of arguments, but can contain `null` entries if a
+ * given argument does not correspond to a formal parameter.
+ */
+ void set correspondingPropagatedParameters(List<ParameterElement> parameters);
+
+ /**
+ * Set the parameter elements corresponding to each of the arguments in this
+ * list to the given list of [parameters]. The list of parameters must be the
+ * same length as the number of arguments, but can contain `null` entries if a
+ * given argument does not correspond to a formal parameter.
+ */
+ void set correspondingStaticParameters(List<ParameterElement> parameters);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+}
+
+/**
+ * An as expression.
+ *
+ * > asExpression ::=
+ * > [Expression] 'as' [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AsExpression extends Expression {
+ /**
+ * Initialize a newly created as expression.
+ */
+ factory AsExpression(Expression expression, Token asOperator, TypeName type) =
+ AsExpressionImpl;
+
+ /**
+ * Return the 'as' operator.
+ */
+ Token get asOperator;
+
+ /**
+ * Set the 'as' operator to the given [token].
+ */
+ void set asOperator(Token token);
+
+ /**
+ * Return the expression used to compute the value being cast.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression used to compute the value being cast to the given
+ * [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the name of the type being cast to.
+ */
+ TypeName get type;
+
+ /**
+ * Set the name of the type being cast to to the given [name].
+ */
+ void set type(TypeName name);
+}
+
+/**
+ * An assert statement.
+ *
+ * > assertStatement ::=
+ * > 'assert' '(' [Expression] ')' ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AssertStatement extends Statement {
+ /**
+ * Initialize a newly created assert statement. The [comma] and [message] can
+ * be `null` if there is no message.
+ */
+ factory AssertStatement(
+ Token assertKeyword,
+ Token leftParenthesis,
+ Expression condition,
+ Token comma,
+ Expression message,
+ Token rightParenthesis,
+ Token semicolon) = AssertStatementImpl;
+
+ /**
+ * Return the token representing the 'assert' keyword.
+ */
+ Token get assertKeyword;
+
+ /**
+ * Set the token representing the 'assert' keyword to the given [token].
+ */
+ void set assertKeyword(Token token);
+
+ /**
+ * Return the comma between the [condition] and the [message], or `null` if no
+ * message was supplied.
+ */
+ Token get comma;
+
+ /**
+ * Set the comma between the [condition] and the [message] to the given [token].
+ */
+ void set comma(Token token);
+
+ /**
+ * Return the condition that is being asserted to be `true`.
+ */
+ Expression get condition;
+
+ /**
+ * Set the condition that is being asserted to be `true` to the given
+ * [expression].
+ */
+ void set condition(Expression condition);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the message to report if the assertion fails, or `null` if no
+ * message was supplied.
+ */
+ Expression get message;
+
+ /**
+ * Set the message to report if the assertion fails to the given
+ * [expression].
+ */
+ void set message(Expression expression);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * An assignment expression.
+ *
+ * > assignmentExpression ::=
+ * > [Expression] operator [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AssignmentExpression extends Expression {
+ /**
+ * Initialize a newly created assignment expression.
+ */
+ factory AssignmentExpression(
+ Expression leftHandSide, Token operator, Expression rightHandSide) =
+ AssignmentExpressionImpl;
+
+ /**
+ * Return the best element available for this operator. If resolution was able
+ * to find a better element based on type propagation, that element will be
+ * returned. Otherwise, the element found using the result of static analysis
+ * will be returned. If resolution has not been performed, then `null` will be
+ * returned.
+ */
+ MethodElement get bestElement;
+
+ /**
+ * Return the expression used to compute the left hand side.
+ */
+ Expression get leftHandSide;
+
+ /**
+ * Return the expression used to compute the left hand side.
+ */
+ void set leftHandSide(Expression expression);
+
+ /**
+ * Return the assignment operator being applied.
+ */
+ Token get operator;
+
+ /**
+ * Set the assignment operator being applied to the given [token].
+ */
+ void set operator(Token token);
+
+ /**
+ * Return the element associated with the operator based on the propagated
+ * type of the left-hand-side, or `null` if the AST structure has not been
+ * resolved, if the operator is not a compound operator, or if the operator
+ * could not be resolved.
+ */
+ MethodElement get propagatedElement;
+
+ /**
+ * Set the element associated with the operator based on the propagated
+ * type of the left-hand-side to the given [element].
+ */
+ void set propagatedElement(MethodElement element);
+
+ /**
+ * Return the expression used to compute the right hand side.
+ */
+ Expression get rightHandSide;
+
+ /**
+ * Set the expression used to compute the left hand side to the given
+ * [expression].
+ */
+ void set rightHandSide(Expression expression);
+
+ /**
+ * Return the element associated with the operator based on the static type of
+ * the left-hand-side, or `null` if the AST structure has not been resolved,
+ * if the operator is not a compound operator, or if the operator could not be
+ * resolved.
+ */
+ MethodElement get staticElement;
+
+ /**
+ * Set the element associated with the operator based on the static type of
+ * the left-hand-side to the given [element].
+ */
+ void set staticElement(MethodElement element);
+}
+
+/**
+ * A node in the AST structure for a Dart program.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AstNode {
+ /**
+ * An empty list of AST nodes.
+ */
+ static const List<AstNode> EMPTY_LIST = const <AstNode>[];
+
+ /**
+ * A comparator that can be used to sort AST nodes in lexical order. In other
+ * words, `compare` will return a negative value if the offset of the first
+ * node is less than the offset of the second node, zero (0) if the nodes have
+ * the same offset, and a positive value if the offset of the first node is
+ * greater than the offset of the second node.
+ */
+ static Comparator<AstNode> LEXICAL_ORDER =
+ (AstNode first, AstNode second) => first.offset - second.offset;
+
+ /**
+ * Return the first token included in this node's source range.
+ */
+ Token get beginToken;
+
+ /**
+ * Return an iterator that can be used to iterate through all the entities
+ * (either AST nodes or tokens) that make up the contents of this node,
+ * including doc comments but excluding other comments.
+ */
+ Iterable/*<AstNode | Token>*/ get childEntities;
+
+ /**
+ * Return the offset of the character immediately following the last character
+ * of this node's source range. This is equivalent to
+ * `node.getOffset() + node.getLength()`. For a compilation unit this will be
+ * equal to the length of the unit's source. For synthetic nodes this will be
+ * equivalent to the node's offset (because the length is zero (0) by
+ * definition).
+ */
+ int get end;
+
+ /**
+ * Return the last token included in this node's source range.
+ */
+ Token get endToken;
+
+ /**
+ * Return `true` if this node is a synthetic node. A synthetic node is a node
+ * that was introduced by the parser in order to recover from an error in the
+ * code. Synthetic nodes always have a length of zero (`0`).
+ */
+ bool get isSynthetic;
+
+ /**
+ * Return the number of characters in the node's source range.
+ */
+ int get length;
+
+ /**
+ * Return the offset from the beginning of the file to the first character in
+ * the node's source range.
+ */
+ int get offset;
+
+ /**
+ * Return this node's parent node, or `null` if this node is the root of an
+ * AST structure.
+ *
+ * Note that the relationship between an AST node and its parent node may
+ * change over the lifetime of a node.
+ */
+ AstNode get parent;
+
+ /**
+ * Return the node at the root of this node's AST structure. Note that this
+ * method's performance is linear with respect to the depth of the node in the
+ * AST structure (O(depth)).
+ */
+ AstNode get root;
+
+ /**
+ * Use the given [visitor] to visit this node. Return the value returned by
+ * the visitor as a result of visiting this node.
+ */
+ dynamic /* =E */ accept/*<E>*/(AstVisitor/*<E>*/ visitor);
+
+ /**
+ * Return the most immediate ancestor of this node for which the [predicate]
+ * returns `true`, or `null` if there is no such ancestor. Note that this node
+ * will never be returned.
+ */
+ AstNode getAncestor(Predicate<AstNode> predicate);
+
+ /**
+ * Return the value of the property with the given [name], or `null` if this
+ * node does not have a property with the given name.
+ */
+ Object getProperty(String name);
+
+ /**
+ * Set the value of the property with the given [name] to the given [value].
+ * If the value is `null`, the property will effectively be removed.
+ */
+ void setProperty(String name, Object value);
+
+ /**
+ * Return a textual description of this node in a form approximating valid
+ * source. The returned string will not be valid source primarily in the case
+ * where the node itself is not well-formed.
+ */
+ String toSource();
+
+ /**
+ * Use the given [visitor] to visit all of the children of this node. The
+ * children will be visited in lexical order.
+ */
+ void visitChildren(AstVisitor visitor);
+}
+
+/**
+ * An object that can be used to visit an AST structure.
+ *
+ * Clients may extend or implement this class.
+ */
+abstract class AstVisitor<R> {
+ R visitAdjacentStrings(AdjacentStrings node);
+
+ R visitAnnotation(Annotation node);
+
+ R visitArgumentList(ArgumentList node);
+
+ R visitAsExpression(AsExpression node);
+
+ R visitAssertStatement(AssertStatement assertStatement);
+
+ R visitAssignmentExpression(AssignmentExpression node);
+
+ R visitAwaitExpression(AwaitExpression node);
+
+ R visitBinaryExpression(BinaryExpression node);
+
+ R visitBlock(Block node);
+
+ R visitBlockFunctionBody(BlockFunctionBody node);
+
+ R visitBooleanLiteral(BooleanLiteral node);
+
+ R visitBreakStatement(BreakStatement node);
+
+ R visitCascadeExpression(CascadeExpression node);
+
+ R visitCatchClause(CatchClause node);
+
+ R visitClassDeclaration(ClassDeclaration node);
+
+ R visitClassTypeAlias(ClassTypeAlias node);
+
+ R visitComment(Comment node);
+
+ R visitCommentReference(CommentReference node);
+
+ R visitCompilationUnit(CompilationUnit node);
+
+ R visitConditionalExpression(ConditionalExpression node);
+
+ R visitConfiguration(Configuration node);
+
+ R visitConstructorDeclaration(ConstructorDeclaration node);
+
+ R visitConstructorFieldInitializer(ConstructorFieldInitializer node);
+
+ R visitConstructorName(ConstructorName node);
+
+ R visitContinueStatement(ContinueStatement node);
+
+ R visitDeclaredIdentifier(DeclaredIdentifier node);
+
+ R visitDefaultFormalParameter(DefaultFormalParameter node);
+
+ R visitDoStatement(DoStatement node);
+
+ R visitDottedName(DottedName node);
+
+ R visitDoubleLiteral(DoubleLiteral node);
+
+ R visitEmptyFunctionBody(EmptyFunctionBody node);
+
+ R visitEmptyStatement(EmptyStatement node);
+
+ R visitEnumConstantDeclaration(EnumConstantDeclaration node);
+
+ R visitEnumDeclaration(EnumDeclaration node);
+
+ R visitExportDirective(ExportDirective node);
+
+ R visitExpressionFunctionBody(ExpressionFunctionBody node);
+
+ R visitExpressionStatement(ExpressionStatement node);
+
+ R visitExtendsClause(ExtendsClause node);
+
+ R visitFieldDeclaration(FieldDeclaration node);
+
+ R visitFieldFormalParameter(FieldFormalParameter node);
+
+ R visitForEachStatement(ForEachStatement node);
+
+ R visitFormalParameterList(FormalParameterList node);
+
+ R visitForStatement(ForStatement node);
+
+ R visitFunctionDeclaration(FunctionDeclaration node);
+
+ R visitFunctionDeclarationStatement(FunctionDeclarationStatement node);
+
+ R visitFunctionExpression(FunctionExpression node);
+
+ R visitFunctionExpressionInvocation(FunctionExpressionInvocation node);
+
+ R visitFunctionTypeAlias(FunctionTypeAlias functionTypeAlias);
+
+ R visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node);
+
+ R visitHideCombinator(HideCombinator node);
+
+ R visitIfStatement(IfStatement node);
+
+ R visitImplementsClause(ImplementsClause node);
+
+ R visitImportDirective(ImportDirective node);
+
+ R visitIndexExpression(IndexExpression node);
+
+ R visitInstanceCreationExpression(InstanceCreationExpression node);
+
+ R visitIntegerLiteral(IntegerLiteral node);
+
+ R visitInterpolationExpression(InterpolationExpression node);
+
+ R visitInterpolationString(InterpolationString node);
+
+ R visitIsExpression(IsExpression node);
+
+ R visitLabel(Label node);
+
+ R visitLabeledStatement(LabeledStatement node);
+
+ R visitLibraryDirective(LibraryDirective node);
+
+ R visitLibraryIdentifier(LibraryIdentifier node);
+
+ R visitListLiteral(ListLiteral node);
+
+ R visitMapLiteral(MapLiteral node);
+
+ R visitMapLiteralEntry(MapLiteralEntry node);
+
+ R visitMethodDeclaration(MethodDeclaration node);
+
+ R visitMethodInvocation(MethodInvocation node);
+
+ R visitNamedExpression(NamedExpression node);
+
+ R visitNativeClause(NativeClause node);
+
+ R visitNativeFunctionBody(NativeFunctionBody node);
+
+ R visitNullLiteral(NullLiteral node);
+
+ R visitParenthesizedExpression(ParenthesizedExpression node);
+
+ R visitPartDirective(PartDirective node);
+
+ R visitPartOfDirective(PartOfDirective node);
+
+ R visitPostfixExpression(PostfixExpression node);
+
+ R visitPrefixedIdentifier(PrefixedIdentifier node);
+
+ R visitPrefixExpression(PrefixExpression node);
+
+ R visitPropertyAccess(PropertyAccess node);
+
+ R visitRedirectingConstructorInvocation(
+ RedirectingConstructorInvocation node);
+
+ R visitRethrowExpression(RethrowExpression node);
+
+ R visitReturnStatement(ReturnStatement node);
+
+ R visitScriptTag(ScriptTag node);
+
+ R visitShowCombinator(ShowCombinator node);
+
+ R visitSimpleFormalParameter(SimpleFormalParameter node);
+
+ R visitSimpleIdentifier(SimpleIdentifier node);
+
+ R visitSimpleStringLiteral(SimpleStringLiteral node);
+
+ R visitStringInterpolation(StringInterpolation node);
+
+ R visitSuperConstructorInvocation(SuperConstructorInvocation node);
+
+ R visitSuperExpression(SuperExpression node);
+
+ R visitSwitchCase(SwitchCase node);
+
+ R visitSwitchDefault(SwitchDefault node);
+
+ R visitSwitchStatement(SwitchStatement node);
+
+ R visitSymbolLiteral(SymbolLiteral node);
+
+ R visitThisExpression(ThisExpression node);
+
+ R visitThrowExpression(ThrowExpression node);
+
+ R visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node);
+
+ R visitTryStatement(TryStatement node);
+
+ R visitTypeArgumentList(TypeArgumentList node);
+
+ R visitTypeName(TypeName node);
+
+ R visitTypeParameter(TypeParameter node);
+
+ R visitTypeParameterList(TypeParameterList node);
+
+ R visitVariableDeclaration(VariableDeclaration node);
+
+ R visitVariableDeclarationList(VariableDeclarationList node);
+
+ R visitVariableDeclarationStatement(VariableDeclarationStatement node);
+
+ R visitWhileStatement(WhileStatement node);
+
+ R visitWithClause(WithClause node);
+
+ R visitYieldStatement(YieldStatement node);
+}
+
+/**
+ * An await expression.
+ *
+ * > awaitExpression ::=
+ * > 'await' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AwaitExpression extends Expression {
+ /**
+ * Initialize a newly created await expression.
+ */
+ factory AwaitExpression(Token awaitKeyword, Expression expression) =
+ AwaitExpressionImpl;
+
+ /**
+ * Return the 'await' keyword.
+ */
+ Token get awaitKeyword;
+
+ /**
+ * Set the 'await' keyword to the given [token].
+ */
+ void set awaitKeyword(Token token);
+
+ /**
+ * Return the expression whose value is being waited on.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression whose value is being waited on to the given [expression].
+ */
+ void set expression(Expression expression);
+}
+
+/**
+ * A binary (infix) expression.
+ *
+ * > binaryExpression ::=
+ * > [Expression] [Token] [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BinaryExpression extends Expression {
+ /**
+ * Initialize a newly created binary expression.
+ */
+ factory BinaryExpression(
+ Expression leftOperand, Token operator, Expression rightOperand) =
+ BinaryExpressionImpl;
+
+ /**
+ * Return the best element available for this operator. If resolution was able
+ * to find a better element based on type propagation, that element will be
+ * returned. Otherwise, the element found using the result of static analysis
+ * will be returned. If resolution has not been performed, then `null` will be
+ * returned.
+ */
+ MethodElement get bestElement;
+
+ /**
+ * Return the expression used to compute the left operand.
+ */
+ Expression get leftOperand;
+
+ /**
+ * Set the expression used to compute the left operand to the given
+ * [expression].
+ */
+ void set leftOperand(Expression expression);
+
+ /**
+ * Return the binary operator being applied.
+ */
+ Token get operator;
+
+ /**
+ * Set the binary operator being applied to the given [token].
+ */
+ void set operator(Token token);
+
+ /**
+ * Return the element associated with the operator based on the propagated
+ * type of the left operand, or `null` if the AST structure has not been
+ * resolved, if the operator is not user definable, or if the operator could
+ * not be resolved.
+ */
+ MethodElement get propagatedElement;
+
+ /**
+ * Set the element associated with the operator based on the propagated
+ * type of the left operand to the given [element].
+ */
+ void set propagatedElement(MethodElement element);
+
+ /**
+ * Return the expression used to compute the right operand.
+ */
+ Expression get rightOperand;
+
+ /**
+ * Set the expression used to compute the right operand to the given
+ * [expression].
+ */
+ void set rightOperand(Expression expression);
+
+ /**
+ * Return the element associated with the operator based on the static type of
+ * the left operand, or `null` if the AST structure has not been resolved, if
+ * the operator is not user definable, or if the operator could not be
+ * resolved.
+ */
+ MethodElement get staticElement;
+
+ /**
+ * Set the element associated with the operator based on the static type of
+ * the left operand to the given [element].
+ */
+ void set staticElement(MethodElement element);
+}
+
+/**
+ * A sequence of statements.
+ *
+ * > block ::=
+ * > '{' statement* '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Block extends Statement {
+ /**
+ * Initialize a newly created block of code.
+ */
+ factory Block(
+ Token leftBracket, List<Statement> statements, Token rightBracket) =
+ BlockImpl;
+
+ /**
+ * Return the left curly bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left curly bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the right curly bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right curly bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+
+ /**
+ * Return the statements contained in the block.
+ */
+ NodeList<Statement> get statements;
+}
+
+/**
+ * A function body that consists of a block of statements.
+ *
+ * > blockFunctionBody ::=
+ * > ('async' | 'async' '*' | 'sync' '*')? [Block]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BlockFunctionBody extends FunctionBody {
+ /**
+ * Initialize a newly created function body consisting of a block of
+ * statements. The [keyword] can be `null` if there is no keyword specified
+ * for the block. The [star] can be `null` if there is no star following the
+ * keyword (and must be `null` if there is no keyword).
+ */
+ factory BlockFunctionBody(Token keyword, Token star, Block block) =
+ BlockFunctionBodyImpl;
+
+ /**
+ * Return the block representing the body of the function.
+ */
+ Block get block;
+
+ /**
+ * Set the block representing the body of the function to the given [block].
+ */
+ void set block(Block block);
+
+ /**
+ * Set token representing the 'async' or 'sync' keyword to the given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Set the star following the 'async' or 'sync' keyword to the given [token].
+ */
+ void set star(Token token);
+}
+
+/**
+ * A boolean literal expression.
+ *
+ * > booleanLiteral ::=
+ * > 'false' | 'true'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BooleanLiteral extends Literal {
+ /**
+ * Initialize a newly created boolean literal.
+ */
+ factory BooleanLiteral(Token literal, bool value) = BooleanLiteralImpl;
+
+ /**
+ * Return the token representing the literal.
+ */
+ Token get literal;
+
+ /**
+ * Set the token representing the literal to the given [token].
+ */
+ void set literal(Token token);
+
+ /**
+ * Return the value of the literal.
+ */
+ bool get value;
+}
+
+/**
+ * A break statement.
+ *
+ * > breakStatement ::=
+ * > 'break' [SimpleIdentifier]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BreakStatement extends Statement {
+ /**
+ * Initialize a newly created break statement. The [label] can be `null` if
+ * there is no label associated with the statement.
+ */
+ factory BreakStatement(
+ Token breakKeyword, SimpleIdentifier label, Token semicolon) =
+ BreakStatementImpl;
+
+ /**
+ * Return the token representing the 'break' keyword.
+ */
+ Token get breakKeyword;
+
+ /**
+ * Set the token representing the 'break' keyword to the given [token].
+ */
+ void set breakKeyword(Token token);
+
+ /**
+ * Return the label associated with the statement, or `null` if there is no
+ * label.
+ */
+ SimpleIdentifier get label;
+
+ /**
+ * Set the label associated with the statement to the given [identifier].
+ */
+ void set label(SimpleIdentifier identifier);
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the node from which this break statement is breaking. This will be
+ * either a [Statement] (in the case of breaking out of a loop), a
+ * [SwitchMember] (in the case of a labeled break statement whose label
+ * matches a label on a switch case in an enclosing switch statement), or
+ * `null` if the AST has not yet been resolved or if the target could not be
+ * resolved. Note that if the source code has errors, the target might be
+ * invalid (e.g. trying to break to a switch case).
+ */
+ AstNode get target;
+
+ /**
+ * Set the node from which this break statement is breaking to the given
+ * [node].
+ */
+ void set target(AstNode node);
+}
+
+/**
+ * A sequence of cascaded expressions: expressions that share a common target.
+ * There are three kinds of expressions that can be used in a cascade
+ * expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
+ *
+ * > cascadeExpression ::=
+ * > [Expression] cascadeSection*
+ * >
+ * > cascadeSection ::=
+ * > '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
+ * > (assignmentOperator expressionWithoutCascade)?
+ * >
+ * > cascadeSelector ::=
+ * > '[ ' expression '] '
+ * > | identifier
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CascadeExpression extends Expression {
+ /**
+ * Initialize a newly created cascade expression. The list of
+ * [cascadeSections] must contain at least one element.
+ */
+ factory CascadeExpression(
+ Expression target, List<Expression> cascadeSections) =
+ CascadeExpressionImpl;
+
+ /**
+ * Return the cascade sections sharing the common target.
+ */
+ NodeList<Expression> get cascadeSections;
+
+ /**
+ * Return the target of the cascade sections.
+ */
+ Expression get target;
+
+ /**
+ * Set the target of the cascade sections to the given [expression].
+ */
+ void set target(Expression target);
+}
+
+/**
+ * A catch clause within a try statement.
+ *
+ * > onPart ::=
+ * > catchPart [Block]
+ * > | 'on' type catchPart? [Block]
+ * >
+ * > catchPart ::=
+ * > 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CatchClause extends AstNode {
+ /**
+ * Initialize a newly created catch clause. The [onKeyword] and
+ * [exceptionType] can be `null` if the clause will catch all exceptions. The
+ * [comma] and [stackTraceParameter] can be `null` if the stack trace
+ * parameter is not defined.
+ */
+ factory CatchClause(
+ Token onKeyword,
+ TypeName exceptionType,
+ Token catchKeyword,
+ Token leftParenthesis,
+ SimpleIdentifier exceptionParameter,
+ Token comma,
+ SimpleIdentifier stackTraceParameter,
+ Token rightParenthesis,
+ Block body) = CatchClauseImpl;
+
+ /**
+ * Return the body of the catch block.
+ */
+ Block get body;
+
+ /**
+ * Set the body of the catch block to the given [block].
+ */
+ void set body(Block block);
+
+ /**
+ * Return the token representing the 'catch' keyword, or `null` if there is no
+ * 'catch' keyword.
+ */
+ Token get catchKeyword;
+
+ /**
+ * Set the token representing the 'catch' keyword to the given [token].
+ */
+ void set catchKeyword(Token token);
+
+ /**
+ * Return the comma separating the exception parameter from the stack trace
+ * parameter, or `null` if there is no stack trace parameter.
+ */
+ Token get comma;
+
+ /**
+ * Set the comma separating the exception parameter from the stack trace
+ * parameter to the given [token].
+ */
+ void set comma(Token token);
+
+ /**
+ * Return the parameter whose value will be the exception that was thrown, or
+ * `null` if there is no 'catch' keyword.
+ */
+ SimpleIdentifier get exceptionParameter;
+
+ /**
+ * Set the parameter whose value will be the exception that was thrown to the
+ * given [parameter].
+ */
+ void set exceptionParameter(SimpleIdentifier parameter);
+
+ /**
+ * Return the type of exceptions caught by this catch clause, or `null` if
+ * this catch clause catches every type of exception.
+ */
+ TypeName get exceptionType;
+
+ /**
+ * Set the type of exceptions caught by this catch clause to the given
+ * [exceptionType].
+ */
+ void set exceptionType(TypeName exceptionType);
+
+ /**
+ * Return the left parenthesis, or `null` if there is no 'catch' keyword.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the token representing the 'on' keyword, or `null` if there is no 'on'
+ * keyword.
+ */
+ Token get onKeyword;
+
+ /**
+ * Set the token representing the 'on' keyword to the given [token].
+ */
+ void set onKeyword(Token token);
+
+ /**
+ * Return the right parenthesis, or `null` if there is no 'catch' keyword.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the parameter whose value will be the stack trace associated with
+ * the exception, or `null` if there is no stack trace parameter.
+ */
+ SimpleIdentifier get stackTraceParameter;
+
+ /**
+ * Set the parameter whose value will be the stack trace associated with the
+ * exception to the given [parameter].
+ */
+ void set stackTraceParameter(SimpleIdentifier parameter);
+}
+
+/**
+ * The declaration of a class.
+ *
+ * > classDeclaration ::=
+ * > 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+ * > ([ExtendsClause] [WithClause]?)?
+ * > [ImplementsClause]?
+ * > '{' [ClassMember]* '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ClassDeclaration extends NamedCompilationUnitMember {
+ /**
+ * Initialize a newly created class declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the class does not have the
+ * corresponding attribute. The [abstractKeyword] can be `null` if the class
+ * is not abstract. The [typeParameters] can be `null` if the class does not
+ * have any type parameters. Any or all of the [extendsClause], [withClause],
+ * and [implementsClause] can be `null` if the class does not have the
+ * corresponding clause. The list of [members] can be `null` if the class does
+ * not have any members.
+ */
+ factory ClassDeclaration(
+ Comment comment,
+ List<Annotation> metadata,
+ Token abstractKeyword,
+ Token classKeyword,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ ExtendsClause extendsClause,
+ WithClause withClause,
+ ImplementsClause implementsClause,
+ Token leftBracket,
+ List<ClassMember> members,
+ Token rightBracket) = ClassDeclarationImpl;
+
+ /**
+ * Return the 'abstract' keyword, or `null` if the keyword was absent.
+ */
+ Token get abstractKeyword;
+
+ /**
+ * Set the 'abstract' keyword to the given [token].
+ */
+ void set abstractKeyword(Token token);
+
+ /**
+ * Return the token representing the 'class' keyword to the given [token].
+ */
+ Token get classKeyword;
+
+ /**
+ * Set the token representing the 'class' keyword.
+ */
+ void set classKeyword(Token token);
+
+ @override
+ ClassElement get element;
+
+ /**
+ * Return the extends clause for this class, or `null` if the class does not
+ * extend any other class.
+ */
+ ExtendsClause get extendsClause;
+
+ /**
+ * Set the extends clause for this class to the given [extendsClause].
+ */
+ void set extendsClause(ExtendsClause extendsClause);
+
+ /**
+ * Return the implements clause for the class, or `null` if the class does not
+ * implement any interfaces.
+ */
+ ImplementsClause get implementsClause;
+
+ /**
+ * Set the implements clause for the class to the given [implementsClause].
+ */
+ void set implementsClause(ImplementsClause implementsClause);
+
+ /**
+ * Return `true` if this class is declared to be an abstract class.
+ */
+ bool get isAbstract;
+
+ /**
+ * Return the left curly bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left curly bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the members defined by the class.
+ */
+ NodeList<ClassMember> get members;
+
+ /**
+ * Return the native clause for this class, or `null` if the class does not
+ * have a native clause.
+ */
+ NativeClause get nativeClause;
+
+ /**
+ * Set the native clause for this class to the given [nativeClause].
+ */
+ void set nativeClause(NativeClause nativeClause);
+
+ /**
+ * Return the right curly bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right curly bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+
+ /**
+ * Return the type parameters for the class, or `null` if the class does not
+ * have any type parameters.
+ */
+ TypeParameterList get typeParameters;
+
+ /**
+ * Set the type parameters for the class to the given list of [typeParameters].
+ */
+ void set typeParameters(TypeParameterList typeParameters);
+
+ /**
+ * Return the with clause for the class, or `null` if the class does not have
+ * a with clause.
+ */
+ WithClause get withClause;
+
+ /**
+ * Set the with clause for the class to the given [withClause].
+ */
+ void set withClause(WithClause withClause);
+
+ /**
+ * Return the constructor declared in the class with the given [name], or
+ * `null` if there is no such constructor. If the [name] is `null` then the
+ * default constructor will be searched for.
+ */
+ ConstructorDeclaration getConstructor(String name);
+
+ /**
+ * Return the field declared in the class with the given [name], or `null` if
+ * there is no such field.
+ */
+ VariableDeclaration getField(String name);
+
+ /**
+ * Return the method declared in the class with the given [name], or `null` if
+ * there is no such method.
+ */
+ MethodDeclaration getMethod(String name);
+}
+
+/**
+ * A node that declares a name within the scope of a class.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ClassMember extends Declaration {}
+
+/**
+ * A class type alias.
+ *
+ * > classTypeAlias ::=
+ * > [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ * >
+ * > mixinApplication ::=
+ * > [TypeName] [WithClause] [ImplementsClause]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ClassTypeAlias extends TypeAlias {
+ /**
+ * Initialize a newly created class type alias. Either or both of the
+ * [comment] and [metadata] can be `null` if the class type alias does not
+ * have the corresponding attribute. The [typeParameters] can be `null` if the
+ * class does not have any type parameters. The [abstractKeyword] can be
+ * `null` if the class is not abstract. The [implementsClause] can be `null`
+ * if the class does not implement any interfaces.
+ */
+ factory ClassTypeAlias(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ Token equals,
+ Token abstractKeyword,
+ TypeName superclass,
+ WithClause withClause,
+ ImplementsClause implementsClause,
+ Token semicolon) = ClassTypeAliasImpl;
+
+ /**
+ * Return the token for the 'abstract' keyword, or `null` if this is not
+ * defining an abstract class.
+ */
+ Token get abstractKeyword;
+
+ /**
+ * Set the token for the 'abstract' keyword to the given [token].
+ */
+ void set abstractKeyword(Token token);
+
+ /**
+ * Return the token for the '=' separating the name from the definition.
+ */
+ Token get equals;
+
+ /**
+ * Set the token for the '=' separating the name from the definition to the
+ * given [token].
+ */
+ void set equals(Token token);
+
+ /**
+ * Return the implements clause for this class, or `null` if there is no
+ * implements clause.
+ */
+ ImplementsClause get implementsClause;
+
+ /**
+ * Set the implements clause for this class to the given [implementsClause].
+ */
+ void set implementsClause(ImplementsClause implementsClause);
+
+ /**
+ * Return `true` if this class is declared to be an abstract class.
+ */
+ bool get isAbstract;
+
+ /**
+ * Return the name of the superclass of the class being declared.
+ */
+ TypeName get superclass;
+
+ /**
+ * Set the name of the superclass of the class being declared to the given
+ * [superclass] name.
+ */
+ void set superclass(TypeName superclass);
+
+ /**
+ * Return the type parameters for the class, or `null` if the class does not
+ * have any type parameters.
+ */
+ TypeParameterList get typeParameters;
+
+ /**
+ * Set the type parameters for the class to the given list of [typeParameters].
+ */
+ void set typeParameters(TypeParameterList typeParameters);
+
+ /**
+ * Return the with clause for this class.
+ */
+ WithClause get withClause;
+
+ /**
+ * Set the with clause for this class to the given with [withClause].
+ */
+ void set withClause(WithClause withClause);
+}
+
+/**
+ * A combinator associated with an import or export directive.
+ *
+ * > combinator ::=
+ * > [HideCombinator]
+ * > | [ShowCombinator]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Combinator extends AstNode {
+ /**
+ * Return the 'hide' or 'show' keyword specifying what kind of processing is
+ * to be done on the names.
+ */
+ Token get keyword;
+
+ /**
+ * Set the 'hide' or 'show' keyword specifying what kind of processing is
+ * to be done on the names to the given [token].
+ */
+ void set keyword(Token token);
+}
+
+/**
+ * A comment within the source code.
+ *
+ * > comment ::=
+ * > endOfLineComment
+ * > | blockComment
+ * > | documentationComment
+ * >
+ * > endOfLineComment ::=
+ * > '//' (CHARACTER - EOL)* EOL
+ * >
+ * > blockComment ::=
+ * > '/ *' CHARACTER* '*/'
+ * >
+ * > documentationComment ::=
+ * > '/ **' (CHARACTER | [CommentReference])* '*/'
+ * > | ('///' (CHARACTER - EOL)* EOL)+
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Comment extends AstNode {
+ /**
+ * Initialize a newly created comment. The list of [tokens] must contain at
+ * least one token. The [type] is the type of the comment. The list of
+ * [references] can be empty if the comment does not contain any embedded
+ * references.
+ */
+ factory Comment(List<Token> tokens, CommentType type,
+ List<CommentReference> references) = CommentImpl;
+
+ /**
+ * Return `true` if this is a block comment.
+ */
+ bool get isBlock;
+
+ /**
+ * Return `true` if this is a documentation comment.
+ */
+ bool get isDocumentation;
+
+ /**
+ * Return `true` if this is an end-of-line comment.
+ */
+ bool get isEndOfLine;
+
+ /**
+ * Return the references embedded within the documentation comment.
+ */
+ NodeList<CommentReference> get references;
+
+ /**
+ * Return the tokens representing the comment.
+ */
+ List<Token> get tokens;
+
+ /**
+ * Create a block comment consisting of the given [tokens].
+ */
+ static Comment createBlockComment(List<Token> tokens) =>
+ CommentImpl.createBlockComment(tokens);
+
+ /**
+ * Create a documentation comment consisting of the given [tokens].
+ */
+ static Comment createDocumentationComment(List<Token> tokens) =>
+ CommentImpl.createDocumentationComment(tokens);
+
+ /**
+ * Create a documentation comment consisting of the given [tokens] and having
+ * the given [references] embedded within it.
+ */
+ static Comment createDocumentationCommentWithReferences(
+ List<Token> tokens, List<CommentReference> references) =>
+ CommentImpl.createDocumentationCommentWithReferences(tokens, references);
+
+ /**
+ * Create an end-of-line comment consisting of the given [tokens].
+ */
+ static Comment createEndOfLineComment(List<Token> tokens) =>
+ CommentImpl.createEndOfLineComment(tokens);
+}
+
+/**
+ * A reference to a Dart element that is found within a documentation comment.
+ *
+ * > commentReference ::=
+ * > '[' 'new'? [Identifier] ']'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CommentReference extends AstNode {
+ /**
+ * Initialize a newly created reference to a Dart element. The [newKeyword]
+ * can be `null` if the reference is not to a constructor.
+ */
+ factory CommentReference(Token newKeyword, Identifier identifier) =
+ CommentReferenceImpl;
+
+ /**
+ * Return the identifier being referenced.
+ */
+ Identifier get identifier;
+
+ /**
+ * Set the identifier being referenced to the given [identifier].
+ */
+ void set identifier(Identifier identifier);
+
+ /**
+ * Return the token representing the 'new' keyword, or `null` if there was no
+ * 'new' keyword.
+ */
+ Token get newKeyword;
+
+ /**
+ * Set the token representing the 'new' keyword to the given [token].
+ */
+ void set newKeyword(Token token);
+}
+
+/**
+ * A compilation unit.
+ *
+ * While the grammar restricts the order of the directives and declarations
+ * within a compilation unit, this class does not enforce those restrictions.
+ * In particular, the children of a compilation unit will be visited in lexical
+ * order even if lexical order does not conform to the restrictions of the
+ * grammar.
+ *
+ * > compilationUnit ::=
+ * > directives declarations
+ * >
+ * > directives ::=
+ * > [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
+ * > | [PartOfDirective]
+ * >
+ * > namespaceDirective ::=
+ * > [ImportDirective]
+ * > | [ExportDirective]
+ * >
+ * > declarations ::=
+ * > [CompilationUnitMember]*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CompilationUnit extends AstNode {
+ /**
+ * Initialize a newly created compilation unit to have the given directives
+ * and declarations. The [scriptTag] can be `null` if there is no script tag
+ * in the compilation unit. The list of [directives] can be `null` if there
+ * are no directives in the compilation unit. The list of [declarations] can
+ * be `null` if there are no declarations in the compilation unit.
+ */
+ factory CompilationUnit(
+ Token beginToken,
+ ScriptTag scriptTag,
+ List<Directive> directives,
+ List<CompilationUnitMember> declarations,
+ Token endToken) = CompilationUnitImpl;
+
+ /**
+ * Set the first token included in this node's source range to the given
+ * [token].
+ */
+ void set beginToken(Token token);
+
+ /**
+ * Return the declarations contained in this compilation unit.
+ */
+ NodeList<CompilationUnitMember> get declarations;
+
+ /**
+ * Return the directives contained in this compilation unit.
+ */
+ NodeList<Directive> get directives;
+
+ /**
+ * Return the element associated with this compilation unit, or `null` if the
+ * AST structure has not been resolved.
+ */
+ CompilationUnitElement get element;
+
+ /**
+ * Set the element associated with this compilation unit to the given
+ * [element].
+ */
+ void set element(CompilationUnitElement element);
+
+ /**
+ * Set the last token included in this node's source range to the given
+ * [token].
+ */
+ void set endToken(Token token);
+
+ /**
+ * Return the line information for this compilation unit.
+ */
+ LineInfo get lineInfo;
+
+ /**
+ * Set the line information for this compilation unit to the given [info].
+ */
+ void set lineInfo(LineInfo info);
+
+ /**
+ * Return the script tag at the beginning of the compilation unit, or `null`
+ * if there is no script tag in this compilation unit.
+ */
+ ScriptTag get scriptTag;
+
+ /**
+ * Set the script tag at the beginning of the compilation unit to the given
+ * [scriptTag].
+ */
+ void set scriptTag(ScriptTag scriptTag);
+
+ /**
+ * Return a list containing all of the directives and declarations in this
+ * compilation unit, sorted in lexical order.
+ */
+ List<AstNode> get sortedDirectivesAndDeclarations;
+}
+
+/**
+ * A node that declares one or more names within the scope of a compilation
+ * unit.
+ *
+ * > compilationUnitMember ::=
+ * > [ClassDeclaration]
+ * > | [TypeAlias]
+ * > | [FunctionDeclaration]
+ * > | [MethodDeclaration]
+ * > | [VariableDeclaration]
+ * > | [VariableDeclaration]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CompilationUnitMember extends Declaration {}
+
+/**
+ * A conditional expression.
+ *
+ * > conditionalExpression ::=
+ * > [Expression] '?' [Expression] ':' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConditionalExpression extends Expression {
+ /**
+ * Initialize a newly created conditional expression.
+ */
+ factory ConditionalExpression(
+ Expression condition,
+ Token question,
+ Expression thenExpression,
+ Token colon,
+ Expression elseExpression) = ConditionalExpressionImpl;
+
+ /**
+ * Return the token used to separate the then expression from the else
+ * expression.
+ */
+ Token get colon;
+
+ /**
+ * Set the token used to separate the then expression from the else expression
+ * to the given [token].
+ */
+ void set colon(Token token);
+
+ /**
+ * Return the condition used to determine which of the expressions is executed
+ * next.
+ */
+ Expression get condition;
+
+ /**
+ * Set the condition used to determine which of the expressions is executed
+ * next to the given [expression].
+ */
+ void set condition(Expression expression);
+
+ /**
+ * Return the expression that is executed if the condition evaluates to
+ * `false`.
+ */
+ Expression get elseExpression;
+
+ /**
+ * Set the expression that is executed if the condition evaluates to `false`
+ * to the given [expression].
+ */
+ void set elseExpression(Expression expression);
+
+ /**
+ * Return the token used to separate the condition from the then expression.
+ */
+ Token get question;
+
+ /**
+ * Set the token used to separate the condition from the then expression to
+ * the given [token].
+ */
+ void set question(Token token);
+
+ /**
+ * Return the expression that is executed if the condition evaluates to
+ * `true`.
+ */
+ Expression get thenExpression;
+
+ /**
+ * Set the expression that is executed if the condition evaluates to `true` to
+ * the given [expression].
+ */
+ void set thenExpression(Expression expression);
+}
+
+/**
+ * A configuration in either an import or export directive.
+ *
+ * > configuration ::=
+ * > 'if' '(' test ')' uri
+ * >
+ * > test ::=
+ * > dottedName ('==' stringLiteral)?
+ * >
+ * > dottedName ::=
+ * > identifier ('.' identifier)*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Configuration extends AstNode {
+ /**
+ * Initialize a newly created configuration.
+ */
+ factory Configuration(
+ Token ifKeyword,
+ Token leftParenthesis,
+ DottedName name,
+ Token equalToken,
+ StringLiteral value,
+ Token rightParenthesis,
+ StringLiteral libraryUri) = ConfigurationImpl;
+
+ /**
+ * Return the token for the equal operator, or `null` if the condition does
+ * not include an equality test.
+ */
+ Token get equalToken;
+
+ /**
+ * Set the token for the equal operator to the given [token].
+ */
+ void set equalToken(Token token);
+
+ /**
+ * Return the token for the 'if' keyword.
+ */
+ Token get ifKeyword;
+
+ /**
+ * Set the token for the 'if' keyword to the given [token].
+ */
+ void set ifKeyword(Token token);
+
+ /**
+ * Return the token for the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the token for the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the URI of the implementation library to be used if the condition is
+ * true.
+ */
+ StringLiteral get libraryUri;
+
+ /**
+ * Set the URI of the implementation library to be used if the condition is
+ * true to the given [uri].
+ */
+ void set libraryUri(StringLiteral uri);
+
+ /**
+ * Return the name of the declared variable whose value is being used in the
+ * condition.
+ */
+ DottedName get name;
+
+ /**
+ * Set the name of the declared variable whose value is being used in the
+ * condition to the given [name].
+ */
+ void set name(DottedName name);
+
+ /**
+ * Return the token for the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the token for the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the value to which the value of the declared variable will be
+ * compared, or `null` if the condition does not include an equality test.
+ */
+ StringLiteral get value;
+
+ /**
+ * Set the value to which the value of the declared variable will be
+ * compared to the given [value].
+ */
+ void set value(StringLiteral value);
+}
+
+/**
+ * A constructor declaration.
+ *
+ * > constructorDeclaration ::=
+ * > constructorSignature [FunctionBody]?
+ * > | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
+ * >
+ * > constructorSignature ::=
+ * > 'external'? constructorName formalParameterList initializerList?
+ * > | 'external'? 'factory' factoryName formalParameterList initializerList?
+ * > | 'external'? 'const' constructorName formalParameterList initializerList?
+ * >
+ * > constructorName ::=
+ * > [SimpleIdentifier] ('.' [SimpleIdentifier])?
+ * >
+ * > factoryName ::=
+ * > [Identifier] ('.' [SimpleIdentifier])?
+ * >
+ * > initializerList ::=
+ * > ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorDeclaration extends ClassMember {
+ /**
+ * Initialize a newly created constructor declaration. The [externalKeyword]
+ * can be `null` if the constructor is not external. Either or both of the
+ * [comment] and [metadata] can be `null` if the constructor does not have the
+ * corresponding attribute. The [constKeyword] can be `null` if the
+ * constructor cannot be used to create a constant. The [factoryKeyword] can
+ * be `null` if the constructor is not a factory. The [period] and [name] can
+ * both be `null` if the constructor is not a named constructor. The
+ * [separator] can be `null` if the constructor does not have any initializers
+ * and does not redirect to a different constructor. The list of
+ * [initializers] can be `null` if the constructor does not have any
+ * initializers. The [redirectedConstructor] can be `null` if the constructor
+ * does not redirect to a different constructor. The [body] can be `null` if
+ * the constructor does not have a body.
+ */
+ factory ConstructorDeclaration(
+ Comment comment,
+ List<Annotation> metadata,
+ Token externalKeyword,
+ Token constKeyword,
+ Token factoryKeyword,
+ Identifier returnType,
+ Token period,
+ SimpleIdentifier name,
+ FormalParameterList parameters,
+ Token separator,
+ List<ConstructorInitializer> initializers,
+ ConstructorName redirectedConstructor,
+ FunctionBody body) = ConstructorDeclarationImpl;
+
+ /**
+ * Return the body of the constructor, or `null` if the constructor does not
+ * have a body.
+ */
+ FunctionBody get body;
+
+ /**
+ * Set the body of the constructor to the given [functionBody].
+ */
+ void set body(FunctionBody functionBody);
+
+ /**
+ * Return the token for the 'const' keyword, or `null` if the constructor is
+ * not a const constructor.
+ */
+ Token get constKeyword;
+
+ /**
+ * Set the token for the 'const' keyword to the given [token].
+ */
+ void set constKeyword(Token token);
+
+ @override
+ ConstructorElement get element;
+
+ /**
+ * Set the element associated with this constructor to the given [element].
+ */
+ void set element(ConstructorElement element);
+
+ /**
+ * Return the token for the 'external' keyword to the given [token].
+ */
+ Token get externalKeyword;
+
+ /**
+ * Set the token for the 'external' keyword, or `null` if the constructor
+ * is not external.
+ */
+ void set externalKeyword(Token token);
+
+ /**
+ * Return the token for the 'factory' keyword, or `null` if the constructor is
+ * not a factory constructor.
+ */
+ Token get factoryKeyword;
+
+ /**
+ * Set the token for the 'factory' keyword to the given [token].
+ */
+ void set factoryKeyword(Token token);
+
+ /**
+ * Return the initializers associated with the constructor.
+ */
+ NodeList<ConstructorInitializer> get initializers;
+
+ /**
+ * Return the name of the constructor, or `null` if the constructor being
+ * declared is unnamed.
+ */
+ SimpleIdentifier get name;
+
+ /**
+ * Set the name of the constructor to the given [identifier].
+ */
+ void set name(SimpleIdentifier identifier);
+
+ /**
+ * Return the parameters associated with the constructor.
+ */
+ FormalParameterList get parameters;
+
+ /**
+ * Set the parameters associated with the constructor to the given list of
+ * [parameters].
+ */
+ void set parameters(FormalParameterList parameters);
+
+ /**
+ * Return the token for the period before the constructor name, or `null` if
+ * the constructor being declared is unnamed.
+ */
+ Token get period;
+
+ /**
+ * Set the token for the period before the constructor name to the given
+ * [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the name of the constructor to which this constructor will be
+ * redirected, or `null` if this is not a redirecting factory constructor.
+ */
+ ConstructorName get redirectedConstructor;
+
+ /**
+ * Set the name of the constructor to which this constructor will be
+ * redirected to the given [redirectedConstructor] name.
+ */
+ void set redirectedConstructor(ConstructorName redirectedConstructor);
+
+ /**
+ * Return the type of object being created. This can be different than the
+ * type in which the constructor is being declared if the constructor is the
+ * implementation of a factory constructor.
+ */
+ Identifier get returnType;
+
+ /**
+ * Set the type of object being created to the given [typeName].
+ */
+ void set returnType(Identifier typeName);
+
+ /**
+ * Return the token for the separator (colon or equals) before the initializer
+ * list or redirection, or `null` if there are no initializers.
+ */
+ Token get separator;
+
+ /**
+ * Set the token for the separator (colon or equals) before the initializer
+ * list or redirection to the given [token].
+ */
+ void set separator(Token token);
+}
+
+/**
+ * The initialization of a field within a constructor's initialization list.
+ *
+ * > fieldInitializer ::=
+ * > ('this' '.')? [SimpleIdentifier] '=' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorFieldInitializer extends ConstructorInitializer {
+ /**
+ * Initialize a newly created field initializer to initialize the field with
+ * the given name to the value of the given expression. The [thisKeyword] and
+ * [period] can be `null` if the 'this' keyword was not specified.
+ */
+ factory ConstructorFieldInitializer(
+ Token thisKeyword,
+ Token period,
+ SimpleIdentifier fieldName,
+ Token equals,
+ Expression expression) = ConstructorFieldInitializerImpl;
+
+ /**
+ * Return the token for the equal sign between the field name and the
+ * expression.
+ */
+ Token get equals;
+
+ /**
+ * Set the token for the equal sign between the field name and the
+ * expression to the given [token].
+ */
+ void set equals(Token token);
+
+ /**
+ * Return the expression computing the value to which the field will be
+ * initialized.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression computing the value to which the field will be
+ * initialized to the given [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the name of the field being initialized.
+ */
+ SimpleIdentifier get fieldName;
+
+ /**
+ * Set the name of the field being initialized to the given [identifier].
+ */
+ void set fieldName(SimpleIdentifier identifier);
+
+ /**
+ * Return the token for the period after the 'this' keyword, or `null` if
+ * there is no 'this' keyword.
+ */
+ Token get period;
+
+ /**
+ * Set the token for the period after the 'this' keyword to the given [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the token for the 'this' keyword, or `null` if there is no 'this'
+ * keyword.
+ */
+ Token get thisKeyword;
+
+ /**
+ * Set the token for the 'this' keyword to the given [token].
+ */
+ void set thisKeyword(Token token);
+}
+
+/**
+ * A node that can occur in the initializer list of a constructor declaration.
+ *
+ * > constructorInitializer ::=
+ * > [SuperConstructorInvocation]
+ * > | [ConstructorFieldInitializer]
+ * > | [RedirectingConstructorInvocation]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorInitializer extends AstNode {}
+
+/**
+ * The name of a constructor.
+ *
+ * > constructorName ::=
+ * > type ('.' identifier)?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorName extends AstNode {
+ /**
+ * Initialize a newly created constructor name. The [period] and [name] can be
+ * `null` if the constructor being named is the unnamed constructor.
+ */
+ factory ConstructorName(TypeName type, Token period, SimpleIdentifier name) =
+ ConstructorNameImpl;
+
+ /**
+ * Return the name of the constructor, or `null` if the specified constructor
+ * is the unnamed constructor.
+ */
+ SimpleIdentifier get name;
+
+ /**
+ * Set the name of the constructor to the given [name].
+ */
+ void set name(SimpleIdentifier name);
+
+ /**
+ * Return the token for the period before the constructor name, or `null` if
+ * the specified constructor is the unnamed constructor.
+ */
+ Token get period;
+
+ /**
+ * Set the token for the period before the constructor name to the given
+ * [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the element associated with this constructor name based on static
+ * type information, or `null` if the AST structure has not been resolved or
+ * if this constructor name could not be resolved.
+ */
+ ConstructorElement get staticElement;
+
+ /**
+ * Set the element associated with this constructor name based on static type
+ * information to the given [element].
+ */
+ void set staticElement(ConstructorElement element);
+
+ /**
+ * Return the name of the type defining the constructor.
+ */
+ TypeName get type;
+
+ /**
+ * Set the name of the type defining the constructor to the given [type] name.
+ */
+ void set type(TypeName type);
+}
+
+/**
+ * A continue statement.
+ *
+ * > continueStatement ::=
+ * > 'continue' [SimpleIdentifier]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ContinueStatement extends Statement {
+ /**
+ * Initialize a newly created continue statement. The [label] can be `null` if
+ * there is no label associated with the statement.
+ */
+ factory ContinueStatement(
+ Token continueKeyword, SimpleIdentifier label, Token semicolon) =
+ ContinueStatementImpl;
+
+ /**
+ * Return the token representing the 'continue' keyword.
+ */
+ Token get continueKeyword;
+
+ /**
+ * Set the token representing the 'continue' keyword to the given [token].
+ */
+ void set continueKeyword(Token token);
+
+ /**
+ * Return the label associated with the statement, or `null` if there is no
+ * label.
+ */
+ SimpleIdentifier get label;
+
+ /**
+ * Set the label associated with the statement to the given [identifier].
+ */
+ void set label(SimpleIdentifier identifier);
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the node to which this continue statement is continuing. This will
+ * be either a [Statement] (in the case of continuing a loop), a
+ * [SwitchMember] (in the case of continuing from one switch case to another),
+ * or `null` if the AST has not yet been resolved or if the target could not
+ * be resolved. Note that if the source code has errors, the target might be
+ * invalid (e.g. the target may be in an enclosing function).
+ */
+ AstNode get target;
+
+ /**
+ * Set the node to which this continue statement is continuing to the given
+ * [node].
+ */
+ void set target(AstNode node);
+}
+
+/**
+ * A node that represents the declaration of one or more names. Each declared
+ * name is visible within a name scope.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Declaration extends AnnotatedNode {
+ /**
+ * Return the element associated with this declaration, or `null` if either
+ * this node corresponds to a list of declarations or if the AST structure has
+ * not been resolved.
+ */
+ Element get element;
+}
+
+/**
+ * The declaration of a single identifier.
+ *
+ * > declaredIdentifier ::=
+ * > [Annotation] finalConstVarOrType [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DeclaredIdentifier extends Declaration {
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The [keyword] can be `null` if a type name is
+ * given. The [type] must be `null` if the keyword is 'var'.
+ */
+ factory DeclaredIdentifier(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ TypeName type,
+ SimpleIdentifier identifier) = DeclaredIdentifierImpl;
+
+ @override
+ LocalVariableElement get element;
+
+ /**
+ * Return the name of the variable being declared.
+ */
+ SimpleIdentifier get identifier;
+
+ /**
+ * Set the name of the variable being declared to the given [identifier].
+ */
+ void set identifier(SimpleIdentifier identifier);
+
+ /**
+ * Return `true` if this variable was declared with the 'const' modifier.
+ */
+ bool get isConst;
+
+ /**
+ * Return `true` if this variable was declared with the 'final' modifier.
+ * Variables that are declared with the 'const' modifier will return `false`
+ * even though they are implicitly final.
+ */
+ bool get isFinal;
+
+ /**
+ * Return the token representing either the 'final', 'const' or 'var' keyword,
+ * or `null` if no keyword was used.
+ */
+ Token get keyword;
+
+ /**
+ * Set the token representing either the 'final', 'const' or 'var' keyword to
+ * the given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the name of the declared type of the parameter, or `null` if the
+ * parameter does not have a declared type.
+ */
+ TypeName get type;
+
+ /**
+ * Set the name of the declared type of the parameter to the given [typeName].
+ */
+ void set type(TypeName typeName);
+}
+
+/**
+ * A formal parameter with a default value. There are two kinds of parameters
+ * that are both represented by this class: named formal parameters and
+ * positional formal parameters.
+ *
+ * > defaultFormalParameter ::=
+ * > [NormalFormalParameter] ('=' [Expression])?
+ * >
+ * > defaultNamedParameter ::=
+ * > [NormalFormalParameter] (':' [Expression])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DefaultFormalParameter extends FormalParameter {
+ /**
+ * Initialize a newly created default formal parameter. The [separator] and
+ * [defaultValue] can be `null` if there is no default value.
+ */
+ factory DefaultFormalParameter(
+ NormalFormalParameter parameter,
+ ParameterKind kind,
+ Token separator,
+ Expression defaultValue) = DefaultFormalParameterImpl;
+
+ /**
+ * Return the expression computing the default value for the parameter, or
+ * `null` if there is no default value.
+ */
+ Expression get defaultValue;
+
+ /**
+ * Set the expression computing the default value for the parameter to the
+ * given [expression].
+ */
+ void set defaultValue(Expression expression);
+
+ /**
+ * Set the kind of this parameter to the given [kind].
+ */
+ void set kind(ParameterKind kind);
+
+ /**
+ * Return the formal parameter with which the default value is associated.
+ */
+ NormalFormalParameter get parameter;
+
+ /**
+ * Set the formal parameter with which the default value is associated to the
+ * given [formalParameter].
+ */
+ void set parameter(NormalFormalParameter formalParameter);
+
+ /**
+ * Return the token separating the parameter from the default value, or `null`
+ * if there is no default value.
+ */
+ Token get separator;
+
+ /**
+ * Set the token separating the parameter from the default value to the given
+ * [token].
+ */
+ void set separator(Token token);
+}
+
+/**
+ * A node that represents a directive.
+ *
+ * > directive ::=
+ * > [ExportDirective]
+ * > | [ImportDirective]
+ * > | [LibraryDirective]
+ * > | [PartDirective]
+ * > | [PartOfDirective]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Directive extends AnnotatedNode {
+ /**
+ * Return the element associated with this directive, or `null` if the AST
+ * structure has not been resolved or if this directive could not be resolved.
+ */
+ Element get element;
+
+ /**
+ * Set the element associated with this directive to the given [element].
+ */
+ void set element(Element element);
+
+ /**
+ * Return the token representing the keyword that introduces this directive
+ * ('import', 'export', 'library' or 'part').
+ */
+ Token get keyword;
+}
+
+/**
+ * A do statement.
+ *
+ * > doStatement ::=
+ * > 'do' [Statement] 'while' '(' [Expression] ')' ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DoStatement extends Statement {
+ /**
+ * Initialize a newly created do loop.
+ */
+ factory DoStatement(
+ Token doKeyword,
+ Statement body,
+ Token whileKeyword,
+ Token leftParenthesis,
+ Expression condition,
+ Token rightParenthesis,
+ Token semicolon) = DoStatementImpl;
+
+ /**
+ * Return the body of the loop.
+ */
+ Statement get body;
+
+ /**
+ * Set the body of the loop to the given [statement].
+ */
+ void set body(Statement statement);
+
+ /**
+ * Return the condition that determines when the loop will terminate.
+ */
+ Expression get condition;
+
+ /**
+ * Set the condition that determines when the loop will terminate to the given
+ * [expression].
+ */
+ void set condition(Expression expression);
+
+ /**
+ * Return the token representing the 'do' keyword.
+ */
+ Token get doKeyword;
+
+ /**
+ * Set the token representing the 'do' keyword to the given [token].
+ */
+ void set doKeyword(Token token);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the token representing the 'while' keyword.
+ */
+ Token get whileKeyword;
+
+ /**
+ * Set the token representing the 'while' keyword to the given [token].
+ */
+ void set whileKeyword(Token token);
+}
+
+/**
+ * A dotted name, used in a configuration within an import or export directive.
+ *
+ * > dottedName ::=
+ * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DottedName extends AstNode {
+ /**
+ * Initialize a newly created dotted name.
+ */
+ factory DottedName(List<SimpleIdentifier> components) = DottedNameImpl;
+
+ /**
+ * Return the components of the identifier.
+ */
+ NodeList<SimpleIdentifier> get components;
+}
+
+/**
+ * A floating point literal expression.
+ *
+ * > doubleLiteral ::=
+ * > decimalDigit+ ('.' decimalDigit*)? exponent?
+ * > | '.' decimalDigit+ exponent?
+ * >
+ * > exponent ::=
+ * > ('e' | 'E') ('+' | '-')? decimalDigit+
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DoubleLiteral extends Literal {
+ /**
+ * Initialize a newly created floating point literal.
+ */
+ factory DoubleLiteral(Token literal, double value) = DoubleLiteralImpl;
+
+ /**
+ * Return the token representing the literal.
+ */
+ Token get literal;
+
+ /**
+ * Set the token representing the literal to the given [token].
+ */
+ void set literal(Token token);
+
+ /**
+ * Return the value of the literal.
+ */
+ double get value;
+
+ /**
+ * Set the value of the literal to the given [value].
+ */
+ void set value(double value);
+}
+
+/**
+ * An empty function body, which can only appear in constructors or abstract
+ * methods.
+ *
+ * > emptyFunctionBody ::=
+ * > ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EmptyFunctionBody extends FunctionBody {
+ /**
+ * Initialize a newly created function body.
+ */
+ factory EmptyFunctionBody(Token semicolon) = EmptyFunctionBodyImpl;
+
+ /**
+ * Return the token representing the semicolon that marks the end of the
+ * function body.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the token representing the semicolon that marks the end of the
+ * function body to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * An empty statement.
+ *
+ * > emptyStatement ::=
+ * > ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EmptyStatement extends Statement {
+ /**
+ * Initialize a newly created empty statement.
+ */
+ factory EmptyStatement(Token semicolon) = EmptyStatementImpl;
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * The declaration of an enum constant.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EnumConstantDeclaration extends Declaration {
+ /**
+ * Initialize a newly created enum constant declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the constant does not have the
+ * corresponding attribute. (Technically, enum constants cannot have metadata,
+ * but we allow it for consistency.)
+ */
+ factory EnumConstantDeclaration(
+ Comment comment, List<Annotation> metadata, SimpleIdentifier name) =
+ EnumConstantDeclarationImpl;
+
+ /**
+ * Return the name of the constant.
+ */
+ SimpleIdentifier get name;
+
+ /**
+ * Set the name of the constant to the given [name].
+ */
+ void set name(SimpleIdentifier name);
+}
+
+/**
+ * The declaration of an enumeration.
+ *
+ * > enumType ::=
+ * > metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EnumDeclaration extends NamedCompilationUnitMember {
+ /**
+ * Initialize a newly created enumeration declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The list of [constants] must contain at least one
+ * value.
+ */
+ factory EnumDeclaration(
+ Comment comment,
+ List<Annotation> metadata,
+ Token enumKeyword,
+ SimpleIdentifier name,
+ Token leftBracket,
+ List<EnumConstantDeclaration> constants,
+ Token rightBracket) = EnumDeclarationImpl;
+
+ /**
+ * Return the enumeration constants being declared.
+ */
+ NodeList<EnumConstantDeclaration> get constants;
+
+ @override
+ ClassElement get element;
+
+ /**
+ * Return the 'enum' keyword.
+ */
+ Token get enumKeyword;
+
+ /**
+ * Set the 'enum' keyword to the given [token].
+ */
+ void set enumKeyword(Token token);
+
+ /**
+ * Return the left curly bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left curly bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the right curly bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right curly bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+}
+
+/**
+ * An export directive.
+ *
+ * > exportDirective ::=
+ * > [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExportDirective extends NamespaceDirective {
+ /**
+ * Initialize a newly created export directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute. The list of [combinators] can be `null` if there
+ * are no combinators.
+ */
+ factory ExportDirective(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ StringLiteral libraryUri,
+ List<Configuration> configurations,
+ List<Combinator> combinators,
+ Token semicolon) = ExportDirectiveImpl;
+}
+
+/**
+ * A node that represents an expression.
+ *
+ * > expression ::=
+ * > [AssignmentExpression]
+ * > | [ConditionalExpression] cascadeSection*
+ * > | [ThrowExpression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Expression extends AstNode {
+ /**
+ * An empty list of expressions.
+ */
+ static const List<Expression> EMPTY_LIST = const <Expression>[];
+
+ /**
+ * Return the best parameter element information available for this
+ * expression. If type propagation was able to find a better parameter element
+ * than static analysis, that type will be returned. Otherwise, the result of
+ * static analysis will be returned.
+ */
+ ParameterElement get bestParameterElement;
+
+ /**
+ * Return the best type information available for this expression. If type
+ * propagation was able to find a better type than static analysis, that type
+ * will be returned. Otherwise, the result of static analysis will be
+ * returned. If no type analysis has been performed, then the type 'dynamic'
+ * will be returned.
+ */
+ DartType get bestType;
+
+ /**
+ * Return `true` if this expression is syntactically valid for the LHS of an
+ * [AssignmentExpression].
+ */
+ bool get isAssignable;
+
+ /**
+ * Return the precedence of this expression. The precedence is a positive
+ * integer value that defines how the source code is parsed into an AST. For
+ * example `a * b + c` is parsed as `(a * b) + c` because the precedence of
+ * `*` is greater than the precedence of `+`.
+ *
+ * Clients should not assume that returned values will stay the same, they
+ * might change as result of specification change. Only relative order should
+ * be used.
+ */
+ int get precedence;
+
+ /**
+ * If this expression is an argument to an invocation, and the AST structure
+ * has been resolved, and the function being invoked is known based on
+ * propagated type information, and this expression corresponds to one of the
+ * parameters of the function being invoked, then return the parameter element
+ * representing the parameter to which the value of this expression will be
+ * bound. Otherwise, return `null`.
+ */
+ ParameterElement get propagatedParameterElement;
+
+ /**
+ * Return the propagated type of this expression, or `null` if type
+ * propagation has not been performed on the AST structure.
+ */
+ DartType get propagatedType;
+
+ /**
+ * Set the propagated type of this expression to the given [type].
+ */
+ void set propagatedType(DartType type);
+
+ /**
+ * If this expression is an argument to an invocation, and the AST structure
+ * has been resolved, and the function being invoked is known based on static
+ * type information, and this expression corresponds to one of the parameters
+ * of the function being invoked, then return the parameter element
+ * representing the parameter to which the value of this expression will be
+ * bound. Otherwise, return `null`.
+ */
+ ParameterElement get staticParameterElement;
+
+ /**
+ * Return the static type of this expression, or `null` if the AST structure
+ * has not been resolved.
+ */
+ DartType get staticType;
+
+ /**
+ * Set the static type of this expression to the given [type].
+ */
+ void set staticType(DartType type);
+}
+
+/**
+ * A function body consisting of a single expression.
+ *
+ * > expressionFunctionBody ::=
+ * > 'async'? '=>' [Expression] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExpressionFunctionBody extends FunctionBody {
+ /**
+ * Initialize a newly created function body consisting of a block of
+ * statements. The [keyword] can be `null` if the function body is not an
+ * async function body.
+ */
+ factory ExpressionFunctionBody(Token keyword, Token functionDefinition,
+ Expression expression, Token semicolon) = ExpressionFunctionBodyImpl;
+
+ /**
+ * Return the expression representing the body of the function.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression representing the body of the function to the given
+ * [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the token introducing the expression that represents the body of the
+ * function.
+ */
+ Token get functionDefinition;
+
+ /**
+ * Set the token introducing the expression that represents the body of the
+ * function to the given [token].
+ */
+ void set functionDefinition(Token token);
+
+ /**
+ * Set token representing the 'async' or 'sync' keyword to the given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * An expression used as a statement.
+ *
+ * > expressionStatement ::=
+ * > [Expression]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExpressionStatement extends Statement {
+ /**
+ * Initialize a newly created expression statement.
+ */
+ factory ExpressionStatement(Expression expression, Token semicolon) =
+ ExpressionStatementImpl;
+
+ /**
+ * Return the expression that comprises the statement.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression that comprises the statement to the given [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the semicolon terminating the statement, or `null` if the expression is a
+ * function expression and therefore isn't followed by a semicolon.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * The "extends" clause in a class declaration.
+ *
+ * > extendsClause ::=
+ * > 'extends' [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExtendsClause extends AstNode {
+ /**
+ * Initialize a newly created extends clause.
+ */
+ factory ExtendsClause(Token extendsKeyword, TypeName superclass) =
+ ExtendsClauseImpl;
+
+ /**
+ * Return the token representing the 'extends' keyword.
+ */
+ Token get extendsKeyword;
+
+ /**
+ * Set the token representing the 'extends' keyword to the given [token].
+ */
+ void set extendsKeyword(Token token);
+
+ /**
+ * Return the name of the class that is being extended.
+ */
+ TypeName get superclass;
+
+ /**
+ * Set the name of the class that is being extended to the given [name].
+ */
+ void set superclass(TypeName name);
+}
+
+/**
+ * The declaration of one or more fields of the same type.
+ *
+ * > fieldDeclaration ::=
+ * > 'static'? [VariableDeclarationList] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FieldDeclaration extends ClassMember {
+ /**
+ * Initialize a newly created field declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The [staticKeyword] can be `null` if the field is
+ * not a static field.
+ */
+ factory FieldDeclaration(
+ Comment comment,
+ List<Annotation> metadata,
+ Token staticKeyword,
+ VariableDeclarationList fieldList,
+ Token semicolon) = FieldDeclarationImpl;
+
+ /**
+ * Return the fields being declared.
+ */
+ VariableDeclarationList get fields;
+
+ /**
+ * Set the fields being declared to the given list of [fields].
+ */
+ void set fields(VariableDeclarationList fields);
+
+ /**
+ * Return `true` if the fields are declared to be static.
+ */
+ bool get isStatic;
+
+ /**
+ * Return the semicolon terminating the declaration.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the declaration to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the token representing the 'static' keyword, or `null` if the fields
+ * are not static.
+ */
+ Token get staticKeyword;
+
+ /**
+ * Set the token representing the 'static' keyword to the given [token].
+ */
+ void set staticKeyword(Token token);
+}
+
+/**
+ * A field formal parameter.
+ *
+ * > fieldFormalParameter ::=
+ * > ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ * > 'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FieldFormalParameter extends NormalFormalParameter {
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [keyword] can be `null` if there is a type.
+ * The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
+ * [period] can be `null` if the keyword 'this' was not provided. The
+ * [parameters] can be `null` if this is not a function-typed field formal
+ * parameter.
+ */
+ factory FieldFormalParameter(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ TypeName type,
+ Token thisKeyword,
+ Token period,
+ SimpleIdentifier identifier,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters) = FieldFormalParameterImpl;
+
+ /**
+ * Return the token representing either the 'final', 'const' or 'var' keyword,
+ * or `null` if no keyword was used.
+ */
+ Token get keyword;
+
+ /**
+ * Set the token representing either the 'final', 'const' or 'var' keyword to
+ * the given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the parameters of the function-typed parameter, or `null` if this is
+ * not a function-typed field formal parameter.
+ */
+ FormalParameterList get parameters;
+
+ /**
+ * Set the parameters of the function-typed parameter to the given
+ * [parameters].
+ */
+ void set parameters(FormalParameterList parameters);
+
+ /**
+ * Return the token representing the period.
+ */
+ Token get period;
+
+ /**
+ * Set the token representing the period to the given [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the token representing the 'this' keyword.
+ */
+ Token get thisKeyword;
+
+ /**
+ * Set the token representing the 'this' keyword to the given [token].
+ */
+ void set thisKeyword(Token token);
+
+ /**
+ * Return the name of the declared type of the parameter, or `null` if the
+ * parameter does not have a declared type. Note that if this is a
+ * function-typed field formal parameter this is the return type of the
+ * function.
+ */
+ TypeName get type;
+
+ /**
+ * Set the name of the declared type of the parameter to the given [typeName].
+ */
+ void set type(TypeName typeName);
+
+ /**
+ * Return the type parameters associated with this method, or `null` if this
+ * method is not a generic method.
+ */
+ TypeParameterList get typeParameters;
+
+ /**
+ * Set the type parameters associated with this method to the given
+ * [typeParameters].
+ */
+ void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * A for-each statement.
+ *
+ * > forEachStatement ::=
+ * > 'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+ * > | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ForEachStatement extends Statement {
+ /**
+ * Initialize a newly created for-each statement whose loop control variable
+ * is declared internally (in the for-loop part). The [awaitKeyword] can be
+ * `null` if this is not an asynchronous for loop.
+ */
+ factory ForEachStatement.withDeclaration(
+ Token awaitKeyword,
+ Token forKeyword,
+ Token leftParenthesis,
+ DeclaredIdentifier loopVariable,
+ Token inKeyword,
+ Expression iterator,
+ Token rightParenthesis,
+ Statement body) = ForEachStatementImpl.withDeclaration;
+
+ /**
+ * Initialize a newly created for-each statement whose loop control variable
+ * is declared outside the for loop. The [awaitKeyword] can be `null` if this
+ * is not an asynchronous for loop.
+ */
+ factory ForEachStatement.withReference(
+ Token awaitKeyword,
+ Token forKeyword,
+ Token leftParenthesis,
+ SimpleIdentifier identifier,
+ Token inKeyword,
+ Expression iterator,
+ Token rightParenthesis,
+ Statement body) = ForEachStatementImpl.withReference;
+
+ /**
+ * Return the token representing the 'await' keyword, or `null` if there is no
+ * 'await' keyword.
+ */
+ Token get awaitKeyword;
+
+ /**
+ * Set the token representing the 'await' keyword to the given [token].
+ */
+ void set awaitKeyword(Token token);
+
+ /**
+ * Return the body of the loop.
+ */
+ Statement get body;
+
+ /**
+ * Set the body of the loop to the given [statement].
+ */
+ void set body(Statement statement);
+
+ /**
+ * Return the token representing the 'for' keyword.
+ */
+ Token get forKeyword;
+
+ /**
+ * Set the token representing the 'for' keyword to the given [token].
+ */
+ void set forKeyword(Token token);
+
+ /**
+ * Return the loop variable, or `null` if the loop variable is declared in the
+ * 'for'.
+ */
+ SimpleIdentifier get identifier;
+
+ /**
+ * Set the loop variable to the given [identifier].
+ */
+ void set identifier(SimpleIdentifier identifier);
+
+ /**
+ * Return the token representing the 'in' keyword.
+ */
+ Token get inKeyword;
+
+ /**
+ * Set the token representing the 'in' keyword to the given [token].
+ */
+ void set inKeyword(Token token);
+
+ /**
+ * Return the expression evaluated to produce the iterator.
+ */
+ Expression get iterable;
+
+ /**
+ * Set the expression evaluated to produce the iterator to the given
+ * [expression].
+ */
+ void set iterable(Expression expression);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the declaration of the loop variable, or `null` if the loop variable
+ * is a simple identifier.
+ */
+ DeclaredIdentifier get loopVariable;
+
+ /**
+ * Set the declaration of the loop variable to the given [variable].
+ */
+ void set loopVariable(DeclaredIdentifier variable);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+}
+
+/**
+ * A node representing a parameter to a function.
+ *
+ * > formalParameter ::=
+ * > [NormalFormalParameter]
+ * > | [DefaultFormalParameter]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FormalParameter extends AstNode {
+ /**
+ * Return the element representing this parameter, or `null` if this parameter
+ * has not been resolved.
+ */
+ ParameterElement get element;
+
+ /**
+ * Return the name of the parameter being declared.
+ */
+ SimpleIdentifier get identifier;
+
+ /**
+ * Return `true` if this parameter was declared with the 'const' modifier.
+ */
+ bool get isConst;
+
+ /**
+ * Return `true` if this parameter was declared with the 'final' modifier.
+ * Parameters that are declared with the 'const' modifier will return `false`
+ * even though they are implicitly final.
+ */
+ bool get isFinal;
+
+ /**
+ * Return the kind of this parameter.
+ */
+ ParameterKind get kind;
+
+ /**
+ * Return the annotations associated with this parameter.
+ */
+ NodeList<Annotation> get metadata;
+}
+
+/**
+ * The formal parameter list of a method declaration, function declaration, or
+ * function type alias.
+ *
+ * While the grammar requires all optional formal parameters to follow all of
+ * the normal formal parameters and at most one grouping of optional formal
+ * parameters, this class does not enforce those constraints. All parameters are
+ * flattened into a single list, which can have any or all kinds of parameters
+ * (normal, named, and positional) in any order.
+ *
+ * > formalParameterList ::=
+ * > '(' ')'
+ * > | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
+ * > | '(' optionalFormalParameters ')'
+ * >
+ * > normalFormalParameters ::=
+ * > [NormalFormalParameter] (',' [NormalFormalParameter])*
+ * >
+ * > optionalFormalParameters ::=
+ * > optionalPositionalFormalParameters
+ * > | namedFormalParameters
+ * >
+ * > optionalPositionalFormalParameters ::=
+ * > '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
+ * >
+ * > namedFormalParameters ::=
+ * > '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FormalParameterList extends AstNode {
+ /**
+ * Initialize a newly created parameter list. The list of [parameters] can be
+ * `null` if there are no parameters. The [leftDelimiter] and [rightDelimiter]
+ * can be `null` if there are no optional parameters.
+ */
+ factory FormalParameterList(
+ Token leftParenthesis,
+ List<FormalParameter> parameters,
+ Token leftDelimiter,
+ Token rightDelimiter,
+ Token rightParenthesis) = FormalParameterListImpl;
+
+ /**
+ * Return the left square bracket ('[') or left curly brace ('{') introducing
+ * the optional parameters, or `null` if there are no optional parameters.
+ */
+ Token get leftDelimiter;
+
+ /**
+ * Set the left square bracket ('[') or left curly brace ('{') introducing
+ * the optional parameters to the given [token].
+ */
+ void set leftDelimiter(Token token);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return a list containing the elements representing the parameters in this
+ * list. The list will contain `null`s if the parameters in this list have not
+ * been resolved.
+ */
+ List<ParameterElement> get parameterElements;
+
+ /**
+ * Return the parameters associated with the method.
+ */
+ NodeList<FormalParameter> get parameters;
+
+ /**
+ * Return the right square bracket (']') or right curly brace ('}') terminating the
+ * optional parameters, or `null` if there are no optional parameters.
+ */
+ Token get rightDelimiter;
+
+ /**
+ * Set the right square bracket (']') or right curly brace ('}') terminating the
+ * optional parameters to the given [token].
+ */
+ void set rightDelimiter(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+}
+
+/**
+ * A for statement.
+ *
+ * > forStatement ::=
+ * > 'for' '(' forLoopParts ')' [Statement]
+ * >
+ * > forLoopParts ::=
+ * > forInitializerStatement ';' [Expression]? ';' [Expression]?
+ * >
+ * > forInitializerStatement ::=
+ * > [DefaultFormalParameter]
+ * > | [Expression]?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ForStatement extends Statement {
+ /**
+ * Initialize a newly created for statement. Either the [variableList] or the
+ * [initialization] must be `null`. Either the [condition] and the list of
+ * [updaters] can be `null` if the loop does not have the corresponding
+ * attribute.
+ */
+ factory ForStatement(
+ Token forKeyword,
+ Token leftParenthesis,
+ VariableDeclarationList variableList,
+ Expression initialization,
+ Token leftSeparator,
+ Expression condition,
+ Token rightSeparator,
+ List<Expression> updaters,
+ Token rightParenthesis,
+ Statement body) = ForStatementImpl;
+
+ /**
+ * Return the body of the loop.
+ */
+ Statement get body;
+
+ /**
+ * Set the body of the loop to the given [statement].
+ */
+ void set body(Statement statement);
+
+ /**
+ * Return the condition used to determine when to terminate the loop, or
+ * `null` if there is no condition.
+ */
+ Expression get condition;
+
+ /**
+ * Set the condition used to determine when to terminate the loop to the given
+ * [expression].
+ */
+ void set condition(Expression expression);
+
+ /**
+ * Return the token representing the 'for' keyword.
+ */
+ Token get forKeyword;
+
+ /**
+ * Set the token representing the 'for' keyword to the given [token].
+ */
+ void set forKeyword(Token token);
+
+ /**
+ * Return the initialization expression, or `null` if there is no
+ * initialization expression.
+ */
+ Expression get initialization;
+
+ /**
+ * Set the initialization expression to the given [expression].
+ */
+ void set initialization(Expression initialization);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the semicolon separating the initializer and the condition.
+ */
+ Token get leftSeparator;
+
+ /**
+ * Set the semicolon separating the initializer and the condition to the given
+ * [token].
+ */
+ void set leftSeparator(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the semicolon separating the condition and the updater.
+ */
+ Token get rightSeparator;
+
+ /**
+ * Set the semicolon separating the condition and the updater to the given
+ * [token].
+ */
+ void set rightSeparator(Token token);
+
+ /**
+ * Return the list of expressions run after each execution of the loop body.
+ */
+ NodeList<Expression> get updaters;
+
+ /**
+ * Return the declaration of the loop variables, or `null` if there are no
+ * variables.
+ */
+ VariableDeclarationList get variables;
+
+ /**
+ * Set the declaration of the loop variables to the given [variableList].
+ */
+ void set variables(VariableDeclarationList variableList);
+}
+
+/**
+ * A node representing the body of a function or method.
+ *
+ * > functionBody ::=
+ * > [BlockFunctionBody]
+ * > | [EmptyFunctionBody]
+ * > | [ExpressionFunctionBody]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionBody extends AstNode {
+ /**
+ * Return `true` if this function body is asynchronous.
+ */
+ bool get isAsynchronous;
+
+ /**
+ * Return `true` if this function body is a generator.
+ */
+ bool get isGenerator;
+
+ /**
+ * Return `true` if this function body is synchronous.
+ */
+ bool get isSynchronous;
+
+ /**
+ * Return the token representing the 'async' or 'sync' keyword, or `null` if
+ * there is no such keyword.
+ */
+ Token get keyword;
+
+ /**
+ * Return the star following the 'async' or 'sync' keyword, or `null` if there
+ * is no star.
+ */
+ Token get star;
+}
+
+/**
+ * A top-level declaration.
+ *
+ * > functionDeclaration ::=
+ * > 'external' functionSignature
+ * > | functionSignature [FunctionBody]
+ * >
+ * > functionSignature ::=
+ * > [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionDeclaration extends NamedCompilationUnitMember {
+ /**
+ * Initialize a newly created function declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the function does not have the
+ * corresponding attribute. The [externalKeyword] can be `null` if the
+ * function is not an external function. The [returnType] can be `null` if no
+ * return type was specified. The [propertyKeyword] can be `null` if the
+ * function is neither a getter or a setter.
+ */
+ factory FunctionDeclaration(
+ Comment comment,
+ List<Annotation> metadata,
+ Token externalKeyword,
+ TypeName returnType,
+ Token propertyKeyword,
+ SimpleIdentifier name,
+ FunctionExpression functionExpression) = FunctionDeclarationImpl;
+
+ @override
+ ExecutableElement get element;
+
+ /**
+ * Return the token representing the 'external' keyword, or `null` if this is
+ * not an external function.
+ */
+ Token get externalKeyword;
+
+ /**
+ * Set the token representing the 'external' keyword to the given [token].
+ */
+ void set externalKeyword(Token token);
+
+ /**
+ * Return the function expression being wrapped.
+ */
+ FunctionExpression get functionExpression;
+
+ /**
+ * Set the function expression being wrapped to the given
+ * [functionExpression].
+ */
+ void set functionExpression(FunctionExpression functionExpression);
+
+ /**
+ * Return `true` if this function declares a getter.
+ */
+ bool get isGetter;
+
+ /**
+ * Return `true` if this function declares a setter.
+ */
+ bool get isSetter;
+
+ /**
+ * Return the token representing the 'get' or 'set' keyword, or `null` if this
+ * is a function declaration rather than a property declaration.
+ */
+ Token get propertyKeyword;
+
+ /**
+ * Set the token representing the 'get' or 'set' keyword to the given [token].
+ */
+ void set propertyKeyword(Token token);
+
+ /**
+ * Return the return type of the function, or `null` if no return type was
+ * declared.
+ */
+ TypeName get returnType;
+
+ /**
+ * Set the return type of the function to the given [returnType].
+ */
+ void set returnType(TypeName returnType);
+}
+
+/**
+ * A [FunctionDeclaration] used as a statement.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionDeclarationStatement extends Statement {
+ /**
+ * Initialize a newly created function declaration statement.
+ */
+ factory FunctionDeclarationStatement(
+ FunctionDeclaration functionDeclaration) =
+ FunctionDeclarationStatementImpl;
+
+ /**
+ * Return the function declaration being wrapped.
+ */
+ FunctionDeclaration get functionDeclaration;
+
+ /**
+ * Set the function declaration being wrapped to the given
+ * [functionDeclaration].
+ */
+ void set functionDeclaration(FunctionDeclaration functionDeclaration);
+}
+
+/**
+ * A function expression.
+ *
+ * > functionExpression ::=
+ * > [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionExpression extends Expression {
+ /**
+ * Initialize a newly created function declaration.
+ */
+ factory FunctionExpression(
+ TypeParameterList typeParameters,
+ FormalParameterList parameters,
+ FunctionBody body) = FunctionExpressionImpl;
+
+ /**
+ * Return the body of the function, or `null` if this is an external function.
+ */
+ FunctionBody get body;
+
+ /**
+ * Set the body of the function to the given [functionBody].
+ */
+ void set body(FunctionBody functionBody);
+
+ /**
+ * Return the element associated with the function, or `null` if the AST
+ * structure has not been resolved.
+ */
+ ExecutableElement get element;
+
+ /**
+ * Set the element associated with the function to the given [element].
+ */
+ void set element(ExecutableElement element);
+
+ /**
+ * Return the parameters associated with the function.
+ */
+ FormalParameterList get parameters;
+
+ /**
+ * Set the parameters associated with the function to the given list of
+ * [parameters].
+ */
+ void set parameters(FormalParameterList parameters);
+
+ /**
+ * Return the type parameters associated with this method, or `null` if this
+ * method is not a generic method.
+ */
+ TypeParameterList get typeParameters;
+
+ /**
+ * Set the type parameters associated with this method to the given
+ * [typeParameters].
+ */
+ void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * The invocation of a function resulting from evaluating an expression.
+ * Invocations of methods and other forms of functions are represented by
+ * [MethodInvocation] nodes. Invocations of getters and setters are represented
+ * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ * > functionExpressionInvocation ::=
+ * > [Expression] [TypeArgumentList]? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionExpressionInvocation extends Expression {
+ /**
+ * Initialize a newly created function expression invocation.
+ */
+ factory FunctionExpressionInvocation(
+ Expression function,
+ TypeArgumentList typeArguments,
+ ArgumentList argumentList) = FunctionExpressionInvocationImpl;
+
+ /**
+ * Return the list of arguments to the method.
+ */
+ ArgumentList get argumentList;
+
+ /**
+ * Set the list of arguments to the method to the given [argumentList].
+ */
+ void set argumentList(ArgumentList argumentList);
+
+ /**
+ * Return the best element available for the function being invoked. If
+ * resolution was able to find a better element based on type propagation,
+ * that element will be returned. Otherwise, the element found using the
+ * result of static analysis will be returned. If resolution has not been
+ * performed, then `null` will be returned.
+ */
+ ExecutableElement get bestElement;
+
+ /**
+ * Return the expression producing the function being invoked.
+ */
+ Expression get function;
+
+ /**
+ * Set the expression producing the function being invoked to the given
+ * [expression].
+ */
+ void set function(Expression expression);
+
+ /**
+ * Return the element associated with the function being invoked based on
+ * propagated type information, or `null` if the AST structure has not been
+ * resolved or the function could not be resolved.
+ */
+ ExecutableElement get propagatedElement;
+
+ /**
+ * Set the element associated with the function being invoked based on
+ * propagated type information to the given [element].
+ */
+ void set propagatedElement(ExecutableElement element);
+
+ /**
+ * Return the function type of the method invocation based on the propagated
+ * type information, or `null` if the AST structure has not been resolved, or
+ * if the invoke could not be resolved.
+ *
+ * This will usually be a [FunctionType], but it can also be an
+ * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+ * interface type that implements `Function`.
+ */
+ DartType get propagatedInvokeType;
+
+ /**
+ * Set the function type of the method invocation based on the propagated type
+ * information to the given [type].
+ */
+ void set propagatedInvokeType(DartType type);
+
+ /**
+ * Return the element associated with the function being invoked based on
+ * static type information, or `null` if the AST structure has not been
+ * resolved or the function could not be resolved.
+ */
+ ExecutableElement get staticElement;
+
+ /**
+ * Set the element associated with the function being invoked based on static
+ * type information to the given [element].
+ */
+ void set staticElement(ExecutableElement element);
+
+ /**
+ * Return the function type of the method invocation based on the static type
+ * information, or `null` if the AST structure has not been resolved, or if
+ * the invoke could not be resolved.
+ *
+ * This will usually be a [FunctionType], but it can also be an
+ * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+ * interface type that implements `Function`.
+ */
+ DartType get staticInvokeType;
+
+ /**
+ * Set the function type of the method invocation based on the static type
+ * information to the given [type].
+ */
+ void set staticInvokeType(DartType type);
+
+ /**
+ * Return the type arguments to be applied to the method being invoked, or
+ * `null` if no type arguments were provided.
+ */
+ TypeArgumentList get typeArguments;
+
+ /**
+ * Set the type arguments to be applied to the method being invoked to the
+ * given [typeArguments].
+ */
+ void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * A function type alias.
+ *
+ * > functionTypeAlias ::=
+ * > functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ * >
+ * > functionPrefix ::=
+ * > [TypeName]? [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionTypeAlias extends TypeAlias {
+ /**
+ * Initialize a newly created function type alias. Either or both of the
+ * [comment] and [metadata] can be `null` if the function does not have the
+ * corresponding attribute. The [returnType] can be `null` if no return type
+ * was specified. The [typeParameters] can be `null` if the function has no
+ * type parameters.
+ */
+ factory FunctionTypeAlias(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ TypeName returnType,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters,
+ Token semicolon) = FunctionTypeAliasImpl;
+
+ /**
+ * Return the parameters associated with the function type.
+ */
+ FormalParameterList get parameters;
+
+ /**
+ * Set the parameters associated with the function type to the given list of
+ * [parameters].
+ */
+ void set parameters(FormalParameterList parameters);
+
+ /**
+ * Return the name of the return type of the function type being defined, or
+ * `null` if no return type was given.
+ */
+ TypeName get returnType;
+
+ /**
+ * Set the name of the return type of the function type being defined to the
+ * given [typeName].
+ */
+ void set returnType(TypeName typeName);
+
+ /**
+ * Return the type parameters for the function type, or `null` if the function
+ * type does not have any type parameters.
+ */
+ TypeParameterList get typeParameters;
+
+ /**
+ * Set the type parameters for the function type to the given list of
+ * [typeParameters].
+ */
+ void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * A function-typed formal parameter.
+ *
+ * > functionSignature ::=
+ * > [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionTypedFormalParameter extends NormalFormalParameter {
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [returnType] can be `null` if no return type
+ * was specified.
+ */
+ factory FunctionTypedFormalParameter(
+ Comment comment,
+ List<Annotation> metadata,
+ TypeName returnType,
+ SimpleIdentifier identifier,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters) = FunctionTypedFormalParameterImpl;
+
+ /**
+ * Return the parameters of the function-typed parameter.
+ */
+ FormalParameterList get parameters;
+
+ /**
+ * Set the parameters of the function-typed parameter to the given
+ * [parameters].
+ */
+ void set parameters(FormalParameterList parameters);
+
+ /**
+ * Return the return type of the function, or `null` if the function does not
+ * have a return type.
+ */
+ TypeName get returnType;
+
+ /**
+ * Set the return type of the function to the given [type].
+ */
+ void set returnType(TypeName type);
+
+ /**
+ * Return the type parameters associated with this function, or `null` if
+ * this function is not a generic function.
+ */
+ TypeParameterList get typeParameters;
+
+ /**
+ * Set the type parameters associated with this method to the given
+ * [typeParameters].
+ */
+ void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * A combinator that restricts the names being imported to those that are not in
+ * a given list.
+ *
+ * > hideCombinator ::=
+ * > 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class HideCombinator extends Combinator {
+ /**
+ * Initialize a newly created import show combinator.
+ */
+ factory HideCombinator(Token keyword, List<SimpleIdentifier> hiddenNames) =
+ HideCombinatorImpl;
+
+ /**
+ * Return the list of names from the library that are hidden by this
+ * combinator.
+ */
+ NodeList<SimpleIdentifier> get hiddenNames;
+}
+
+/**
+ * A node that represents an identifier.
+ *
+ * > identifier ::=
+ * > [SimpleIdentifier]
+ * > | [PrefixedIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Identifier extends Expression {
+ /**
+ * Return the best element available for this operator. If resolution was able
+ * to find a better element based on type propagation, that element will be
+ * returned. Otherwise, the element found using the result of static analysis
+ * will be returned. If resolution has not been performed, then `null` will be
+ * returned.
+ */
+ Element get bestElement;
+
+ /**
+ * Return the lexical representation of the identifier.
+ */
+ String get name;
+
+ /**
+ * Return the element associated with this identifier based on propagated type
+ * information, or `null` if the AST structure has not been resolved or if
+ * this identifier could not be resolved. One example of the latter case is an
+ * identifier that is not defined within the scope in which it appears.
+ */
+ Element get propagatedElement;
+
+ /**
+ * Return the element associated with this identifier based on static type
+ * information, or `null` if the AST structure has not been resolved or if
+ * this identifier could not be resolved. One example of the latter case is an
+ * identifier that is not defined within the scope in which it appears
+ */
+ Element get staticElement;
+
+ /**
+ * Return `true` if the given [name] is visible only within the library in
+ * which it is declared.
+ */
+ static bool isPrivateName(String name) =>
+ StringUtilities.startsWithChar(name, 0x5F); // '_'
+}
+
+/**
+ * An if statement.
+ *
+ * > ifStatement ::=
+ * > 'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IfStatement extends Statement {
+ /**
+ * Initialize a newly created if statement. The [elseKeyword] and
+ * [elseStatement] can be `null` if there is no else clause.
+ */
+ factory IfStatement(
+ Token ifKeyword,
+ Token leftParenthesis,
+ Expression condition,
+ Token rightParenthesis,
+ Statement thenStatement,
+ Token elseKeyword,
+ Statement elseStatement) = IfStatementImpl;
+
+ /**
+ * Return the condition used to determine which of the statements is executed
+ * next.
+ */
+ Expression get condition;
+
+ /**
+ * Set the condition used to determine which of the statements is executed
+ * next to the given [expression].
+ */
+ void set condition(Expression expression);
+
+ /**
+ * Return the token representing the 'else' keyword, or `null` if there is no
+ * else statement.
+ */
+ Token get elseKeyword;
+
+ /**
+ * Set the token representing the 'else' keyword to the given [token].
+ */
+ void set elseKeyword(Token token);
+
+ /**
+ * Return the statement that is executed if the condition evaluates to
+ * `false`, or `null` if there is no else statement.
+ */
+ Statement get elseStatement;
+
+ /**
+ * Set the statement that is executed if the condition evaluates to `false`
+ * to the given [statement].
+ */
+ void set elseStatement(Statement statement);
+
+ /**
+ * Return the token representing the 'if' keyword.
+ */
+ Token get ifKeyword;
+
+ /**
+ * Set the token representing the 'if' keyword to the given [token].
+ */
+ void set ifKeyword(Token token);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the statement that is executed if the condition evaluates to `true`.
+ */
+ Statement get thenStatement;
+
+ /**
+ * Set the statement that is executed if the condition evaluates to `true` to
+ * the given [statement].
+ */
+ void set thenStatement(Statement statement);
+}
+
+/**
+ * The "implements" clause in an class declaration.
+ *
+ * > implementsClause ::=
+ * > 'implements' [TypeName] (',' [TypeName])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ImplementsClause extends AstNode {
+ /**
+ * Initialize a newly created implements clause.
+ */
+ factory ImplementsClause(Token implementsKeyword, List<TypeName> interfaces) =
+ ImplementsClauseImpl;
+
+ /**
+ * Return the token representing the 'implements' keyword.
+ */
+ Token get implementsKeyword;
+
+ /**
+ * Set the token representing the 'implements' keyword to the given [token].
+ */
+ void set implementsKeyword(Token token);
+
+ /**
+ * Return the list of the interfaces that are being implemented.
+ */
+ NodeList<TypeName> get interfaces;
+}
+
+/**
+ * An import directive.
+ *
+ * > importDirective ::=
+ * > [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ * > | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ImportDirective extends NamespaceDirective {
+ static Comparator<ImportDirective> COMPARATOR =
+ (ImportDirective import1, ImportDirective import2) {
+ //
+ // uri
+ //
+ StringLiteral uri1 = import1.uri;
+ StringLiteral uri2 = import2.uri;
+ String uriStr1 = uri1.stringValue;
+ String uriStr2 = uri2.stringValue;
+ if (uriStr1 != null || uriStr2 != null) {
+ if (uriStr1 == null) {
+ return -1;
+ } else if (uriStr2 == null) {
+ return 1;
+ } else {
+ int compare = uriStr1.compareTo(uriStr2);
+ if (compare != 0) {
+ return compare;
+ }
+ }
+ }
+ //
+ // as
+ //
+ SimpleIdentifier prefix1 = import1.prefix;
+ SimpleIdentifier prefix2 = import2.prefix;
+ String prefixStr1 = prefix1 != null ? prefix1.name : null;
+ String prefixStr2 = prefix2 != null ? prefix2.name : null;
+ if (prefixStr1 != null || prefixStr2 != null) {
+ if (prefixStr1 == null) {
+ return -1;
+ } else if (prefixStr2 == null) {
+ return 1;
+ } else {
+ int compare = prefixStr1.compareTo(prefixStr2);
+ if (compare != 0) {
+ return compare;
+ }
+ }
+ }
+ //
+ // hides and shows
+ //
+ NodeList<Combinator> combinators1 = import1.combinators;
+ List<String> allHides1 = new List<String>();
+ List<String> allShows1 = new List<String>();
+ for (Combinator combinator in combinators1) {
+ if (combinator is HideCombinator) {
+ NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
+ for (SimpleIdentifier simpleIdentifier in hides) {
+ allHides1.add(simpleIdentifier.name);
+ }
+ } else {
+ NodeList<SimpleIdentifier> shows =
+ (combinator as ShowCombinator).shownNames;
+ for (SimpleIdentifier simpleIdentifier in shows) {
+ allShows1.add(simpleIdentifier.name);
+ }
+ }
+ }
+ NodeList<Combinator> combinators2 = import2.combinators;
+ List<String> allHides2 = new List<String>();
+ List<String> allShows2 = new List<String>();
+ for (Combinator combinator in combinators2) {
+ if (combinator is HideCombinator) {
+ NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
+ for (SimpleIdentifier simpleIdentifier in hides) {
+ allHides2.add(simpleIdentifier.name);
+ }
+ } else {
+ NodeList<SimpleIdentifier> shows =
+ (combinator as ShowCombinator).shownNames;
+ for (SimpleIdentifier simpleIdentifier in shows) {
+ allShows2.add(simpleIdentifier.name);
+ }
+ }
+ }
+ // test lengths of combinator lists first
+ if (allHides1.length != allHides2.length) {
+ return allHides1.length - allHides2.length;
+ }
+ if (allShows1.length != allShows2.length) {
+ return allShows1.length - allShows2.length;
+ }
+ // next ensure that the lists are equivalent
+ if (!javaCollectionContainsAll(allHides1, allHides2)) {
+ return -1;
+ }
+ if (!javaCollectionContainsAll(allShows1, allShows2)) {
+ return -1;
+ }
+ return 0;
+ };
+
+ /**
+ * Initialize a newly created import directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the function does not have the
+ * corresponding attribute. The [deferredKeyword] can be `null` if the import
+ * is not deferred. The [asKeyword] and [prefix] can be `null` if the import
+ * does not specify a prefix. The list of [combinators] can be `null` if there
+ * are no combinators.
+ */
+ factory ImportDirective(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ StringLiteral libraryUri,
+ List<Configuration> configurations,
+ Token deferredKeyword,
+ Token asKeyword,
+ SimpleIdentifier prefix,
+ List<Combinator> combinators,
+ Token semicolon) = ImportDirectiveImpl;
+
+ /**
+ * Return the token representing the 'as' keyword, or `null` if the imported
+ * names are not prefixed.
+ */
+ Token get asKeyword;
+
+ /**
+ * Set the token representing the 'as' keyword to the given [token].
+ */
+ void set asKeyword(Token token);
+
+ /**
+ * Return the token representing the 'deferred' keyword, or `null` if the
+ * imported URI is not deferred.
+ */
+ Token get deferredKeyword;
+
+ /**
+ * Set the token representing the 'deferred' keyword to the given [token].
+ */
+ void set deferredKeyword(Token token);
+
+ /**
+ * Return the prefix to be used with the imported names, or `null` if the
+ * imported names are not prefixed.
+ */
+ SimpleIdentifier get prefix;
+
+ /**
+ * Set the prefix to be used with the imported names to the given [identifier].
+ */
+ void set prefix(SimpleIdentifier identifier);
+}
+
+/**
+ * An index expression.
+ *
+ * > indexExpression ::=
+ * > [Expression] '[' [Expression] ']'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IndexExpression extends Expression {
+ /**
+ * Initialize a newly created index expression.
+ */
+ factory IndexExpression.forCascade(Token period, Token leftBracket,
+ Expression index, Token rightBracket) = IndexExpressionImpl.forCascade;
+
+ /**
+ * Initialize a newly created index expression.
+ */
+ factory IndexExpression.forTarget(Expression target, Token leftBracket,
+ Expression index, Token rightBracket) = IndexExpressionImpl.forTarget;
+
+ /**
+ * Return the auxiliary elements associated with this identifier, or `null` if
+ * this identifier is not in both a getter and setter context. The auxiliary
+ * elements hold the static and propagated elements associated with the getter
+ * context.
+ */
+ // TODO(brianwilkerson) Replace this API.
+ AuxiliaryElements get auxiliaryElements;
+
+ /**
+ * Set the auxiliary elements associated with this identifier to the given
+ * [elements].
+ */
+ // TODO(brianwilkerson) Replace this API.
+ void set auxiliaryElements(AuxiliaryElements elements);
+
+ /**
+ * Return the best element available for this operator. If resolution was able
+ * to find a better element based on type propagation, that element will be
+ * returned. Otherwise, the element found using the result of static analysis
+ * will be returned. If resolution has not been performed, then `null` will be
+ * returned.
+ */
+ MethodElement get bestElement;
+
+ /**
+ * Return the expression used to compute the index.
+ */
+ Expression get index;
+
+ /**
+ * Set the expression used to compute the index to the given [expression].
+ */
+ void set index(Expression expression);
+
+ /**
+ * Return `true` if this expression is cascaded. If it is, then the target of
+ * this expression is not stored locally but is stored in the nearest ancestor
+ * that is a [CascadeExpression].
+ */
+ bool get isCascaded;
+
+ /**
+ * Return the left square bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left square bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the period ("..") before a cascaded index expression, or `null` if
+ * this index expression is not part of a cascade expression.
+ */
+ Token get period;
+
+ /**
+ * Set the period ("..") before a cascaded index expression to the given
+ * [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the element associated with the operator based on the propagated
+ * type of the target, or `null` if the AST structure has not been resolved or
+ * if the operator could not be resolved.
+ */
+ MethodElement get propagatedElement;
+
+ /**
+ * Set the element associated with the operator based on the propagated
+ * type of the target to the given [element].
+ */
+ void set propagatedElement(MethodElement element);
+
+ /**
+ * Return the expression used to compute the object being indexed. If this
+ * index expression is not part of a cascade expression, then this is the same
+ * as [target]. If this index expression is part of a cascade expression, then
+ * the target expression stored with the cascade expression is returned.
+ */
+ Expression get realTarget;
+
+ /**
+ * Return the right square bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Return the element associated with the operator based on the static type of
+ * the target, or `null` if the AST structure has not been resolved or if the
+ * operator could not be resolved.
+ */
+ MethodElement get staticElement;
+
+ /**
+ * Set the element associated with the operator based on the static type of
+ * the target to the given [element].
+ */
+ void set staticElement(MethodElement element);
+
+ /**
+ * Return the expression used to compute the object being indexed, or `null`
+ * if this index expression is part of a cascade expression.
+ *
+ * Use [realTarget] to get the target independent of whether this is part of a
+ * cascade expression.
+ */
+ Expression get target;
+
+ /**
+ * Set the expression used to compute the object being indexed to the given
+ * [expression].
+ */
+ void set target(Expression expression);
+
+ /**
+ * Return `true` if this expression is computing a right-hand value (that is,
+ * if this expression is in a context where the operator '[]' will be
+ * invoked).
+ *
+ * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+ * are they mutually exclusive. In other words, it is possible for both
+ * methods to return `true` when invoked on the same node.
+ */
+ // TODO(brianwilkerson) Convert this to a getter.
+ bool inGetterContext();
+
+ /**
+ * Return `true` if this expression is computing a left-hand value (that is,
+ * if this expression is in a context where the operator '[]=' will be
+ * invoked).
+ *
+ * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+ * are they mutually exclusive. In other words, it is possible for both
+ * methods to return `true` when invoked on the same node.
+ */
+ // TODO(brianwilkerson) Convert this to a getter.
+ bool inSetterContext();
+}
+
+/**
+ * An instance creation expression.
+ *
+ * > newExpression ::=
+ * > ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InstanceCreationExpression extends Expression {
+ /**
+ * Initialize a newly created instance creation expression.
+ */
+ factory InstanceCreationExpression(
+ Token keyword,
+ ConstructorName constructorName,
+ ArgumentList argumentList) = InstanceCreationExpressionImpl;
+
+ /**
+ * Return the list of arguments to the constructor.
+ */
+ ArgumentList get argumentList;
+
+ /**
+ * Set the list of arguments to the constructor to the given [argumentList].
+ */
+ void set argumentList(ArgumentList argumentList);
+
+ /**
+ * Return the name of the constructor to be invoked.
+ */
+ ConstructorName get constructorName;
+
+ /**
+ * Set the name of the constructor to be invoked to the given [name].
+ */
+ void set constructorName(ConstructorName name);
+
+ /**
+ * Return `true` if this creation expression is used to invoke a constant
+ * constructor.
+ */
+ bool get isConst;
+
+ /**
+ * Return the 'new' or 'const' keyword used to indicate how an object should
+ * be created.
+ */
+ Token get keyword;
+
+ /**
+ * Set the 'new' or 'const' keyword used to indicate how an object should be
+ * created to the given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the element associated with the constructor based on static type
+ * information, or `null` if the AST structure has not been resolved or if the
+ * constructor could not be resolved.
+ */
+ ConstructorElement get staticElement;
+
+ /**
+ * Set the element associated with the constructor based on static type
+ * information to the given [element].
+ */
+ void set staticElement(ConstructorElement element);
+}
+
+/**
+ * An integer literal expression.
+ *
+ * > integerLiteral ::=
+ * > decimalIntegerLiteral
+ * > | hexadecimalIntegerLiteral
+ * >
+ * > decimalIntegerLiteral ::=
+ * > decimalDigit+
+ * >
+ * > hexadecimalIntegerLiteral ::=
+ * > '0x' hexadecimalDigit+
+ * > | '0X' hexadecimalDigit+
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IntegerLiteral extends Literal {
+ /**
+ * Initialize a newly created integer literal.
+ */
+ factory IntegerLiteral(Token literal, int value) = IntegerLiteralImpl;
+
+ /**
+ * Return the token representing the literal.
+ */
+ Token get literal;
+
+ /**
+ * Set the token representing the literal to the given [token].
+ */
+ void set literal(Token token);
+
+ /**
+ * Return the value of the literal.
+ */
+ int get value;
+
+ /**
+ * Set the value of the literal to the given [value].
+ */
+ void set value(int value);
+}
+
+/**
+ * A node within a [StringInterpolation].
+ *
+ * > interpolationElement ::=
+ * > [InterpolationExpression]
+ * > | [InterpolationString]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InterpolationElement extends AstNode {}
+
+/**
+ * An expression embedded in a string interpolation.
+ *
+ * > interpolationExpression ::=
+ * > '$' [SimpleIdentifier]
+ * > | '$' '{' [Expression] '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InterpolationExpression extends InterpolationElement {
+ /**
+ * Initialize a newly created interpolation expression.
+ */
+ factory InterpolationExpression(
+ Token leftBracket, Expression expression, Token rightBracket) =
+ InterpolationExpressionImpl;
+
+ /**
+ * Return the expression to be evaluated for the value to be converted into a
+ * string.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression to be evaluated for the value to be converted into a
+ * string to the given [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the token used to introduce the interpolation expression; either '$'
+ * if the expression is a simple identifier or '${' if the expression is a
+ * full expression.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the token used to introduce the interpolation expression; either '$'
+ * if the expression is a simple identifier or '${' if the expression is a
+ * full expression to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the right curly bracket, or `null` if the expression is an
+ * identifier without brackets.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right curly bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+}
+
+/**
+ * A non-empty substring of an interpolated string.
+ *
+ * > interpolationString ::=
+ * > characters
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InterpolationString extends InterpolationElement {
+ /**
+ * Initialize a newly created string of characters that are part of a string
+ * interpolation.
+ */
+ factory InterpolationString(Token contents, String value) =
+ InterpolationStringImpl;
+
+ /**
+ * Return the characters that will be added to the string.
+ */
+ Token get contents;
+
+ /**
+ * Set the characters that will be added to the string to the given [token].
+ */
+ void set contents(Token token);
+
+ /**
+ * Return the offset of the after-last contents character.
+ */
+ int get contentsEnd;
+
+ /**
+ * Return the offset of the first contents character.
+ */
+ int get contentsOffset;
+
+ /**
+ * Return the value of the literal.
+ */
+ String get value;
+
+ /**
+ * Set the value of the literal to the given [value].
+ */
+ void set value(String value);
+}
+
+/**
+ * An is expression.
+ *
+ * > isExpression ::=
+ * > [Expression] 'is' '!'? [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IsExpression extends Expression {
+ /**
+ * Initialize a newly created is expression. The [notOperator] can be `null`
+ * if the sense of the test is not negated.
+ */
+ factory IsExpression(Expression expression, Token isOperator,
+ Token notOperator, TypeName type) = IsExpressionImpl;
+
+ /**
+ * Return the expression used to compute the value whose type is being tested.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression used to compute the value whose type is being tested to
+ * the given [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the is operator.
+ */
+ Token get isOperator;
+
+ /**
+ * Set the is operator to the given [token].
+ */
+ void set isOperator(Token token);
+
+ /**
+ * Return the not operator, or `null` if the sense of the test is not negated.
+ */
+ Token get notOperator;
+
+ /**
+ * Set the not operator to the given [token].
+ */
+ void set notOperator(Token token);
+
+ /**
+ * Return the name of the type being tested for.
+ */
+ TypeName get type;
+
+ /**
+ * Set the name of the type being tested for to the given [name].
+ */
+ void set type(TypeName name);
+}
+
+/**
+ * A label on either a [LabeledStatement] or a [NamedExpression].
+ *
+ * > label ::=
+ * > [SimpleIdentifier] ':'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Label extends AstNode {
+ /**
+ * Initialize a newly created label.
+ */
+ factory Label(SimpleIdentifier label, Token colon) = LabelImpl;
+
+ /**
+ * Return the colon that separates the label from the statement.
+ */
+ Token get colon;
+
+ /**
+ * Set the colon that separates the label from the statement to the given
+ * [token].
+ */
+ void set colon(Token token);
+
+ /**
+ * Return the label being associated with the statement.
+ */
+ SimpleIdentifier get label;
+
+ /**
+ * Set the label being associated with the statement to the given [label].
+ */
+ void set label(SimpleIdentifier label);
+}
+
+/**
+ * A statement that has a label associated with them.
+ *
+ * > labeledStatement ::=
+ * > [Label]+ [Statement]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class LabeledStatement extends Statement {
+ /**
+ * Initialize a newly created labeled statement.
+ */
+ factory LabeledStatement(List<Label> labels, Statement statement) =
+ LabeledStatementImpl;
+
+ /**
+ * Return the labels being associated with the statement.
+ */
+ NodeList<Label> get labels;
+
+ /**
+ * Return the statement with which the labels are being associated.
+ */
+ Statement get statement;
+
+ /**
+ * Set the statement with which the labels are being associated to the given
+ * [statement].
+ */
+ void set statement(Statement statement);
+}
+
+/**
+ * A library directive.
+ *
+ * > libraryDirective ::=
+ * > [Annotation] 'library' [Identifier] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class LibraryDirective extends Directive {
+ /**
+ * Initialize a newly created library directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute.
+ */
+ factory LibraryDirective(
+ Comment comment,
+ List<Annotation> metadata,
+ Token libraryKeyword,
+ LibraryIdentifier name,
+ Token semicolon) = LibraryDirectiveImpl;
+
+ /**
+ * Return the token representing the 'library' keyword.
+ */
+ Token get libraryKeyword;
+
+ /**
+ * Set the token representing the 'library' keyword to the given [token].
+ */
+ void set libraryKeyword(Token token);
+
+ /**
+ * Return the name of the library being defined.
+ */
+ LibraryIdentifier get name;
+
+ /**
+ * Set the name of the library being defined to the given [name].
+ */
+ void set name(LibraryIdentifier name);
+
+ /**
+ * Return the semicolon terminating the directive.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the directive to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * The identifier for a library.
+ *
+ * > libraryIdentifier ::=
+ * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class LibraryIdentifier extends Identifier {
+ /**
+ * Initialize a newly created prefixed identifier.
+ */
+ factory LibraryIdentifier(List<SimpleIdentifier> components) =
+ LibraryIdentifierImpl;
+
+ /**
+ * Return the components of the identifier.
+ */
+ NodeList<SimpleIdentifier> get components;
+}
+
+/**
+ * A list literal.
+ *
+ * > listLiteral ::=
+ * > 'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ListLiteral extends TypedLiteral {
+ /**
+ * Initialize a newly created list literal. The [constKeyword] can be `null`
+ * if the literal is not a constant. The [typeArguments] can be `null` if no
+ * type arguments were declared. The list of [elements] can be `null` if the
+ * list is empty.
+ */
+ factory ListLiteral(
+ Token constKeyword,
+ TypeArgumentList typeArguments,
+ Token leftBracket,
+ List<Expression> elements,
+ Token rightBracket) = ListLiteralImpl;
+
+ /**
+ * Return the expressions used to compute the elements of the list.
+ */
+ NodeList<Expression> get elements;
+
+ /**
+ * Return the left square bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left square bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the right square bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right square bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+}
+
+/**
+ * A node that represents a literal expression.
+ *
+ * > literal ::=
+ * > [BooleanLiteral]
+ * > | [DoubleLiteral]
+ * > | [IntegerLiteral]
+ * > | [ListLiteral]
+ * > | [MapLiteral]
+ * > | [NullLiteral]
+ * > | [StringLiteral]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Literal extends Expression {}
+
+/**
+ * A literal map.
+ *
+ * > mapLiteral ::=
+ * > 'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ * > '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class MapLiteral extends TypedLiteral {
+ /**
+ * Initialize a newly created map literal. The [constKeyword] can be `null` if
+ * the literal is not a constant. The [typeArguments] can be `null` if no type
+ * arguments were declared. The [entries] can be `null` if the map is empty.
+ */
+ factory MapLiteral(
+ Token constKeyword,
+ TypeArgumentList typeArguments,
+ Token leftBracket,
+ List<MapLiteralEntry> entries,
+ Token rightBracket) = MapLiteralImpl;
+
+ /**
+ * Return the entries in the map.
+ */
+ NodeList<MapLiteralEntry> get entries;
+
+ /**
+ * Return the left curly bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left curly bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the right curly bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right curly bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+}
+
+/**
+ * A single key/value pair in a map literal.
+ *
+ * > mapLiteralEntry ::=
+ * > [Expression] ':' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class MapLiteralEntry extends AstNode {
+ /**
+ * Initialize a newly created map literal entry.
+ */
+ factory MapLiteralEntry(Expression key, Token separator, Expression value) =
+ MapLiteralEntryImpl;
+
+ /**
+ * Return the expression computing the key with which the value will be
+ * associated.
+ */
+ Expression get key;
+
+ /**
+ * Set the expression computing the key with which the value will be
+ * associated to the given [string].
+ */
+ void set key(Expression string);
+
+ /**
+ * Return the colon that separates the key from the value.
+ */
+ Token get separator;
+
+ /**
+ * Set the colon that separates the key from the value to the given [token].
+ */
+ void set separator(Token token);
+
+ /**
+ * Return the expression computing the value that will be associated with the
+ * key.
+ */
+ Expression get value;
+
+ /**
+ * Set the expression computing the value that will be associated with the key
+ * to the given [expression].
+ */
+ void set value(Expression expression);
+}
+
+/**
+ * A method declaration.
+ *
+ * > methodDeclaration ::=
+ * > methodSignature [FunctionBody]
+ * >
+ * > methodSignature ::=
+ * > 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+ * > methodName [TypeParameterList] [FormalParameterList]
+ * >
+ * > methodName ::=
+ * > [SimpleIdentifier]
+ * > | 'operator' [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class MethodDeclaration extends ClassMember {
+ /**
+ * Initialize a newly created method declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The [externalKeyword] can be `null` if the method
+ * is not external. The [modifierKeyword] can be `null` if the method is
+ * neither abstract nor static. The [returnType] can be `null` if no return
+ * type was specified. The [propertyKeyword] can be `null` if the method is
+ * neither a getter or a setter. The [operatorKeyword] can be `null` if the
+ * method does not implement an operator. The [parameters] must be `null` if
+ * this method declares a getter.
+ */
+ factory MethodDeclaration(
+ Comment comment,
+ List<Annotation> metadata,
+ Token externalKeyword,
+ Token modifierKeyword,
+ TypeName returnType,
+ Token propertyKeyword,
+ Token operatorKeyword,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters,
+ FunctionBody body) = MethodDeclarationImpl;
+
+ /**
+ * Return the body of the method.
+ */
+ FunctionBody get body;
+
+ /**
+ * Set the body of the method to the given [functionBody].
+ */
+ void set body(FunctionBody functionBody);
+
+ @override
+ ExecutableElement get element;
+
+ /**
+ * Return the token for the 'external' keyword, or `null` if the constructor
+ * is not external.
+ */
+ Token get externalKeyword;
+
+ /**
+ * Set the token for the 'external' keyword to the given [token].
+ */
+ void set externalKeyword(Token token);
+
+ /**
+ * Return `true` if this method is declared to be an abstract method.
+ */
+ bool get isAbstract;
+
+ /**
+ * Return `true` if this method declares a getter.
+ */
+ bool get isGetter;
+
+ /**
+ * Return `true` if this method declares an operator.
+ */
+ bool get isOperator;
+
+ /**
+ * Return `true` if this method declares a setter.
+ */
+ bool get isSetter;
+
+ /**
+ * Return `true` if this method is declared to be a static method.
+ */
+ bool get isStatic;
+
+ /**
+ * Return the token representing the 'abstract' or 'static' keyword, or `null`
+ * if neither modifier was specified.
+ */
+ Token get modifierKeyword;
+
+ /**
+ * Set the token representing the 'abstract' or 'static' keyword to the given
+ * [token].
+ */
+ void set modifierKeyword(Token token);
+
+ /**
+ * Return the name of the method.
+ */
+ SimpleIdentifier get name;
+
+ /**
+ * Set the name of the method to the given [identifier].
+ */
+ void set name(SimpleIdentifier identifier);
+
+ /**
+ * Return the token representing the 'operator' keyword, or `null` if this
+ * method does not declare an operator.
+ */
+ Token get operatorKeyword;
+
+ /**
+ * Set the token representing the 'operator' keyword to the given [token].
+ */
+ void set operatorKeyword(Token token);
+
+ /**
+ * Return the parameters associated with the method, or `null` if this method
+ * declares a getter.
+ */
+ FormalParameterList get parameters;
+
+ /**
+ * Set the parameters associated with the method to the given list of
+ * [parameters].
+ */
+ void set parameters(FormalParameterList parameters);
+
+ /**
+ * Return the token representing the 'get' or 'set' keyword, or `null` if this
+ * is a method declaration rather than a property declaration.
+ */
+ Token get propertyKeyword;
+
+ /**
+ * Set the token representing the 'get' or 'set' keyword to the given [token].
+ */
+ void set propertyKeyword(Token token);
+
+ /**
+ * Return the return type of the method, or `null` if no return type was
+ * declared.
+ */
+ TypeName get returnType;
+
+ /**
+ * Set the return type of the method to the given [typeName].
+ */
+ void set returnType(TypeName typeName);
+
+ /**
+ * Return the type parameters associated with this method, or `null` if this
+ * method is not a generic method.
+ */
+ TypeParameterList get typeParameters;
+
+ /**
+ * Set the type parameters associated with this method to the given
+ * [typeParameters].
+ */
+ void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * The invocation of either a function or a method. Invocations of functions
+ * resulting from evaluating an expression are represented by
+ * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
+ * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ * > methodInvocation ::=
+ * > ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class MethodInvocation extends Expression {
+ /**
+ * Initialize a newly created method invocation. The [target] and [operator]
+ * can be `null` if there is no target.
+ */
+ factory MethodInvocation(
+ Expression target,
+ Token operator,
+ SimpleIdentifier methodName,
+ TypeArgumentList typeArguments,
+ ArgumentList argumentList) = MethodInvocationImpl;
+
+ /**
+ * Return the list of arguments to the method.
+ */
+ ArgumentList get argumentList;
+
+ /**
+ * Set the list of arguments to the method to the given [argumentList].
+ */
+ void set argumentList(ArgumentList argumentList);
+
+ /**
+ * Return `true` if this expression is cascaded. If it is, then the target of
+ * this expression is not stored locally but is stored in the nearest ancestor
+ * that is a [CascadeExpression].
+ */
+ bool get isCascaded;
+
+ /**
+ * Return the name of the method being invoked.
+ */
+ SimpleIdentifier get methodName;
+
+ /**
+ * Set the name of the method being invoked to the given [identifier].
+ */
+ void set methodName(SimpleIdentifier identifier);
+
+ /**
+ * Return the operator that separates the target from the method name, or
+ * `null` if there is no target. In an ordinary method invocation this will be
+ * * period ('.'). In a cascade section this will be the cascade operator
+ * ('..').
+ */
+ Token get operator;
+
+ /**
+ * Set the operator that separates the target from the method name to the
+ * given [token].
+ */
+ void set operator(Token token);
+
+ /**
+ * Return the function type of the method invocation based on the propagated
+ * type information, or `null` if the AST structure has not been resolved, or
+ * if the invoke could not be resolved.
+ *
+ * This will usually be a [FunctionType], but it can also be an
+ * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+ * interface type that implements `Function`.
+ */
+ DartType get propagatedInvokeType;
+
+ /**
+ * Set the function type of the method invocation based on the propagated type
+ * information to the given [type].
+ */
+ void set propagatedInvokeType(DartType type);
+
+ /**
+ * Return the expression used to compute the receiver of the invocation. If
+ * this invocation is not part of a cascade expression, then this is the same
+ * as [target]. If this invocation is part of a cascade expression, then the
+ * target stored with the cascade expression is returned.
+ */
+ Expression get realTarget;
+
+ /**
+ * Return the function type of the method invocation based on the static type
+ * information, or `null` if the AST structure has not been resolved, or if
+ * the invoke could not be resolved.
+ *
+ * This will usually be a [FunctionType], but it can also be an
+ * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+ * interface type that implements `Function`.
+ */
+ DartType get staticInvokeType;
+
+ /**
+ * Set the function type of the method invocation based on the static type
+ * information to the given [type].
+ */
+ void set staticInvokeType(DartType type);
+
+ /**
+ * Return the expression producing the object on which the method is defined,
+ * or `null` if there is no target (that is, the target is implicitly `this`)
+ * or if this method invocation is part of a cascade expression.
+ *
+ * Use [realTarget] to get the target independent of whether this is part of a
+ * cascade expression.
+ */
+ Expression get target;
+
+ /**
+ * Set the expression producing the object on which the method is defined to
+ * the given [expression].
+ */
+ void set target(Expression expression);
+
+ /**
+ * Return the type arguments to be applied to the method being invoked, or
+ * `null` if no type arguments were provided.
+ */
+ TypeArgumentList get typeArguments;
+
+ /**
+ * Set the type arguments to be applied to the method being invoked to the
+ * given [typeArguments].
+ */
+ void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * A node that declares a single name within the scope of a compilation unit.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NamedCompilationUnitMember extends CompilationUnitMember {
+ /**
+ * Return the name of the member being declared.
+ */
+ SimpleIdentifier get name;
+
+ /**
+ * Set the name of the member being declared to the given [identifier].
+ */
+ void set name(SimpleIdentifier identifier);
+}
+
+/**
+ * An expression that has a name associated with it. They are used in method
+ * invocations when there are named parameters.
+ *
+ * > namedExpression ::=
+ * > [Label] [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NamedExpression extends Expression {
+ /**
+ * Initialize a newly created named expression..
+ */
+ factory NamedExpression(Label name, Expression expression) =
+ NamedExpressionImpl;
+
+ /**
+ * Return the element representing the parameter being named by this
+ * expression, or `null` if the AST structure has not been resolved or if
+ * there is no parameter with the same name as this expression.
+ */
+ ParameterElement get element;
+
+ /**
+ * Return the expression with which the name is associated.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression with which the name is associated to the given
+ * [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the name associated with the expression.
+ */
+ Label get name;
+
+ /**
+ * Set the name associated with the expression to the given [identifier].
+ */
+ void set name(Label identifier);
+}
+
+/**
+ * A node that represents a directive that impacts the namespace of a library.
+ *
+ * > directive ::=
+ * > [ExportDirective]
+ * > | [ImportDirective]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NamespaceDirective extends UriBasedDirective {
+ /**
+ * Return the combinators used to control how names are imported or exported.
+ */
+ NodeList<Combinator> get combinators;
+
+ /**
+ * Return the configurations used to control which library will actually be
+ * loaded at run-time.
+ */
+ NodeList<Configuration> get configurations;
+
+ /**
+ * Set the token representing the keyword that introduces this directive
+ * ('import', 'export', 'library' or 'part') to the given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the semicolon terminating the directive.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the directive to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * The "native" clause in an class declaration.
+ *
+ * > nativeClause ::=
+ * > 'native' [StringLiteral]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NativeClause extends AstNode {
+ /**
+ * Initialize a newly created native clause.
+ */
+ factory NativeClause(Token nativeKeyword, StringLiteral name) =
+ NativeClauseImpl;
+
+ /**
+ * Return the name of the native object that implements the class.
+ */
+ StringLiteral get name;
+
+ /**
+ * Set the name of the native object that implements the class to the given
+ * [name].
+ */
+ void set name(StringLiteral name);
+
+ /**
+ * Return the token representing the 'native' keyword.
+ */
+ Token get nativeKeyword;
+
+ /**
+ * Set the token representing the 'native' keyword to the given [token].
+ */
+ void set nativeKeyword(Token token);
+}
+
+/**
+ * A function body that consists of a native keyword followed by a string
+ * literal.
+ *
+ * > nativeFunctionBody ::=
+ * > 'native' [SimpleStringLiteral] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NativeFunctionBody extends FunctionBody {
+ /**
+ * Initialize a newly created function body consisting of the 'native' token,
+ * a string literal, and a semicolon.
+ */
+ factory NativeFunctionBody(
+ Token nativeKeyword, StringLiteral stringLiteral, Token semicolon) =
+ NativeFunctionBodyImpl;
+
+ /**
+ * Return the token representing 'native' that marks the start of the function
+ * body.
+ */
+ Token get nativeKeyword;
+
+ /**
+ * Set the token representing 'native' that marks the start of the function
+ * body to the given [token].
+ */
+ void set nativeKeyword(Token token);
+
+ /**
+ * Return the token representing the semicolon that marks the end of the
+ * function body.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the token representing the semicolon that marks the end of the
+ * function body to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the string literal representing the string after the 'native' token.
+ */
+ StringLiteral get stringLiteral;
+
+ /**
+ * Set the string literal representing the string after the 'native' token to
+ * the given [stringLiteral].
+ */
+ void set stringLiteral(StringLiteral stringLiteral);
+}
+
+/**
+ * A list of AST nodes that have a common parent.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NodeList<E extends AstNode> implements List<E> {
+ /**
+ * Initialize a newly created list of nodes such that all of the nodes that
+ * are added to the list will have their parent set to the given [owner]. The
+ * list will initially be populated with the given [elements].
+ */
+ factory NodeList(AstNode owner, [List<E> elements]) = NodeListImpl;
+
+ /**
+ * Return the first token included in this node list's source range, or `null`
+ * if the list is empty.
+ */
+ Token get beginToken;
+
+ /**
+ * Return the last token included in this node list's source range, or `null`
+ * if the list is empty.
+ */
+ Token get endToken;
+
+ /**
+ * Return the node that is the parent of each of the elements in the list.
+ */
+ AstNode get owner;
+
+ /**
+ * Set the node that is the parent of each of the elements in the list to the
+ * given [node].
+ */
+ @deprecated // Never intended for public use.
+ void set owner(AstNode node);
+
+ /**
+ * Return the node at the given [index] in the list or throw a [RangeError] if
+ * [index] is out of bounds.
+ */
+ E operator [](int index);
+
+ /**
+ * Set the node at the given [index] in the list to the given [node] or throw
+ * a [RangeError] if [index] is out of bounds.
+ */
+ void operator []=(int index, E node);
+
+ /**
+ * Use the given [visitor] to visit each of the nodes in this list.
+ */
+ accept(AstVisitor visitor);
+}
+
+/**
+ * A formal parameter that is required (is not optional).
+ *
+ * > normalFormalParameter ::=
+ * > [FunctionTypedFormalParameter]
+ * > | [FieldFormalParameter]
+ * > | [SimpleFormalParameter]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NormalFormalParameter extends FormalParameter {
+ /**
+ * Return the documentation comment associated with this parameter, or `null`
+ * if this parameter does not have a documentation comment associated with it.
+ */
+ Comment get documentationComment;
+
+ /**
+ * Set the documentation comment associated with this parameter to the given
+ * [comment].
+ */
+ void set documentationComment(Comment comment);
+
+ /**
+ * Set the name of the parameter being declared to the given [identifier].
+ */
+ void set identifier(SimpleIdentifier identifier);
+
+ /**
+ * Set the metadata associated with this node to the given [metadata].
+ */
+ void set metadata(List<Annotation> metadata);
+
+ /**
+ * Return a list containing the comment and annotations associated with this
+ * parameter, sorted in lexical order.
+ */
+ List<AstNode> get sortedCommentAndAnnotations;
+}
+
+/**
+ * A null literal expression.
+ *
+ * > nullLiteral ::=
+ * > 'null'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NullLiteral extends Literal {
+ /**
+ * Initialize a newly created null literal.
+ */
+ factory NullLiteral(Token literal) = NullLiteralImpl;
+
+ /**
+ * Return the token representing the literal.
+ */
+ Token get literal;
+
+ /**
+ * Set the token representing the literal to the given [token].
+ */
+ void set literal(Token token);
+}
+
+/**
+ * A parenthesized expression.
+ *
+ * > parenthesizedExpression ::=
+ * > '(' [Expression] ')'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ParenthesizedExpression extends Expression {
+ /**
+ * Initialize a newly created parenthesized expression.
+ */
+ factory ParenthesizedExpression(Token leftParenthesis, Expression expression,
+ Token rightParenthesis) = ParenthesizedExpressionImpl;
+
+ /**
+ * Return the expression within the parentheses.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression within the parentheses to the given [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+}
+
+/**
+ * A part directive.
+ *
+ * > partDirective ::=
+ * > [Annotation] 'part' [StringLiteral] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PartDirective extends UriBasedDirective {
+ /**
+ * Initialize a newly created part directive. Either or both of the [comment]
+ * and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute.
+ */
+ factory PartDirective(
+ Comment comment,
+ List<Annotation> metadata,
+ Token partKeyword,
+ StringLiteral partUri,
+ Token semicolon) = PartDirectiveImpl;
+
+ /**
+ * Return the token representing the 'part' keyword.
+ */
+ Token get partKeyword;
+
+ /**
+ * Set the token representing the 'part' keyword to the given [token].
+ */
+ void set partKeyword(Token token);
+
+ /**
+ * Return the semicolon terminating the directive.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the directive to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * A part-of directive.
+ *
+ * > partOfDirective ::=
+ * > [Annotation] 'part' 'of' [Identifier] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PartOfDirective extends Directive {
+ /**
+ * Initialize a newly created part-of directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute.
+ */
+ factory PartOfDirective(
+ Comment comment,
+ List<Annotation> metadata,
+ Token partKeyword,
+ Token ofKeyword,
+ LibraryIdentifier libraryName,
+ Token semicolon) = PartOfDirectiveImpl;
+
+ /**
+ * Return the name of the library that the containing compilation unit is part
+ * of.
+ */
+ LibraryIdentifier get libraryName;
+
+ /**
+ * Set the name of the library that the containing compilation unit is part of
+ * to the given [libraryName].
+ */
+ void set libraryName(LibraryIdentifier libraryName);
+
+ /**
+ * Return the token representing the 'of' keyword.
+ */
+ Token get ofKeyword;
+
+ /**
+ * Set the token representing the 'of' keyword to the given [token].
+ */
+ void set ofKeyword(Token token);
+
+ /**
+ * Return the token representing the 'part' keyword.
+ */
+ Token get partKeyword;
+
+ /**
+ * Set the token representing the 'part' keyword to the given [token].
+ */
+ void set partKeyword(Token token);
+
+ /**
+ * Return the semicolon terminating the directive.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the directive to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * A postfix unary expression.
+ *
+ * > postfixExpression ::=
+ * > [Expression] [Token]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PostfixExpression extends Expression {
+ /**
+ * Initialize a newly created postfix expression.
+ */
+ factory PostfixExpression(Expression operand, Token operator) =
+ PostfixExpressionImpl;
+
+ /**
+ * Return the best element available for this operator. If resolution was able
+ * to find a better element based on type propagation, that element will be
+ * returned. Otherwise, the element found using the result of static analysis
+ * will be returned. If resolution has not been performed, then `null` will be
+ * returned.
+ */
+ MethodElement get bestElement;
+
+ /**
+ * Return the expression computing the operand for the operator.
+ */
+ Expression get operand;
+
+ /**
+ * Set the expression computing the operand for the operator to the given
+ * [expression].
+ */
+ void set operand(Expression expression);
+
+ /**
+ * Return the postfix operator being applied to the operand.
+ */
+ Token get operator;
+
+ /**
+ * Set the postfix operator being applied to the operand to the given [token].
+ */
+ void set operator(Token token);
+
+ /**
+ * Return the element associated with this the operator based on the
+ * propagated type of the operand, or `null` if the AST structure has not been
+ * resolved, if the operator is not user definable, or if the operator could
+ * not be resolved.
+ */
+ MethodElement get propagatedElement;
+
+ /**
+ * Set the element associated with this the operator based on the propagated
+ * type of the operand to the given [element].
+ */
+ void set propagatedElement(MethodElement element);
+
+ /**
+ * Return the element associated with the operator based on the static type of
+ * the operand, or `null` if the AST structure has not been resolved, if the
+ * operator is not user definable, or if the operator could not be resolved.
+ */
+ MethodElement get staticElement;
+
+ /**
+ * Set the element associated with the operator based on the static type of
+ * the operand to the given [element].
+ */
+ void set staticElement(MethodElement element);
+}
+
+/**
+ * An identifier that is prefixed or an access to an object property where the
+ * target of the property access is a simple identifier.
+ *
+ * > prefixedIdentifier ::=
+ * > [SimpleIdentifier] '.' [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PrefixedIdentifier extends Identifier {
+ /**
+ * Initialize a newly created prefixed identifier.
+ */
+ factory PrefixedIdentifier(
+ SimpleIdentifier prefix, Token period, SimpleIdentifier identifier) =
+ PrefixedIdentifierImpl;
+
+ /**
+ * Return the identifier being prefixed.
+ */
+ SimpleIdentifier get identifier;
+
+ /**
+ * Set the identifier being prefixed to the given [identifier].
+ */
+ void set identifier(SimpleIdentifier identifier);
+
+ /**
+ * Return `true` if this type is a deferred type. If the AST structure has not
+ * been resolved, then return `false`.
+ *
+ * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
+ * </i>p.T</i> where <i>p</i> is a deferred prefix.
+ */
+ bool get isDeferred;
+
+ /**
+ * Return the period used to separate the prefix from the identifier.
+ */
+ Token get period;
+
+ /**
+ * Set the period used to separate the prefix from the identifier to the given
+ * [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the prefix associated with the library in which the identifier is
+ * defined.
+ */
+ SimpleIdentifier get prefix;
+
+ /**
+ * Set the prefix associated with the library in which the identifier is
+ * defined to the given [identifier].
+ */
+ void set prefix(SimpleIdentifier identifier);
+}
+
+/**
+ * A prefix unary expression.
+ *
+ * > prefixExpression ::=
+ * > [Token] [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PrefixExpression extends Expression {
+ /**
+ * Initialize a newly created prefix expression.
+ */
+ factory PrefixExpression(Token operator, Expression operand) =
+ PrefixExpressionImpl;
+
+ /**
+ * Return the best element available for this operator. If resolution was able
+ * to find a better element based on type propagation, that element will be
+ * returned. Otherwise, the element found using the result of static analysis
+ * will be returned. If resolution has not been performed, then `null` will be
+ * returned.
+ */
+ MethodElement get bestElement;
+
+ /**
+ * Return the expression computing the operand for the operator.
+ */
+ Expression get operand;
+
+ /**
+ * Set the expression computing the operand for the operator to the given
+ * [expression].
+ */
+ void set operand(Expression expression);
+
+ /**
+ * Return the prefix operator being applied to the operand.
+ */
+ Token get operator;
+
+ /**
+ * Set the prefix operator being applied to the operand to the given [token].
+ */
+ void set operator(Token token);
+
+ /**
+ * Return the element associated with the operator based on the propagated
+ * type of the operand, or `null` if the AST structure has not been resolved,
+ * if the operator is not user definable, or if the operator could not be
+ * resolved.
+ */
+ MethodElement get propagatedElement;
+
+ /**
+ * Set the element associated with the operator based on the propagated type
+ * of the operand to the given [element].
+ */
+ void set propagatedElement(MethodElement element);
+
+ /**
+ * Return the element associated with the operator based on the static type of
+ * the operand, or `null` if the AST structure has not been resolved, if the
+ * operator is not user definable, or if the operator could not be resolved.
+ */
+ MethodElement get staticElement;
+
+ /**
+ * Set the element associated with the operator based on the static type of
+ * the operand to the given [element].
+ */
+ void set staticElement(MethodElement element);
+}
+
+/**
+ * The access of a property of an object.
+ *
+ * Note, however, that accesses to properties of objects can also be represented
+ * as [PrefixedIdentifier] nodes in cases where the target is also a simple
+ * identifier.
+ *
+ * > propertyAccess ::=
+ * > [Expression] '.' [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PropertyAccess extends Expression {
+ /**
+ * Initialize a newly created property access expression.
+ */
+ factory PropertyAccess(
+ Expression target, Token operator, SimpleIdentifier propertyName) =
+ PropertyAccessImpl;
+
+ /**
+ * Return `true` if this expression is cascaded. If it is, then the target of
+ * this expression is not stored locally but is stored in the nearest ancestor
+ * that is a [CascadeExpression].
+ */
+ bool get isCascaded;
+
+ /**
+ * Return the property access operator.
+ */
+ Token get operator;
+
+ /**
+ * Set the property access operator to the given [token].
+ */
+ void set operator(Token token);
+
+ /**
+ * Return the name of the property being accessed.
+ */
+ SimpleIdentifier get propertyName;
+
+ /**
+ * Set the name of the property being accessed to the given [identifier].
+ */
+ void set propertyName(SimpleIdentifier identifier);
+
+ /**
+ * Return the expression used to compute the receiver of the invocation. If
+ * this invocation is not part of a cascade expression, then this is the same
+ * as [target]. If this invocation is part of a cascade expression, then the
+ * target stored with the cascade expression is returned.
+ */
+ Expression get realTarget;
+
+ /**
+ * Return the expression computing the object defining the property being
+ * accessed, or `null` if this property access is part of a cascade expression.
+ *
+ * Use [realTarget] to get the target independent of whether this is part of a
+ * cascade expression.
+ */
+ Expression get target;
+
+ /**
+ * Set the expression computing the object defining the property being
+ * accessed to the given [expression].
+ */
+ void set target(Expression expression);
+}
+
+/**
+ * The invocation of a constructor in the same class from within a constructor's
+ * initialization list.
+ *
+ * > redirectingConstructorInvocation ::=
+ * > 'this' ('.' identifier)? arguments
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class RedirectingConstructorInvocation extends ConstructorInitializer {
+ /**
+ * Initialize a newly created redirecting invocation to invoke the constructor
+ * with the given name with the given arguments. The [constructorName] can be
+ * `null` if the constructor being invoked is the unnamed constructor.
+ */
+ factory RedirectingConstructorInvocation(
+ Token thisKeyword,
+ Token period,
+ SimpleIdentifier constructorName,
+ ArgumentList argumentList) = RedirectingConstructorInvocationImpl;
+
+ /**
+ * Return the list of arguments to the constructor.
+ */
+ ArgumentList get argumentList;
+
+ /**
+ * Set the list of arguments to the constructor to the given [argumentList].
+ */
+ void set argumentList(ArgumentList argumentList);
+
+ /**
+ * Return the name of the constructor that is being invoked, or `null` if the
+ * unnamed constructor is being invoked.
+ */
+ SimpleIdentifier get constructorName;
+
+ /**
+ * Set the name of the constructor that is being invoked to the given
+ * [identifier].
+ */
+ void set constructorName(SimpleIdentifier identifier);
+
+ /**
+ * Return the token for the period before the name of the constructor that is
+ * being invoked, or `null` if the unnamed constructor is being invoked.
+ */
+ Token get period;
+
+ /**
+ * Set the token for the period before the name of the constructor that is
+ * being invoked to the given [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the element associated with the constructor based on static type
+ * information, or `null` if the AST structure has not been resolved or if the
+ * constructor could not be resolved.
+ */
+ ConstructorElement get staticElement;
+
+ /**
+ * Set the element associated with the constructor based on static type
+ * information to the given [element].
+ */
+ void set staticElement(ConstructorElement element);
+
+ /**
+ * Return the token for the 'this' keyword.
+ */
+ Token get thisKeyword;
+
+ /**
+ * Set the token for the 'this' keyword to the given [token].
+ */
+ void set thisKeyword(Token token);
+}
+
+/**
+ * A rethrow expression.
+ *
+ * > rethrowExpression ::=
+ * > 'rethrow'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class RethrowExpression extends Expression {
+ /**
+ * Initialize a newly created rethrow expression.
+ */
+ factory RethrowExpression(Token rethrowKeyword) = RethrowExpressionImpl;
+
+ /**
+ * Return the token representing the 'rethrow' keyword.
+ */
+ Token get rethrowKeyword;
+
+ /**
+ * Set the token representing the 'rethrow' keyword to the given [token].
+ */
+ void set rethrowKeyword(Token token);
+}
+
+/**
+ * A return statement.
+ *
+ * > returnStatement ::=
+ * > 'return' [Expression]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ReturnStatement extends Statement {
+ /**
+ * Initialize a newly created return statement. The [expression] can be `null`
+ * if no explicit value was provided.
+ */
+ factory ReturnStatement(
+ Token returnKeyword, Expression expression, Token semicolon) =
+ ReturnStatementImpl;
+
+ /**
+ * Return the expression computing the value to be returned, or `null` if no
+ * explicit value was provided.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression computing the value to be returned to the given
+ * [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the token representing the 'return' keyword.
+ */
+ Token get returnKeyword;
+
+ /**
+ * Set the token representing the 'return' keyword to the given [token].
+ */
+ void set returnKeyword(Token token);
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+}
+
+/**
+ * A script tag that can optionally occur at the beginning of a compilation unit.
+ *
+ * > scriptTag ::=
+ * > '#!' (~NEWLINE)* NEWLINE
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ScriptTag extends AstNode {
+ /**
+ * Initialize a newly created script tag.
+ */
+ factory ScriptTag(Token scriptTag) = ScriptTagImpl;
+
+ /**
+ * Return the token representing this script tag.
+ */
+ Token get scriptTag;
+
+ /**
+ * Set the token representing this script tag to the given [token].
+ */
+ void set scriptTag(Token token);
+}
+
+/**
+ * A combinator that restricts the names being imported to those in a given list.
+ *
+ * > showCombinator ::=
+ * > 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ShowCombinator extends Combinator {
+ /**
+ * Initialize a newly created import show combinator.
+ */
+ factory ShowCombinator(Token keyword, List<SimpleIdentifier> shownNames) =
+ ShowCombinatorImpl;
+
+ /**
+ * Return the list of names from the library that are made visible by this
+ * combinator.
+ */
+ NodeList<SimpleIdentifier> get shownNames;
+}
+
+/**
+ * A simple formal parameter.
+ *
+ * > simpleFormalParameter ::=
+ * > ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SimpleFormalParameter extends NormalFormalParameter {
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [keyword] can be `null` if a type was
+ * specified. The [type] must be `null` if the keyword is 'var'.
+ */
+ factory SimpleFormalParameter(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ TypeName type,
+ SimpleIdentifier identifier) = SimpleFormalParameterImpl;
+
+ /**
+ * Return the token representing either the 'final', 'const' or 'var' keyword,
+ * or `null` if no keyword was used.
+ */
+ Token get keyword;
+
+ /**
+ * Set the token representing either the 'final', 'const' or 'var' keyword to
+ * the given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the name of the declared type of the parameter, or `null` if the
+ * parameter does not have a declared type.
+ */
+ TypeName get type;
+
+ /**
+ * Set the name of the declared type of the parameter to the given [typeName].
+ */
+ void set type(TypeName typeName);
+}
+
+/**
+ * A simple identifier.
+ *
+ * > simpleIdentifier ::=
+ * > initialCharacter internalCharacter*
+ * >
+ * > initialCharacter ::= '_' | '$' | letter
+ * >
+ * > internalCharacter ::= '_' | '$' | letter | digit
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SimpleIdentifier extends Identifier {
+ /**
+ * Initialize a newly created identifier.
+ */
+ factory SimpleIdentifier(Token token) = SimpleIdentifierImpl;
+
+ /**
+ * Return the auxiliary elements associated with this identifier, or `null` if
+ * this identifier is not in both a getter and setter context. The auxiliary
+ * elements hold the static and propagated elements associated with the getter
+ * context.
+ */
+ // TODO(brianwilkerson) Replace this API.
+ AuxiliaryElements get auxiliaryElements;
+
+ /**
+ * Set the auxiliary elements associated with this identifier to the given
+ * [elements].
+ */
+ // TODO(brianwilkerson) Replace this API.
+ void set auxiliaryElements(AuxiliaryElements elements);
+
+ /**
+ * Return `true` if this identifier is the "name" part of a prefixed
+ * identifier or a method invocation.
+ */
+ bool get isQualified;
+
+ /**
+ * Set the element associated with this identifier based on propagated type
+ * information to the given [element].
+ */
+ void set propagatedElement(Element element);
+
+ /**
+ * Set the element associated with this identifier based on static type
+ * information to the given [element].
+ */
+ void set staticElement(Element element);
+
+ /**
+ * Return the token representing the identifier.
+ */
+ Token get token;
+
+ /**
+ * Set the token representing the identifier to the given [token].
+ */
+ void set token(Token token);
+
+ /**
+ * Return `true` if this identifier is the name being declared in a
+ * declaration.
+ */
+ // TODO(brianwilkerson) Convert this to a getter.
+ bool inDeclarationContext();
+
+ /**
+ * Return `true` if this expression is computing a right-hand value.
+ *
+ * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+ * are they mutually exclusive. In other words, it is possible for both
+ * methods to return `true` when invoked on the same node.
+ */
+ // TODO(brianwilkerson) Convert this to a getter.
+ bool inGetterContext();
+
+ /**
+ * Return `true` if this expression is computing a left-hand value.
+ *
+ * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+ * are they mutually exclusive. In other words, it is possible for both
+ * methods to return `true` when invoked on the same node.
+ */
+ // TODO(brianwilkerson) Convert this to a getter.
+ bool inSetterContext();
+}
+
+/**
+ * A string literal expression that does not contain any interpolations.
+ *
+ * > simpleStringLiteral ::=
+ * > rawStringLiteral
+ * > | basicStringLiteral
+ * >
+ * > rawStringLiteral ::=
+ * > 'r' basicStringLiteral
+ * >
+ * > simpleStringLiteral ::=
+ * > multiLineStringLiteral
+ * > | singleLineStringLiteral
+ * >
+ * > multiLineStringLiteral ::=
+ * > "'''" characters "'''"
+ * > | '"""' characters '"""'
+ * >
+ * > singleLineStringLiteral ::=
+ * > "'" characters "'"
+ * > | '"' characters '"'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SimpleStringLiteral extends SingleStringLiteral {
+ /**
+ * Initialize a newly created simple string literal.
+ */
+ factory SimpleStringLiteral(Token literal, String value) =
+ SimpleStringLiteralImpl;
+
+ /**
+ * Return the token representing the literal.
+ */
+ Token get literal;
+
+ /**
+ * Set the token representing the literal to the given [token].
+ */
+ void set literal(Token token);
+
+ /**
+ * Return the value of the literal.
+ */
+ String get value;
+
+ /**
+ * Set the value of the literal to the given [string].
+ */
+ void set value(String string);
+}
+
+/**
+ * A single string literal expression.
+ *
+ * > singleStringLiteral ::=
+ * > [SimpleStringLiteral]
+ * > | [StringInterpolation]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SingleStringLiteral extends StringLiteral {
+ /**
+ * Return the offset of the after-last contents character.
+ */
+ int get contentsEnd;
+
+ /**
+ * Return the offset of the first contents character.
+ * If the string is multiline, then leading whitespaces are skipped.
+ */
+ int get contentsOffset;
+
+ /**
+ * Return `true` if this string literal is a multi-line string.
+ */
+ bool get isMultiline;
+
+ /**
+ * Return `true` if this string literal is a raw string.
+ */
+ bool get isRaw;
+
+ /**
+ * Return `true` if this string literal uses single quotes (' or ''').
+ * Return `false` if this string literal uses double quotes (" or """).
+ */
+ bool get isSingleQuoted;
+}
+
+/**
+ * A node that represents a statement.
+ *
+ * > statement ::=
+ * > [Block]
+ * > | [VariableDeclarationStatement]
+ * > | [ForStatement]
+ * > | [ForEachStatement]
+ * > | [WhileStatement]
+ * > | [DoStatement]
+ * > | [SwitchStatement]
+ * > | [IfStatement]
+ * > | [TryStatement]
+ * > | [BreakStatement]
+ * > | [ContinueStatement]
+ * > | [ReturnStatement]
+ * > | [ExpressionStatement]
+ * > | [FunctionDeclarationStatement]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Statement extends AstNode {
+ /**
+ * If this is a labeled statement, return the unlabeled portion of the
+ * statement, otherwise return the statement itself.
+ */
+ Statement get unlabeled;
+}
+
+/**
+ * A string interpolation literal.
+ *
+ * > stringInterpolation ::=
+ * > ''' [InterpolationElement]* '''
+ * > | '"' [InterpolationElement]* '"'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class StringInterpolation extends SingleStringLiteral {
+ /**
+ * Initialize a newly created string interpolation expression.
+ */
+ factory StringInterpolation(List<InterpolationElement> elements) =
+ StringInterpolationImpl;
+
+ /**
+ * Return the elements that will be composed to produce the resulting string.
+ */
+ NodeList<InterpolationElement> get elements;
+}
+
+/**
+ * A string literal expression.
+ *
+ * > stringLiteral ::=
+ * > [SimpleStringLiteral]
+ * > | [AdjacentStrings]
+ * > | [StringInterpolation]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class StringLiteral extends Literal {
+ /**
+ * Return the value of the string literal, or `null` if the string is not a
+ * constant string without any string interpolation.
+ */
+ String get stringValue;
+}
+
+/**
+ * The invocation of a superclass' constructor from within a constructor's
+ * initialization list.
+ *
+ * > superInvocation ::=
+ * > 'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SuperConstructorInvocation extends ConstructorInitializer {
+ /**
+ * Initialize a newly created super invocation to invoke the inherited
+ * constructor with the given name with the given arguments. The [period] and
+ * [constructorName] can be `null` if the constructor being invoked is the
+ * unnamed constructor.
+ */
+ factory SuperConstructorInvocation(
+ Token superKeyword,
+ Token period,
+ SimpleIdentifier constructorName,
+ ArgumentList argumentList) = SuperConstructorInvocationImpl;
+
+ /**
+ * Return the list of arguments to the constructor.
+ */
+ ArgumentList get argumentList;
+
+ /**
+ * Set the list of arguments to the constructor to the given [argumentList].
+ */
+ void set argumentList(ArgumentList argumentList);
+
+ /**
+ * Return the name of the constructor that is being invoked, or `null` if the
+ * unnamed constructor is being invoked.
+ */
+ SimpleIdentifier get constructorName;
+
+ /**
+ * Set the name of the constructor that is being invoked to the given
+ * [identifier].
+ */
+ void set constructorName(SimpleIdentifier identifier);
+
+ /**
+ * Return the token for the period before the name of the constructor that is
+ * being invoked, or `null` if the unnamed constructor is being invoked.
+ */
+ Token get period;
+
+ /**
+ * Set the token for the period before the name of the constructor that is
+ * being invoked to the given [token].
+ */
+ void set period(Token token);
+
+ /**
+ * Return the element associated with the constructor based on static type
+ * information, or `null` if the AST structure has not been resolved or if the
+ * constructor could not be resolved.
+ */
+ ConstructorElement get staticElement;
+
+ /**
+ * Set the element associated with the constructor based on static type
+ * information to the given [element].
+ */
+ void set staticElement(ConstructorElement element);
+
+ /**
+ * Return the token for the 'super' keyword.
+ */
+ Token get superKeyword;
+
+ /**
+ * Set the token for the 'super' keyword to the given [token].
+ */
+ void set superKeyword(Token token);
+}
+
+/**
+ * A super expression.
+ *
+ * > superExpression ::=
+ * > 'super'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SuperExpression extends Expression {
+ /**
+ * Initialize a newly created super expression.
+ */
+ factory SuperExpression(Token superKeyword) = SuperExpressionImpl;
+
+ /**
+ * Return the token representing the 'super' keyword.
+ */
+ Token get superKeyword;
+
+ /**
+ * Set the token representing the 'super' keyword to the given [token].
+ */
+ void set superKeyword(Token token);
+}
+
+/**
+ * A case in a switch statement.
+ *
+ * > switchCase ::=
+ * > [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchCase extends SwitchMember {
+ /**
+ * Initialize a newly created switch case. The list of [labels] can be `null`
+ * if there are no labels.
+ */
+ factory SwitchCase(List<Label> labels, Token keyword, Expression expression,
+ Token colon, List<Statement> statements) = SwitchCaseImpl;
+
+ /**
+ * Return the expression controlling whether the statements will be executed.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression controlling whether the statements will be executed to
+ * the given [expression].
+ */
+ void set expression(Expression expression);
+}
+
+/**
+ * The default case in a switch statement.
+ *
+ * > switchDefault ::=
+ * > [SimpleIdentifier]* 'default' ':' [Statement]*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchDefault extends SwitchMember {
+ /**
+ * Initialize a newly created switch default. The list of [labels] can be
+ * `null` if there are no labels.
+ */
+ factory SwitchDefault(List<Label> labels, Token keyword, Token colon,
+ List<Statement> statements) = SwitchDefaultImpl;
+}
+
+/**
+ * An element within a switch statement.
+ *
+ * > switchMember ::=
+ * > switchCase
+ * > | switchDefault
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchMember extends AstNode {
+ /**
+ * Return the colon separating the keyword or the expression from the
+ * statements.
+ */
+ Token get colon;
+
+ /**
+ * Set the colon separating the keyword or the expression from the
+ * statements to the given [token].
+ */
+ void set colon(Token token);
+
+ /**
+ * Return the token representing the 'case' or 'default' keyword.
+ */
+ Token get keyword;
+
+ /**
+ * Set the token representing the 'case' or 'default' keyword to the given
+ * [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the labels associated with the switch member.
+ */
+ NodeList<Label> get labels;
+
+ /**
+ * Return the statements that will be executed if this switch member is
+ * selected.
+ */
+ NodeList<Statement> get statements;
+}
+
+/**
+ * A switch statement.
+ *
+ * > switchStatement ::=
+ * > 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchStatement extends Statement {
+ /**
+ * Initialize a newly created switch statement. The list of [members] can be
+ * `null` if there are no switch members.
+ */
+ factory SwitchStatement(
+ Token switchKeyword,
+ Token leftParenthesis,
+ Expression expression,
+ Token rightParenthesis,
+ Token leftBracket,
+ List<SwitchMember> members,
+ Token rightBracket) = SwitchStatementImpl;
+
+ /**
+ * Return the expression used to determine which of the switch members will be
+ * selected.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression used to determine which of the switch members will be
+ * selected to the given [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the left curly bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left curly bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the switch members that can be selected by the expression.
+ */
+ NodeList<SwitchMember> get members;
+
+ /**
+ * Return the right curly bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right curly bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the token representing the 'switch' keyword.
+ */
+ Token get switchKeyword;
+
+ /**
+ * Set the token representing the 'switch' keyword to the given [token].
+ */
+ void set switchKeyword(Token token);
+}
+
+/**
+ * A symbol literal expression.
+ *
+ * > symbolLiteral ::=
+ * > '#' (operator | (identifier ('.' identifier)*))
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SymbolLiteral extends Literal {
+ /**
+ * Initialize a newly created symbol literal.
+ */
+ factory SymbolLiteral(Token poundSign, List<Token> components) =
+ SymbolLiteralImpl;
+
+ /**
+ * Return the components of the literal.
+ */
+ List<Token> get components;
+
+ /**
+ * Return the token introducing the literal.
+ */
+ Token get poundSign;
+
+ /**
+ * Set the token introducing the literal to the given [token].
+ */
+ void set poundSign(Token token);
+}
+
+/**
+ * A this expression.
+ *
+ * > thisExpression ::=
+ * > 'this'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ThisExpression extends Expression {
+ /**
+ * Initialize a newly created this expression.
+ */
+ factory ThisExpression(Token thisKeyword) = ThisExpressionImpl;
+
+ /**
+ * Return the token representing the 'this' keyword.
+ */
+ Token get thisKeyword;
+
+ /**
+ * Set the token representing the 'this' keyword to the given [token].
+ */
+ void set thisKeyword(Token token);
+}
+
+/**
+ * A throw expression.
+ *
+ * > throwExpression ::=
+ * > 'throw' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ThrowExpression extends Expression {
+ /**
+ * Initialize a newly created throw expression.
+ */
+ factory ThrowExpression(Token throwKeyword, Expression expression) =
+ ThrowExpressionImpl;
+
+ /**
+ * Return the expression computing the exception to be thrown.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression computing the exception to be thrown to the given
+ * [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the token representing the 'throw' keyword.
+ */
+ Token get throwKeyword;
+
+ /**
+ * Set the token representing the 'throw' keyword to the given [token].
+ */
+ void set throwKeyword(Token token);
+}
+
+/**
+ * The declaration of one or more top-level variables of the same type.
+ *
+ * > topLevelVariableDeclaration ::=
+ * > ('final' | 'const') type? staticFinalDeclarationList ';'
+ * > | variableDeclaration ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TopLevelVariableDeclaration extends CompilationUnitMember {
+ /**
+ * Initialize a newly created top-level variable declaration. Either or both
+ * of the [comment] and [metadata] can be `null` if the variable does not have
+ * the corresponding attribute.
+ */
+ factory TopLevelVariableDeclaration(
+ Comment comment,
+ List<Annotation> metadata,
+ VariableDeclarationList variableList,
+ Token semicolon) = TopLevelVariableDeclarationImpl;
+
+ /**
+ * Return the semicolon terminating the declaration.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the declaration to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the top-level variables being declared.
+ */
+ VariableDeclarationList get variables;
+
+ /**
+ * Set the top-level variables being declared to the given list of
+ * [variables].
+ */
+ void set variables(VariableDeclarationList variables);
+}
+
+/**
+ * A try statement.
+ *
+ * > tryStatement ::=
+ * > 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ * >
+ * > finallyClause ::=
+ * > 'finally' [Block]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TryStatement extends Statement {
+ /**
+ * Initialize a newly created try statement. The list of [catchClauses] can be
+ * `null` if there are no catch clauses. The [finallyKeyword] and
+ * [finallyBlock] can be `null` if there is no finally clause.
+ */
+ factory TryStatement(
+ Token tryKeyword,
+ Block body,
+ List<CatchClause> catchClauses,
+ Token finallyKeyword,
+ Block finallyBlock) = TryStatementImpl;
+
+ /**
+ * Return the body of the statement.
+ */
+ Block get body;
+
+ /**
+ * Set the body of the statement to the given [block].
+ */
+ void set body(Block block);
+
+ /**
+ * Return the catch clauses contained in the try statement.
+ */
+ NodeList<CatchClause> get catchClauses;
+
+ /**
+ * Return the finally block contained in the try statement, or `null` if the
+ * statement does not contain a finally clause.
+ */
+ Block get finallyBlock;
+
+ /**
+ * Set the finally block contained in the try statement to the given [block].
+ */
+ void set finallyBlock(Block block);
+
+ /**
+ * Return the token representing the 'finally' keyword, or `null` if the
+ * statement does not contain a finally clause.
+ */
+ Token get finallyKeyword;
+
+ /**
+ * Set the token representing the 'finally' keyword to the given [token].
+ */
+ void set finallyKeyword(Token token);
+
+ /**
+ * Return the token representing the 'try' keyword.
+ */
+ Token get tryKeyword;
+
+ /**
+ * Set the token representing the 'try' keyword to the given [token].
+ */
+ void set tryKeyword(Token token);
+}
+
+/**
+ * The declaration of a type alias.
+ *
+ * > typeAlias ::=
+ * > 'typedef' typeAliasBody
+ * >
+ * > typeAliasBody ::=
+ * > classTypeAlias
+ * > | functionTypeAlias
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeAlias extends NamedCompilationUnitMember {
+ /**
+ * Return the semicolon terminating the declaration.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the declaration to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the token representing the 'typedef' keyword.
+ */
+ Token get typedefKeyword;
+
+ /**
+ * Set the token representing the 'typedef' keyword to the given [token].
+ */
+ void set typedefKeyword(Token token);
+}
+
+/**
+ * A list of type arguments.
+ *
+ * > typeArguments ::=
+ * > '<' typeName (',' typeName)* '>'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeArgumentList extends AstNode {
+ /**
+ * Initialize a newly created list of type arguments.
+ */
+ factory TypeArgumentList(
+ Token leftBracket, List<TypeName> arguments, Token rightBracket) =
+ TypeArgumentListImpl;
+
+ /**
+ * Return the type arguments associated with the type.
+ */
+ NodeList<TypeName> get arguments;
+
+ /**
+ * Return the left bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Set the left bracket to the given [token].
+ */
+ void set leftBracket(Token token);
+
+ /**
+ * Return the right bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Set the right bracket to the given [token].
+ */
+ void set rightBracket(Token token);
+}
+
+/**
+ * A literal that has a type associated with it.
+ *
+ * > typedLiteral ::=
+ * > [ListLiteral]
+ * > | [MapLiteral]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypedLiteral extends Literal {
+ /**
+ * Return the token representing the 'const' keyword, or `null` if the literal
+ * is not a constant.
+ */
+ Token get constKeyword;
+
+ /**
+ * Set the token representing the 'const' keyword to the given [token].
+ */
+ void set constKeyword(Token token);
+
+ /**
+ * Return the type argument associated with this literal, or `null` if no type
+ * arguments were declared.
+ */
+ TypeArgumentList get typeArguments;
+
+ /**
+ * Set the type argument associated with this literal to the given
+ * [typeArguments].
+ */
+ void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * The name of a type, which can optionally include type arguments.
+ *
+ * > typeName ::=
+ * > [Identifier] typeArguments?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeName extends AstNode {
+ /**
+ * Initialize a newly created type name. The [typeArguments] can be `null` if
+ * there are no type arguments.
+ */
+ factory TypeName(Identifier name, TypeArgumentList typeArguments) =
+ TypeNameImpl;
+
+ /**
+ * Return `true` if this type is a deferred type.
+ *
+ * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
+ * </i>p.T</i> where <i>p</i> is a deferred prefix.
+ */
+ bool get isDeferred;
+
+ /**
+ * Return the name of the type.
+ */
+ Identifier get name;
+
+ /**
+ * Set the name of the type to the given [identifier].
+ */
+ void set name(Identifier identifier);
+
+ /**
+ * Return the type being named, or `null` if the AST structure has not been
+ * resolved.
+ */
+ DartType get type;
+
+ /**
+ * Set the type being named to the given [type].
+ */
+ void set type(DartType type);
+
+ /**
+ * Return the type arguments associated with the type, or `null` if there are
+ * no type arguments.
+ */
+ TypeArgumentList get typeArguments;
+
+ /**
+ * Set the type arguments associated with the type to the given
+ * [typeArguments].
+ */
+ void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * A type parameter.
+ *
+ * > typeParameter ::=
+ * > [SimpleIdentifier] ('extends' [TypeName])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeParameter extends Declaration {
+ /**
+ * Initialize a newly created type parameter. Either or both of the [comment]
+ * and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [extendsKeyword] and [bound] can be `null` if
+ * the parameter does not have an upper bound.
+ */
+ factory TypeParameter(
+ Comment comment,
+ List<Annotation> metadata,
+ SimpleIdentifier name,
+ Token extendsKeyword,
+ TypeName bound) = TypeParameterImpl;
+
+ /**
+ * Return the name of the upper bound for legal arguments, or `null` if there
+ * is no explicit upper bound.
+ */
+ TypeName get bound;
+
+ /**
+ * Set the name of the upper bound for legal arguments to the given
+ * [typeName].
+ */
+ void set bound(TypeName typeName);
+
+ /**
+ * Return the token representing the 'extends' keyword, or `null` if there is
+ * no explicit upper bound.
+ */
+ Token get extendsKeyword;
+
+ /**
+ * Set the token representing the 'extends' keyword to the given [token].
+ */
+ void set extendsKeyword(Token token);
+
+ /**
+ * Return the name of the type parameter.
+ */
+ SimpleIdentifier get name;
+
+ /**
+ * Set the name of the type parameter to the given [identifier].
+ */
+ void set name(SimpleIdentifier identifier);
+}
+
+/**
+ * Type parameters within a declaration.
+ *
+ * > typeParameterList ::=
+ * > '<' [TypeParameter] (',' [TypeParameter])* '>'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeParameterList extends AstNode {
+ /**
+ * Initialize a newly created list of type parameters.
+ */
+ factory TypeParameterList(
+ Token leftBracket,
+ List<TypeParameter> typeParameters,
+ Token rightBracket) = TypeParameterListImpl;
+
+ /**
+ * Return the left angle bracket.
+ */
+ Token get leftBracket;
+
+ /**
+ * Return the right angle bracket.
+ */
+ Token get rightBracket;
+
+ /**
+ * Return the type parameters for the type.
+ */
+ NodeList<TypeParameter> get typeParameters;
+}
+
+/**
+ * A directive that references a URI.
+ *
+ * > uriBasedDirective ::=
+ * > [ExportDirective]
+ * > | [ImportDirective]
+ * > | [PartDirective]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class UriBasedDirective extends Directive {
+ /**
+ * Return the source to which the URI was resolved.
+ */
+ Source get source;
+
+ /**
+ * Set the source to which the URI was resolved to the given [source].
+ */
+ void set source(Source source);
+
+ /**
+ * Return the URI referenced by this directive.
+ */
+ StringLiteral get uri;
+
+ /**
+ * Set the URI referenced by this directive to the given [uri].
+ */
+ void set uri(StringLiteral uri);
+
+ /**
+ * Return the content of the URI.
+ */
+ String get uriContent;
+
+ /**
+ * Set the content of the URI to the given [content].
+ */
+ void set uriContent(String content);
+
+ /**
+ * Return the element associated with the URI of this directive, or `null` if
+ * the AST structure has not been resolved or if the URI could not be
+ * resolved. Examples of the latter case include a directive that contains an
+ * invalid URL or a URL that does not exist.
+ */
+ Element get uriElement;
+
+ /**
+ * Validate this directive, but do not check for existence. Return a code
+ * indicating the problem if there is one, or `null` no problem
+ */
+ UriValidationCode validate();
+}
+
+/**
+ * Validation codes returned by [UriBasedDirective.validate].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class UriValidationCode {
+ static const UriValidationCode INVALID_URI =
+ UriValidationCodeImpl.INVALID_URI;
+
+ static const UriValidationCode URI_WITH_INTERPOLATION =
+ UriValidationCodeImpl.URI_WITH_INTERPOLATION;
+
+ static const UriValidationCode URI_WITH_DART_EXT_SCHEME =
+ UriValidationCodeImpl.URI_WITH_DART_EXT_SCHEME;
+}
+
+/**
+ * An identifier that has an initial value associated with it. Instances of this
+ * class are always children of the class [VariableDeclarationList].
+ *
+ * > variableDeclaration ::=
+ * > [SimpleIdentifier] ('=' [Expression])?
+ *
+ * TODO(paulberry): the grammar does not allow metadata to be associated with
+ * a VariableDeclaration, and currently we don't record comments for it either.
+ * Consider changing the class hierarchy so that [VariableDeclaration] does not
+ * extend [Declaration].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class VariableDeclaration extends Declaration {
+ /**
+ * Initialize a newly created variable declaration. The [equals] and
+ * [initializer] can be `null` if there is no initializer.
+ */
+ factory VariableDeclaration(
+ SimpleIdentifier name, Token equals, Expression initializer) =
+ VariableDeclarationImpl;
+
+ @override
+ VariableElement get element;
+
+ /**
+ * Return the equal sign separating the variable name from the initial value,
+ * or `null` if the initial value was not specified.
+ */
+ Token get equals;
+
+ /**
+ * Set the equal sign separating the variable name from the initial value to
+ * the given [token].
+ */
+ void set equals(Token token);
+
+ /**
+ * Return the expression used to compute the initial value for the variable,
+ * or `null` if the initial value was not specified.
+ */
+ Expression get initializer;
+
+ /**
+ * Set the expression used to compute the initial value for the variable to
+ * the given [expression].
+ */
+ void set initializer(Expression expression);
+
+ /**
+ * Return `true` if this variable was declared with the 'const' modifier.
+ */
+ bool get isConst;
+
+ /**
+ * Return `true` if this variable was declared with the 'final' modifier.
+ * Variables that are declared with the 'const' modifier will return `false`
+ * even though they are implicitly final.
+ */
+ bool get isFinal;
+
+ /**
+ * Return the name of the variable being declared.
+ */
+ SimpleIdentifier get name;
+
+ /**
+ * Set the name of the variable being declared to the given [identifier].
+ */
+ void set name(SimpleIdentifier identifier);
+}
+
+/**
+ * The declaration of one or more variables of the same type.
+ *
+ * > variableDeclarationList ::=
+ * > finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ * >
+ * > finalConstVarOrType ::=
+ * > | 'final' [TypeName]?
+ * > | 'const' [TypeName]?
+ * > | 'var'
+ * > | [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class VariableDeclarationList extends AnnotatedNode {
+ /**
+ * Initialize a newly created variable declaration list. Either or both of the
+ * [comment] and [metadata] can be `null` if the variable list does not have
+ * the corresponding attribute. The [keyword] can be `null` if a type was
+ * specified. The [type] must be `null` if the keyword is 'var'.
+ */
+ factory VariableDeclarationList(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ TypeName type,
+ List<VariableDeclaration> variables) = VariableDeclarationListImpl;
+
+ /**
+ * Return `true` if the variables in this list were declared with the 'const'
+ * modifier.
+ */
+ bool get isConst;
+
+ /**
+ * Return `true` if the variables in this list were declared with the 'final'
+ * modifier. Variables that are declared with the 'const' modifier will return
+ * `false` even though they are implicitly final. (In other words, this is a
+ * syntactic check rather than a semantic check.)
+ */
+ bool get isFinal;
+
+ /**
+ * Return the token representing the 'final', 'const' or 'var' keyword, or
+ * `null` if no keyword was included.
+ */
+ Token get keyword;
+
+ /**
+ * Set the token representing the 'final', 'const' or 'var' keyword to the
+ * given [token].
+ */
+ void set keyword(Token token);
+
+ /**
+ * Return the type of the variables being declared, or `null` if no type was
+ * provided.
+ */
+ TypeName get type;
+
+ /**
+ * Set the type of the variables being declared to the given [typeName].
+ */
+ void set type(TypeName typeName);
+
+ /**
+ * Return a list containing the individual variables being declared.
+ */
+ NodeList<VariableDeclaration> get variables;
+}
+
+/**
+ * A list of variables that are being declared in a context where a statement is
+ * required.
+ *
+ * > variableDeclarationStatement ::=
+ * > [VariableDeclarationList] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class VariableDeclarationStatement extends Statement {
+ /**
+ * Initialize a newly created variable declaration statement.
+ */
+ factory VariableDeclarationStatement(
+ VariableDeclarationList variableList, Token semicolon) =
+ VariableDeclarationStatementImpl;
+
+ /**
+ * Return the semicolon terminating the statement.
+ */
+ Token get semicolon;
+
+ /**
+ * Set the semicolon terminating the statement to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the variables being declared.
+ */
+ VariableDeclarationList get variables;
+
+ /**
+ * Set the variables being declared to the given list of [variables].
+ */
+ void set variables(VariableDeclarationList variables);
+}
+
+/**
+ * A while statement.
+ *
+ * > whileStatement ::=
+ * > 'while' '(' [Expression] ')' [Statement]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class WhileStatement extends Statement {
+ /**
+ * Initialize a newly created while statement.
+ */
+ factory WhileStatement(
+ Token whileKeyword,
+ Token leftParenthesis,
+ Expression condition,
+ Token rightParenthesis,
+ Statement body) = WhileStatementImpl;
+
+ /**
+ * Return the body of the loop.
+ */
+ Statement get body;
+
+ /**
+ * Set the body of the loop to the given [statement].
+ */
+ void set body(Statement statement);
+
+ /**
+ * Return the expression used to determine whether to execute the body of the
+ * loop.
+ */
+ Expression get condition;
+
+ /**
+ * Set the expression used to determine whether to execute the body of the
+ * loop to the given [expression].
+ */
+ void set condition(Expression expression);
+
+ /**
+ * Return the left parenthesis.
+ */
+ Token get leftParenthesis;
+
+ /**
+ * Set the left parenthesis to the given [token].
+ */
+ void set leftParenthesis(Token token);
+
+ /**
+ * Return the right parenthesis.
+ */
+ Token get rightParenthesis;
+
+ /**
+ * Set the right parenthesis to the given [token].
+ */
+ void set rightParenthesis(Token token);
+
+ /**
+ * Return the token representing the 'while' keyword.
+ */
+ Token get whileKeyword;
+
+ /**
+ * Set the token representing the 'while' keyword to the given [token].
+ */
+ void set whileKeyword(Token token);
+}
+
+/**
+ * The with clause in a class declaration.
+ *
+ * > withClause ::=
+ * > 'with' [TypeName] (',' [TypeName])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class WithClause extends AstNode {
+ /**
+ * Initialize a newly created with clause.
+ */
+ factory WithClause(Token withKeyword, List<TypeName> mixinTypes) =
+ WithClauseImpl;
+
+ /**
+ * Return the names of the mixins that were specified.
+ */
+ NodeList<TypeName> get mixinTypes;
+
+ /**
+ * Return the token representing the 'with' keyword.
+ */
+ Token get withKeyword;
+
+ /**
+ * Set the token representing the 'with' keyword to the given [token].
+ */
+ void set withKeyword(Token token);
+}
+
+/**
+ * A yield statement.
+ *
+ * > yieldStatement ::=
+ * > 'yield' '*'? [Expression] ‘;’
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class YieldStatement extends Statement {
+ /**
+ * Initialize a newly created yield expression. The [star] can be `null` if no
+ * star was provided.
+ */
+ factory YieldStatement(Token yieldKeyword, Token star, Expression expression,
+ Token semicolon) = YieldStatementImpl;
+
+ /**
+ * Return the expression whose value will be yielded.
+ */
+ Expression get expression;
+
+ /**
+ * Set the expression whose value will be yielded to the given [expression].
+ */
+ void set expression(Expression expression);
+
+ /**
+ * Return the semicolon following the expression.
+ */
+ Token get semicolon;
+
+ /**
+ * Return the semicolon following the expression to the given [token].
+ */
+ void set semicolon(Token token);
+
+ /**
+ * Return the star optionally following the 'yield' keyword.
+ */
+ Token get star;
+
+ /**
+ * Return the star optionally following the 'yield' keyword to the given [token].
+ */
+ void set star(Token token);
+
+ /**
+ * Return the 'yield' keyword.
+ */
+ Token get yieldKeyword;
+
+ /**
+ * Return the 'yield' keyword to the given [token].
+ */
+ void set yieldKeyword(Token token);
+}
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index c9b345a..7e2848e 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -6,7 +6,7 @@
import 'dart:collection';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
/**
* An AST visitor that will recursively visit all of the nodes in an AST
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index ab468ed..bb52303d 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -4,8 +4,8 @@
library analyzer.dart.element.element;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart' show DartObject;
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/java_core.dart';
@@ -1347,6 +1347,11 @@
bool get isBrowserApplication;
/**
+ * Return `true` if this library is the dart:async library.
+ */
+ bool get isDartAsync;
+
+ /**
* Return `true` if this library is the dart:core library.
*/
bool get isDartCore;
@@ -1470,154 +1475,6 @@
}
/**
- * The enumeration `Modifier` defines constants for all of the modifiers defined
- * by the Dart language and for a few additional flags that are useful.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-class Modifier extends Enum<Modifier> {
- /**
- * Indicates that the modifier 'abstract' was applied to the element.
- */
- static const Modifier ABSTRACT = const Modifier('ABSTRACT', 0);
-
- /**
- * Indicates that an executable element has a body marked as being
- * asynchronous.
- */
- static const Modifier ASYNCHRONOUS = const Modifier('ASYNCHRONOUS', 1);
-
- /**
- * Indicates that the modifier 'const' was applied to the element.
- */
- static const Modifier CONST = const Modifier('CONST', 2);
-
- /**
- * Indicates that the import element represents a deferred library.
- */
- static const Modifier DEFERRED = const Modifier('DEFERRED', 3);
-
- /**
- * Indicates that a class element was defined by an enum declaration.
- */
- static const Modifier ENUM = const Modifier('ENUM', 4);
-
- /**
- * Indicates that a class element was defined by an enum declaration.
- */
- static const Modifier EXTERNAL = const Modifier('EXTERNAL', 5);
-
- /**
- * Indicates that the modifier 'factory' was applied to the element.
- */
- static const Modifier FACTORY = const Modifier('FACTORY', 6);
-
- /**
- * Indicates that the modifier 'final' was applied to the element.
- */
- static const Modifier FINAL = const Modifier('FINAL', 7);
-
- /**
- * Indicates that an executable element has a body marked as being a
- * generator.
- */
- static const Modifier GENERATOR = const Modifier('GENERATOR', 8);
-
- /**
- * Indicates that the pseudo-modifier 'get' was applied to the element.
- */
- static const Modifier GETTER = const Modifier('GETTER', 9);
-
- /**
- * A flag used for libraries indicating that the defining compilation unit
- * contains at least one import directive whose URI uses the "dart-ext"
- * scheme.
- */
- static const Modifier HAS_EXT_URI = const Modifier('HAS_EXT_URI', 10);
-
- /**
- * Indicates that the associated element did not have an explicit type
- * associated with it. If the element is an [ExecutableElement], then the
- * type being referred to is the return type.
- */
- static const Modifier IMPLICIT_TYPE = const Modifier('IMPLICIT_TYPE', 11);
-
- /**
- * Indicates that a class can validly be used as a mixin.
- */
- static const Modifier MIXIN = const Modifier('MIXIN', 12);
-
- /**
- * Indicates that a class is a mixin application.
- */
- static const Modifier MIXIN_APPLICATION =
- const Modifier('MIXIN_APPLICATION', 13);
-
- /**
- * Indicates that the value of a parameter or local variable might be mutated
- * within the context.
- */
- static const Modifier POTENTIALLY_MUTATED_IN_CONTEXT =
- const Modifier('POTENTIALLY_MUTATED_IN_CONTEXT', 14);
-
- /**
- * Indicates that the value of a parameter or local variable might be mutated
- * within the scope.
- */
- static const Modifier POTENTIALLY_MUTATED_IN_SCOPE =
- const Modifier('POTENTIALLY_MUTATED_IN_SCOPE', 15);
-
- /**
- * Indicates that a class contains an explicit reference to 'super'.
- */
- static const Modifier REFERENCES_SUPER =
- const Modifier('REFERENCES_SUPER', 16);
-
- /**
- * Indicates that the pseudo-modifier 'set' was applied to the element.
- */
- static const Modifier SETTER = const Modifier('SETTER', 17);
-
- /**
- * Indicates that the modifier 'static' was applied to the element.
- */
- static const Modifier STATIC = const Modifier('STATIC', 18);
-
- /**
- * Indicates that the element does not appear in the source code but was
- * implicitly created. For example, if a class does not define any
- * constructors, an implicit zero-argument constructor will be created and it
- * will be marked as being synthetic.
- */
- static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 19);
-
- static const List<Modifier> values = const [
- ABSTRACT,
- ASYNCHRONOUS,
- CONST,
- DEFERRED,
- ENUM,
- EXTERNAL,
- FACTORY,
- FINAL,
- GENERATOR,
- GETTER,
- HAS_EXT_URI,
- IMPLICIT_TYPE,
- MIXIN,
- MIXIN_APPLICATION,
- POTENTIALLY_MUTATED_IN_CONTEXT,
- POTENTIALLY_MUTATED_IN_SCOPE,
- REFERENCES_SUPER,
- SETTER,
- STATIC,
- SYNTHETIC
- ];
-
- const Modifier(String name, int ordinal) : super(name, ordinal);
-}
-
-/**
* A pseudo-element that represents multiple elements defined within a single
* scope that have the same name. This situation is not allowed by the language,
* so objects implementing this interface always represent an error. As a
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 548dc1d..5b92819 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart' show InterfaceTypeImpl;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystem;
/**
* The type associated with elements in the element model.
@@ -38,6 +39,12 @@
bool get isBottom;
/**
+ * Return `true` if this type represents the type 'Future' defined in the
+ * dart:async library.
+ */
+ bool get isDartAsyncFuture;
+
+ /**
* Return `true` if this type represents the type 'Function' defined in the
* dart:core library.
*/
@@ -70,6 +77,19 @@
String get name;
/**
+ * Implements the function "flatten" defined in the spec, where T is this
+ * type:
+ *
+ * If T = Future<S> then flatten(T) = flatten(S).
+ *
+ * Otherwise if T <: Future then let S be a type such that T << Future<S>
+ * and for all R, if T << Future<R> then S << R. Then flatten(T) = S.
+ *
+ * In any other circumstance, flatten(T) = T.
+ */
+ DartType flattenFutures(TypeSystem typeSystem);
+
+ /**
* Return `true` if this type is assignable to the given [type]. A type
* <i>T</i> may be assigned to a type <i>S</i>, written <i>T</i> ⇔
* <i>S</i>, iff either <i>T</i> <: <i>S</i> or <i>S</i> <: <i>T</i>.
@@ -137,16 +157,6 @@
List<TypeParameterElement> get boundTypeParameters;
/**
- * The formal type parameters of this generic function.
- * For example `<T> T -> T`.
- *
- * These are distinct from the [typeParameters] list, which contains type
- * parameters from surrounding contexts, and thus are free type variables from
- * the perspective of this function type.
- */
- List<TypeParameterElement> get typeFormals;
-
- /**
* Return a map from the names of named parameters to the types of the named
* parameters of this type of function. The entries in the map will be
* iterated in the same order as the order in which the named parameters were
@@ -184,6 +194,16 @@
DartType get returnType;
/**
+ * The formal type parameters of this generic function.
+ * For example `<T> T -> T`.
+ *
+ * These are distinct from the [typeParameters] list, which contains type
+ * parameters from surrounding contexts, and thus are free type variables from
+ * the perspective of this function type.
+ */
+ List<TypeParameterElement> get typeFormals;
+
+ /**
* Return the type resulting from instantiating (replacing) the given
* [argumentTypes] for this function's bound type parameters.
*/
diff --git a/pkg/analyzer/lib/source/embedder.dart b/pkg/analyzer/lib/source/embedder.dart
index c82e4f3..f77ff7c 100644
--- a/pkg/analyzer/lib/source/embedder.dart
+++ b/pkg/analyzer/lib/source/embedder.dart
@@ -8,12 +8,18 @@
import 'dart:core' hide Resource;
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/java_io.dart' show JavaFile;
+import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource;
-import 'package:path/path.dart' as pathos;
import 'package:yaml/yaml.dart';
+const String _DART_COLON_PREFIX = 'dart:';
+
/// Given a packageMap, check in each package's lib directory for the
/// existence of an `_embedder.yaml` file. If the file contains a top level
/// YamlMap, it will be added to the [embedderYamls] map.
@@ -79,7 +85,6 @@
embedderYamls[libDir] = yaml;
}
-
/// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string.
/// Returns null if the file doesn't exist.
String _readEmbedderYaml(Folder libDir) {
@@ -104,14 +109,14 @@
///
/// If a key doesn't begin with `dart:` it is ignored.
///
-class EmbedderUriResolver extends UriResolver {
- static const String DART_COLON_PREFIX = 'dart:';
-
+class EmbedderUriResolver extends DartUriResolver {
final Map<String, String> _urlMappings = <String, String>{};
/// Construct a [EmbedderUriResolver] from a package map
/// (see [PackageMapProvider]).
- EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls) {
+ EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls)
+ : super(new EmbedderSdk()) {
+ (dartSdk as EmbedderSdk)._resolver = this;
if (embedderYamls == null) {
return;
}
@@ -126,108 +131,159 @@
if (embedder_libs is! YamlMap) {
return;
}
- (embedder_libs as YamlMap).forEach((k, v) =>
- _processEmbedderLibs(k, v, libDir));
+ (embedder_libs as YamlMap)
+ .forEach((k, v) => _processEmbedderLibs(k, v, libDir));
}
/// Install the mapping from [name] to [libDir]/[file].
void _processEmbedderLibs(String name, String file, Folder libDir) {
- if (!name.startsWith(DART_COLON_PREFIX)) {
+ if (!name.startsWith(_DART_COLON_PREFIX)) {
// SDK libraries must begin with 'dart:'.
// TODO(pquitslund): Notify developer that something is wrong with the
// _embedder.yaml file in libDir.
return;
}
- String key = name;
- String value = libDir.canonicalizePath(file);
- _urlMappings[key] = value;
+ String libPath = libDir.canonicalizePath(file);
+ _urlMappings[name] = libPath;
+ String shortName = name.substring(_DART_COLON_PREFIX.length);
+ SdkLibraryImpl library = new SdkLibraryImpl(shortName);
+ library.path = libPath;
+ (dartSdk as EmbedderSdk)._librariesMap.setLibrary(name, library);
}
/// Number of embedder libraries.
int get length => _urlMappings.length;
- /// Return the path mapping for [libName] or null if there is none.
- String operator [](String libName) => _urlMappings[libName];
-
- @override
- Source resolveAbsolute(Uri importUri, [Uri actualUri]) {
- String libraryName = _libraryName(importUri);
- String partPath = _partPath(importUri);
- // Lookup library name in mappings.
- String mapping = _urlMappings[libraryName];
- if (mapping == null) {
- // Not found.
- return null;
- }
- // This mapping points to the main entry file of the dart: library.
- Uri libraryEntry = new Uri.file(mapping);
- if (!libraryEntry.isAbsolute) {
- // We expect an absolute path.
- return null;
- }
-
- if (partPath != null) {
- return _resolvePart(libraryEntry, partPath, importUri);
- } else {
- return _resolveEntry(libraryEntry, importUri);
- }
- }
-
@override
Uri restoreAbsolute(Source source) {
- String extensionName = _findExtensionNameFor(source.fullName);
- if (extensionName != null) {
- return Uri.parse(extensionName);
- }
- // TODO(johnmccutchan): Handle restoring parts.
- return null;
+ Source sdkSource = dartSdk.fromFileUri(Uri.parse(source.fullName));
+ return sdkSource?.uri;
}
+}
- /// Return the extension name for [fullName] or `null`.
- String _findExtensionNameFor(String fullName) {
- String result;
- _urlMappings.forEach((extensionName, pathMapping) {
- if (pathMapping == fullName) {
- result = extensionName;
+class EmbedderSdk implements DartSdk {
+ // TODO(danrubel) Refactor this with DirectoryBasedDartSdk
+
+ /// The resolver associated with this embedder sdk.
+ EmbedderUriResolver _resolver;
+
+ /// The [AnalysisContext] which is used for all of the sources in this sdk.
+ InternalAnalysisContext _analysisContext;
+
+ /// The library map that is populated by visiting the AST structure parsed from
+ /// the contents of the libraries file.
+ final LibraryMap _librariesMap = new LibraryMap();
+
+ @override
+ AnalysisContext get context {
+ if (_analysisContext == null) {
+ _analysisContext = new SdkAnalysisContext();
+ SourceFactory factory = new SourceFactory([_resolver]);
+ _analysisContext.sourceFactory = factory;
+ List<String> uris = this.uris;
+ ChangeSet changeSet = new ChangeSet();
+ for (String uri in uris) {
+ changeSet.addedSource(factory.forUri(uri));
}
- });
- return result;
- }
-
- /// Return the library name of [importUri].
- String _libraryName(Uri importUri) {
- String uri = importUri.toString();
- int index = uri.indexOf('/');
- if (index >= 0) {
- return uri.substring(0, index);
+ _analysisContext.applyChanges(changeSet);
}
- return uri;
+ return _analysisContext;
}
- /// Return the part path of [importUri].
- String _partPath(Uri importUri) {
- String uri = importUri.toString();
- int index = uri.indexOf('/');
- if (index >= 0) {
- return uri.substring(index + 1);
+ @override
+ List<SdkLibrary> get sdkLibraries => _librariesMap.sdkLibraries;
+
+ // TODO(danrubel) Determine SDK version
+ @override
+ String get sdkVersion => '0';
+
+ @override
+ List<String> get uris => _librariesMap.uris;
+
+ @override
+ Source fromFileUri(Uri uri) {
+ JavaFile file = new JavaFile.fromUri(uri);
+ String filePath = file.getAbsolutePath();
+
+ String path;
+ for (SdkLibrary library in _librariesMap.sdkLibraries) {
+ String libraryPath = library.path.replaceAll('/', JavaFile.separator);
+ if (filePath == libraryPath) {
+ path = '$_DART_COLON_PREFIX${library.shortName}';
+ break;
+ }
+ }
+ if (path == null) {
+ for (SdkLibrary library in _librariesMap.sdkLibraries) {
+ String libraryPath = library.path.replaceAll('/', JavaFile.separator);
+ int index = libraryPath.lastIndexOf(JavaFile.separator);
+ if (index == -1) {
+ continue;
+ }
+ String prefix = libraryPath.substring(0, index + 1);
+ if (!filePath.startsWith(prefix)) {
+ continue;
+ }
+ var relPath = filePath
+ .substring(prefix.length).replaceAll(JavaFile.separator, '/');
+ path = '$_DART_COLON_PREFIX${library.shortName}/$relPath';
+ break;
+ }
+ }
+
+ if (path != null) {
+ try {
+ return new FileBasedSource(file, parseUriWithException(path));
+ } on URISyntaxException catch (exception, stackTrace) {
+ AnalysisEngine.instance.logger.logInformation(
+ "Failed to create URI: $path",
+ new CaughtException(exception, stackTrace));
+ return null;
+ }
}
return null;
}
- /// Resolve an import of an sdk extension.
- Source _resolveEntry(Uri libraryEntry, Uri importUri) {
- // Library entry.
- JavaFile javaFile = new JavaFile.fromUri(libraryEntry);
- return new FileBasedSource(javaFile, importUri);
- }
+ @override
+ SdkLibrary getSdkLibrary(String dartUri) => _librariesMap.getLibrary(dartUri);
- /// Resolve a 'part' statement inside an sdk extension.
- Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) {
- // Library part.
- String directory = pathos.dirname(libraryEntry.path);
- Uri partUri = new Uri.file(pathos.join(directory, partPath));
- assert(partUri.isAbsolute);
- JavaFile javaFile = new JavaFile.fromUri(partUri);
- return new FileBasedSource(javaFile, importUri);
+ @override
+ Source mapDartUri(String dartUri) {
+ String libraryName;
+ String relativePath;
+ int index = dartUri.indexOf('/');
+ if (index >= 0) {
+ libraryName = dartUri.substring(0, index);
+ relativePath = dartUri.substring(index + 1);
+ } else {
+ libraryName = dartUri;
+ relativePath = "";
+ }
+ SdkLibrary library = getSdkLibrary(libraryName);
+ if (library == null) {
+ return null;
+ }
+ String srcPath;
+ if (relativePath.isEmpty) {
+ srcPath = library.path;
+ } else {
+ String libraryPath = library.path;
+ int index = libraryPath.lastIndexOf(JavaFile.separator);
+ if (index == -1) {
+ index = libraryPath.lastIndexOf('/');
+ if (index == -1) {
+ return null;
+ }
+ }
+ String prefix = libraryPath.substring(0, index + 1);
+ srcPath = '$prefix$relativePath';
+ }
+ String filePath = srcPath.replaceAll('/', JavaFile.separator);
+ try {
+ JavaFile file = new JavaFile(filePath);
+ return new FileBasedSource(file, parseUriWithException(dartUri));
+ } on URISyntaxException {
+ return null;
+ }
}
}
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 4714557..09c35ac 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -7,14 +7,16 @@
import 'dart:async';
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/plugin/task.dart';
import 'package:analyzer/source/embedder.dart';
import 'package:analyzer/src/cancelable_future.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -24,6 +26,7 @@
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/src/task/dart_work_manager.dart';
@@ -185,6 +188,9 @@
*/
List<AnalysisListener> _listeners = new List<AnalysisListener>();
+ @override
+ ResultProvider resultProvider;
+
/**
* The most recently incrementally resolved source, or `null` when it was
* already validated, or the most recent change was not incrementally resolved.
@@ -459,13 +465,19 @@
if (coreElement == null) {
throw new AnalysisException("Could not create an element for dart:core");
}
- Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
- if (asyncSource == null) {
- throw new AnalysisException("Could not create a source for dart:async");
- }
- LibraryElement asyncElement = computeLibraryElement(asyncSource);
- if (asyncElement == null) {
- throw new AnalysisException("Could not create an element for dart:async");
+ LibraryElement asyncElement;
+ if (analysisOptions.enableAsync) {
+ Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
+ if (asyncSource == null) {
+ throw new AnalysisException("Could not create a source for dart:async");
+ }
+ asyncElement = computeLibraryElement(asyncSource);
+ if (asyncElement == null) {
+ throw new AnalysisException(
+ "Could not create an element for dart:async");
+ }
+ } else {
+ asyncElement = createMockAsyncLib(coreElement);
}
_typeProvider = new TypeProviderImpl(coreElement, asyncElement);
return _typeProvider;
@@ -489,26 +501,20 @@
@override
bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result) {
return PerformanceStatistics.summary.makeCurrentWhile(() {
- AnalysisTarget target = entry.target;
- // TYPE_PROVIDER
- if (target is AnalysisContextTarget && result == TYPE_PROVIDER) {
- DartSdk dartSdk = sourceFactory.dartSdk;
- if (dartSdk != null) {
- AnalysisContext sdkContext = dartSdk.context;
- if (!identical(sdkContext, this) &&
- sdkContext is InternalAnalysisContext) {
- return sdkContext.aboutToComputeResult(entry, result);
- }
+ // Use this helper if it is set.
+ if (resultProvider != null && resultProvider.compute(entry, result)) {
+ return true;
+ }
+ // Ask the SDK.
+ DartSdk dartSdk = sourceFactory.dartSdk;
+ if (dartSdk != null) {
+ AnalysisContext sdkContext = dartSdk.context;
+ if (!identical(sdkContext, this) &&
+ sdkContext is InternalAnalysisContext) {
+ return sdkContext.aboutToComputeResult(entry, result);
}
}
- // A result for a Source.
- Source source = target.source;
- if (source != null) {
- InternalAnalysisContext context = _cache.getContextFor(source);
- if (!identical(context, this)) {
- return context.aboutToComputeResult(entry, result);
- }
- }
+ // Cannot provide the result.
return false;
});
}
@@ -640,8 +646,8 @@
}
@override
- Object /*=V*/ computeResult /*<V>*/ (
- AnalysisTarget target, ResultDescriptor /*<V>*/ descriptor) {
+ Object/*=V*/ computeResult/*<V>*/(
+ AnalysisTarget target, ResultDescriptor/*<V>*/ descriptor) {
// Make sure we are not trying to invoke the task model in a reentrant
// fashion.
assert(!driver.isTaskRunning);
@@ -675,6 +681,54 @@
]);
}
+ /**
+ * Create a minimalistic mock dart:async library
+ * to stand in for a real one if one does not exist
+ * facilitating creation a type provider without dart:async.
+ */
+ LibraryElement createMockAsyncLib(LibraryElement coreLibrary) {
+ InterfaceType objType = coreLibrary.getType('Object').type;
+
+ ClassElement _classElement(String typeName, [List<String> parameterNames]) {
+ ClassElementImpl element =
+ new ClassElementImpl.forNode(AstFactory.identifier3(typeName));
+ element.supertype = objType;
+ InterfaceTypeImpl type = new InterfaceTypeImpl(element);
+ element.type = type;
+ if (parameterNames != null) {
+ int count = parameterNames.length;
+ if (count > 0) {
+ List<TypeParameterElementImpl> typeParameters =
+ new List<TypeParameterElementImpl>(count);
+ List<TypeParameterTypeImpl> typeArguments =
+ new List<TypeParameterTypeImpl>(count);
+ for (int i = 0; i < count; i++) {
+ TypeParameterElementImpl typeParameter =
+ new TypeParameterElementImpl.forNode(
+ AstFactory.identifier3(parameterNames[i]));
+ typeParameters[i] = typeParameter;
+ typeArguments[i] = new TypeParameterTypeImpl(typeParameter);
+ typeParameter.type = typeArguments[i];
+ }
+ element.typeParameters = typeParameters;
+ type.typeArguments = typeArguments;
+ }
+ }
+ return element;
+ }
+
+ InterfaceType futureType = _classElement('Future', ['T']).type;
+ InterfaceType streamType = _classElement('Stream', ['T']).type;
+ CompilationUnitElementImpl asyncUnit =
+ new CompilationUnitElementImpl("mock_async.dart");
+ asyncUnit.types = <ClassElement>[futureType.element, streamType.element];
+ LibraryElementImpl mockLib = new LibraryElementImpl.forNode(
+ this, AstFactory.libraryIdentifier2(["dart.async"]));
+ mockLib.definingCompilationUnit = asyncUnit;
+ mockLib.publicNamespace = new PublicNamespaceBuilder().build(mockLib);
+ return mockLib;
+ }
+
@override
void dispose() {
_disposed = true;
@@ -2023,6 +2077,24 @@
}
/**
+ * Provider for analysis results.
+ */
+abstract class ResultProvider {
+ /**
+ * This method is invoked by an [InternalAnalysisContext] when the state of
+ * the [result] of the [entry] is [CacheState.INVALID], so it is about to be
+ * computed.
+ *
+ * If the provider knows how to provide the value, it sets the value into
+ * the [entry] with all required dependencies, and returns `true`.
+ *
+ * Otherwise, it returns `false` to indicate that the result should be
+ * computed as usually.
+ */
+ bool compute(CacheEntry entry, ResultDescriptor result);
+}
+
+/**
* An [AnalysisContext] that only contains sources for a Dart SDK.
*/
class SdkAnalysisContext extends AnalysisContextImpl {
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
new file mode 100644
index 0000000..26e3b76
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -0,0 +1,10805 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.src.dart.ast.ast;
+
+import 'dart:collection';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Two or more string literals that are implicitly concatenated because of being
+ * adjacent (separated only by whitespace).
+ *
+ * While the grammar only allows adjacent strings when all of the strings are of
+ * the same kind (single line or multi-line), this class doesn't enforce that
+ * restriction.
+ *
+ * > adjacentStrings ::=
+ * > [StringLiteral] [StringLiteral]+
+ */
+class AdjacentStringsImpl extends StringLiteralImpl implements AdjacentStrings {
+ /**
+ * The strings that are implicitly concatenated.
+ */
+ NodeList<StringLiteral> _strings;
+
+ /**
+ * Initialize a newly created list of adjacent strings. To be syntactically
+ * valid, the list of [strings] must contain at least two elements.
+ */
+ AdjacentStringsImpl(List<StringLiteral> strings) {
+ _strings = new NodeList<StringLiteral>(this, strings);
+ }
+
+ @override
+ Token get beginToken => _strings.beginToken;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..addAll(_strings);
+
+ @override
+ Token get endToken => _strings.endToken;
+
+ @override
+ NodeList<StringLiteral> get strings => _strings;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitAdjacentStrings(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _strings.accept(visitor);
+ }
+
+ @override
+ void _appendStringValue(StringBuffer buffer) {
+ for (StringLiteralImpl stringLiteral in strings) {
+ stringLiteral._appendStringValue(buffer);
+ }
+ }
+}
+
+/**
+ * An AST node that can be annotated with both a documentation comment and a
+ * list of annotations.
+ */
+abstract class AnnotatedNodeImpl extends AstNodeImpl implements AnnotatedNode {
+ /**
+ * The documentation comment associated with this node, or `null` if this node
+ * does not have a documentation comment associated with it.
+ */
+ Comment _comment;
+
+ /**
+ * The annotations associated with this node.
+ */
+ NodeList<Annotation> _metadata;
+
+ /**
+ * Initialize a newly created annotated node. Either or both of the [comment]
+ * and [metadata] can be `null` if the node does not have the corresponding
+ * attribute.
+ */
+ AnnotatedNodeImpl(Comment comment, List<Annotation> metadata) {
+ _comment = _becomeParentOf(comment);
+ _metadata = new NodeList<Annotation>(this, metadata);
+ }
+
+ @override
+ Token get beginToken {
+ if (_comment == null) {
+ if (_metadata.isEmpty) {
+ return firstTokenAfterCommentAndMetadata;
+ }
+ return _metadata.beginToken;
+ } else if (_metadata.isEmpty) {
+ return _comment.beginToken;
+ }
+ Token commentToken = _comment.beginToken;
+ Token metadataToken = _metadata.beginToken;
+ if (commentToken.offset < metadataToken.offset) {
+ return commentToken;
+ }
+ return metadataToken;
+ }
+
+ @override
+ Comment get documentationComment => _comment;
+
+ @override
+ void set documentationComment(Comment comment) {
+ _comment = _becomeParentOf(comment);
+ }
+
+ @override
+ NodeList<Annotation> get metadata => _metadata;
+
+ @override
+ List<AstNode> get sortedCommentAndAnnotations {
+ return <AstNode>[]
+ ..add(_comment)
+ ..addAll(_metadata)
+ ..sort(AstNode.LEXICAL_ORDER);
+ }
+
+ /**
+ * Return a holder of child entities that subclasses can add to.
+ */
+ ChildEntities get _childEntities {
+ ChildEntities result = new ChildEntities();
+ if (_commentIsBeforeAnnotations()) {
+ result
+ ..add(_comment)
+ ..addAll(_metadata);
+ } else {
+ result.addAll(sortedCommentAndAnnotations);
+ }
+ return result;
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ if (_commentIsBeforeAnnotations()) {
+ _safelyVisitChild(_comment, visitor);
+ _metadata.accept(visitor);
+ } else {
+ for (AstNode child in sortedCommentAndAnnotations) {
+ child.accept(visitor);
+ }
+ }
+ }
+
+ /**
+ * Return `true` if there are no annotations before the comment. Note that a
+ * result of `true` does not imply that there is a comment, nor that there are
+ * annotations associated with this node.
+ */
+ bool _commentIsBeforeAnnotations() {
+ if (_comment == null || _metadata.isEmpty) {
+ return true;
+ }
+ Annotation firstAnnotation = _metadata[0];
+ return _comment.offset < firstAnnotation.offset;
+ }
+}
+
+/**
+ * An annotation that can be associated with an AST node.
+ *
+ * > metadata ::=
+ * > annotation*
+ * >
+ * > annotation ::=
+ * > '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ */
+class AnnotationImpl extends AstNodeImpl implements Annotation {
+ /**
+ * The at sign that introduced the annotation.
+ */
+ Token atSign;
+
+ /**
+ * The name of the class defining the constructor that is being invoked or the
+ * name of the field that is being referenced.
+ */
+ Identifier _name;
+
+ /**
+ * The period before the constructor name, or `null` if this annotation is not
+ * the invocation of a named constructor.
+ */
+ Token period;
+
+ /**
+ * The name of the constructor being invoked, or `null` if this annotation is
+ * not the invocation of a named constructor.
+ */
+ SimpleIdentifier _constructorName;
+
+ /**
+ * The arguments to the constructor being invoked, or `null` if this
+ * annotation is not the invocation of a constructor.
+ */
+ ArgumentList _arguments;
+
+ /**
+ * The element associated with this annotation, or `null` if the AST structure
+ * has not been resolved or if this annotation could not be resolved.
+ */
+ Element _element;
+
+ /**
+ * The element annotation representing this annotation in the element model.
+ */
+ ElementAnnotation elementAnnotation;
+
+ /**
+ * Initialize a newly created annotation. Both the [period] and the
+ * [constructorName] can be `null` if the annotation is not referencing a
+ * named constructor. The [arguments] can be `null` if the annotation is not
+ * referencing a constructor.
+ */
+ AnnotationImpl(this.atSign, Identifier name, this.period,
+ SimpleIdentifier constructorName, ArgumentList arguments) {
+ _name = _becomeParentOf(name);
+ _constructorName = _becomeParentOf(constructorName);
+ _arguments = _becomeParentOf(arguments);
+ }
+
+ @override
+ ArgumentList get arguments => _arguments;
+
+ @override
+ void set arguments(ArgumentList arguments) {
+ _arguments = _becomeParentOf(arguments);
+ }
+
+ @override
+ Token get beginToken => atSign;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(atSign)
+ ..add(_name)
+ ..add(period)
+ ..add(_constructorName)
+ ..add(_arguments);
+
+ @override
+ SimpleIdentifier get constructorName => _constructorName;
+
+ @override
+ void set constructorName(SimpleIdentifier name) {
+ _constructorName = _becomeParentOf(name);
+ }
+
+ @override
+ Element get element {
+ if (_element != null) {
+ return _element;
+ } else if (_name != null) {
+ return _name.staticElement;
+ }
+ return null;
+ }
+
+ @override
+ void set element(Element element) {
+ _element = element;
+ }
+
+ @override
+ Token get endToken {
+ if (_arguments != null) {
+ return _arguments.endToken;
+ } else if (_constructorName != null) {
+ return _constructorName.endToken;
+ }
+ return _name.endToken;
+ }
+
+ @override
+ Identifier get name => _name;
+
+ @override
+ void set name(Identifier name) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitAnnotation(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_constructorName, visitor);
+ _safelyVisitChild(_arguments, visitor);
+ }
+}
+
+/**
+ * A list of arguments in the invocation of an executable element (that is, a
+ * function, method, or constructor).
+ *
+ * > argumentList ::=
+ * > '(' arguments? ')'
+ * >
+ * > arguments ::=
+ * > [NamedExpression] (',' [NamedExpression])*
+ * > | [Expression] (',' [Expression])* (',' [NamedExpression])*
+ */
+class ArgumentListImpl extends AstNodeImpl implements ArgumentList {
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The expressions producing the values of the arguments.
+ */
+ NodeList<Expression> _arguments;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * A list containing the elements representing the parameters corresponding to
+ * each of the arguments in this list, or `null` if the AST has not been
+ * resolved or if the function or method being invoked could not be determined
+ * based on static type information. The list must be the same length as the
+ * number of arguments, but can contain `null` entries if a given argument
+ * does not correspond to a formal parameter.
+ */
+ List<ParameterElement> _correspondingStaticParameters;
+
+ /**
+ * A list containing the elements representing the parameters corresponding to
+ * each of the arguments in this list, or `null` if the AST has not been
+ * resolved or if the function or method being invoked could not be determined
+ * based on propagated type information. The list must be the same length as
+ * the number of arguments, but can contain `null` entries if a given argument
+ * does not correspond to a formal parameter.
+ */
+ List<ParameterElement> _correspondingPropagatedParameters;
+
+ /**
+ * Initialize a newly created list of arguments. The list of [arguments] can
+ * be `null` if there are no arguments.
+ */
+ ArgumentListImpl(
+ this.leftParenthesis, List<Expression> arguments, this.rightParenthesis) {
+ _arguments = new NodeList<Expression>(this, arguments);
+ }
+
+ @override
+ NodeList<Expression> get arguments => _arguments;
+
+ @override
+ Token get beginToken => leftParenthesis;
+
+ @override
+ // TODO(paulberry): Add commas.
+ Iterable get childEntities => new ChildEntities()
+ ..add(leftParenthesis)
+ ..addAll(_arguments)
+ ..add(rightParenthesis);
+
+ @override
+ void set correspondingPropagatedParameters(
+ List<ParameterElement> parameters) {
+ if (parameters.length != _arguments.length) {
+ throw new IllegalArgumentException(
+ "Expected ${_arguments.length} parameters, not ${parameters.length}");
+ }
+ _correspondingPropagatedParameters = parameters;
+ }
+
+ @override
+ void set correspondingStaticParameters(List<ParameterElement> parameters) {
+ if (parameters.length != _arguments.length) {
+ throw new IllegalArgumentException(
+ "Expected ${_arguments.length} parameters, not ${parameters.length}");
+ }
+ _correspondingStaticParameters = parameters;
+ }
+
+ @override
+ Token get endToken => rightParenthesis;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitArgumentList(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _arguments.accept(visitor);
+ }
+
+ /**
+ * If
+ * * the given [expression] is a child of this list,
+ * * the AST structure has been resolved,
+ * * the function being invoked is known based on propagated type information,
+ * and
+ * * the expression corresponds to one of the parameters of the function being
+ * invoked,
+ * then return the parameter element representing the parameter to which the
+ * value of the given expression will be bound. Otherwise, return `null`.
+ */
+ ParameterElement _getPropagatedParameterElementFor(Expression expression) {
+ if (_correspondingPropagatedParameters == null ||
+ _correspondingPropagatedParameters.length != _arguments.length) {
+ // Either the AST structure has not been resolved, the invocation of which
+ // this list is a part could not be resolved, or the argument list was
+ // modified after the parameters were set.
+ return null;
+ }
+ int index = _arguments.indexOf(expression);
+ if (index < 0) {
+ // The expression isn't a child of this node.
+ return null;
+ }
+ return _correspondingPropagatedParameters[index];
+ }
+
+ /**
+ * If
+ * * the given [expression] is a child of this list,
+ * * the AST structure has been resolved,
+ * * the function being invoked is known based on static type information, and
+ * * the expression corresponds to one of the parameters of the function being
+ * invoked,
+ * then return the parameter element representing the parameter to which the
+ * value of the given expression will be bound. Otherwise, return `null`.
+ */
+ ParameterElement _getStaticParameterElementFor(Expression expression) {
+ if (_correspondingStaticParameters == null ||
+ _correspondingStaticParameters.length != _arguments.length) {
+ // Either the AST structure has not been resolved, the invocation of which
+ // this list is a part could not be resolved, or the argument list was
+ // modified after the parameters were set.
+ return null;
+ }
+ int index = _arguments.indexOf(expression);
+ if (index < 0) {
+ // The expression isn't a child of this node.
+ return null;
+ }
+ return _correspondingStaticParameters[index];
+ }
+}
+
+/**
+ * An as expression.
+ *
+ * > asExpression ::=
+ * > [Expression] 'as' [TypeName]
+ */
+class AsExpressionImpl extends ExpressionImpl implements AsExpression {
+ /**
+ * The expression used to compute the value being cast.
+ */
+ Expression _expression;
+
+ /**
+ * The 'as' operator.
+ */
+ Token asOperator;
+
+ /**
+ * The name of the type being cast to.
+ */
+ TypeName _type;
+
+ /**
+ * Initialize a newly created as expression.
+ */
+ AsExpressionImpl(Expression expression, this.asOperator, TypeName type) {
+ _expression = _becomeParentOf(expression);
+ _type = _becomeParentOf(type);
+ }
+
+ @override
+ Token get beginToken => _expression.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_expression)..add(asOperator)..add(_type);
+
+ @override
+ Token get endToken => _type.endToken;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 7;
+
+ @override
+ TypeName get type => _type;
+
+ @override
+ void set type(TypeName name) {
+ _type = _becomeParentOf(name);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitAsExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ _safelyVisitChild(_type, visitor);
+ }
+}
+
+/**
+ * An assert statement.
+ *
+ * > assertStatement ::=
+ * > 'assert' '(' [Expression] ')' ';'
+ */
+class AssertStatementImpl extends StatementImpl implements AssertStatement {
+ /**
+ * The token representing the 'assert' keyword.
+ */
+ Token assertKeyword;
+
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The condition that is being asserted to be `true`.
+ */
+ Expression _condition;
+
+ /**
+ * The comma, if a message expression was supplied. Otherwise `null`.
+ */
+ Token comma;
+
+ /**
+ * The message to report if the assertion fails. `null` if no message was
+ * supplied.
+ */
+ Expression _message;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created assert statement.
+ */
+ AssertStatementImpl(
+ this.assertKeyword,
+ this.leftParenthesis,
+ Expression condition,
+ this.comma,
+ Expression message,
+ this.rightParenthesis,
+ this.semicolon) {
+ _condition = _becomeParentOf(condition);
+ _message = _becomeParentOf(message);
+ }
+
+ @override
+ Token get beginToken => assertKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(assertKeyword)
+ ..add(leftParenthesis)
+ ..add(_condition)
+ ..add(comma)
+ ..add(_message)
+ ..add(rightParenthesis)
+ ..add(semicolon);
+
+ @override
+ Expression get condition => _condition;
+
+ @override
+ void set condition(Expression condition) {
+ _condition = _becomeParentOf(condition);
+ }
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Expression get message => _message;
+
+ @override
+ void set message(Expression expression) {
+ _message = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitAssertStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_condition, visitor);
+ _safelyVisitChild(message, visitor);
+ }
+}
+
+/**
+ * An assignment expression.
+ *
+ * > assignmentExpression ::=
+ * > [Expression] operator [Expression]
+ */
+class AssignmentExpressionImpl extends ExpressionImpl
+ implements AssignmentExpression {
+ /**
+ * The expression used to compute the left hand side.
+ */
+ Expression _leftHandSide;
+
+ /**
+ * The assignment operator being applied.
+ */
+ Token operator;
+
+ /**
+ * The expression used to compute the right hand side.
+ */
+ Expression _rightHandSide;
+
+ /**
+ * The element associated with the operator based on the static type of the
+ * left-hand-side, or `null` if the AST structure has not been resolved, if
+ * the operator is not a compound operator, or if the operator could not be
+ * resolved.
+ */
+ MethodElement staticElement;
+
+ /**
+ * The element associated with the operator based on the propagated type of
+ * the left-hand-side, or `null` if the AST structure has not been resolved,
+ * if the operator is not a compound operator, or if the operator could not be
+ * resolved.
+ */
+ MethodElement propagatedElement;
+
+ /**
+ * Initialize a newly created assignment expression.
+ */
+ AssignmentExpressionImpl(
+ Expression leftHandSide, this.operator, Expression rightHandSide) {
+ if (leftHandSide == null || rightHandSide == null) {
+ String message;
+ if (leftHandSide == null) {
+ if (rightHandSide == null) {
+ message = "Both the left-hand and right-hand sides are null";
+ } else {
+ message = "The left-hand size is null";
+ }
+ } else {
+ message = "The right-hand size is null";
+ }
+ AnalysisEngine.instance.logger.logError(
+ message, new CaughtException(new AnalysisException(message), null));
+ }
+ _leftHandSide = _becomeParentOf(leftHandSide);
+ _rightHandSide = _becomeParentOf(rightHandSide);
+ }
+
+ @override
+ Token get beginToken => _leftHandSide.beginToken;
+
+ @override
+ MethodElement get bestElement {
+ MethodElement element = propagatedElement;
+ if (element == null) {
+ element = staticElement;
+ }
+ return element;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(_leftHandSide)
+ ..add(operator)
+ ..add(_rightHandSide);
+
+ @override
+ Token get endToken => _rightHandSide.endToken;
+
+ @override
+ Expression get leftHandSide => _leftHandSide;
+
+ @override
+ void set leftHandSide(Expression expression) {
+ _leftHandSide = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 1;
+
+ @override
+ Expression get rightHandSide => _rightHandSide;
+
+ @override
+ void set rightHandSide(Expression expression) {
+ _rightHandSide = _becomeParentOf(expression);
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on propagated type information, then return the parameter
+ * element representing the parameter to which the value of the right operand
+ * will be bound. Otherwise, return `null`.
+ */
+ ParameterElement get _propagatedParameterElementForRightHandSide {
+ ExecutableElement executableElement = null;
+ if (propagatedElement != null) {
+ executableElement = propagatedElement;
+ } else {
+ if (_leftHandSide is Identifier) {
+ Identifier identifier = _leftHandSide as Identifier;
+ Element leftElement = identifier.propagatedElement;
+ if (leftElement is ExecutableElement) {
+ executableElement = leftElement;
+ }
+ }
+ if (_leftHandSide is PropertyAccess) {
+ SimpleIdentifier identifier =
+ (_leftHandSide as PropertyAccess).propertyName;
+ Element leftElement = identifier.propagatedElement;
+ if (leftElement is ExecutableElement) {
+ executableElement = leftElement;
+ }
+ }
+ }
+ if (executableElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = executableElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on static type information, then return the parameter element
+ * representing the parameter to which the value of the right operand will be
+ * bound. Otherwise, return `null`.
+ */
+ ParameterElement get _staticParameterElementForRightHandSide {
+ ExecutableElement executableElement = null;
+ if (staticElement != null) {
+ executableElement = staticElement;
+ } else {
+ if (_leftHandSide is Identifier) {
+ Element leftElement = (_leftHandSide as Identifier).staticElement;
+ if (leftElement is ExecutableElement) {
+ executableElement = leftElement;
+ }
+ }
+ if (_leftHandSide is PropertyAccess) {
+ Element leftElement =
+ (_leftHandSide as PropertyAccess).propertyName.staticElement;
+ if (leftElement is ExecutableElement) {
+ executableElement = leftElement;
+ }
+ }
+ }
+ if (executableElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = executableElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitAssignmentExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_leftHandSide, visitor);
+ _safelyVisitChild(_rightHandSide, visitor);
+ }
+}
+
+/**
+ * A node in the AST structure for a Dart program.
+ */
+abstract class AstNodeImpl implements AstNode {
+ /**
+ * The parent of the node, or `null` if the node is the root of an AST
+ * structure.
+ */
+ AstNode _parent;
+
+ /**
+ * A table mapping the names of properties to their values, or `null` if this
+ * node does not have any properties associated with it.
+ */
+ Map<String, Object> _propertyMap;
+
+ @override
+ int get end => offset + length;
+
+ @override
+ bool get isSynthetic => false;
+
+ @override
+ int get length {
+ Token beginToken = this.beginToken;
+ Token endToken = this.endToken;
+ if (beginToken == null || endToken == null) {
+ return -1;
+ }
+ return endToken.offset + endToken.length - beginToken.offset;
+ }
+
+ @override
+ int get offset {
+ Token beginToken = this.beginToken;
+ if (beginToken == null) {
+ return -1;
+ }
+ return beginToken.offset;
+ }
+
+ @override
+ AstNode get parent => _parent;
+
+ @override
+ AstNode get root {
+ AstNode root = this;
+ AstNode parent = this.parent;
+ while (parent != null) {
+ root = parent;
+ parent = root.parent;
+ }
+ return root;
+ }
+
+ @override
+ AstNode getAncestor(Predicate<AstNode> predicate) {
+ // TODO(brianwilkerson) It is a bug that this method can return `this`.
+ AstNode node = this;
+ while (node != null && !predicate(node)) {
+ node = node.parent;
+ }
+ return node;
+ }
+
+ @override
+ Object getProperty(String name) {
+ if (_propertyMap == null) {
+ return null;
+ }
+ return _propertyMap[name];
+ }
+
+ @override
+ void setProperty(String name, Object value) {
+ if (value == null) {
+ if (_propertyMap != null) {
+ _propertyMap.remove(name);
+ if (_propertyMap.isEmpty) {
+ _propertyMap = null;
+ }
+ }
+ } else {
+ if (_propertyMap == null) {
+ _propertyMap = new HashMap<String, Object>();
+ }
+ _propertyMap[name] = value;
+ }
+ }
+
+ @override
+ String toSource() {
+ PrintStringWriter writer = new PrintStringWriter();
+ accept(new ToSourceVisitor(writer));
+ return writer.toString();
+ }
+
+ @override
+ String toString() => toSource();
+
+ /**
+ * Make this node the parent of the given [child] node. Return the child node.
+ */
+ AstNode _becomeParentOf(AstNode child) {
+ if (child != null) {
+ (child as AstNodeImpl)._parent = this;
+ }
+ return child;
+ }
+
+ /**
+ * If the given [child] is not `null`, use the given [visitor] to visit it.
+ */
+ void _safelyVisitChild(AstNode child, AstVisitor visitor) {
+ if (child != null) {
+ child.accept(visitor);
+ }
+ }
+}
+
+/**
+ * An await expression.
+ *
+ * > awaitExpression ::=
+ * > 'await' [Expression]
+ */
+class AwaitExpressionImpl extends ExpressionImpl implements AwaitExpression {
+ /**
+ * The 'await' keyword.
+ */
+ Token awaitKeyword;
+
+ /**
+ * The expression whose value is being waited on.
+ */
+ Expression _expression;
+
+ /**
+ * Initialize a newly created await expression.
+ */
+ AwaitExpressionImpl(this.awaitKeyword, Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken {
+ if (awaitKeyword != null) {
+ return awaitKeyword;
+ }
+ return _expression.beginToken;
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(awaitKeyword)..add(_expression);
+
+ @override
+ Token get endToken => _expression.endToken;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 0;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitAwaitExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * A binary (infix) expression.
+ *
+ * > binaryExpression ::=
+ * > [Expression] [Token] [Expression]
+ */
+class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
+ /**
+ * The expression used to compute the left operand.
+ */
+ Expression _leftOperand;
+
+ /**
+ * The binary operator being applied.
+ */
+ Token operator;
+
+ /**
+ * The expression used to compute the right operand.
+ */
+ Expression _rightOperand;
+
+ /**
+ * The element associated with the operator based on the static type of the
+ * left operand, or `null` if the AST structure has not been resolved, if the
+ * operator is not user definable, or if the operator could not be resolved.
+ */
+ MethodElement staticElement;
+
+ /**
+ * The element associated with the operator based on the propagated type of
+ * the left operand, or `null` if the AST structure has not been resolved, if
+ * the operator is not user definable, or if the operator could not be
+ * resolved.
+ */
+ MethodElement propagatedElement;
+
+ /**
+ * Initialize a newly created binary expression.
+ */
+ BinaryExpressionImpl(
+ Expression leftOperand, this.operator, Expression rightOperand) {
+ _leftOperand = _becomeParentOf(leftOperand);
+ _rightOperand = _becomeParentOf(rightOperand);
+ }
+
+ @override
+ Token get beginToken => _leftOperand.beginToken;
+
+ @override
+ MethodElement get bestElement {
+ MethodElement element = propagatedElement;
+ if (element == null) {
+ element = staticElement;
+ }
+ return element;
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_leftOperand)..add(operator)..add(_rightOperand);
+
+ @override
+ Token get endToken => _rightOperand.endToken;
+
+ @override
+ Expression get leftOperand => _leftOperand;
+
+ @override
+ void set leftOperand(Expression expression) {
+ _leftOperand = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => operator.type.precedence;
+
+ @override
+ Expression get rightOperand => _rightOperand;
+
+ @override
+ void set rightOperand(Expression expression) {
+ _rightOperand = _becomeParentOf(expression);
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on propagated type information, then return the parameter
+ * element representing the parameter to which the value of the right operand
+ * will be bound. Otherwise, return `null`.
+ */
+ ParameterElement get _propagatedParameterElementForRightOperand {
+ if (propagatedElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = propagatedElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on static type information, then return the parameter element
+ * representing the parameter to which the value of the right operand will be
+ * bound. Otherwise, return `null`.
+ */
+ ParameterElement get _staticParameterElementForRightOperand {
+ if (staticElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = staticElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitBinaryExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_leftOperand, visitor);
+ _safelyVisitChild(_rightOperand, visitor);
+ }
+}
+
+/**
+ * A function body that consists of a block of statements.
+ *
+ * > blockFunctionBody ::=
+ * > ('async' | 'async' '*' | 'sync' '*')? [Block]
+ */
+class BlockFunctionBodyImpl extends FunctionBodyImpl
+ implements BlockFunctionBody {
+ /**
+ * The token representing the 'async' or 'sync' keyword, or `null` if there is
+ * no such keyword.
+ */
+ Token keyword;
+
+ /**
+ * The star optionally following the 'async' or 'sync' keyword, or `null` if
+ * there is wither no such keyword or no star.
+ */
+ Token star;
+
+ /**
+ * The block representing the body of the function.
+ */
+ Block _block;
+
+ /**
+ * Initialize a newly created function body consisting of a block of
+ * statements. The [keyword] can be `null` if there is no keyword specified
+ * for the block. The [star] can be `null` if there is no star following the
+ * keyword (and must be `null` if there is no keyword).
+ */
+ BlockFunctionBodyImpl(this.keyword, this.star, Block block) {
+ _block = _becomeParentOf(block);
+ }
+
+ @override
+ Token get beginToken {
+ if (keyword != null) {
+ return keyword;
+ }
+ return _block.beginToken;
+ }
+
+ @override
+ Block get block => _block;
+
+ @override
+ void set block(Block block) {
+ _block = _becomeParentOf(block);
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(keyword)..add(star)..add(_block);
+
+ @override
+ Token get endToken => _block.endToken;
+
+ @override
+ bool get isAsynchronous => keyword != null && keyword.lexeme == Parser.ASYNC;
+
+ @override
+ bool get isGenerator => star != null;
+
+ @override
+ bool get isSynchronous => keyword == null || keyword.lexeme != Parser.ASYNC;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitBlockFunctionBody(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_block, visitor);
+ }
+}
+
+/**
+ * A sequence of statements.
+ *
+ * > block ::=
+ * > '{' statement* '}'
+ */
+class BlockImpl extends StatementImpl implements Block {
+ /**
+ * The left curly bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The statements contained in the block.
+ */
+ NodeList<Statement> _statements;
+
+ /**
+ * The right curly bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created block of code.
+ */
+ BlockImpl(this.leftBracket, List<Statement> statements, this.rightBracket) {
+ _statements = new NodeList<Statement>(this, statements);
+ }
+
+ @override
+ Token get beginToken => leftBracket;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(leftBracket)
+ ..addAll(_statements)
+ ..add(rightBracket);
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ NodeList<Statement> get statements => _statements;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitBlock(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _statements.accept(visitor);
+ }
+}
+
+/**
+ * A boolean literal expression.
+ *
+ * > booleanLiteral ::=
+ * > 'false' | 'true'
+ */
+class BooleanLiteralImpl extends LiteralImpl implements BooleanLiteral {
+ /**
+ * The token representing the literal.
+ */
+ Token literal;
+
+ /**
+ * The value of the literal.
+ */
+ bool value = false;
+
+ /**
+ * Initialize a newly created boolean literal.
+ */
+ BooleanLiteralImpl(this.literal, this.value);
+
+ @override
+ Token get beginToken => literal;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(literal);
+
+ @override
+ Token get endToken => literal;
+
+ @override
+ bool get isSynthetic => literal.isSynthetic;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitBooleanLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A break statement.
+ *
+ * > breakStatement ::=
+ * > 'break' [SimpleIdentifier]? ';'
+ */
+class BreakStatementImpl extends StatementImpl implements BreakStatement {
+ /**
+ * The token representing the 'break' keyword.
+ */
+ Token breakKeyword;
+
+ /**
+ * The label associated with the statement, or `null` if there is no label.
+ */
+ SimpleIdentifier _label;
+
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * The AstNode which this break statement is breaking from. This will be
+ * either a [Statement] (in the case of breaking out of a loop), a
+ * [SwitchMember] (in the case of a labeled break statement whose label
+ * matches a label on a switch case in an enclosing switch statement), or
+ * `null` if the AST has not yet been resolved or if the target could not be
+ * resolved. Note that if the source code has errors, the target might be
+ * invalid (e.g. trying to break to a switch case).
+ */
+ AstNode target;
+
+ /**
+ * Initialize a newly created break statement. The [label] can be `null` if
+ * there is no label associated with the statement.
+ */
+ BreakStatementImpl(
+ this.breakKeyword, SimpleIdentifier label, this.semicolon) {
+ _label = _becomeParentOf(label);
+ }
+
+ @override
+ Token get beginToken => breakKeyword;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(breakKeyword)..add(_label)..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ SimpleIdentifier get label => _label;
+
+ @override
+ void set label(SimpleIdentifier identifier) {
+ _label = _becomeParentOf(identifier);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitBreakStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_label, visitor);
+ }
+}
+
+/**
+ * A sequence of cascaded expressions: expressions that share a common target.
+ * There are three kinds of expressions that can be used in a cascade
+ * expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
+ *
+ * > cascadeExpression ::=
+ * > [Expression] cascadeSection*
+ * >
+ * > cascadeSection ::=
+ * > '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
+ * > (assignmentOperator expressionWithoutCascade)?
+ * >
+ * > cascadeSelector ::=
+ * > '[ ' expression '] '
+ * > | identifier
+ */
+class CascadeExpressionImpl extends ExpressionImpl
+ implements CascadeExpression {
+ /**
+ * The target of the cascade sections.
+ */
+ Expression _target;
+
+ /**
+ * The cascade sections sharing the common target.
+ */
+ NodeList<Expression> _cascadeSections;
+
+ /**
+ * Initialize a newly created cascade expression. The list of
+ * [cascadeSections] must contain at least one element.
+ */
+ CascadeExpressionImpl(Expression target, List<Expression> cascadeSections) {
+ _target = _becomeParentOf(target);
+ _cascadeSections = new NodeList<Expression>(this, cascadeSections);
+ }
+
+ @override
+ Token get beginToken => _target.beginToken;
+
+ @override
+ NodeList<Expression> get cascadeSections => _cascadeSections;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(_target)
+ ..addAll(_cascadeSections);
+
+ @override
+ Token get endToken => _cascadeSections.endToken;
+
+ @override
+ int get precedence => 2;
+
+ @override
+ Expression get target => _target;
+
+ @override
+ void set target(Expression target) {
+ _target = _becomeParentOf(target);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitCascadeExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_target, visitor);
+ _cascadeSections.accept(visitor);
+ }
+}
+
+/**
+ * A catch clause within a try statement.
+ *
+ * > onPart ::=
+ * > catchPart [Block]
+ * > | 'on' type catchPart? [Block]
+ * >
+ * > catchPart ::=
+ * > 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+ */
+class CatchClauseImpl extends AstNodeImpl implements CatchClause {
+ /**
+ * The token representing the 'on' keyword, or `null` if there is no 'on'
+ * keyword.
+ */
+ Token onKeyword;
+
+ /**
+ * The type of exceptions caught by this catch clause, or `null` if this catch
+ * clause catches every type of exception.
+ */
+ TypeName _exceptionType;
+
+ /**
+ * The token representing the 'catch' keyword, or `null` if there is no
+ * 'catch' keyword.
+ */
+ Token catchKeyword;
+
+ /**
+ * The left parenthesis, or `null` if there is no 'catch' keyword.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The parameter whose value will be the exception that was thrown, or `null`
+ * if there is no 'catch' keyword.
+ */
+ SimpleIdentifier _exceptionParameter;
+
+ /**
+ * The comma separating the exception parameter from the stack trace
+ * parameter, or `null` if there is no stack trace parameter.
+ */
+ Token comma;
+
+ /**
+ * The parameter whose value will be the stack trace associated with the
+ * exception, or `null` if there is no stack trace parameter.
+ */
+ SimpleIdentifier _stackTraceParameter;
+
+ /**
+ * The right parenthesis, or `null` if there is no 'catch' keyword.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The body of the catch block.
+ */
+ Block _body;
+
+ /**
+ * Initialize a newly created catch clause. The [onKeyword] and
+ * [exceptionType] can be `null` if the clause will catch all exceptions. The
+ * [comma] and [stackTraceParameter] can be `null` if the stack trace
+ * parameter is not defined.
+ */
+ CatchClauseImpl(
+ this.onKeyword,
+ TypeName exceptionType,
+ this.catchKeyword,
+ this.leftParenthesis,
+ SimpleIdentifier exceptionParameter,
+ this.comma,
+ SimpleIdentifier stackTraceParameter,
+ this.rightParenthesis,
+ Block body) {
+ _exceptionType = _becomeParentOf(exceptionType);
+ _exceptionParameter = _becomeParentOf(exceptionParameter);
+ _stackTraceParameter = _becomeParentOf(stackTraceParameter);
+ _body = _becomeParentOf(body);
+ }
+
+ @override
+ Token get beginToken {
+ if (onKeyword != null) {
+ return onKeyword;
+ }
+ return catchKeyword;
+ }
+
+ @override
+ Block get body => _body;
+
+ @override
+ void set body(Block block) {
+ _body = _becomeParentOf(block);
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(onKeyword)
+ ..add(_exceptionType)
+ ..add(catchKeyword)
+ ..add(leftParenthesis)
+ ..add(_exceptionParameter)
+ ..add(comma)
+ ..add(_stackTraceParameter)
+ ..add(rightParenthesis)
+ ..add(_body);
+
+ @override
+ Token get endToken => _body.endToken;
+
+ @override
+ SimpleIdentifier get exceptionParameter => _exceptionParameter;
+
+ @override
+ void set exceptionParameter(SimpleIdentifier parameter) {
+ _exceptionParameter = _becomeParentOf(parameter);
+ }
+
+ @override
+ TypeName get exceptionType => _exceptionType;
+
+ @override
+ void set exceptionType(TypeName exceptionType) {
+ _exceptionType = _becomeParentOf(exceptionType);
+ }
+
+ @override
+ SimpleIdentifier get stackTraceParameter => _stackTraceParameter;
+
+ @override
+ void set stackTraceParameter(SimpleIdentifier parameter) {
+ _stackTraceParameter = _becomeParentOf(parameter);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitCatchClause(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_exceptionType, visitor);
+ _safelyVisitChild(_exceptionParameter, visitor);
+ _safelyVisitChild(_stackTraceParameter, visitor);
+ _safelyVisitChild(_body, visitor);
+ }
+}
+
+/**
+ * Helper class to allow iteration of child entities of an AST node.
+ */
+class ChildEntities extends Object with IterableMixin implements Iterable {
+ /**
+ * The list of child entities to be iterated over.
+ */
+ List _entities = [];
+
+ @override
+ Iterator get iterator => _entities.iterator;
+
+ /**
+ * Add an AST node or token as the next child entity, if it is not null.
+ */
+ void add(entity) {
+ if (entity != null) {
+ assert(entity is Token || entity is AstNode);
+ _entities.add(entity);
+ }
+ }
+
+ /**
+ * Add the given items as the next child entities, if [items] is not null.
+ */
+ void addAll(Iterable items) {
+ if (items != null) {
+ _entities.addAll(items);
+ }
+ }
+}
+
+/**
+ * The declaration of a class.
+ *
+ * > classDeclaration ::=
+ * > 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+ * > ([ExtendsClause] [WithClause]?)?
+ * > [ImplementsClause]?
+ * > '{' [ClassMember]* '}'
+ */
+class ClassDeclarationImpl extends NamedCompilationUnitMemberImpl
+ implements ClassDeclaration {
+ /**
+ * The 'abstract' keyword, or `null` if the keyword was absent.
+ */
+ Token abstractKeyword;
+
+ /**
+ * The token representing the 'class' keyword.
+ */
+ Token classKeyword;
+
+ /**
+ * The type parameters for the class, or `null` if the class does not have any
+ * type parameters.
+ */
+ TypeParameterList _typeParameters;
+
+ /**
+ * The extends clause for the class, or `null` if the class does not extend
+ * any other class.
+ */
+ ExtendsClause _extendsClause;
+
+ /**
+ * The with clause for the class, or `null` if the class does not have a with
+ * clause.
+ */
+ WithClause _withClause;
+
+ /**
+ * The implements clause for the class, or `null` if the class does not
+ * implement any interfaces.
+ */
+ ImplementsClause _implementsClause;
+
+ /**
+ * The native clause for the class, or `null` if the class does not have a
+ * native clause.
+ */
+ NativeClause _nativeClause;
+
+ /**
+ * The left curly bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The members defined by the class.
+ */
+ NodeList<ClassMember> _members;
+
+ /**
+ * The right curly bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created class declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the class does not have the
+ * corresponding attribute. The [abstractKeyword] can be `null` if the class
+ * is not abstract. The [typeParameters] can be `null` if the class does not
+ * have any type parameters. Any or all of the [extendsClause], [withClause],
+ * and [implementsClause] can be `null` if the class does not have the
+ * corresponding clause. The list of [members] can be `null` if the class does
+ * not have any members.
+ */
+ ClassDeclarationImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.abstractKeyword,
+ this.classKeyword,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ ExtendsClause extendsClause,
+ WithClause withClause,
+ ImplementsClause implementsClause,
+ this.leftBracket,
+ List<ClassMember> members,
+ this.rightBracket)
+ : super(comment, metadata, name) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ _extendsClause = _becomeParentOf(extendsClause);
+ _withClause = _becomeParentOf(withClause);
+ _implementsClause = _becomeParentOf(implementsClause);
+ _members = new NodeList<ClassMember>(this, members);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(abstractKeyword)
+ ..add(classKeyword)
+ ..add(_name)
+ ..add(_typeParameters)
+ ..add(_extendsClause)
+ ..add(_withClause)
+ ..add(_implementsClause)
+ ..add(_nativeClause)
+ ..add(leftBracket)
+ ..addAll(members)
+ ..add(rightBracket);
+
+ @override
+ ClassElement get element =>
+ _name != null ? (_name.staticElement as ClassElement) : null;
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ ExtendsClause get extendsClause => _extendsClause;
+
+ @override
+ void set extendsClause(ExtendsClause extendsClause) {
+ _extendsClause = _becomeParentOf(extendsClause);
+ }
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata {
+ if (abstractKeyword != null) {
+ return abstractKeyword;
+ }
+ return classKeyword;
+ }
+
+ @override
+ ImplementsClause get implementsClause => _implementsClause;
+
+ @override
+ void set implementsClause(ImplementsClause implementsClause) {
+ _implementsClause = _becomeParentOf(implementsClause);
+ }
+
+ @override
+ bool get isAbstract => abstractKeyword != null;
+
+ @override
+ NodeList<ClassMember> get members => _members;
+
+ @override
+ NativeClause get nativeClause => _nativeClause;
+
+ @override
+ void set nativeClause(NativeClause nativeClause) {
+ _nativeClause = _becomeParentOf(nativeClause);
+ }
+
+ @override
+ TypeParameterList get typeParameters => _typeParameters;
+
+ @override
+ void set typeParameters(TypeParameterList typeParameters) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ }
+
+ @override
+ WithClause get withClause => _withClause;
+
+ @override
+ void set withClause(WithClause withClause) {
+ _withClause = _becomeParentOf(withClause);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitClassDeclaration(this);
+
+ @override
+ ConstructorDeclaration getConstructor(String name) {
+ for (ClassMember classMember in _members) {
+ if (classMember is ConstructorDeclaration) {
+ ConstructorDeclaration constructor = classMember;
+ SimpleIdentifier constructorName = constructor.name;
+ if (name == null && constructorName == null) {
+ return constructor;
+ }
+ if (constructorName != null && constructorName.name == name) {
+ return constructor;
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
+ VariableDeclaration getField(String name) {
+ for (ClassMember classMember in _members) {
+ if (classMember is FieldDeclaration) {
+ FieldDeclaration fieldDeclaration = classMember;
+ NodeList<VariableDeclaration> fields =
+ fieldDeclaration.fields.variables;
+ for (VariableDeclaration field in fields) {
+ SimpleIdentifier fieldName = field.name;
+ if (fieldName != null && name == fieldName.name) {
+ return field;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
+ MethodDeclaration getMethod(String name) {
+ for (ClassMember classMember in _members) {
+ if (classMember is MethodDeclaration) {
+ MethodDeclaration method = classMember;
+ SimpleIdentifier methodName = method.name;
+ if (methodName != null && name == methodName.name) {
+ return method;
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_typeParameters, visitor);
+ _safelyVisitChild(_extendsClause, visitor);
+ _safelyVisitChild(_withClause, visitor);
+ _safelyVisitChild(_implementsClause, visitor);
+ _safelyVisitChild(_nativeClause, visitor);
+ members.accept(visitor);
+ }
+}
+
+/**
+ * A node that declares a name within the scope of a class.
+ */
+abstract class ClassMemberImpl extends DeclarationImpl implements ClassMember {
+ /**
+ * Initialize a newly created member of a class. Either or both of the
+ * [comment] and [metadata] can be `null` if the member does not have the
+ * corresponding attribute.
+ */
+ ClassMemberImpl(Comment comment, List<Annotation> metadata)
+ : super(comment, metadata);
+}
+
+/**
+ * A class type alias.
+ *
+ * > classTypeAlias ::=
+ * > [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ * >
+ * > mixinApplication ::=
+ * > [TypeName] [WithClause] [ImplementsClause]? ';'
+ */
+class ClassTypeAliasImpl extends TypeAliasImpl implements ClassTypeAlias {
+ /**
+ * The type parameters for the class, or `null` if the class does not have any
+ * type parameters.
+ */
+ TypeParameterList _typeParameters;
+
+ /**
+ * The token for the '=' separating the name from the definition.
+ */
+ Token equals;
+
+ /**
+ * The token for the 'abstract' keyword, or `null` if this is not defining an
+ * abstract class.
+ */
+ Token abstractKeyword;
+
+ /**
+ * The name of the superclass of the class being declared.
+ */
+ TypeName _superclass;
+
+ /**
+ * The with clause for this class.
+ */
+ WithClause _withClause;
+
+ /**
+ * The implements clause for this class, or `null` if there is no implements
+ * clause.
+ */
+ ImplementsClause _implementsClause;
+
+ /**
+ * Initialize a newly created class type alias. Either or both of the
+ * [comment] and [metadata] can be `null` if the class type alias does not
+ * have the corresponding attribute. The [typeParameters] can be `null` if the
+ * class does not have any type parameters. The [abstractKeyword] can be
+ * `null` if the class is not abstract. The [implementsClause] can be `null`
+ * if the class does not implement any interfaces.
+ */
+ ClassTypeAliasImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ this.equals,
+ this.abstractKeyword,
+ TypeName superclass,
+ WithClause withClause,
+ ImplementsClause implementsClause,
+ Token semicolon)
+ : super(comment, metadata, keyword, name, semicolon) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ _superclass = _becomeParentOf(superclass);
+ _withClause = _becomeParentOf(withClause);
+ _implementsClause = _becomeParentOf(implementsClause);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(typedefKeyword)
+ ..add(_name)
+ ..add(_typeParameters)
+ ..add(equals)
+ ..add(abstractKeyword)
+ ..add(_superclass)
+ ..add(_withClause)
+ ..add(_implementsClause)
+ ..add(semicolon);
+
+ @override
+ ClassElement get element =>
+ _name != null ? (_name.staticElement as ClassElement) : null;
+
+ @override
+ ImplementsClause get implementsClause => _implementsClause;
+
+ @override
+ void set implementsClause(ImplementsClause implementsClause) {
+ _implementsClause = _becomeParentOf(implementsClause);
+ }
+
+ @override
+ bool get isAbstract => abstractKeyword != null;
+
+ @override
+ TypeName get superclass => _superclass;
+
+ @override
+ void set superclass(TypeName superclass) {
+ _superclass = _becomeParentOf(superclass);
+ }
+
+ @override
+ TypeParameterList get typeParameters => _typeParameters;
+
+ @override
+ void set typeParameters(TypeParameterList typeParameters) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ }
+
+ @override
+ WithClause get withClause => _withClause;
+
+ @override
+ void set withClause(WithClause withClause) {
+ _withClause = _becomeParentOf(withClause);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitClassTypeAlias(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_typeParameters, visitor);
+ _safelyVisitChild(_superclass, visitor);
+ _safelyVisitChild(_withClause, visitor);
+ _safelyVisitChild(_implementsClause, visitor);
+ }
+}
+
+/**
+ * A combinator associated with an import or export directive.
+ *
+ * > combinator ::=
+ * > [HideCombinator]
+ * > | [ShowCombinator]
+ */
+abstract class CombinatorImpl extends AstNodeImpl implements Combinator {
+ /**
+ * The 'hide' or 'show' keyword specifying what kind of processing is to be
+ * done on the names.
+ */
+ Token keyword;
+
+ /**
+ * Initialize a newly created combinator.
+ */
+ CombinatorImpl(this.keyword);
+
+ @override
+ Token get beginToken => keyword;
+}
+
+/**
+ * A comment within the source code.
+ *
+ * > comment ::=
+ * > endOfLineComment
+ * > | blockComment
+ * > | documentationComment
+ * >
+ * > endOfLineComment ::=
+ * > '//' (CHARACTER - EOL)* EOL
+ * >
+ * > blockComment ::=
+ * > '/ *' CHARACTER* '*/'
+ * >
+ * > documentationComment ::=
+ * > '/ **' (CHARACTER | [CommentReference])* '*/'
+ * > | ('///' (CHARACTER - EOL)* EOL)+
+ */
+class CommentImpl extends AstNodeImpl implements Comment {
+ /**
+ * The tokens representing the comment.
+ */
+ final List<Token> tokens;
+
+ /**
+ * The type of the comment.
+ */
+ final CommentType _type;
+
+ /**
+ * The references embedded within the documentation comment. This list will be
+ * empty unless this is a documentation comment that has references embedded
+ * within it.
+ */
+ NodeList<CommentReference> _references;
+
+ /**
+ * Initialize a newly created comment. The list of [tokens] must contain at
+ * least one token. The [type] is the type of the comment. The list of
+ * [references] can be empty if the comment does not contain any embedded
+ * references.
+ */
+ CommentImpl(this.tokens, this._type, List<CommentReference> references) {
+ _references = new NodeList<CommentReference>(this, references);
+ }
+
+ @override
+ Token get beginToken => tokens[0];
+
+ @override
+ Iterable get childEntities => new ChildEntities()..addAll(tokens);
+
+ @override
+ Token get endToken => tokens[tokens.length - 1];
+
+ @override
+ bool get isBlock => _type == CommentType.BLOCK;
+
+ @override
+ bool get isDocumentation => _type == CommentType.DOCUMENTATION;
+
+ @override
+ bool get isEndOfLine => _type == CommentType.END_OF_LINE;
+
+ @override
+ NodeList<CommentReference> get references => _references;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitComment(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _references.accept(visitor);
+ }
+
+ /**
+ * Create a block comment consisting of the given [tokens].
+ */
+ static Comment createBlockComment(List<Token> tokens) =>
+ new CommentImpl(tokens, CommentType.BLOCK, null);
+
+ /**
+ * Create a documentation comment consisting of the given [tokens].
+ */
+ static Comment createDocumentationComment(List<Token> tokens) =>
+ new CommentImpl(
+ tokens, CommentType.DOCUMENTATION, new List<CommentReference>());
+
+ /**
+ * Create a documentation comment consisting of the given [tokens] and having
+ * the given [references] embedded within it.
+ */
+ static Comment createDocumentationCommentWithReferences(
+ List<Token> tokens, List<CommentReference> references) =>
+ new CommentImpl(tokens, CommentType.DOCUMENTATION, references);
+
+ /**
+ * Create an end-of-line comment consisting of the given [tokens].
+ */
+ static Comment createEndOfLineComment(List<Token> tokens) =>
+ new CommentImpl(tokens, CommentType.END_OF_LINE, null);
+}
+
+/**
+ * A reference to a Dart element that is found within a documentation comment.
+ *
+ * > commentReference ::=
+ * > '[' 'new'? [Identifier] ']'
+ */
+class CommentReferenceImpl extends AstNodeImpl implements CommentReference {
+ /**
+ * The token representing the 'new' keyword, or `null` if there was no 'new'
+ * keyword.
+ */
+ Token newKeyword;
+
+ /**
+ * The identifier being referenced.
+ */
+ Identifier _identifier;
+
+ /**
+ * Initialize a newly created reference to a Dart element. The [newKeyword]
+ * can be `null` if the reference is not to a constructor.
+ */
+ CommentReferenceImpl(this.newKeyword, Identifier identifier) {
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ Token get beginToken => _identifier.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(newKeyword)..add(_identifier);
+
+ @override
+ Token get endToken => _identifier.endToken;
+
+ @override
+ Identifier get identifier => _identifier;
+
+ @override
+ void set identifier(Identifier identifier) {
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitCommentReference(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_identifier, visitor);
+ }
+}
+
+/**
+ * The possible types of comments that are recognized by the parser.
+ */
+class CommentType {
+ /**
+ * A block comment.
+ */
+ static const CommentType BLOCK = const CommentType('BLOCK');
+
+ /**
+ * A documentation comment.
+ */
+ static const CommentType DOCUMENTATION = const CommentType('DOCUMENTATION');
+
+ /**
+ * An end-of-line comment.
+ */
+ static const CommentType END_OF_LINE = const CommentType('END_OF_LINE');
+
+ /**
+ * The name of the comment type.
+ */
+ final String name;
+
+ /**
+ * Initialize a newly created comment type to have the given [name].
+ */
+ const CommentType(this.name);
+
+ @override
+ String toString() => name;
+}
+
+/**
+ * A compilation unit.
+ *
+ * While the grammar restricts the order of the directives and declarations
+ * within a compilation unit, this class does not enforce those restrictions.
+ * In particular, the children of a compilation unit will be visited in lexical
+ * order even if lexical order does not conform to the restrictions of the
+ * grammar.
+ *
+ * > compilationUnit ::=
+ * > directives declarations
+ * >
+ * > directives ::=
+ * > [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
+ * > | [PartOfDirective]
+ * >
+ * > namespaceDirective ::=
+ * > [ImportDirective]
+ * > | [ExportDirective]
+ * >
+ * > declarations ::=
+ * > [CompilationUnitMember]*
+ */
+class CompilationUnitImpl extends AstNodeImpl implements CompilationUnit {
+ /**
+ * The first token in the token stream that was parsed to form this
+ * compilation unit.
+ */
+ Token beginToken;
+
+ /**
+ * The script tag at the beginning of the compilation unit, or `null` if there
+ * is no script tag in this compilation unit.
+ */
+ ScriptTag _scriptTag;
+
+ /**
+ * The directives contained in this compilation unit.
+ */
+ NodeList<Directive> _directives;
+
+ /**
+ * The declarations contained in this compilation unit.
+ */
+ NodeList<CompilationUnitMember> _declarations;
+
+ /**
+ * The last token in the token stream that was parsed to form this compilation
+ * unit. This token should always have a type of [TokenType.EOF].
+ */
+ Token endToken;
+
+ /**
+ * The element associated with this compilation unit, or `null` if the AST
+ * structure has not been resolved.
+ */
+ CompilationUnitElement element;
+
+ /**
+ * The line information for this compilation unit.
+ */
+ LineInfo lineInfo;
+
+ /**
+ * Initialize a newly created compilation unit to have the given directives
+ * and declarations. The [scriptTag] can be `null` if there is no script tag
+ * in the compilation unit. The list of [directives] can be `null` if there
+ * are no directives in the compilation unit. The list of [declarations] can
+ * be `null` if there are no declarations in the compilation unit.
+ */
+ CompilationUnitImpl(
+ this.beginToken,
+ ScriptTag scriptTag,
+ List<Directive> directives,
+ List<CompilationUnitMember> declarations,
+ this.endToken) {
+ _scriptTag = _becomeParentOf(scriptTag);
+ _directives = new NodeList<Directive>(this, directives);
+ _declarations = new NodeList<CompilationUnitMember>(this, declarations);
+ }
+
+ @override
+ Iterable get childEntities {
+ ChildEntities result = new ChildEntities()..add(_scriptTag);
+ if (_directivesAreBeforeDeclarations) {
+ result..addAll(_directives)..addAll(_declarations);
+ } else {
+ result.addAll(sortedDirectivesAndDeclarations);
+ }
+ return result;
+ }
+
+ @override
+ NodeList<CompilationUnitMember> get declarations => _declarations;
+
+ @override
+ NodeList<Directive> get directives => _directives;
+
+ @override
+ int get length {
+ Token endToken = this.endToken;
+ if (endToken == null) {
+ return 0;
+ }
+ return endToken.offset + endToken.length;
+ }
+
+ @override
+ int get offset => 0;
+
+ @override
+ ScriptTag get scriptTag => _scriptTag;
+
+ @override
+ void set scriptTag(ScriptTag scriptTag) {
+ _scriptTag = _becomeParentOf(scriptTag);
+ }
+
+ @override
+ List<AstNode> get sortedDirectivesAndDeclarations {
+ return <AstNode>[]
+ ..addAll(_directives)
+ ..addAll(_declarations)
+ ..sort(AstNode.LEXICAL_ORDER);
+ }
+
+ /**
+ * Return `true` if all of the directives are lexically before any
+ * declarations.
+ */
+ bool get _directivesAreBeforeDeclarations {
+ if (_directives.isEmpty || _declarations.isEmpty) {
+ return true;
+ }
+ Directive lastDirective = _directives[_directives.length - 1];
+ CompilationUnitMember firstDeclaration = _declarations[0];
+ return lastDirective.offset < firstDeclaration.offset;
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitCompilationUnit(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_scriptTag, visitor);
+ if (_directivesAreBeforeDeclarations) {
+ _directives.accept(visitor);
+ _declarations.accept(visitor);
+ } else {
+ for (AstNode child in sortedDirectivesAndDeclarations) {
+ child.accept(visitor);
+ }
+ }
+ }
+}
+
+/**
+ * A node that declares one or more names within the scope of a compilation
+ * unit.
+ *
+ * > compilationUnitMember ::=
+ * > [ClassDeclaration]
+ * > | [TypeAlias]
+ * > | [FunctionDeclaration]
+ * > | [MethodDeclaration]
+ * > | [VariableDeclaration]
+ * > | [VariableDeclaration]
+ */
+abstract class CompilationUnitMemberImpl extends DeclarationImpl
+ implements CompilationUnitMember {
+ /**
+ * Initialize a newly created generic compilation unit member. Either or both
+ * of the [comment] and [metadata] can be `null` if the member does not have
+ * the corresponding attribute.
+ */
+ CompilationUnitMemberImpl(Comment comment, List<Annotation> metadata)
+ : super(comment, metadata);
+}
+
+/**
+ * A conditional expression.
+ *
+ * > conditionalExpression ::=
+ * > [Expression] '?' [Expression] ':' [Expression]
+ */
+class ConditionalExpressionImpl extends ExpressionImpl
+ implements ConditionalExpression {
+ /**
+ * The condition used to determine which of the expressions is executed next.
+ */
+ Expression _condition;
+
+ /**
+ * The token used to separate the condition from the then expression.
+ */
+ Token question;
+
+ /**
+ * The expression that is executed if the condition evaluates to `true`.
+ */
+ Expression _thenExpression;
+
+ /**
+ * The token used to separate the then expression from the else expression.
+ */
+ Token colon;
+
+ /**
+ * The expression that is executed if the condition evaluates to `false`.
+ */
+ Expression _elseExpression;
+
+ /**
+ * Initialize a newly created conditional expression.
+ */
+ ConditionalExpressionImpl(Expression condition, this.question,
+ Expression thenExpression, this.colon, Expression elseExpression) {
+ _condition = _becomeParentOf(condition);
+ _thenExpression = _becomeParentOf(thenExpression);
+ _elseExpression = _becomeParentOf(elseExpression);
+ }
+
+ @override
+ Token get beginToken => _condition.beginToken;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(_condition)
+ ..add(question)
+ ..add(_thenExpression)
+ ..add(colon)
+ ..add(_elseExpression);
+
+ @override
+ Expression get condition => _condition;
+
+ @override
+ void set condition(Expression expression) {
+ _condition = _becomeParentOf(expression);
+ }
+
+ @override
+ Expression get elseExpression => _elseExpression;
+
+ @override
+ void set elseExpression(Expression expression) {
+ _elseExpression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get endToken => _elseExpression.endToken;
+
+ @override
+ int get precedence => 3;
+
+ @override
+ Expression get thenExpression => _thenExpression;
+
+ @override
+ void set thenExpression(Expression expression) {
+ _thenExpression = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitConditionalExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_condition, visitor);
+ _safelyVisitChild(_thenExpression, visitor);
+ _safelyVisitChild(_elseExpression, visitor);
+ }
+}
+
+/**
+ * A configuration in either an import or export directive.
+ *
+ * configuration ::=
+ * 'if' '(' test ')' uri
+ *
+ * test ::=
+ * dottedName ('==' stringLiteral)?
+ *
+ * dottedName ::=
+ * identifier ('.' identifier)*
+ */
+class ConfigurationImpl extends AstNodeImpl implements Configuration {
+ Token ifKeyword;
+ Token leftParenthesis;
+ DottedName _name;
+ Token equalToken;
+ StringLiteral _value;
+ Token rightParenthesis;
+ StringLiteral _libraryUri;
+
+ ConfigurationImpl(
+ this.ifKeyword,
+ this.leftParenthesis,
+ DottedName name,
+ this.equalToken,
+ StringLiteral value,
+ this.rightParenthesis,
+ StringLiteral libraryUri) {
+ _name = _becomeParentOf(name);
+ _value = _becomeParentOf(value);
+ _libraryUri = _becomeParentOf(libraryUri);
+ }
+
+ @override
+ Token get beginToken => ifKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(ifKeyword)
+ ..add(leftParenthesis)
+ ..add(_name)
+ ..add(equalToken)
+ ..add(_value)
+ ..add(rightParenthesis)
+ ..add(_libraryUri);
+
+ @override
+ Token get endToken => _libraryUri.endToken;
+
+ @override
+ StringLiteral get libraryUri => _libraryUri;
+
+ @override
+ void set libraryUri(StringLiteral libraryUri) {
+ _libraryUri = _becomeParentOf(libraryUri);
+ }
+
+ @override
+ DottedName get name => _name;
+
+ @override
+ void set name(DottedName name) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ StringLiteral get value => _value;
+
+ @override
+ void set value(StringLiteral value) {
+ _value = _becomeParentOf(value);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitConfiguration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_value, visitor);
+ _safelyVisitChild(_libraryUri, visitor);
+ }
+}
+
+/**
+ * A constructor declaration.
+ *
+ * > constructorDeclaration ::=
+ * > constructorSignature [FunctionBody]?
+ * > | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
+ * >
+ * > constructorSignature ::=
+ * > 'external'? constructorName formalParameterList initializerList?
+ * > | 'external'? 'factory' factoryName formalParameterList initializerList?
+ * > | 'external'? 'const' constructorName formalParameterList initializerList?
+ * >
+ * > constructorName ::=
+ * > [SimpleIdentifier] ('.' [SimpleIdentifier])?
+ * >
+ * > factoryName ::=
+ * > [Identifier] ('.' [SimpleIdentifier])?
+ * >
+ * > initializerList ::=
+ * > ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
+ */
+class ConstructorDeclarationImpl extends ClassMemberImpl
+ implements ConstructorDeclaration {
+ /**
+ * The token for the 'external' keyword, or `null` if the constructor is not
+ * external.
+ */
+ Token externalKeyword;
+
+ /**
+ * The token for the 'const' keyword, or `null` if the constructor is not a
+ * const constructor.
+ */
+ Token constKeyword;
+
+ /**
+ * The token for the 'factory' keyword, or `null` if the constructor is not a
+ * factory constructor.
+ */
+ Token factoryKeyword;
+
+ /**
+ * The type of object being created. This can be different than the type in
+ * which the constructor is being declared if the constructor is the
+ * implementation of a factory constructor.
+ */
+ Identifier _returnType;
+
+ /**
+ * The token for the period before the constructor name, or `null` if the
+ * constructor being declared is unnamed.
+ */
+ Token period;
+
+ /**
+ * The name of the constructor, or `null` if the constructor being declared is
+ * unnamed.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * The parameters associated with the constructor.
+ */
+ FormalParameterList _parameters;
+
+ /**
+ * The token for the separator (colon or equals) before the initializer list
+ * or redirection, or `null` if there are no initializers.
+ */
+ Token separator;
+
+ /**
+ * The initializers associated with the constructor.
+ */
+ NodeList<ConstructorInitializer> _initializers;
+
+ /**
+ * The name of the constructor to which this constructor will be redirected,
+ * or `null` if this is not a redirecting factory constructor.
+ */
+ ConstructorName _redirectedConstructor;
+
+ /**
+ * The body of the constructor, or `null` if the constructor does not have a
+ * body.
+ */
+ FunctionBody _body;
+
+ /**
+ * The element associated with this constructor, or `null` if the AST
+ * structure has not been resolved or if this constructor could not be
+ * resolved.
+ */
+ ConstructorElement element;
+
+ /**
+ * Initialize a newly created constructor declaration. The [externalKeyword]
+ * can be `null` if the constructor is not external. Either or both of the
+ * [comment] and [metadata] can be `null` if the constructor does not have the
+ * corresponding attribute. The [constKeyword] can be `null` if the
+ * constructor cannot be used to create a constant. The [factoryKeyword] can
+ * be `null` if the constructor is not a factory. The [period] and [name] can
+ * both be `null` if the constructor is not a named constructor. The
+ * [separator] can be `null` if the constructor does not have any initializers
+ * and does not redirect to a different constructor. The list of
+ * [initializers] can be `null` if the constructor does not have any
+ * initializers. The [redirectedConstructor] can be `null` if the constructor
+ * does not redirect to a different constructor. The [body] can be `null` if
+ * the constructor does not have a body.
+ */
+ ConstructorDeclarationImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.externalKeyword,
+ this.constKeyword,
+ this.factoryKeyword,
+ Identifier returnType,
+ this.period,
+ SimpleIdentifier name,
+ FormalParameterList parameters,
+ this.separator,
+ List<ConstructorInitializer> initializers,
+ ConstructorName redirectedConstructor,
+ FunctionBody body)
+ : super(comment, metadata) {
+ _returnType = _becomeParentOf(returnType);
+ _name = _becomeParentOf(name);
+ _parameters = _becomeParentOf(parameters);
+ _initializers = new NodeList<ConstructorInitializer>(this, initializers);
+ _redirectedConstructor = _becomeParentOf(redirectedConstructor);
+ _body = _becomeParentOf(body);
+ }
+
+ @override
+ FunctionBody get body => _body;
+
+ @override
+ void set body(FunctionBody functionBody) {
+ _body = _becomeParentOf(functionBody);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(externalKeyword)
+ ..add(constKeyword)
+ ..add(factoryKeyword)
+ ..add(_returnType)
+ ..add(period)
+ ..add(_name)
+ ..add(_parameters)
+ ..add(separator)
+ ..addAll(initializers)
+ ..add(_redirectedConstructor)
+ ..add(_body);
+
+ @override
+ Token get endToken {
+ if (_body != null) {
+ return _body.endToken;
+ } else if (!_initializers.isEmpty) {
+ return _initializers.endToken;
+ }
+ return _parameters.endToken;
+ }
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata {
+ Token leftMost =
+ Token.lexicallyFirst([externalKeyword, constKeyword, factoryKeyword]);
+ if (leftMost != null) {
+ return leftMost;
+ }
+ return _returnType.beginToken;
+ }
+
+ @override
+ NodeList<ConstructorInitializer> get initializers => _initializers;
+
+ @override
+ SimpleIdentifier get name => _name;
+
+ @override
+ void set name(SimpleIdentifier identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+
+ @override
+ FormalParameterList get parameters => _parameters;
+
+ @override
+ void set parameters(FormalParameterList parameters) {
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ ConstructorName get redirectedConstructor => _redirectedConstructor;
+
+ @override
+ void set redirectedConstructor(ConstructorName redirectedConstructor) {
+ _redirectedConstructor = _becomeParentOf(redirectedConstructor);
+ }
+
+ @override
+ Identifier get returnType => _returnType;
+
+ @override
+ void set returnType(Identifier typeName) {
+ _returnType = _becomeParentOf(typeName);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitConstructorDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_returnType, visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_parameters, visitor);
+ _initializers.accept(visitor);
+ _safelyVisitChild(_redirectedConstructor, visitor);
+ _safelyVisitChild(_body, visitor);
+ }
+}
+
+/**
+ * The initialization of a field within a constructor's initialization list.
+ *
+ * > fieldInitializer ::=
+ * > ('this' '.')? [SimpleIdentifier] '=' [Expression]
+ */
+class ConstructorFieldInitializerImpl extends ConstructorInitializerImpl
+ implements ConstructorFieldInitializer {
+ /**
+ * The token for the 'this' keyword, or `null` if there is no 'this' keyword.
+ */
+ Token thisKeyword;
+
+ /**
+ * The token for the period after the 'this' keyword, or `null` if there is no
+ * 'this' keyword.
+ */
+ Token period;
+
+ /**
+ * The name of the field being initialized.
+ */
+ SimpleIdentifier _fieldName;
+
+ /**
+ * The token for the equal sign between the field name and the expression.
+ */
+ Token equals;
+
+ /**
+ * The expression computing the value to which the field will be initialized.
+ */
+ Expression _expression;
+
+ /**
+ * Initialize a newly created field initializer to initialize the field with
+ * the given name to the value of the given expression. The [thisKeyword] and
+ * [period] can be `null` if the 'this' keyword was not specified.
+ */
+ ConstructorFieldInitializerImpl(this.thisKeyword, this.period,
+ SimpleIdentifier fieldName, this.equals, Expression expression) {
+ _fieldName = _becomeParentOf(fieldName);
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken {
+ if (thisKeyword != null) {
+ return thisKeyword;
+ }
+ return _fieldName.beginToken;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(thisKeyword)
+ ..add(period)
+ ..add(_fieldName)
+ ..add(equals)
+ ..add(_expression);
+
+ @override
+ Token get endToken => _expression.endToken;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ SimpleIdentifier get fieldName => _fieldName;
+
+ @override
+ void set fieldName(SimpleIdentifier identifier) {
+ _fieldName = _becomeParentOf(identifier);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitConstructorFieldInitializer(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_fieldName, visitor);
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * A node that can occur in the initializer list of a constructor declaration.
+ *
+ * > constructorInitializer ::=
+ * > [SuperConstructorInvocation]
+ * > | [ConstructorFieldInitializer]
+ * > | [RedirectingConstructorInvocation]
+ */
+abstract class ConstructorInitializerImpl extends AstNodeImpl
+ implements ConstructorInitializer {}
+
+/**
+ * The name of the constructor.
+ *
+ * > constructorName ::=
+ * > type ('.' identifier)?
+ */
+class ConstructorNameImpl extends AstNodeImpl implements ConstructorName {
+ /**
+ * The name of the type defining the constructor.
+ */
+ TypeName _type;
+
+ /**
+ * The token for the period before the constructor name, or `null` if the
+ * specified constructor is the unnamed constructor.
+ */
+ Token period;
+
+ /**
+ * The name of the constructor, or `null` if the specified constructor is the
+ * unnamed constructor.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * The element associated with this constructor name based on static type
+ * information, or `null` if the AST structure has not been resolved or if
+ * this constructor name could not be resolved.
+ */
+ ConstructorElement staticElement;
+
+ /**
+ * Initialize a newly created constructor name. The [period] and [name] can be
+ * `null` if the constructor being named is the unnamed constructor.
+ */
+ ConstructorNameImpl(TypeName type, this.period, SimpleIdentifier name) {
+ _type = _becomeParentOf(type);
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ Token get beginToken => _type.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_type)..add(period)..add(_name);
+
+ @override
+ Token get endToken {
+ if (_name != null) {
+ return _name.endToken;
+ }
+ return _type.endToken;
+ }
+
+ @override
+ SimpleIdentifier get name => _name;
+
+ @override
+ void set name(SimpleIdentifier name) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ TypeName get type => _type;
+
+ @override
+ void set type(TypeName type) {
+ _type = _becomeParentOf(type);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitConstructorName(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_type, visitor);
+ _safelyVisitChild(_name, visitor);
+ }
+}
+
+/**
+ * A continue statement.
+ *
+ * > continueStatement ::=
+ * > 'continue' [SimpleIdentifier]? ';'
+ */
+class ContinueStatementImpl extends StatementImpl implements ContinueStatement {
+ /**
+ * The token representing the 'continue' keyword.
+ */
+ Token continueKeyword;
+
+ /**
+ * The label associated with the statement, or `null` if there is no label.
+ */
+ SimpleIdentifier _label;
+
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * The AstNode which this continue statement is continuing to. This will be
+ * either a Statement (in the case of continuing a loop) or a SwitchMember
+ * (in the case of continuing from one switch case to another). Null if the
+ * AST has not yet been resolved or if the target could not be resolved.
+ * Note that if the source code has errors, the target may be invalid (e.g.
+ * the target may be in an enclosing function).
+ */
+ AstNode target;
+
+ /**
+ * Initialize a newly created continue statement. The [label] can be `null` if
+ * there is no label associated with the statement.
+ */
+ ContinueStatementImpl(
+ this.continueKeyword, SimpleIdentifier label, this.semicolon) {
+ _label = _becomeParentOf(label);
+ }
+
+ @override
+ Token get beginToken => continueKeyword;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(continueKeyword)..add(_label)..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ SimpleIdentifier get label => _label;
+
+ @override
+ void set label(SimpleIdentifier identifier) {
+ _label = _becomeParentOf(identifier);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitContinueStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_label, visitor);
+ }
+}
+
+/**
+ * A node that represents the declaration of one or more names. Each declared
+ * name is visible within a name scope.
+ */
+abstract class DeclarationImpl extends AnnotatedNodeImpl
+ implements Declaration {
+ /**
+ * Initialize a newly created declaration. Either or both of the [comment] and
+ * [metadata] can be `null` if the declaration does not have the corresponding
+ * attribute.
+ */
+ DeclarationImpl(Comment comment, List<Annotation> metadata)
+ : super(comment, metadata);
+}
+
+/**
+ * The declaration of a single identifier.
+ *
+ * > declaredIdentifier ::=
+ * > [Annotation] finalConstVarOrType [SimpleIdentifier]
+ */
+class DeclaredIdentifierImpl extends DeclarationImpl
+ implements DeclaredIdentifier {
+ /**
+ * The token representing either the 'final', 'const' or 'var' keyword, or
+ * `null` if no keyword was used.
+ */
+ Token keyword;
+
+ /**
+ * The name of the declared type of the parameter, or `null` if the parameter
+ * does not have a declared type.
+ */
+ TypeName _type;
+
+ /**
+ * The name of the variable being declared.
+ */
+ SimpleIdentifier _identifier;
+
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The [keyword] can be `null` if a type name is
+ * given. The [type] must be `null` if the keyword is 'var'.
+ */
+ DeclaredIdentifierImpl(Comment comment, List<Annotation> metadata,
+ this.keyword, TypeName type, SimpleIdentifier identifier)
+ : super(comment, metadata) {
+ _type = _becomeParentOf(type);
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(keyword)..add(_type)..add(_identifier);
+
+ @override
+ LocalVariableElement get element {
+ if (_identifier == null) {
+ return null;
+ }
+ return _identifier.staticElement as LocalVariableElement;
+ }
+
+ @override
+ Token get endToken => _identifier.endToken;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata {
+ if (keyword != null) {
+ return keyword;
+ } else if (_type != null) {
+ return _type.beginToken;
+ }
+ return _identifier.beginToken;
+ }
+
+ @override
+ SimpleIdentifier get identifier => _identifier;
+
+ @override
+ void set identifier(SimpleIdentifier identifier) {
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ bool get isConst =>
+ (keyword is KeywordToken) &&
+ (keyword as KeywordToken).keyword == Keyword.CONST;
+
+ @override
+ bool get isFinal =>
+ (keyword is KeywordToken) &&
+ (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+ @override
+ TypeName get type => _type;
+
+ @override
+ void set type(TypeName typeName) {
+ _type = _becomeParentOf(typeName);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitDeclaredIdentifier(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_type, visitor);
+ _safelyVisitChild(_identifier, visitor);
+ }
+}
+
+/**
+ * A formal parameter with a default value. There are two kinds of parameters
+ * that are both represented by this class: named formal parameters and
+ * positional formal parameters.
+ *
+ * > defaultFormalParameter ::=
+ * > [NormalFormalParameter] ('=' [Expression])?
+ * >
+ * > defaultNamedParameter ::=
+ * > [NormalFormalParameter] (':' [Expression])?
+ */
+class DefaultFormalParameterImpl extends FormalParameterImpl
+ implements DefaultFormalParameter {
+ /**
+ * The formal parameter with which the default value is associated.
+ */
+ NormalFormalParameter _parameter;
+
+ /**
+ * The kind of this parameter.
+ */
+ ParameterKind kind;
+
+ /**
+ * The token separating the parameter from the default value, or `null` if
+ * there is no default value.
+ */
+ Token separator;
+
+ /**
+ * The expression computing the default value for the parameter, or `null` if
+ * there is no default value.
+ */
+ Expression _defaultValue;
+
+ /**
+ * Initialize a newly created default formal parameter. The [separator] and
+ * [defaultValue] can be `null` if there is no default value.
+ */
+ DefaultFormalParameterImpl(NormalFormalParameter parameter, this.kind,
+ this.separator, Expression defaultValue) {
+ _parameter = _becomeParentOf(parameter);
+ _defaultValue = _becomeParentOf(defaultValue);
+ }
+
+ @override
+ Token get beginToken => _parameter.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_parameter)..add(separator)..add(_defaultValue);
+
+ @override
+ Expression get defaultValue => _defaultValue;
+
+ @override
+ void set defaultValue(Expression expression) {
+ _defaultValue = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get endToken {
+ if (_defaultValue != null) {
+ return _defaultValue.endToken;
+ }
+ return _parameter.endToken;
+ }
+
+ @override
+ SimpleIdentifier get identifier => _parameter.identifier;
+
+ @override
+ bool get isConst => _parameter != null && _parameter.isConst;
+
+ @override
+ bool get isFinal => _parameter != null && _parameter.isFinal;
+
+ @override
+ NodeList<Annotation> get metadata => _parameter.metadata;
+
+ @override
+ NormalFormalParameter get parameter => _parameter;
+
+ @override
+ void set parameter(NormalFormalParameter formalParameter) {
+ _parameter = _becomeParentOf(formalParameter);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitDefaultFormalParameter(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_parameter, visitor);
+ _safelyVisitChild(_defaultValue, visitor);
+ }
+}
+
+/**
+ * A node that represents a directive.
+ *
+ * > directive ::=
+ * > [ExportDirective]
+ * > | [ImportDirective]
+ * > | [LibraryDirective]
+ * > | [PartDirective]
+ * > | [PartOfDirective]
+ */
+abstract class DirectiveImpl extends AnnotatedNodeImpl implements Directive {
+ /**
+ * The element associated with this directive, or `null` if the AST structure
+ * has not been resolved or if this directive could not be resolved.
+ */
+ Element element;
+
+ /**
+ * Initialize a newly create directive. Either or both of the [comment] and
+ * [metadata] can be `null` if the directive does not have the corresponding
+ * attribute.
+ */
+ DirectiveImpl(Comment comment, List<Annotation> metadata)
+ : super(comment, metadata);
+}
+
+/**
+ * A do statement.
+ *
+ * > doStatement ::=
+ * > 'do' [Statement] 'while' '(' [Expression] ')' ';'
+ */
+class DoStatementImpl extends StatementImpl implements DoStatement {
+ /**
+ * The token representing the 'do' keyword.
+ */
+ Token doKeyword;
+
+ /**
+ * The body of the loop.
+ */
+ Statement _body;
+
+ /**
+ * The token representing the 'while' keyword.
+ */
+ Token whileKeyword;
+
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The condition that determines when the loop will terminate.
+ */
+ Expression _condition;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created do loop.
+ */
+ DoStatementImpl(
+ this.doKeyword,
+ Statement body,
+ this.whileKeyword,
+ this.leftParenthesis,
+ Expression condition,
+ this.rightParenthesis,
+ this.semicolon) {
+ _body = _becomeParentOf(body);
+ _condition = _becomeParentOf(condition);
+ }
+
+ @override
+ Token get beginToken => doKeyword;
+
+ @override
+ Statement get body => _body;
+
+ @override
+ void set body(Statement statement) {
+ _body = _becomeParentOf(statement);
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(doKeyword)
+ ..add(_body)
+ ..add(whileKeyword)
+ ..add(leftParenthesis)
+ ..add(_condition)
+ ..add(rightParenthesis)
+ ..add(semicolon);
+
+ @override
+ Expression get condition => _condition;
+
+ @override
+ void set condition(Expression expression) {
+ _condition = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitDoStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_body, visitor);
+ _safelyVisitChild(_condition, visitor);
+ }
+}
+
+/**
+ * A dotted name, used in a configuration within an import or export directive.
+ *
+ * > dottedName ::=
+ * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ */
+class DottedNameImpl extends AstNodeImpl implements DottedName {
+ /**
+ * The components of the identifier.
+ */
+ NodeList<SimpleIdentifier> _components;
+
+ /**
+ * Initialize a newly created dotted name.
+ */
+ DottedNameImpl(List<SimpleIdentifier> components) {
+ _components = new NodeList<SimpleIdentifier>(this, components);
+ }
+
+ @override
+ Token get beginToken => _components.beginToken;
+
+ @override
+ // TODO(paulberry): add "." tokens.
+ Iterable get childEntities => new ChildEntities()..addAll(_components);
+
+ @override
+ NodeList<SimpleIdentifier> get components => _components;
+
+ @override
+ Token get endToken => _components.endToken;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitDottedName(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _components.accept(visitor);
+ }
+}
+
+/**
+ * A floating point literal expression.
+ *
+ * > doubleLiteral ::=
+ * > decimalDigit+ ('.' decimalDigit*)? exponent?
+ * > | '.' decimalDigit+ exponent?
+ * >
+ * > exponent ::=
+ * > ('e' | 'E') ('+' | '-')? decimalDigit+
+ */
+class DoubleLiteralImpl extends LiteralImpl implements DoubleLiteral {
+ /**
+ * The token representing the literal.
+ */
+ Token literal;
+
+ /**
+ * The value of the literal.
+ */
+ double value;
+
+ /**
+ * Initialize a newly created floating point literal.
+ */
+ DoubleLiteralImpl(this.literal, this.value);
+
+ @override
+ Token get beginToken => literal;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(literal);
+
+ @override
+ Token get endToken => literal;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitDoubleLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * An empty function body, which can only appear in constructors or abstract
+ * methods.
+ *
+ * > emptyFunctionBody ::=
+ * > ';'
+ */
+class EmptyFunctionBodyImpl extends FunctionBodyImpl
+ implements EmptyFunctionBody {
+ /**
+ * The token representing the semicolon that marks the end of the function
+ * body.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created function body.
+ */
+ EmptyFunctionBodyImpl(this.semicolon);
+
+ @override
+ Token get beginToken => semicolon;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitEmptyFunctionBody(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // Empty function bodies have no children.
+ }
+}
+
+/**
+ * An empty statement.
+ *
+ * > emptyStatement ::=
+ * > ';'
+ */
+class EmptyStatementImpl extends StatementImpl implements EmptyStatement {
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created empty statement.
+ */
+ EmptyStatementImpl(this.semicolon);
+
+ @override
+ Token get beginToken => semicolon;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitEmptyStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * The declaration of an enum constant.
+ */
+class EnumConstantDeclarationImpl extends DeclarationImpl
+ implements EnumConstantDeclaration {
+ /**
+ * The name of the constant.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * Initialize a newly created enum constant declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the constant does not have the
+ * corresponding attribute. (Technically, enum constants cannot have metadata,
+ * but we allow it for consistency.)
+ */
+ EnumConstantDeclarationImpl(
+ Comment comment, List<Annotation> metadata, SimpleIdentifier name)
+ : super(comment, metadata) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities..add(_name);
+
+ @override
+ FieldElement get element =>
+ _name == null ? null : (_name.staticElement as FieldElement);
+
+ @override
+ Token get endToken => _name.endToken;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
+
+ @override
+ SimpleIdentifier get name => _name;
+
+ @override
+ void set name(SimpleIdentifier name) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitEnumConstantDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_name, visitor);
+ }
+}
+
+/**
+ * The declaration of an enumeration.
+ *
+ * > enumType ::=
+ * > metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+ */
+class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
+ implements EnumDeclaration {
+ /**
+ * The 'enum' keyword.
+ */
+ Token enumKeyword;
+
+ /**
+ * The left curly bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The enumeration constants being declared.
+ */
+ NodeList<EnumConstantDeclaration> _constants;
+
+ /**
+ * The right curly bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created enumeration declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The list of [constants] must contain at least one
+ * value.
+ */
+ EnumDeclarationImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.enumKeyword,
+ SimpleIdentifier name,
+ this.leftBracket,
+ List<EnumConstantDeclaration> constants,
+ this.rightBracket)
+ : super(comment, metadata, name) {
+ _constants = new NodeList<EnumConstantDeclaration>(this, constants);
+ }
+
+ @override
+ // TODO(brianwilkerson) Add commas?
+ Iterable get childEntities => super._childEntities
+ ..add(enumKeyword)
+ ..add(_name)
+ ..add(leftBracket)
+ ..addAll(_constants)
+ ..add(rightBracket);
+
+ @override
+ NodeList<EnumConstantDeclaration> get constants => _constants;
+
+ @override
+ ClassElement get element =>
+ _name != null ? (_name.staticElement as ClassElement) : null;
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => enumKeyword;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitEnumDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_name, visitor);
+ _constants.accept(visitor);
+ }
+}
+
+/**
+ * Ephemeral identifiers are created as needed to mimic the presence of an empty
+ * identifier.
+ */
+class EphemeralIdentifier extends SimpleIdentifierImpl {
+ EphemeralIdentifier(AstNode parent, int location)
+ : super(new StringToken(TokenType.IDENTIFIER, "", location)) {
+ (parent as AstNodeImpl)._becomeParentOf(this);
+ }
+}
+
+/**
+ * An export directive.
+ *
+ * > exportDirective ::=
+ * > [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ */
+class ExportDirectiveImpl extends NamespaceDirectiveImpl
+ implements ExportDirective {
+ /**
+ * Initialize a newly created export directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute. The list of [combinators] can be `null` if there
+ * are no combinators.
+ */
+ ExportDirectiveImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ StringLiteral libraryUri,
+ List<Configuration> configurations,
+ List<Combinator> combinators,
+ Token semicolon)
+ : super(comment, metadata, keyword, libraryUri, configurations,
+ combinators, semicolon);
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(_uri)
+ ..addAll(combinators)
+ ..add(semicolon);
+
+ @override
+ ExportElement get element => super.element as ExportElement;
+
+ @override
+ LibraryElement get uriElement {
+ if (element != null) {
+ return element.exportedLibrary;
+ }
+ return null;
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitExportDirective(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ combinators.accept(visitor);
+ }
+}
+
+/**
+ * A function body consisting of a single expression.
+ *
+ * > expressionFunctionBody ::=
+ * > 'async'? '=>' [Expression] ';'
+ */
+class ExpressionFunctionBodyImpl extends FunctionBodyImpl
+ implements ExpressionFunctionBody {
+ /**
+ * The token representing the 'async' keyword, or `null` if there is no such
+ * keyword.
+ */
+ Token keyword;
+
+ /**
+ * The token introducing the expression that represents the body of the
+ * function.
+ */
+ Token functionDefinition;
+
+ /**
+ * The expression representing the body of the function.
+ */
+ Expression _expression;
+
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created function body consisting of a block of
+ * statements. The [keyword] can be `null` if the function body is not an
+ * async function body.
+ */
+ ExpressionFunctionBodyImpl(this.keyword, this.functionDefinition,
+ Expression expression, this.semicolon) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken {
+ if (keyword != null) {
+ return keyword;
+ }
+ return functionDefinition;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(keyword)
+ ..add(functionDefinition)
+ ..add(_expression)
+ ..add(semicolon);
+
+ @override
+ Token get endToken {
+ if (semicolon != null) {
+ return semicolon;
+ }
+ return _expression.endToken;
+ }
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ bool get isAsynchronous => keyword != null;
+
+ @override
+ bool get isSynchronous => keyword == null;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitExpressionFunctionBody(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * A node that represents an expression.
+ *
+ * > expression ::=
+ * > [AssignmentExpression]
+ * > | [ConditionalExpression] cascadeSection*
+ * > | [ThrowExpression]
+ */
+abstract class ExpressionImpl extends AstNodeImpl implements Expression {
+ /**
+ * The static type of this expression, or `null` if the AST structure has not
+ * been resolved.
+ */
+ DartType staticType;
+
+ /**
+ * The propagated type of this expression, or `null` if type propagation has
+ * not been performed on the AST structure.
+ */
+ DartType propagatedType;
+
+ /**
+ * Return the best parameter element information available for this
+ * expression. If type propagation was able to find a better parameter element
+ * than static analysis, that type will be returned. Otherwise, the result of
+ * static analysis will be returned.
+ */
+ ParameterElement get bestParameterElement {
+ ParameterElement propagatedElement = propagatedParameterElement;
+ if (propagatedElement != null) {
+ return propagatedElement;
+ }
+ return staticParameterElement;
+ }
+
+ @override
+ DartType get bestType {
+ if (propagatedType != null) {
+ return propagatedType;
+ } else if (staticType != null) {
+ return staticType;
+ }
+ return DynamicTypeImpl.instance;
+ }
+
+ @override
+ bool get isAssignable => false;
+
+ @override
+ ParameterElement get propagatedParameterElement {
+ AstNode parent = this.parent;
+ if (parent is ArgumentListImpl) {
+ return parent._getPropagatedParameterElementFor(this);
+ } else if (parent is IndexExpressionImpl) {
+ if (identical(parent.index, this)) {
+ return parent._propagatedParameterElementForIndex;
+ }
+ } else if (parent is BinaryExpressionImpl) {
+ if (identical(parent.rightOperand, this)) {
+ return parent._propagatedParameterElementForRightOperand;
+ }
+ } else if (parent is AssignmentExpressionImpl) {
+ if (identical(parent.rightHandSide, this)) {
+ return parent._propagatedParameterElementForRightHandSide;
+ }
+ } else if (parent is PrefixExpressionImpl) {
+ return parent._propagatedParameterElementForOperand;
+ } else if (parent is PostfixExpressionImpl) {
+ return parent._propagatedParameterElementForOperand;
+ }
+ return null;
+ }
+
+ @override
+ ParameterElement get staticParameterElement {
+ AstNode parent = this.parent;
+ if (parent is ArgumentListImpl) {
+ return parent._getStaticParameterElementFor(this);
+ } else if (parent is IndexExpressionImpl) {
+ if (identical(parent.index, this)) {
+ return parent._staticParameterElementForIndex;
+ }
+ } else if (parent is BinaryExpressionImpl) {
+ if (identical(parent.rightOperand, this)) {
+ return parent._staticParameterElementForRightOperand;
+ }
+ } else if (parent is AssignmentExpressionImpl) {
+ if (identical(parent.rightHandSide, this)) {
+ return parent._staticParameterElementForRightHandSide;
+ }
+ } else if (parent is PrefixExpressionImpl) {
+ return parent._staticParameterElementForOperand;
+ } else if (parent is PostfixExpressionImpl) {
+ return parent._staticParameterElementForOperand;
+ }
+ return null;
+ }
+}
+
+/**
+ * An expression used as a statement.
+ *
+ * > expressionStatement ::=
+ * > [Expression]? ';'
+ */
+class ExpressionStatementImpl extends StatementImpl
+ implements ExpressionStatement {
+ /**
+ * The expression that comprises the statement.
+ */
+ Expression _expression;
+
+ /**
+ * The semicolon terminating the statement, or `null` if the expression is a
+ * function expression and therefore isn't followed by a semicolon.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created expression statement.
+ */
+ ExpressionStatementImpl(Expression expression, this.semicolon) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken => _expression.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_expression)..add(semicolon);
+
+ @override
+ Token get endToken {
+ if (semicolon != null) {
+ return semicolon;
+ }
+ return _expression.endToken;
+ }
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ bool get isSynthetic => _expression.isSynthetic && semicolon.isSynthetic;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitExpressionStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * The "extends" clause in a class declaration.
+ *
+ * > extendsClause ::=
+ * > 'extends' [TypeName]
+ */
+class ExtendsClauseImpl extends AstNodeImpl implements ExtendsClause {
+ /**
+ * The token representing the 'extends' keyword.
+ */
+ Token extendsKeyword;
+
+ /**
+ * The name of the class that is being extended.
+ */
+ TypeName _superclass;
+
+ /**
+ * Initialize a newly created extends clause.
+ */
+ ExtendsClauseImpl(this.extendsKeyword, TypeName superclass) {
+ _superclass = _becomeParentOf(superclass);
+ }
+
+ @override
+ Token get beginToken => extendsKeyword;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(extendsKeyword)..add(_superclass);
+
+ @override
+ Token get endToken => _superclass.endToken;
+
+ @override
+ TypeName get superclass => _superclass;
+
+ @override
+ void set superclass(TypeName name) {
+ _superclass = _becomeParentOf(name);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitExtendsClause(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_superclass, visitor);
+ }
+}
+
+/**
+ * The declaration of one or more fields of the same type.
+ *
+ * > fieldDeclaration ::=
+ * > 'static'? [VariableDeclarationList] ';'
+ */
+class FieldDeclarationImpl extends ClassMemberImpl implements FieldDeclaration {
+ /**
+ * The token representing the 'static' keyword, or `null` if the fields are
+ * not static.
+ */
+ Token staticKeyword;
+
+ /**
+ * The fields being declared.
+ */
+ VariableDeclarationList _fieldList;
+
+ /**
+ * The semicolon terminating the declaration.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created field declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The [staticKeyword] can be `null` if the field is
+ * not a static field.
+ */
+ FieldDeclarationImpl(Comment comment, List<Annotation> metadata,
+ this.staticKeyword, VariableDeclarationList fieldList, this.semicolon)
+ : super(comment, metadata) {
+ _fieldList = _becomeParentOf(fieldList);
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(staticKeyword)..add(_fieldList)..add(semicolon);
+
+ @override
+ Element get element => null;
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ VariableDeclarationList get fields => _fieldList;
+
+ @override
+ void set fields(VariableDeclarationList fields) {
+ _fieldList = _becomeParentOf(fields);
+ }
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata {
+ if (staticKeyword != null) {
+ return staticKeyword;
+ }
+ return _fieldList.beginToken;
+ }
+
+ @override
+ bool get isStatic => staticKeyword != null;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFieldDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_fieldList, visitor);
+ }
+}
+
+/**
+ * A field formal parameter.
+ *
+ * > fieldFormalParameter ::=
+ * > ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ * > 'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ */
+class FieldFormalParameterImpl extends NormalFormalParameterImpl
+ implements FieldFormalParameter {
+ /**
+ * The token representing either the 'final', 'const' or 'var' keyword, or
+ * `null` if no keyword was used.
+ */
+ Token keyword;
+
+ /**
+ * The name of the declared type of the parameter, or `null` if the parameter
+ * does not have a declared type.
+ */
+ TypeName _type;
+
+ /**
+ * The token representing the 'this' keyword.
+ */
+ Token thisKeyword;
+
+ /**
+ * The token representing the period.
+ */
+ Token period;
+
+ /**
+ * The type parameters associated with the method, or `null` if the method is
+ * not a generic method.
+ */
+ TypeParameterList _typeParameters;
+
+ /**
+ * The parameters of the function-typed parameter, or `null` if this is not a
+ * function-typed field formal parameter.
+ */
+ FormalParameterList _parameters;
+
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [keyword] can be `null` if there is a type.
+ * The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
+ * [period] can be `null` if the keyword 'this' was not provided. The
+ * [parameters] can be `null` if this is not a function-typed field formal
+ * parameter.
+ */
+ FieldFormalParameterImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.keyword,
+ TypeName type,
+ this.thisKeyword,
+ this.period,
+ SimpleIdentifier identifier,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters)
+ : super(comment, metadata, identifier) {
+ _type = _becomeParentOf(type);
+ _typeParameters = _becomeParentOf(typeParameters);
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ Token get beginToken {
+ if (keyword != null) {
+ return keyword;
+ } else if (_type != null) {
+ return _type.beginToken;
+ }
+ return thisKeyword;
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(keyword)
+ ..add(_type)
+ ..add(thisKeyword)
+ ..add(period)
+ ..add(identifier)
+ ..add(_parameters);
+
+ @override
+ Token get endToken {
+ if (_parameters != null) {
+ return _parameters.endToken;
+ }
+ return identifier.endToken;
+ }
+
+ @override
+ bool get isConst =>
+ (keyword is KeywordToken) &&
+ (keyword as KeywordToken).keyword == Keyword.CONST;
+
+ @override
+ bool get isFinal =>
+ (keyword is KeywordToken) &&
+ (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+ @override
+ FormalParameterList get parameters => _parameters;
+
+ @override
+ void set parameters(FormalParameterList parameters) {
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ TypeName get type => _type;
+
+ @override
+ void set type(TypeName typeName) {
+ _type = _becomeParentOf(typeName);
+ }
+
+ @override
+ TypeParameterList get typeParameters => _typeParameters;
+
+ @override
+ void set typeParameters(TypeParameterList typeParameters) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFieldFormalParameter(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_type, visitor);
+ _safelyVisitChild(identifier, visitor);
+ _safelyVisitChild(_typeParameters, visitor);
+ _safelyVisitChild(_parameters, visitor);
+ }
+}
+
+/**
+ * A for-each statement.
+ *
+ * > forEachStatement ::=
+ * > 'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+ * > | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+ */
+class ForEachStatementImpl extends StatementImpl implements ForEachStatement {
+ /**
+ * The token representing the 'await' keyword, or `null` if there is no
+ * 'await' keyword.
+ */
+ Token awaitKeyword;
+
+ /**
+ * The token representing the 'for' keyword.
+ */
+ Token forKeyword;
+
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The declaration of the loop variable, or `null` if the loop variable is a
+ * simple identifier.
+ */
+ DeclaredIdentifier _loopVariable;
+
+ /**
+ * The loop variable, or `null` if the loop variable is declared in the 'for'.
+ */
+ SimpleIdentifier _identifier;
+
+ /**
+ * The token representing the 'in' keyword.
+ */
+ Token inKeyword;
+
+ /**
+ * The expression evaluated to produce the iterator.
+ */
+ Expression _iterable;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The body of the loop.
+ */
+ Statement _body;
+
+ /**
+ * Initialize a newly created for-each statement whose loop control variable
+ * is declared internally (in the for-loop part). The [awaitKeyword] can be
+ * `null` if this is not an asynchronous for loop.
+ */
+ ForEachStatementImpl.withDeclaration(
+ this.awaitKeyword,
+ this.forKeyword,
+ this.leftParenthesis,
+ DeclaredIdentifier loopVariable,
+ this.inKeyword,
+ Expression iterator,
+ this.rightParenthesis,
+ Statement body) {
+ _loopVariable = _becomeParentOf(loopVariable);
+ _iterable = _becomeParentOf(iterator);
+ _body = _becomeParentOf(body);
+ }
+
+ /**
+ * Initialize a newly created for-each statement whose loop control variable
+ * is declared outside the for loop. The [awaitKeyword] can be `null` if this
+ * is not an asynchronous for loop.
+ */
+ ForEachStatementImpl.withReference(
+ this.awaitKeyword,
+ this.forKeyword,
+ this.leftParenthesis,
+ SimpleIdentifier identifier,
+ this.inKeyword,
+ Expression iterator,
+ this.rightParenthesis,
+ Statement body) {
+ _identifier = _becomeParentOf(identifier);
+ _iterable = _becomeParentOf(iterator);
+ _body = _becomeParentOf(body);
+ }
+
+ @override
+ Token get beginToken => forKeyword;
+
+ @override
+ Statement get body => _body;
+
+ @override
+ void set body(Statement statement) {
+ _body = _becomeParentOf(statement);
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(awaitKeyword)
+ ..add(forKeyword)
+ ..add(leftParenthesis)
+ ..add(_loopVariable)
+ ..add(_identifier)
+ ..add(inKeyword)
+ ..add(_iterable)
+ ..add(rightParenthesis)
+ ..add(_body);
+
+ @override
+ Token get endToken => _body.endToken;
+
+ @override
+ SimpleIdentifier get identifier => _identifier;
+
+ @override
+ void set identifier(SimpleIdentifier identifier) {
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ Expression get iterable => _iterable;
+
+ @override
+ void set iterable(Expression expression) {
+ _iterable = _becomeParentOf(expression);
+ }
+
+ @override
+ DeclaredIdentifier get loopVariable => _loopVariable;
+
+ @override
+ void set loopVariable(DeclaredIdentifier variable) {
+ _loopVariable = _becomeParentOf(variable);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitForEachStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_loopVariable, visitor);
+ _safelyVisitChild(_identifier, visitor);
+ _safelyVisitChild(_iterable, visitor);
+ _safelyVisitChild(_body, visitor);
+ }
+}
+
+/**
+ * A node representing a parameter to a function.
+ *
+ * > formalParameter ::=
+ * > [NormalFormalParameter]
+ * > | [DefaultFormalParameter]
+ */
+abstract class FormalParameterImpl extends AstNodeImpl
+ implements FormalParameter {
+ @override
+ ParameterElement get element {
+ SimpleIdentifier identifier = this.identifier;
+ if (identifier == null) {
+ return null;
+ }
+ return identifier.staticElement as ParameterElement;
+ }
+}
+
+/**
+ * The formal parameter list of a method declaration, function declaration, or
+ * function type alias.
+ *
+ * While the grammar requires all optional formal parameters to follow all of
+ * the normal formal parameters and at most one grouping of optional formal
+ * parameters, this class does not enforce those constraints. All parameters are
+ * flattened into a single list, which can have any or all kinds of parameters
+ * (normal, named, and positional) in any order.
+ *
+ * > formalParameterList ::=
+ * > '(' ')'
+ * > | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
+ * > | '(' optionalFormalParameters ')'
+ * >
+ * > normalFormalParameters ::=
+ * > [NormalFormalParameter] (',' [NormalFormalParameter])*
+ * >
+ * > optionalFormalParameters ::=
+ * > optionalPositionalFormalParameters
+ * > | namedFormalParameters
+ * >
+ * > optionalPositionalFormalParameters ::=
+ * > '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
+ * >
+ * > namedFormalParameters ::=
+ * > '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
+ */
+class FormalParameterListImpl extends AstNodeImpl
+ implements FormalParameterList {
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The parameters associated with the method.
+ */
+ NodeList<FormalParameter> _parameters;
+
+ /**
+ * The left square bracket ('[') or left curly brace ('{') introducing the
+ * optional parameters, or `null` if there are no optional parameters.
+ */
+ Token leftDelimiter;
+
+ /**
+ * The right square bracket (']') or right curly brace ('}') terminating the
+ * optional parameters, or `null` if there are no optional parameters.
+ */
+ Token rightDelimiter;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * Initialize a newly created parameter list. The list of [parameters] can be
+ * `null` if there are no parameters. The [leftDelimiter] and [rightDelimiter]
+ * can be `null` if there are no optional parameters.
+ */
+ FormalParameterListImpl(
+ this.leftParenthesis,
+ List<FormalParameter> parameters,
+ this.leftDelimiter,
+ this.rightDelimiter,
+ this.rightParenthesis) {
+ _parameters = new NodeList<FormalParameter>(this, parameters);
+ }
+
+ @override
+ Token get beginToken => leftParenthesis;
+
+ @override
+ Iterable get childEntities {
+ // TODO(paulberry): include commas.
+ ChildEntities result = new ChildEntities()..add(leftParenthesis);
+ bool leftDelimiterNeeded = leftDelimiter != null;
+ for (FormalParameter parameter in _parameters) {
+ if (leftDelimiterNeeded && leftDelimiter.offset < parameter.offset) {
+ result.add(leftDelimiter);
+ leftDelimiterNeeded = false;
+ }
+ result.add(parameter);
+ }
+ return result..add(rightDelimiter)..add(rightParenthesis);
+ }
+
+ @override
+ Token get endToken => rightParenthesis;
+
+ @override
+ List<ParameterElement> get parameterElements {
+ int count = _parameters.length;
+ List<ParameterElement> types = new List<ParameterElement>(count);
+ for (int i = 0; i < count; i++) {
+ types[i] = _parameters[i].element;
+ }
+ return types;
+ }
+
+ @override
+ NodeList<FormalParameter> get parameters => _parameters;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFormalParameterList(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _parameters.accept(visitor);
+ }
+}
+
+/**
+ * A for statement.
+ *
+ * > forStatement ::=
+ * > 'for' '(' forLoopParts ')' [Statement]
+ * >
+ * > forLoopParts ::=
+ * > forInitializerStatement ';' [Expression]? ';' [Expression]?
+ * >
+ * > forInitializerStatement ::=
+ * > [DefaultFormalParameter]
+ * > | [Expression]?
+ */
+class ForStatementImpl extends StatementImpl implements ForStatement {
+ /**
+ * The token representing the 'for' keyword.
+ */
+ Token forKeyword;
+
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The declaration of the loop variables, or `null` if there are no variables.
+ * Note that a for statement cannot have both a variable list and an
+ * initialization expression, but can validly have neither.
+ */
+ VariableDeclarationList _variableList;
+
+ /**
+ * The initialization expression, or `null` if there is no initialization
+ * expression. Note that a for statement cannot have both a variable list and
+ * an initialization expression, but can validly have neither.
+ */
+ Expression _initialization;
+
+ /**
+ * The semicolon separating the initializer and the condition.
+ */
+ Token leftSeparator;
+
+ /**
+ * The condition used to determine when to terminate the loop, or `null` if
+ * there is no condition.
+ */
+ Expression _condition;
+
+ /**
+ * The semicolon separating the condition and the updater.
+ */
+ Token rightSeparator;
+
+ /**
+ * The list of expressions run after each execution of the loop body.
+ */
+ NodeList<Expression> _updaters;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The body of the loop.
+ */
+ Statement _body;
+
+ /**
+ * Initialize a newly created for statement. Either the [variableList] or the
+ * [initialization] must be `null`. Either the [condition] and the list of
+ * [updaters] can be `null` if the loop does not have the corresponding
+ * attribute.
+ */
+ ForStatementImpl(
+ this.forKeyword,
+ this.leftParenthesis,
+ VariableDeclarationList variableList,
+ Expression initialization,
+ this.leftSeparator,
+ Expression condition,
+ this.rightSeparator,
+ List<Expression> updaters,
+ this.rightParenthesis,
+ Statement body) {
+ _variableList = _becomeParentOf(variableList);
+ _initialization = _becomeParentOf(initialization);
+ _condition = _becomeParentOf(condition);
+ _updaters = new NodeList<Expression>(this, updaters);
+ _body = _becomeParentOf(body);
+ }
+
+ @override
+ Token get beginToken => forKeyword;
+
+ @override
+ Statement get body => _body;
+
+ @override
+ void set body(Statement statement) {
+ _body = _becomeParentOf(statement);
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(forKeyword)
+ ..add(leftParenthesis)
+ ..add(_variableList)
+ ..add(_initialization)
+ ..add(leftSeparator)
+ ..add(_condition)
+ ..add(rightSeparator)
+ ..addAll(_updaters)
+ ..add(rightParenthesis)
+ ..add(_body);
+
+ @override
+ Expression get condition => _condition;
+
+ @override
+ void set condition(Expression expression) {
+ _condition = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get endToken => _body.endToken;
+
+ @override
+ Expression get initialization => _initialization;
+
+ @override
+ void set initialization(Expression initialization) {
+ _initialization = _becomeParentOf(initialization);
+ }
+
+ @override
+ NodeList<Expression> get updaters => _updaters;
+
+ @override
+ VariableDeclarationList get variables => _variableList;
+
+ @override
+ void set variables(VariableDeclarationList variableList) {
+ _variableList = _becomeParentOf(variableList);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitForStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_variableList, visitor);
+ _safelyVisitChild(_initialization, visitor);
+ _safelyVisitChild(_condition, visitor);
+ _updaters.accept(visitor);
+ _safelyVisitChild(_body, visitor);
+ }
+}
+
+/**
+ * A node representing the body of a function or method.
+ *
+ * > functionBody ::=
+ * > [BlockFunctionBody]
+ * > | [EmptyFunctionBody]
+ * > | [ExpressionFunctionBody]
+ */
+abstract class FunctionBodyImpl extends AstNodeImpl implements FunctionBody {
+ /**
+ * Return `true` if this function body is asynchronous.
+ */
+ bool get isAsynchronous => false;
+
+ /**
+ * Return `true` if this function body is a generator.
+ */
+ bool get isGenerator => false;
+
+ /**
+ * Return `true` if this function body is synchronous.
+ */
+ bool get isSynchronous => true;
+
+ /**
+ * Return the token representing the 'async' or 'sync' keyword, or `null` if
+ * there is no such keyword.
+ */
+ Token get keyword => null;
+
+ /**
+ * Return the star following the 'async' or 'sync' keyword, or `null` if there
+ * is no star.
+ */
+ Token get star => null;
+}
+
+/**
+ * A top-level declaration.
+ *
+ * > functionDeclaration ::=
+ * > 'external' functionSignature
+ * > | functionSignature [FunctionBody]
+ * >
+ * > functionSignature ::=
+ * > [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ */
+class FunctionDeclarationImpl extends NamedCompilationUnitMemberImpl
+ implements FunctionDeclaration {
+ /**
+ * The token representing the 'external' keyword, or `null` if this is not an
+ * external function.
+ */
+ Token externalKeyword;
+
+ /**
+ * The return type of the function, or `null` if no return type was declared.
+ */
+ TypeName _returnType;
+
+ /**
+ * The token representing the 'get' or 'set' keyword, or `null` if this is a
+ * function declaration rather than a property declaration.
+ */
+ Token propertyKeyword;
+
+ /**
+ * The function expression being wrapped.
+ */
+ FunctionExpression _functionExpression;
+
+ /**
+ * Initialize a newly created function declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the function does not have the
+ * corresponding attribute. The [externalKeyword] can be `null` if the
+ * function is not an external function. The [returnType] can be `null` if no
+ * return type was specified. The [propertyKeyword] can be `null` if the
+ * function is neither a getter or a setter.
+ */
+ FunctionDeclarationImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.externalKeyword,
+ TypeName returnType,
+ this.propertyKeyword,
+ SimpleIdentifier name,
+ FunctionExpression functionExpression)
+ : super(comment, metadata, name) {
+ _returnType = _becomeParentOf(returnType);
+ _functionExpression = _becomeParentOf(functionExpression);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(externalKeyword)
+ ..add(_returnType)
+ ..add(propertyKeyword)
+ ..add(_name)
+ ..add(_functionExpression);
+
+ @override
+ ExecutableElement get element =>
+ _name != null ? (_name.staticElement as ExecutableElement) : null;
+
+ @override
+ Token get endToken => _functionExpression.endToken;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata {
+ if (externalKeyword != null) {
+ return externalKeyword;
+ } else if (_returnType != null) {
+ return _returnType.beginToken;
+ } else if (propertyKeyword != null) {
+ return propertyKeyword;
+ } else if (_name != null) {
+ return _name.beginToken;
+ }
+ return _functionExpression.beginToken;
+ }
+
+ @override
+ FunctionExpression get functionExpression => _functionExpression;
+
+ @override
+ void set functionExpression(FunctionExpression functionExpression) {
+ _functionExpression = _becomeParentOf(functionExpression);
+ }
+
+ @override
+ bool get isGetter =>
+ propertyKeyword != null &&
+ (propertyKeyword as KeywordToken).keyword == Keyword.GET;
+
+ @override
+ bool get isSetter =>
+ propertyKeyword != null &&
+ (propertyKeyword as KeywordToken).keyword == Keyword.SET;
+
+ @override
+ TypeName get returnType => _returnType;
+
+ @override
+ void set returnType(TypeName returnType) {
+ _returnType = _becomeParentOf(returnType);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFunctionDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_returnType, visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_functionExpression, visitor);
+ }
+}
+
+/**
+ * A [FunctionDeclaration] used as a statement.
+ */
+class FunctionDeclarationStatementImpl extends StatementImpl
+ implements FunctionDeclarationStatement {
+ /**
+ * The function declaration being wrapped.
+ */
+ FunctionDeclaration _functionDeclaration;
+
+ /**
+ * Initialize a newly created function declaration statement.
+ */
+ FunctionDeclarationStatementImpl(FunctionDeclaration functionDeclaration) {
+ _functionDeclaration = _becomeParentOf(functionDeclaration);
+ }
+
+ @override
+ Token get beginToken => _functionDeclaration.beginToken;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(_functionDeclaration);
+
+ @override
+ Token get endToken => _functionDeclaration.endToken;
+
+ @override
+ FunctionDeclaration get functionDeclaration => _functionDeclaration;
+
+ @override
+ void set functionDeclaration(FunctionDeclaration functionDeclaration) {
+ _functionDeclaration = _becomeParentOf(functionDeclaration);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFunctionDeclarationStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_functionDeclaration, visitor);
+ }
+}
+
+/**
+ * A function expression.
+ *
+ * > functionExpression ::=
+ * > [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ */
+class FunctionExpressionImpl extends ExpressionImpl
+ implements FunctionExpression {
+ /**
+ * The type parameters associated with the method, or `null` if the method is
+ * not a generic method.
+ */
+ TypeParameterList _typeParameters;
+
+ /**
+ * The parameters associated with the function.
+ */
+ FormalParameterList _parameters;
+
+ /**
+ * The body of the function, or `null` if this is an external function.
+ */
+ FunctionBody _body;
+
+ /**
+ * The element associated with the function, or `null` if the AST structure
+ * has not been resolved.
+ */
+ ExecutableElement element;
+
+ /**
+ * Initialize a newly created function declaration.
+ */
+ FunctionExpressionImpl(TypeParameterList typeParameters,
+ FormalParameterList parameters, FunctionBody body) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ _parameters = _becomeParentOf(parameters);
+ _body = _becomeParentOf(body);
+ }
+
+ @override
+ Token get beginToken {
+ if (_typeParameters != null) {
+ return _typeParameters.beginToken;
+ } else if (_parameters != null) {
+ return _parameters.beginToken;
+ } else if (_body != null) {
+ return _body.beginToken;
+ }
+ // This should never be reached because external functions must be named,
+ // hence either the body or the name should be non-null.
+ throw new IllegalStateException("Non-external functions must have a body");
+ }
+
+ @override
+ FunctionBody get body => _body;
+
+ @override
+ void set body(FunctionBody functionBody) {
+ _body = _becomeParentOf(functionBody);
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_parameters)..add(_body);
+
+ @override
+ Token get endToken {
+ if (_body != null) {
+ return _body.endToken;
+ } else if (_parameters != null) {
+ return _parameters.endToken;
+ }
+ // This should never be reached because external functions must be named,
+ // hence either the body or the name should be non-null.
+ throw new IllegalStateException("Non-external functions must have a body");
+ }
+
+ @override
+ FormalParameterList get parameters => _parameters;
+
+ @override
+ void set parameters(FormalParameterList parameters) {
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ int get precedence => 16;
+
+ @override
+ TypeParameterList get typeParameters => _typeParameters;
+
+ @override
+ void set typeParameters(TypeParameterList typeParameters) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFunctionExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_typeParameters, visitor);
+ _safelyVisitChild(_parameters, visitor);
+ _safelyVisitChild(_body, visitor);
+ }
+}
+
+/**
+ * The invocation of a function resulting from evaluating an expression.
+ * Invocations of methods and other forms of functions are represented by
+ * [MethodInvocation] nodes. Invocations of getters and setters are represented
+ * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ * > functionExpressionInvocation ::=
+ * > [Expression] [TypeArgumentList]? [ArgumentList]
+ */
+class FunctionExpressionInvocationImpl extends ExpressionImpl
+ implements FunctionExpressionInvocation {
+ /**
+ * The expression producing the function being invoked.
+ */
+ Expression _function;
+
+ /**
+ * The type arguments to be applied to the method being invoked, or `null` if
+ * no type arguments were provided.
+ */
+ TypeArgumentList _typeArguments;
+
+ /**
+ * The list of arguments to the function.
+ */
+ ArgumentList _argumentList;
+
+ /**
+ * The element associated with the function being invoked based on static type
+ * information, or `null` if the AST structure has not been resolved or the
+ * function could not be resolved.
+ */
+ ExecutableElement staticElement;
+
+ /**
+ * The function type of the method invocation, or `null` if the AST
+ * structure has not been resolved, or if the invoke could not be resolved.
+ *
+ * This will usually be a [FunctionType], but it can also be an
+ * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+ * interface type that implements `Function`.
+ */
+ DartType staticInvokeType;
+
+ /**
+ * The element associated with the function being invoked based on propagated
+ * type information, or `null` if the AST structure has not been resolved or
+ * the function could not be resolved.
+ */
+ ExecutableElement propagatedElement;
+
+ /**
+ * Like [staticInvokeType], but reflects propagated type information.
+ */
+ DartType propagatedInvokeType;
+
+ /**
+ * Initialize a newly created function expression invocation.
+ */
+ FunctionExpressionInvocationImpl(Expression function,
+ TypeArgumentList typeArguments, ArgumentList argumentList) {
+ _function = _becomeParentOf(function);
+ _typeArguments = _becomeParentOf(typeArguments);
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ ArgumentList get argumentList => _argumentList;
+
+ @override
+ void set argumentList(ArgumentList argumentList) {
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ Token get beginToken => _function.beginToken;
+
+ @override
+ ExecutableElement get bestElement {
+ ExecutableElement element = propagatedElement;
+ if (element == null) {
+ element = staticElement;
+ }
+ return element;
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_function)..add(_argumentList);
+
+ @override
+ Token get endToken => _argumentList.endToken;
+
+ @override
+ Expression get function => _function;
+
+ @override
+ void set function(Expression expression) {
+ _function = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 15;
+
+ @override
+ TypeArgumentList get typeArguments => _typeArguments;
+
+ @override
+ void set typeArguments(TypeArgumentList typeArguments) {
+ _typeArguments = _becomeParentOf(typeArguments);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFunctionExpressionInvocation(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_function, visitor);
+ _safelyVisitChild(_typeArguments, visitor);
+ _safelyVisitChild(_argumentList, visitor);
+ }
+}
+
+/**
+ * A function type alias.
+ *
+ * > functionTypeAlias ::=
+ * > functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ * >
+ * > functionPrefix ::=
+ * > [TypeName]? [SimpleIdentifier]
+ */
+class FunctionTypeAliasImpl extends TypeAliasImpl implements FunctionTypeAlias {
+ /**
+ * The name of the return type of the function type being defined, or `null`
+ * if no return type was given.
+ */
+ TypeName _returnType;
+
+ /**
+ * The type parameters for the function type, or `null` if the function type
+ * does not have any type parameters.
+ */
+ TypeParameterList _typeParameters;
+
+ /**
+ * The parameters associated with the function type.
+ */
+ FormalParameterList _parameters;
+
+ /**
+ * Initialize a newly created function type alias. Either or both of the
+ * [comment] and [metadata] can be `null` if the function does not have the
+ * corresponding attribute. The [returnType] can be `null` if no return type
+ * was specified. The [typeParameters] can be `null` if the function has no
+ * type parameters.
+ */
+ FunctionTypeAliasImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ TypeName returnType,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters,
+ Token semicolon)
+ : super(comment, metadata, keyword, name, semicolon) {
+ _returnType = _becomeParentOf(returnType);
+ _typeParameters = _becomeParentOf(typeParameters);
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(typedefKeyword)
+ ..add(_returnType)
+ ..add(_name)
+ ..add(_typeParameters)
+ ..add(_parameters)
+ ..add(semicolon);
+
+ @override
+ FunctionTypeAliasElement get element =>
+ _name != null ? (_name.staticElement as FunctionTypeAliasElement) : null;
+
+ @override
+ FormalParameterList get parameters => _parameters;
+
+ @override
+ void set parameters(FormalParameterList parameters) {
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ TypeName get returnType => _returnType;
+
+ @override
+ void set returnType(TypeName typeName) {
+ _returnType = _becomeParentOf(typeName);
+ }
+
+ @override
+ TypeParameterList get typeParameters => _typeParameters;
+
+ @override
+ void set typeParameters(TypeParameterList typeParameters) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFunctionTypeAlias(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_returnType, visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_typeParameters, visitor);
+ _safelyVisitChild(_parameters, visitor);
+ }
+}
+
+/**
+ * A function-typed formal parameter.
+ *
+ * > functionSignature ::=
+ * > [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ */
+class FunctionTypedFormalParameterImpl extends NormalFormalParameterImpl
+ implements FunctionTypedFormalParameter {
+ /**
+ * The return type of the function, or `null` if the function does not have a
+ * return type.
+ */
+ TypeName _returnType;
+
+ /**
+ * The type parameters associated with the function, or `null` if the function
+ * is not a generic function.
+ */
+ TypeParameterList _typeParameters;
+
+ /**
+ * The parameters of the function-typed parameter.
+ */
+ FormalParameterList _parameters;
+
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [returnType] can be `null` if no return type
+ * was specified.
+ */
+ FunctionTypedFormalParameterImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ TypeName returnType,
+ SimpleIdentifier identifier,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters)
+ : super(comment, metadata, identifier) {
+ _returnType = _becomeParentOf(returnType);
+ _typeParameters = _becomeParentOf(typeParameters);
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ Token get beginToken {
+ if (_returnType != null) {
+ return _returnType.beginToken;
+ }
+ return identifier.beginToken;
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(_returnType)..add(identifier)..add(parameters);
+
+ @override
+ Token get endToken => _parameters.endToken;
+
+ @override
+ bool get isConst => false;
+
+ @override
+ bool get isFinal => false;
+
+ @override
+ FormalParameterList get parameters => _parameters;
+
+ @override
+ void set parameters(FormalParameterList parameters) {
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ TypeName get returnType => _returnType;
+
+ @override
+ void set returnType(TypeName type) {
+ _returnType = _becomeParentOf(type);
+ }
+
+ @override
+ TypeParameterList get typeParameters => _typeParameters;
+
+ @override
+ void set typeParameters(TypeParameterList typeParameters) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitFunctionTypedFormalParameter(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_returnType, visitor);
+ _safelyVisitChild(identifier, visitor);
+ _safelyVisitChild(_typeParameters, visitor);
+ _safelyVisitChild(_parameters, visitor);
+ }
+}
+
+/**
+ * A combinator that restricts the names being imported to those that are not in
+ * a given list.
+ *
+ * > hideCombinator ::=
+ * > 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ */
+class HideCombinatorImpl extends CombinatorImpl implements HideCombinator {
+ /**
+ * The list of names from the library that are hidden by this combinator.
+ */
+ NodeList<SimpleIdentifier> _hiddenNames;
+
+ /**
+ * Initialize a newly created import show combinator.
+ */
+ HideCombinatorImpl(Token keyword, List<SimpleIdentifier> hiddenNames)
+ : super(keyword) {
+ _hiddenNames = new NodeList<SimpleIdentifier>(this, hiddenNames);
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(keyword)
+ ..addAll(_hiddenNames);
+
+ @override
+ Token get endToken => _hiddenNames.endToken;
+
+ @override
+ NodeList<SimpleIdentifier> get hiddenNames => _hiddenNames;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitHideCombinator(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _hiddenNames.accept(visitor);
+ }
+}
+
+/**
+ * A node that represents an identifier.
+ *
+ * > identifier ::=
+ * > [SimpleIdentifier]
+ * > | [PrefixedIdentifier]
+ */
+abstract class IdentifierImpl extends ExpressionImpl implements Identifier {
+ /**
+ * Return the best element available for this operator. If resolution was able
+ * to find a better element based on type propagation, that element will be
+ * returned. Otherwise, the element found using the result of static analysis
+ * will be returned. If resolution has not been performed, then `null` will be
+ * returned.
+ */
+ Element get bestElement;
+
+ @override
+ bool get isAssignable => true;
+}
+
+/**
+ * An if statement.
+ *
+ * > ifStatement ::=
+ * > 'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+ */
+class IfStatementImpl extends StatementImpl implements IfStatement {
+ /**
+ * The token representing the 'if' keyword.
+ */
+ Token ifKeyword;
+
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The condition used to determine which of the statements is executed next.
+ */
+ Expression _condition;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The statement that is executed if the condition evaluates to `true`.
+ */
+ Statement _thenStatement;
+
+ /**
+ * The token representing the 'else' keyword, or `null` if there is no else
+ * statement.
+ */
+ Token elseKeyword;
+
+ /**
+ * The statement that is executed if the condition evaluates to `false`, or
+ * `null` if there is no else statement.
+ */
+ Statement _elseStatement;
+
+ /**
+ * Initialize a newly created if statement. The [elseKeyword] and
+ * [elseStatement] can be `null` if there is no else clause.
+ */
+ IfStatementImpl(
+ this.ifKeyword,
+ this.leftParenthesis,
+ Expression condition,
+ this.rightParenthesis,
+ Statement thenStatement,
+ this.elseKeyword,
+ Statement elseStatement) {
+ _condition = _becomeParentOf(condition);
+ _thenStatement = _becomeParentOf(thenStatement);
+ _elseStatement = _becomeParentOf(elseStatement);
+ }
+
+ @override
+ Token get beginToken => ifKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(ifKeyword)
+ ..add(leftParenthesis)
+ ..add(_condition)
+ ..add(rightParenthesis)
+ ..add(_thenStatement)
+ ..add(elseKeyword)
+ ..add(_elseStatement);
+
+ @override
+ Expression get condition => _condition;
+
+ @override
+ void set condition(Expression expression) {
+ _condition = _becomeParentOf(expression);
+ }
+
+ @override
+ Statement get elseStatement => _elseStatement;
+
+ @override
+ void set elseStatement(Statement statement) {
+ _elseStatement = _becomeParentOf(statement);
+ }
+
+ @override
+ Token get endToken {
+ if (_elseStatement != null) {
+ return _elseStatement.endToken;
+ }
+ return _thenStatement.endToken;
+ }
+
+ @override
+ Statement get thenStatement => _thenStatement;
+
+ @override
+ void set thenStatement(Statement statement) {
+ _thenStatement = _becomeParentOf(statement);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitIfStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_condition, visitor);
+ _safelyVisitChild(_thenStatement, visitor);
+ _safelyVisitChild(_elseStatement, visitor);
+ }
+}
+
+/**
+ * The "implements" clause in an class declaration.
+ *
+ * > implementsClause ::=
+ * > 'implements' [TypeName] (',' [TypeName])*
+ */
+class ImplementsClauseImpl extends AstNodeImpl implements ImplementsClause {
+ /**
+ * The token representing the 'implements' keyword.
+ */
+ Token implementsKeyword;
+
+ /**
+ * The interfaces that are being implemented.
+ */
+ NodeList<TypeName> _interfaces;
+
+ /**
+ * Initialize a newly created implements clause.
+ */
+ ImplementsClauseImpl(this.implementsKeyword, List<TypeName> interfaces) {
+ _interfaces = new NodeList<TypeName>(this, interfaces);
+ }
+
+ @override
+ Token get beginToken => implementsKeyword;
+
+ @override
+ // TODO(paulberry): add commas.
+ Iterable get childEntities => new ChildEntities()
+ ..add(implementsKeyword)
+ ..addAll(interfaces);
+
+ @override
+ Token get endToken => _interfaces.endToken;
+
+ @override
+ NodeList<TypeName> get interfaces => _interfaces;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitImplementsClause(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _interfaces.accept(visitor);
+ }
+}
+
+/**
+ * An import directive.
+ *
+ * > importDirective ::=
+ * > [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ * > | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ */
+class ImportDirectiveImpl extends NamespaceDirectiveImpl
+ implements ImportDirective {
+ /**
+ * The token representing the 'deferred' keyword, or `null` if the imported is
+ * not deferred.
+ */
+ Token deferredKeyword;
+
+ /**
+ * The token representing the 'as' keyword, or `null` if the imported names are
+ * not prefixed.
+ */
+ Token asKeyword;
+
+ /**
+ * The prefix to be used with the imported names, or `null` if the imported
+ * names are not prefixed.
+ */
+ SimpleIdentifier _prefix;
+
+ /**
+ * Initialize a newly created import directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the function does not have the
+ * corresponding attribute. The [deferredKeyword] can be `null` if the import
+ * is not deferred. The [asKeyword] and [prefix] can be `null` if the import
+ * does not specify a prefix. The list of [combinators] can be `null` if there
+ * are no combinators.
+ */
+ ImportDirectiveImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ Token keyword,
+ StringLiteral libraryUri,
+ List<Configuration> configurations,
+ this.deferredKeyword,
+ this.asKeyword,
+ SimpleIdentifier prefix,
+ List<Combinator> combinators,
+ Token semicolon)
+ : super(comment, metadata, keyword, libraryUri, configurations,
+ combinators, semicolon) {
+ _prefix = _becomeParentOf(prefix);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(_uri)
+ ..add(deferredKeyword)
+ ..add(asKeyword)
+ ..add(_prefix)
+ ..addAll(combinators)
+ ..add(semicolon);
+
+ @override
+ ImportElement get element => super.element as ImportElement;
+
+ @override
+ SimpleIdentifier get prefix => _prefix;
+
+ @override
+ void set prefix(SimpleIdentifier identifier) {
+ _prefix = _becomeParentOf(identifier);
+ }
+
+ @override
+ LibraryElement get uriElement {
+ ImportElement element = this.element;
+ if (element == null) {
+ return null;
+ }
+ return element.importedLibrary;
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitImportDirective(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_prefix, visitor);
+ combinators.accept(visitor);
+ }
+}
+
+/**
+ * An index expression.
+ *
+ * > indexExpression ::=
+ * > [Expression] '[' [Expression] ']'
+ */
+class IndexExpressionImpl extends ExpressionImpl implements IndexExpression {
+ /**
+ * The expression used to compute the object being indexed, or `null` if this
+ * index expression is part of a cascade expression.
+ */
+ Expression _target;
+
+ /**
+ * The period ("..") before a cascaded index expression, or `null` if this
+ * index expression is not part of a cascade expression.
+ */
+ Token period;
+
+ /**
+ * The left square bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The expression used to compute the index.
+ */
+ Expression _index;
+
+ /**
+ * The right square bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * The element associated with the operator based on the static type of the
+ * target, or `null` if the AST structure has not been resolved or if the
+ * operator could not be resolved.
+ */
+ MethodElement staticElement;
+
+ /**
+ * The element associated with the operator based on the propagated type of
+ * the target, or `null` if the AST structure has not been resolved or if the
+ * operator could not be resolved.
+ */
+ MethodElement propagatedElement;
+
+ /**
+ * If this expression is both in a getter and setter context, the
+ * [AuxiliaryElements] will be set to hold onto the static and propagated
+ * information. The auxiliary element will hold onto the elements from the
+ * getter context.
+ */
+ AuxiliaryElements auxiliaryElements = null;
+
+ /**
+ * Initialize a newly created index expression.
+ */
+ IndexExpressionImpl.forCascade(
+ this.period, this.leftBracket, Expression index, this.rightBracket) {
+ _index = _becomeParentOf(index);
+ }
+
+ /**
+ * Initialize a newly created index expression.
+ */
+ IndexExpressionImpl.forTarget(Expression target, this.leftBracket,
+ Expression index, this.rightBracket) {
+ _target = _becomeParentOf(target);
+ _index = _becomeParentOf(index);
+ }
+
+ @override
+ Token get beginToken {
+ if (_target != null) {
+ return _target.beginToken;
+ }
+ return period;
+ }
+
+ @override
+ MethodElement get bestElement {
+ MethodElement element = propagatedElement;
+ if (element == null) {
+ element = staticElement;
+ }
+ return element;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(_target)
+ ..add(period)
+ ..add(leftBracket)
+ ..add(_index)
+ ..add(rightBracket);
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ Expression get index => _index;
+
+ @override
+ void set index(Expression expression) {
+ _index = _becomeParentOf(expression);
+ }
+
+ @override
+ bool get isAssignable => true;
+
+ @override
+ bool get isCascaded => period != null;
+
+ @override
+ int get precedence => 15;
+
+ @override
+ Expression get realTarget {
+ if (isCascaded) {
+ AstNode ancestor = parent;
+ while (ancestor is! CascadeExpression) {
+ if (ancestor == null) {
+ return _target;
+ }
+ ancestor = ancestor.parent;
+ }
+ return (ancestor as CascadeExpression).target;
+ }
+ return _target;
+ }
+
+ @override
+ Expression get target => _target;
+
+ @override
+ void set target(Expression expression) {
+ _target = _becomeParentOf(expression);
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on propagated type information, then return the parameter
+ * element representing the parameter to which the value of the index
+ * expression will be bound. Otherwise, return `null`.
+ */
+ ParameterElement get _propagatedParameterElementForIndex {
+ if (propagatedElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = propagatedElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on static type information, then return the parameter element
+ * representing the parameter to which the value of the index expression will
+ * be bound. Otherwise, return `null`.
+ */
+ ParameterElement get _staticParameterElementForIndex {
+ if (staticElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = staticElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitIndexExpression(this);
+
+ @override
+ bool inGetterContext() {
+ // TODO(brianwilkerson) Convert this to a getter.
+ AstNode parent = this.parent;
+ if (parent is AssignmentExpression) {
+ AssignmentExpression assignment = parent;
+ if (identical(assignment.leftHandSide, this) &&
+ assignment.operator.type == TokenType.EQ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @override
+ bool inSetterContext() {
+ // TODO(brianwilkerson) Convert this to a getter.
+ AstNode parent = this.parent;
+ if (parent is PrefixExpression) {
+ return parent.operator.type.isIncrementOperator;
+ } else if (parent is PostfixExpression) {
+ return true;
+ } else if (parent is AssignmentExpression) {
+ return identical(parent.leftHandSide, this);
+ }
+ return false;
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_target, visitor);
+ _safelyVisitChild(_index, visitor);
+ }
+}
+
+/**
+ * An instance creation expression.
+ *
+ * > newExpression ::=
+ * > ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ */
+class InstanceCreationExpressionImpl extends ExpressionImpl
+ implements InstanceCreationExpression {
+ /**
+ * The 'new' or 'const' keyword used to indicate how an object should be
+ * created.
+ */
+ Token keyword;
+
+ /**
+ * The name of the constructor to be invoked.
+ */
+ ConstructorName _constructorName;
+
+ /**
+ * The list of arguments to the constructor.
+ */
+ ArgumentList _argumentList;
+
+ /**
+ * The element associated with the constructor based on static type
+ * information, or `null` if the AST structure has not been resolved or if the
+ * constructor could not be resolved.
+ */
+ ConstructorElement staticElement;
+
+ /**
+ * Initialize a newly created instance creation expression.
+ */
+ InstanceCreationExpressionImpl(this.keyword, ConstructorName constructorName,
+ ArgumentList argumentList) {
+ _constructorName = _becomeParentOf(constructorName);
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ ArgumentList get argumentList => _argumentList;
+
+ @override
+ void set argumentList(ArgumentList argumentList) {
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ Token get beginToken => keyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(keyword)
+ ..add(_constructorName)
+ ..add(_argumentList);
+
+ @override
+ ConstructorName get constructorName => _constructorName;
+
+ @override
+ void set constructorName(ConstructorName name) {
+ _constructorName = _becomeParentOf(name);
+ }
+
+ @override
+ Token get endToken => _argumentList.endToken;
+
+ @override
+ bool get isConst =>
+ keyword is KeywordToken &&
+ (keyword as KeywordToken).keyword == Keyword.CONST;
+
+ @override
+ int get precedence => 16;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitInstanceCreationExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_constructorName, visitor);
+ _safelyVisitChild(_argumentList, visitor);
+ }
+}
+
+/**
+ * An integer literal expression.
+ *
+ * > integerLiteral ::=
+ * > decimalIntegerLiteral
+ * > | hexadecimalIntegerLiteral
+ * >
+ * > decimalIntegerLiteral ::=
+ * > decimalDigit+
+ * >
+ * > hexadecimalIntegerLiteral ::=
+ * > '0x' hexadecimalDigit+
+ * > | '0X' hexadecimalDigit+
+ */
+class IntegerLiteralImpl extends LiteralImpl implements IntegerLiteral {
+ /**
+ * The token representing the literal.
+ */
+ Token literal;
+
+ /**
+ * The value of the literal.
+ */
+ int value = 0;
+
+ /**
+ * Initialize a newly created integer literal.
+ */
+ IntegerLiteralImpl(this.literal, this.value);
+
+ @override
+ Token get beginToken => literal;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(literal);
+
+ @override
+ Token get endToken => literal;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitIntegerLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A node within a [StringInterpolation].
+ *
+ * > interpolationElement ::=
+ * > [InterpolationExpression]
+ * > | [InterpolationString]
+ */
+abstract class InterpolationElementImpl extends AstNodeImpl
+ implements InterpolationElement {}
+
+/**
+ * An expression embedded in a string interpolation.
+ *
+ * > interpolationExpression ::=
+ * > '$' [SimpleIdentifier]
+ * > | '$' '{' [Expression] '}'
+ */
+class InterpolationExpressionImpl extends InterpolationElementImpl
+ implements InterpolationExpression {
+ /**
+ * The token used to introduce the interpolation expression; either '$' if the
+ * expression is a simple identifier or '${' if the expression is a full
+ * expression.
+ */
+ Token leftBracket;
+
+ /**
+ * The expression to be evaluated for the value to be converted into a string.
+ */
+ Expression _expression;
+
+ /**
+ * The right curly bracket, or `null` if the expression is an identifier
+ * without brackets.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created interpolation expression.
+ */
+ InterpolationExpressionImpl(
+ this.leftBracket, Expression expression, this.rightBracket) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken => leftBracket;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(leftBracket)
+ ..add(_expression)
+ ..add(rightBracket);
+
+ @override
+ Token get endToken {
+ if (rightBracket != null) {
+ return rightBracket;
+ }
+ return _expression.endToken;
+ }
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitInterpolationExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * A non-empty substring of an interpolated string.
+ *
+ * > interpolationString ::=
+ * > characters
+ */
+class InterpolationStringImpl extends InterpolationElementImpl
+ implements InterpolationString {
+ /**
+ * The characters that will be added to the string.
+ */
+ Token contents;
+
+ /**
+ * The value of the literal.
+ */
+ String value;
+
+ /**
+ * Initialize a newly created string of characters that are part of a string
+ * interpolation.
+ */
+ InterpolationStringImpl(this.contents, this.value);
+
+ @override
+ Token get beginToken => contents;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(contents);
+
+ @override
+ int get contentsEnd {
+ String lexeme = contents.lexeme;
+ return offset + new StringLexemeHelper(lexeme, true, true).end;
+ }
+
+ @override
+ int get contentsOffset {
+ int offset = contents.offset;
+ String lexeme = contents.lexeme;
+ return offset + new StringLexemeHelper(lexeme, true, true).start;
+ }
+
+ @override
+ Token get endToken => contents;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitInterpolationString(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {}
+}
+
+/**
+ * An is expression.
+ *
+ * > isExpression ::=
+ * > [Expression] 'is' '!'? [TypeName]
+ */
+class IsExpressionImpl extends ExpressionImpl implements IsExpression {
+ /**
+ * The expression used to compute the value whose type is being tested.
+ */
+ Expression _expression;
+
+ /**
+ * The is operator.
+ */
+ Token isOperator;
+
+ /**
+ * The not operator, or `null` if the sense of the test is not negated.
+ */
+ Token notOperator;
+
+ /**
+ * The name of the type being tested for.
+ */
+ TypeName _type;
+
+ /**
+ * Initialize a newly created is expression. The [notOperator] can be `null`
+ * if the sense of the test is not negated.
+ */
+ IsExpressionImpl(
+ Expression expression, this.isOperator, this.notOperator, TypeName type) {
+ _expression = _becomeParentOf(expression);
+ _type = _becomeParentOf(type);
+ }
+
+ @override
+ Token get beginToken => _expression.beginToken;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(_expression)
+ ..add(isOperator)
+ ..add(notOperator)
+ ..add(_type);
+
+ @override
+ Token get endToken => _type.endToken;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 7;
+
+ @override
+ TypeName get type => _type;
+
+ @override
+ void set type(TypeName name) {
+ _type = _becomeParentOf(name);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitIsExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ _safelyVisitChild(_type, visitor);
+ }
+}
+
+/**
+ * A statement that has a label associated with them.
+ *
+ * > labeledStatement ::=
+ * > [Label]+ [Statement]
+ */
+class LabeledStatementImpl extends StatementImpl implements LabeledStatement {
+ /**
+ * The labels being associated with the statement.
+ */
+ NodeList<Label> _labels;
+
+ /**
+ * The statement with which the labels are being associated.
+ */
+ Statement _statement;
+
+ /**
+ * Initialize a newly created labeled statement.
+ */
+ LabeledStatementImpl(List<Label> labels, Statement statement) {
+ _labels = new NodeList<Label>(this, labels);
+ _statement = _becomeParentOf(statement);
+ }
+
+ @override
+ Token get beginToken {
+ if (!_labels.isEmpty) {
+ return _labels.beginToken;
+ }
+ return _statement.beginToken;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..addAll(_labels)
+ ..add(_statement);
+
+ @override
+ Token get endToken => _statement.endToken;
+
+ @override
+ NodeList<Label> get labels => _labels;
+
+ @override
+ Statement get statement => _statement;
+
+ @override
+ void set statement(Statement statement) {
+ _statement = _becomeParentOf(statement);
+ }
+
+ @override
+ Statement get unlabeled => _statement.unlabeled;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitLabeledStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _labels.accept(visitor);
+ _safelyVisitChild(_statement, visitor);
+ }
+}
+
+/**
+ * A label on either a [LabeledStatement] or a [NamedExpression].
+ *
+ * > label ::=
+ * > [SimpleIdentifier] ':'
+ */
+class LabelImpl extends AstNodeImpl implements Label {
+ /**
+ * The label being associated with the statement.
+ */
+ SimpleIdentifier _label;
+
+ /**
+ * The colon that separates the label from the statement.
+ */
+ Token colon;
+
+ /**
+ * Initialize a newly created label.
+ */
+ LabelImpl(SimpleIdentifier label, this.colon) {
+ _label = _becomeParentOf(label);
+ }
+
+ @override
+ Token get beginToken => _label.beginToken;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(_label)..add(colon);
+
+ @override
+ Token get endToken => colon;
+
+ @override
+ SimpleIdentifier get label => _label;
+
+ @override
+ void set label(SimpleIdentifier label) {
+ _label = _becomeParentOf(label);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitLabel(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_label, visitor);
+ }
+}
+
+/**
+ * A library directive.
+ *
+ * > libraryDirective ::=
+ * > [Annotation] 'library' [Identifier] ';'
+ */
+class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
+ /**
+ * The token representing the 'library' keyword.
+ */
+ Token libraryKeyword;
+
+ /**
+ * The name of the library being defined.
+ */
+ LibraryIdentifier _name;
+
+ /**
+ * The semicolon terminating the directive.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created library directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute.
+ */
+ LibraryDirectiveImpl(Comment comment, List<Annotation> metadata,
+ this.libraryKeyword, LibraryIdentifier name, this.semicolon)
+ : super(comment, metadata) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(libraryKeyword)..add(_name)..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
+
+ @override
+ Token get keyword => libraryKeyword;
+
+ @override
+ LibraryIdentifier get name => _name;
+
+ @override
+ void set name(LibraryIdentifier name) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitLibraryDirective(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_name, visitor);
+ }
+}
+
+/**
+ * The identifier for a library.
+ *
+ * > libraryIdentifier ::=
+ * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ */
+class LibraryIdentifierImpl extends IdentifierImpl
+ implements LibraryIdentifier {
+ /**
+ * The components of the identifier.
+ */
+ NodeList<SimpleIdentifier> _components;
+
+ /**
+ * Initialize a newly created prefixed identifier.
+ */
+ LibraryIdentifierImpl(List<SimpleIdentifier> components) {
+ _components = new NodeList<SimpleIdentifier>(this, components);
+ }
+
+ @override
+ Token get beginToken => _components.beginToken;
+
+ @override
+ Element get bestElement => staticElement;
+
+ @override
+ // TODO(paulberry): add "." tokens.
+ Iterable get childEntities => new ChildEntities()..addAll(_components);
+
+ @override
+ NodeList<SimpleIdentifier> get components => _components;
+
+ @override
+ Token get endToken => _components.endToken;
+
+ @override
+ String get name {
+ StringBuffer buffer = new StringBuffer();
+ bool needsPeriod = false;
+ for (SimpleIdentifier identifier in _components) {
+ if (needsPeriod) {
+ buffer.write(".");
+ } else {
+ needsPeriod = true;
+ }
+ buffer.write(identifier.name);
+ }
+ return buffer.toString();
+ }
+
+ @override
+ int get precedence => 15;
+
+ @override
+ Element get propagatedElement => null;
+
+ @override
+ Element get staticElement => null;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitLibraryIdentifier(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _components.accept(visitor);
+ }
+}
+
+/**
+ * A list literal.
+ *
+ * > listLiteral ::=
+ * > 'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ */
+class ListLiteralImpl extends TypedLiteralImpl implements ListLiteral {
+ /**
+ * The left square bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The expressions used to compute the elements of the list.
+ */
+ NodeList<Expression> _elements;
+
+ /**
+ * The right square bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created list literal. The [constKeyword] can be `null`
+ * if the literal is not a constant. The [typeArguments] can be `null` if no
+ * type arguments were declared. The list of [elements] can be `null` if the
+ * list is empty.
+ */
+ ListLiteralImpl(Token constKeyword, TypeArgumentList typeArguments,
+ this.leftBracket, List<Expression> elements, this.rightBracket)
+ : super(constKeyword, typeArguments) {
+ _elements = new NodeList<Expression>(this, elements);
+ }
+
+ @override
+ Token get beginToken {
+ if (constKeyword != null) {
+ return constKeyword;
+ }
+ TypeArgumentList typeArguments = this.typeArguments;
+ if (typeArguments != null) {
+ return typeArguments.beginToken;
+ }
+ return leftBracket;
+ }
+
+ @override
+ // TODO(paulberry): add commas.
+ Iterable get childEntities => super._childEntities
+ ..add(leftBracket)
+ ..addAll(_elements)
+ ..add(rightBracket);
+
+ @override
+ NodeList<Expression> get elements => _elements;
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitListLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _elements.accept(visitor);
+ }
+}
+
+/**
+ * A node that represents a literal expression.
+ *
+ * > literal ::=
+ * > [BooleanLiteral]
+ * > | [DoubleLiteral]
+ * > | [IntegerLiteral]
+ * > | [ListLiteral]
+ * > | [MapLiteral]
+ * > | [NullLiteral]
+ * > | [StringLiteral]
+ */
+abstract class LiteralImpl extends ExpressionImpl implements Literal {
+ @override
+ int get precedence => 16;
+}
+
+/**
+ * A single key/value pair in a map literal.
+ *
+ * > mapLiteralEntry ::=
+ * > [Expression] ':' [Expression]
+ */
+class MapLiteralEntryImpl extends AstNodeImpl implements MapLiteralEntry {
+ /**
+ * The expression computing the key with which the value will be associated.
+ */
+ Expression _key;
+
+ /**
+ * The colon that separates the key from the value.
+ */
+ Token separator;
+
+ /**
+ * The expression computing the value that will be associated with the key.
+ */
+ Expression _value;
+
+ /**
+ * Initialize a newly created map literal entry.
+ */
+ MapLiteralEntryImpl(Expression key, this.separator, Expression value) {
+ _key = _becomeParentOf(key);
+ _value = _becomeParentOf(value);
+ }
+
+ @override
+ Token get beginToken => _key.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_key)..add(separator)..add(_value);
+
+ @override
+ Token get endToken => _value.endToken;
+
+ @override
+ Expression get key => _key;
+
+ @override
+ void set key(Expression string) {
+ _key = _becomeParentOf(string);
+ }
+
+ @override
+ Expression get value => _value;
+
+ @override
+ void set value(Expression expression) {
+ _value = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitMapLiteralEntry(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_key, visitor);
+ _safelyVisitChild(_value, visitor);
+ }
+}
+
+/**
+ * A literal map.
+ *
+ * > mapLiteral ::=
+ * > 'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ * > '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ */
+class MapLiteralImpl extends TypedLiteralImpl implements MapLiteral {
+ /**
+ * The left curly bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The entries in the map.
+ */
+ NodeList<MapLiteralEntry> _entries;
+
+ /**
+ * The right curly bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created map literal. The [constKeyword] can be `null` if
+ * the literal is not a constant. The [typeArguments] can be `null` if no type
+ * arguments were declared. The [entries] can be `null` if the map is empty.
+ */
+ MapLiteralImpl(Token constKeyword, TypeArgumentList typeArguments,
+ this.leftBracket, List<MapLiteralEntry> entries, this.rightBracket)
+ : super(constKeyword, typeArguments) {
+ _entries = new NodeList<MapLiteralEntry>(this, entries);
+ }
+
+ @override
+ Token get beginToken {
+ if (constKeyword != null) {
+ return constKeyword;
+ }
+ TypeArgumentList typeArguments = this.typeArguments;
+ if (typeArguments != null) {
+ return typeArguments.beginToken;
+ }
+ return leftBracket;
+ }
+
+ @override
+ // TODO(paulberry): add commas.
+ Iterable get childEntities => super._childEntities
+ ..add(leftBracket)
+ ..addAll(entries)
+ ..add(rightBracket);
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ NodeList<MapLiteralEntry> get entries => _entries;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitMapLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _entries.accept(visitor);
+ }
+}
+
+/**
+ * A method declaration.
+ *
+ * > methodDeclaration ::=
+ * > methodSignature [FunctionBody]
+ * >
+ * > methodSignature ::=
+ * > 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+ * > methodName [TypeParameterList] [FormalParameterList]
+ * >
+ * > methodName ::=
+ * > [SimpleIdentifier]
+ * > | 'operator' [SimpleIdentifier]
+ */
+class MethodDeclarationImpl extends ClassMemberImpl
+ implements MethodDeclaration {
+ /**
+ * The token for the 'external' keyword, or `null` if the constructor is not
+ * external.
+ */
+ Token externalKeyword;
+
+ /**
+ * The token representing the 'abstract' or 'static' keyword, or `null` if
+ * neither modifier was specified.
+ */
+ Token modifierKeyword;
+
+ /**
+ * The return type of the method, or `null` if no return type was declared.
+ */
+ TypeName _returnType;
+
+ /**
+ * The token representing the 'get' or 'set' keyword, or `null` if this is a
+ * method declaration rather than a property declaration.
+ */
+ Token propertyKeyword;
+
+ /**
+ * The token representing the 'operator' keyword, or `null` if this method
+ * does not declare an operator.
+ */
+ Token operatorKeyword;
+
+ /**
+ * The name of the method.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * The type parameters associated with the method, or `null` if the method is
+ * not a generic method.
+ */
+ TypeParameterList _typeParameters;
+
+ /**
+ * The parameters associated with the method, or `null` if this method
+ * declares a getter.
+ */
+ FormalParameterList _parameters;
+
+ /**
+ * The body of the method.
+ */
+ FunctionBody _body;
+
+ /**
+ * Initialize a newly created method declaration. Either or both of the
+ * [comment] and [metadata] can be `null` if the declaration does not have the
+ * corresponding attribute. The [externalKeyword] can be `null` if the method
+ * is not external. The [modifierKeyword] can be `null` if the method is
+ * neither abstract nor static. The [returnType] can be `null` if no return
+ * type was specified. The [propertyKeyword] can be `null` if the method is
+ * neither a getter or a setter. The [operatorKeyword] can be `null` if the
+ * method does not implement an operator. The [parameters] must be `null` if
+ * this method declares a getter.
+ */
+ MethodDeclarationImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.externalKeyword,
+ this.modifierKeyword,
+ TypeName returnType,
+ this.propertyKeyword,
+ this.operatorKeyword,
+ SimpleIdentifier name,
+ TypeParameterList typeParameters,
+ FormalParameterList parameters,
+ FunctionBody body)
+ : super(comment, metadata) {
+ _returnType = _becomeParentOf(returnType);
+ _name = _becomeParentOf(name);
+ _typeParameters = _becomeParentOf(typeParameters);
+ _parameters = _becomeParentOf(parameters);
+ _body = _becomeParentOf(body);
+ }
+
+ @override
+ FunctionBody get body => _body;
+
+ @override
+ void set body(FunctionBody functionBody) {
+ _body = _becomeParentOf(functionBody);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(externalKeyword)
+ ..add(modifierKeyword)
+ ..add(_returnType)
+ ..add(propertyKeyword)
+ ..add(operatorKeyword)
+ ..add(_name)
+ ..add(_parameters)
+ ..add(_body);
+
+ /**
+ * Return the element associated with this method, or `null` if the AST
+ * structure has not been resolved. The element can either be a
+ * [MethodElement], if this represents the declaration of a normal method, or
+ * a [PropertyAccessorElement] if this represents the declaration of either a
+ * getter or a setter.
+ */
+ @override
+ ExecutableElement get element =>
+ _name != null ? (_name.staticElement as ExecutableElement) : null;
+
+ @override
+ Token get endToken => _body.endToken;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata {
+ if (modifierKeyword != null) {
+ return modifierKeyword;
+ } else if (_returnType != null) {
+ return _returnType.beginToken;
+ } else if (propertyKeyword != null) {
+ return propertyKeyword;
+ } else if (operatorKeyword != null) {
+ return operatorKeyword;
+ }
+ return _name.beginToken;
+ }
+
+ @override
+ bool get isAbstract {
+ FunctionBody body = _body;
+ return externalKeyword == null &&
+ (body is EmptyFunctionBody && !body.semicolon.isSynthetic);
+ }
+
+ @override
+ bool get isGetter =>
+ propertyKeyword != null &&
+ (propertyKeyword as KeywordToken).keyword == Keyword.GET;
+
+ @override
+ bool get isOperator => operatorKeyword != null;
+
+ @override
+ bool get isSetter =>
+ propertyKeyword != null &&
+ (propertyKeyword as KeywordToken).keyword == Keyword.SET;
+
+ @override
+ bool get isStatic =>
+ modifierKeyword != null &&
+ (modifierKeyword as KeywordToken).keyword == Keyword.STATIC;
+
+ @override
+ SimpleIdentifier get name => _name;
+
+ @override
+ void set name(SimpleIdentifier identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+
+ @override
+ FormalParameterList get parameters => _parameters;
+
+ @override
+ void set parameters(FormalParameterList parameters) {
+ _parameters = _becomeParentOf(parameters);
+ }
+
+ @override
+ TypeName get returnType => _returnType;
+
+ @override
+ void set returnType(TypeName typeName) {
+ _returnType = _becomeParentOf(typeName);
+ }
+
+ @override
+ TypeParameterList get typeParameters => _typeParameters;
+
+ @override
+ void set typeParameters(TypeParameterList typeParameters) {
+ _typeParameters = _becomeParentOf(typeParameters);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitMethodDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_returnType, visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_typeParameters, visitor);
+ _safelyVisitChild(_parameters, visitor);
+ _safelyVisitChild(_body, visitor);
+ }
+}
+
+/**
+ * The invocation of either a function or a method. Invocations of functions
+ * resulting from evaluating an expression are represented by
+ * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
+ * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ * > methodInvocation ::=
+ * > ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ */
+class MethodInvocationImpl extends ExpressionImpl implements MethodInvocation {
+ /**
+ * The expression producing the object on which the method is defined, or
+ * `null` if there is no target (that is, the target is implicitly `this`).
+ */
+ Expression _target;
+
+ /**
+ * The operator that separates the target from the method name, or `null`
+ * if there is no target. In an ordinary method invocation this will be a
+ * period ('.'). In a cascade section this will be the cascade operator
+ * ('..').
+ */
+ Token operator;
+
+ /**
+ * The name of the method being invoked.
+ */
+ SimpleIdentifier _methodName;
+
+ /**
+ * The type arguments to be applied to the method being invoked, or `null` if
+ * no type arguments were provided.
+ */
+ TypeArgumentList _typeArguments;
+
+ /**
+ * The list of arguments to the method.
+ */
+ ArgumentList _argumentList;
+
+ /**
+ * The function type of the method invocation, or `null` if the AST
+ * structure has not been resolved, or if the invoke could not be resolved.
+ *
+ * This will usually be a [FunctionType], but it can also be an
+ * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+ * interface type that implements `Function`.
+ */
+ DartType staticInvokeType;
+
+ /**
+ * Like [staticInvokeType], but reflects propagated type information.
+ */
+ DartType propagatedInvokeType;
+
+ /**
+ * Initialize a newly created method invocation. The [target] and [operator]
+ * can be `null` if there is no target.
+ */
+ MethodInvocationImpl(
+ Expression target,
+ this.operator,
+ SimpleIdentifier methodName,
+ TypeArgumentList typeArguments,
+ ArgumentList argumentList) {
+ _target = _becomeParentOf(target);
+ _methodName = _becomeParentOf(methodName);
+ _typeArguments = _becomeParentOf(typeArguments);
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ ArgumentList get argumentList => _argumentList;
+
+ @override
+ void set argumentList(ArgumentList argumentList) {
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ Token get beginToken {
+ if (_target != null) {
+ return _target.beginToken;
+ } else if (operator != null) {
+ return operator;
+ }
+ return _methodName.beginToken;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(_target)
+ ..add(operator)
+ ..add(_methodName)
+ ..add(_argumentList);
+
+ @override
+ Token get endToken => _argumentList.endToken;
+
+ @override
+ bool get isCascaded =>
+ operator != null && operator.type == TokenType.PERIOD_PERIOD;
+
+ @override
+ SimpleIdentifier get methodName => _methodName;
+
+ @override
+ void set methodName(SimpleIdentifier identifier) {
+ _methodName = _becomeParentOf(identifier);
+ }
+
+ @override
+ int get precedence => 15;
+
+ @override
+ Expression get realTarget {
+ if (isCascaded) {
+ AstNode ancestor = parent;
+ while (ancestor is! CascadeExpression) {
+ if (ancestor == null) {
+ return _target;
+ }
+ ancestor = ancestor.parent;
+ }
+ return (ancestor as CascadeExpression).target;
+ }
+ return _target;
+ }
+
+ @override
+ Expression get target => _target;
+
+ @override
+ void set target(Expression expression) {
+ _target = _becomeParentOf(expression);
+ }
+
+ @override
+ TypeArgumentList get typeArguments => _typeArguments;
+
+ @override
+ void set typeArguments(TypeArgumentList typeArguments) {
+ _typeArguments = _becomeParentOf(typeArguments);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitMethodInvocation(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_target, visitor);
+ _safelyVisitChild(_methodName, visitor);
+ _safelyVisitChild(_typeArguments, visitor);
+ _safelyVisitChild(_argumentList, visitor);
+ }
+}
+
+/**
+ * A node that declares a single name within the scope of a compilation unit.
+ */
+abstract class NamedCompilationUnitMemberImpl extends CompilationUnitMemberImpl
+ implements NamedCompilationUnitMember {
+ /**
+ * The name of the member being declared.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * Initialize a newly created compilation unit member with the given [name].
+ * Either or both of the [comment] and [metadata] can be `null` if the member
+ * does not have the corresponding attribute.
+ */
+ NamedCompilationUnitMemberImpl(
+ Comment comment, List<Annotation> metadata, SimpleIdentifier name)
+ : super(comment, metadata) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ SimpleIdentifier get name => _name;
+
+ @override
+ void set name(SimpleIdentifier identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+}
+
+/**
+ * An expression that has a name associated with it. They are used in method
+ * invocations when there are named parameters.
+ *
+ * > namedExpression ::=
+ * > [Label] [Expression]
+ */
+class NamedExpressionImpl extends ExpressionImpl implements NamedExpression {
+ /**
+ * The name associated with the expression.
+ */
+ Label _name;
+
+ /**
+ * The expression with which the name is associated.
+ */
+ Expression _expression;
+
+ /**
+ * Initialize a newly created named expression..
+ */
+ NamedExpressionImpl(Label name, Expression expression) {
+ _name = _becomeParentOf(name);
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken => _name.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_name)..add(_expression);
+
+ @override
+ ParameterElement get element {
+ Element element = _name.label.staticElement;
+ if (element is ParameterElement) {
+ return element;
+ }
+ return null;
+ }
+
+ @override
+ Token get endToken => _expression.endToken;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Label get name => _name;
+
+ @override
+ void set name(Label identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+
+ @override
+ int get precedence => 0;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitNamedExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * A node that represents a directive that impacts the namespace of a library.
+ *
+ * > directive ::=
+ * > [ExportDirective]
+ * > | [ImportDirective]
+ */
+abstract class NamespaceDirectiveImpl extends UriBasedDirectiveImpl
+ implements NamespaceDirective {
+ /**
+ * The token representing the 'import' or 'export' keyword.
+ */
+ Token keyword;
+
+ /**
+ * The configurations used to control which library will actually be loaded at
+ * run-time.
+ */
+ NodeList<Configuration> _configurations;
+
+ /**
+ * The combinators used to control which names are imported or exported.
+ */
+ NodeList<Combinator> _combinators;
+
+ /**
+ * The semicolon terminating the directive.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created namespace directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute. The list of [combinators] can be `null` if there
+ * are no combinators.
+ */
+ NamespaceDirectiveImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.keyword,
+ StringLiteral libraryUri,
+ List<Configuration> configurations,
+ List<Combinator> combinators,
+ this.semicolon)
+ : super(comment, metadata, libraryUri) {
+ _configurations = new NodeList<Configuration>(this, configurations);
+ _combinators = new NodeList<Combinator>(this, combinators);
+ }
+
+ @override
+ NodeList<Combinator> get combinators => _combinators;
+
+ @override
+ NodeList<Configuration> get configurations => _configurations;
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => keyword;
+
+ @override
+ LibraryElement get uriElement;
+}
+
+/**
+ * The "native" clause in an class declaration.
+ *
+ * > nativeClause ::=
+ * > 'native' [StringLiteral]
+ */
+class NativeClauseImpl extends AstNodeImpl implements NativeClause {
+ /**
+ * The token representing the 'native' keyword.
+ */
+ Token nativeKeyword;
+
+ /**
+ * The name of the native object that implements the class.
+ */
+ StringLiteral _name;
+
+ /**
+ * Initialize a newly created native clause.
+ */
+ NativeClauseImpl(this.nativeKeyword, StringLiteral name) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ Token get beginToken => nativeKeyword;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(nativeKeyword)..add(_name);
+
+ @override
+ Token get endToken => _name.endToken;
+
+ @override
+ StringLiteral get name => _name;
+
+ @override
+ void set name(StringLiteral name) {
+ _name = _becomeParentOf(name);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitNativeClause(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_name, visitor);
+ }
+}
+
+/**
+ * A function body that consists of a native keyword followed by a string
+ * literal.
+ *
+ * > nativeFunctionBody ::=
+ * > 'native' [SimpleStringLiteral] ';'
+ */
+class NativeFunctionBodyImpl extends FunctionBodyImpl
+ implements NativeFunctionBody {
+ /**
+ * The token representing 'native' that marks the start of the function body.
+ */
+ Token nativeKeyword;
+
+ /**
+ * The string literal, after the 'native' token.
+ */
+ StringLiteral _stringLiteral;
+
+ /**
+ * The token representing the semicolon that marks the end of the function
+ * body.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created function body consisting of the 'native' token,
+ * a string literal, and a semicolon.
+ */
+ NativeFunctionBodyImpl(
+ this.nativeKeyword, StringLiteral stringLiteral, this.semicolon) {
+ _stringLiteral = _becomeParentOf(stringLiteral);
+ }
+
+ @override
+ Token get beginToken => nativeKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(nativeKeyword)
+ ..add(_stringLiteral)
+ ..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ StringLiteral get stringLiteral => _stringLiteral;
+
+ @override
+ void set stringLiteral(StringLiteral stringLiteral) {
+ _stringLiteral = _becomeParentOf(stringLiteral);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitNativeFunctionBody(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_stringLiteral, visitor);
+ }
+}
+
+/**
+ * A list of AST nodes that have a common parent.
+ */
+class NodeListImpl<E extends AstNode> extends Object
+ with ListMixin<E>
+ implements NodeList<E> {
+ /**
+ * The node that is the parent of each of the elements in the list.
+ */
+ AstNodeImpl owner;
+
+ /**
+ * The elements contained in the list.
+ */
+ List<E> _elements = <E>[];
+
+ /**
+ * Initialize a newly created list of nodes such that all of the nodes that
+ * are added to the list will have their parent set to the given [owner]. The
+ * list will initially be populated with the given [elements].
+ */
+ NodeListImpl(this.owner, [List<E> elements]) {
+ addAll(elements);
+ }
+
+ @override
+ Token get beginToken {
+ if (_elements.length == 0) {
+ return null;
+ }
+ return _elements[0].beginToken;
+ }
+
+ @override
+ Token get endToken {
+ int length = _elements.length;
+ if (length == 0) {
+ return null;
+ }
+ return _elements[length - 1].endToken;
+ }
+
+ int get length => _elements.length;
+
+ @deprecated // Never intended for public use.
+ @override
+ void set length(int newLength) {
+ throw new UnsupportedError("Cannot resize NodeList.");
+ }
+
+ E operator [](int index) {
+ if (index < 0 || index >= _elements.length) {
+ throw new RangeError("Index: $index, Size: ${_elements.length}");
+ }
+ return _elements[index];
+ }
+
+ void operator []=(int index, E node) {
+ if (index < 0 || index >= _elements.length) {
+ throw new RangeError("Index: $index, Size: ${_elements.length}");
+ }
+ owner._becomeParentOf(node);
+ _elements[index] = node;
+ }
+
+ @override
+ accept(AstVisitor visitor) {
+ int length = _elements.length;
+ for (var i = 0; i < length; i++) {
+ _elements[i].accept(visitor);
+ }
+ }
+
+ @override
+ void add(E node) {
+ insert(length, node);
+ }
+
+ @override
+ bool addAll(Iterable<E> nodes) {
+ if (nodes != null && !nodes.isEmpty) {
+ _elements.addAll(nodes);
+ for (E node in nodes) {
+ owner._becomeParentOf(node);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @override
+ void clear() {
+ _elements = <E>[];
+ }
+
+ @override
+ void insert(int index, E node) {
+ int length = _elements.length;
+ if (index < 0 || index > length) {
+ throw new RangeError("Index: $index, Size: ${_elements.length}");
+ }
+ owner._becomeParentOf(node);
+ if (length == 0) {
+ _elements.add(node);
+ } else {
+ _elements.insert(index, node);
+ }
+ }
+
+ @override
+ E removeAt(int index) {
+ if (index < 0 || index >= _elements.length) {
+ throw new RangeError("Index: $index, Size: ${_elements.length}");
+ }
+ E removedNode = _elements[index];
+ _elements.removeAt(index);
+ return removedNode;
+ }
+}
+
+/**
+ * A formal parameter that is required (is not optional).
+ *
+ * > normalFormalParameter ::=
+ * > [FunctionTypedFormalParameter]
+ * > | [FieldFormalParameter]
+ * > | [SimpleFormalParameter]
+ */
+abstract class NormalFormalParameterImpl extends FormalParameterImpl
+ implements NormalFormalParameter {
+ /**
+ * The documentation comment associated with this parameter, or `null` if this
+ * parameter does not have a documentation comment associated with it.
+ */
+ Comment _comment;
+
+ /**
+ * The annotations associated with this parameter.
+ */
+ NodeList<Annotation> _metadata;
+
+ /**
+ * The name of the parameter being declared.
+ */
+ SimpleIdentifier _identifier;
+
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute.
+ */
+ NormalFormalParameterImpl(
+ Comment comment, List<Annotation> metadata, SimpleIdentifier identifier) {
+ _comment = _becomeParentOf(comment);
+ _metadata = new NodeList<Annotation>(this, metadata);
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ Comment get documentationComment => _comment;
+
+ @override
+ void set documentationComment(Comment comment) {
+ _comment = _becomeParentOf(comment);
+ }
+
+ @override
+ SimpleIdentifier get identifier => _identifier;
+
+ @override
+ void set identifier(SimpleIdentifier identifier) {
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ ParameterKind get kind {
+ AstNode parent = this.parent;
+ if (parent is DefaultFormalParameter) {
+ return parent.kind;
+ }
+ return ParameterKind.REQUIRED;
+ }
+
+ @override
+ NodeList<Annotation> get metadata => _metadata;
+
+ @override
+ void set metadata(List<Annotation> metadata) {
+ _metadata.clear();
+ _metadata.addAll(metadata);
+ }
+
+ @override
+ List<AstNode> get sortedCommentAndAnnotations {
+ return <AstNode>[]
+ ..add(_comment)
+ ..addAll(_metadata)
+ ..sort(AstNode.LEXICAL_ORDER);
+ }
+
+ ChildEntities get _childEntities {
+ ChildEntities result = new ChildEntities();
+ if (_commentIsBeforeAnnotations()) {
+ result
+ ..add(_comment)
+ ..addAll(_metadata);
+ } else {
+ result.addAll(sortedCommentAndAnnotations);
+ }
+ return result;
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ //
+ // Note that subclasses are responsible for visiting the identifier because
+ // they often need to visit other nodes before visiting the identifier.
+ //
+ if (_commentIsBeforeAnnotations()) {
+ _safelyVisitChild(_comment, visitor);
+ _metadata.accept(visitor);
+ } else {
+ for (AstNode child in sortedCommentAndAnnotations) {
+ child.accept(visitor);
+ }
+ }
+ }
+
+ /**
+ * Return `true` if the comment is lexically before any annotations.
+ */
+ bool _commentIsBeforeAnnotations() {
+ if (_comment == null || _metadata.isEmpty) {
+ return true;
+ }
+ Annotation firstAnnotation = _metadata[0];
+ return _comment.offset < firstAnnotation.offset;
+ }
+}
+
+/**
+ * A null literal expression.
+ *
+ * > nullLiteral ::=
+ * > 'null'
+ */
+class NullLiteralImpl extends LiteralImpl implements NullLiteral {
+ /**
+ * The token representing the literal.
+ */
+ Token literal;
+
+ /**
+ * Initialize a newly created null literal.
+ */
+ NullLiteralImpl(this.literal);
+
+ @override
+ Token get beginToken => literal;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(literal);
+
+ @override
+ Token get endToken => literal;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitNullLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A parenthesized expression.
+ *
+ * > parenthesizedExpression ::=
+ * > '(' [Expression] ')'
+ */
+class ParenthesizedExpressionImpl extends ExpressionImpl
+ implements ParenthesizedExpression {
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The expression within the parentheses.
+ */
+ Expression _expression;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * Initialize a newly created parenthesized expression.
+ */
+ ParenthesizedExpressionImpl(
+ this.leftParenthesis, Expression expression, this.rightParenthesis) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken => leftParenthesis;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(leftParenthesis)
+ ..add(_expression)
+ ..add(rightParenthesis);
+
+ @override
+ Token get endToken => rightParenthesis;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 15;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitParenthesizedExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * A part directive.
+ *
+ * > partDirective ::=
+ * > [Annotation] 'part' [StringLiteral] ';'
+ */
+class PartDirectiveImpl extends UriBasedDirectiveImpl implements PartDirective {
+ /**
+ * The token representing the 'part' keyword.
+ */
+ Token partKeyword;
+
+ /**
+ * The semicolon terminating the directive.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created part directive. Either or both of the [comment]
+ * and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute.
+ */
+ PartDirectiveImpl(Comment comment, List<Annotation> metadata,
+ this.partKeyword, StringLiteral partUri, this.semicolon)
+ : super(comment, metadata, partUri);
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(partKeyword)..add(_uri)..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => partKeyword;
+
+ @override
+ Token get keyword => partKeyword;
+
+ @override
+ CompilationUnitElement get uriElement => element as CompilationUnitElement;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitPartDirective(this);
+}
+
+/**
+ * A part-of directive.
+ *
+ * > partOfDirective ::=
+ * > [Annotation] 'part' 'of' [Identifier] ';'
+ */
+class PartOfDirectiveImpl extends DirectiveImpl implements PartOfDirective {
+ /**
+ * The token representing the 'part' keyword.
+ */
+ Token partKeyword;
+
+ /**
+ * The token representing the 'of' keyword.
+ */
+ Token ofKeyword;
+
+ /**
+ * The name of the library that the containing compilation unit is part of.
+ */
+ LibraryIdentifier _libraryName;
+
+ /**
+ * The semicolon terminating the directive.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created part-of directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute.
+ */
+ PartOfDirectiveImpl(
+ Comment comment,
+ List<Annotation> metadata,
+ this.partKeyword,
+ this.ofKeyword,
+ LibraryIdentifier libraryName,
+ this.semicolon)
+ : super(comment, metadata) {
+ _libraryName = _becomeParentOf(libraryName);
+ }
+
+ @override
+ Iterable get childEntities => super._childEntities
+ ..add(partKeyword)
+ ..add(ofKeyword)
+ ..add(_libraryName)
+ ..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => partKeyword;
+
+ @override
+ Token get keyword => partKeyword;
+
+ @override
+ LibraryIdentifier get libraryName => _libraryName;
+
+ @override
+ void set libraryName(LibraryIdentifier libraryName) {
+ _libraryName = _becomeParentOf(libraryName);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitPartOfDirective(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_libraryName, visitor);
+ }
+}
+
+/**
+ * A postfix unary expression.
+ *
+ * > postfixExpression ::=
+ * > [Expression] [Token]
+ */
+class PostfixExpressionImpl extends ExpressionImpl
+ implements PostfixExpression {
+ /**
+ * The expression computing the operand for the operator.
+ */
+ Expression _operand;
+
+ /**
+ * The postfix operator being applied to the operand.
+ */
+ Token operator;
+
+ /**
+ * The element associated with this the operator based on the propagated type
+ * of the operand, or `null` if the AST structure has not been resolved, if
+ * the operator is not user definable, or if the operator could not be
+ * resolved.
+ */
+ MethodElement propagatedElement;
+
+ /**
+ * The element associated with the operator based on the static type of the
+ * operand, or `null` if the AST structure has not been resolved, if the
+ * operator is not user definable, or if the operator could not be resolved.
+ */
+ MethodElement staticElement;
+
+ /**
+ * Initialize a newly created postfix expression.
+ */
+ PostfixExpressionImpl(Expression operand, this.operator) {
+ _operand = _becomeParentOf(operand);
+ }
+
+ @override
+ Token get beginToken => _operand.beginToken;
+
+ @override
+ MethodElement get bestElement {
+ MethodElement element = propagatedElement;
+ if (element == null) {
+ element = staticElement;
+ }
+ return element;
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_operand)..add(operator);
+
+ @override
+ Token get endToken => operator;
+
+ @override
+ Expression get operand => _operand;
+
+ @override
+ void set operand(Expression expression) {
+ _operand = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 15;
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on propagated type information, then return the parameter
+ * element representing the parameter to which the value of the operand will
+ * be bound. Otherwise, return `null`.
+ */
+ ParameterElement get _propagatedParameterElementForOperand {
+ if (propagatedElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = propagatedElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on static type information, then return the parameter element
+ * representing the parameter to which the value of the operand will be bound.
+ * Otherwise, return `null`.
+ */
+ ParameterElement get _staticParameterElementForOperand {
+ if (staticElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = staticElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitPostfixExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_operand, visitor);
+ }
+}
+
+/**
+ * An identifier that is prefixed or an access to an object property where the
+ * target of the property access is a simple identifier.
+ *
+ * > prefixedIdentifier ::=
+ * > [SimpleIdentifier] '.' [SimpleIdentifier]
+ */
+class PrefixedIdentifierImpl extends IdentifierImpl
+ implements PrefixedIdentifier {
+ /**
+ * The prefix associated with the library in which the identifier is defined.
+ */
+ SimpleIdentifier _prefix;
+
+ /**
+ * The period used to separate the prefix from the identifier.
+ */
+ Token period;
+
+ /**
+ * The identifier being prefixed.
+ */
+ SimpleIdentifier _identifier;
+
+ /**
+ * Initialize a newly created prefixed identifier.
+ */
+ PrefixedIdentifierImpl(
+ SimpleIdentifier prefix, this.period, SimpleIdentifier identifier) {
+ _prefix = _becomeParentOf(prefix);
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ Token get beginToken => _prefix.beginToken;
+
+ @override
+ Element get bestElement {
+ if (_identifier == null) {
+ return null;
+ }
+ return _identifier.bestElement;
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_prefix)..add(period)..add(_identifier);
+
+ @override
+ Token get endToken => _identifier.endToken;
+
+ @override
+ SimpleIdentifier get identifier => _identifier;
+
+ @override
+ void set identifier(SimpleIdentifier identifier) {
+ _identifier = _becomeParentOf(identifier);
+ }
+
+ @override
+ bool get isDeferred {
+ Element element = _prefix.staticElement;
+ if (element is! PrefixElement) {
+ return false;
+ }
+ PrefixElement prefixElement = element as PrefixElement;
+ List<ImportElement> imports =
+ prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
+ if (imports.length != 1) {
+ return false;
+ }
+ return imports[0].isDeferred;
+ }
+
+ @override
+ String get name => "${_prefix.name}.${_identifier.name}";
+
+ @override
+ int get precedence => 15;
+
+ @override
+ SimpleIdentifier get prefix => _prefix;
+
+ @override
+ void set prefix(SimpleIdentifier identifier) {
+ _prefix = _becomeParentOf(identifier);
+ }
+
+ @override
+ Element get propagatedElement {
+ if (_identifier == null) {
+ return null;
+ }
+ return _identifier.propagatedElement;
+ }
+
+ @override
+ Element get staticElement {
+ if (_identifier == null) {
+ return null;
+ }
+ return _identifier.staticElement;
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitPrefixedIdentifier(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_prefix, visitor);
+ _safelyVisitChild(_identifier, visitor);
+ }
+}
+
+/**
+ * A prefix unary expression.
+ *
+ * > prefixExpression ::=
+ * > [Token] [Expression]
+ */
+class PrefixExpressionImpl extends ExpressionImpl implements PrefixExpression {
+ /**
+ * The prefix operator being applied to the operand.
+ */
+ Token operator;
+
+ /**
+ * The expression computing the operand for the operator.
+ */
+ Expression _operand;
+
+ /**
+ * The element associated with the operator based on the static type of the
+ * operand, or `null` if the AST structure has not been resolved, if the
+ * operator is not user definable, or if the operator could not be resolved.
+ */
+ MethodElement staticElement;
+
+ /**
+ * The element associated with the operator based on the propagated type of
+ * the operand, or `null` if the AST structure has not been resolved, if the
+ * operator is not user definable, or if the operator could not be resolved.
+ */
+ MethodElement propagatedElement;
+
+ /**
+ * Initialize a newly created prefix expression.
+ */
+ PrefixExpressionImpl(this.operator, Expression operand) {
+ _operand = _becomeParentOf(operand);
+ }
+
+ @override
+ Token get beginToken => operator;
+
+ @override
+ MethodElement get bestElement {
+ MethodElement element = propagatedElement;
+ if (element == null) {
+ element = staticElement;
+ }
+ return element;
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(operator)..add(_operand);
+
+ @override
+ Token get endToken => _operand.endToken;
+
+ @override
+ Expression get operand => _operand;
+
+ @override
+ void set operand(Expression expression) {
+ _operand = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 14;
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on propagated type information, then return the parameter
+ * element representing the parameter to which the value of the operand will
+ * be bound. Otherwise, return `null`.
+ */
+ ParameterElement get _propagatedParameterElementForOperand {
+ if (propagatedElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = propagatedElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ /**
+ * If the AST structure has been resolved, and the function being invoked is
+ * known based on static type information, then return the parameter element
+ * representing the parameter to which the value of the operand will be bound.
+ * Otherwise, return `null`.
+ */
+ ParameterElement get _staticParameterElementForOperand {
+ if (staticElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = staticElement.parameters;
+ if (parameters.length < 1) {
+ return null;
+ }
+ return parameters[0];
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitPrefixExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_operand, visitor);
+ }
+}
+
+/**
+ * The access of a property of an object.
+ *
+ * Note, however, that accesses to properties of objects can also be represented
+ * as [PrefixedIdentifier] nodes in cases where the target is also a simple
+ * identifier.
+ *
+ * > propertyAccess ::=
+ * > [Expression] '.' [SimpleIdentifier]
+ */
+class PropertyAccessImpl extends ExpressionImpl implements PropertyAccess {
+ /**
+ * The expression computing the object defining the property being accessed.
+ */
+ Expression _target;
+
+ /**
+ * The property access operator.
+ */
+ Token operator;
+
+ /**
+ * The name of the property being accessed.
+ */
+ SimpleIdentifier _propertyName;
+
+ /**
+ * Initialize a newly created property access expression.
+ */
+ PropertyAccessImpl(
+ Expression target, this.operator, SimpleIdentifier propertyName) {
+ _target = _becomeParentOf(target);
+ _propertyName = _becomeParentOf(propertyName);
+ }
+
+ @override
+ Token get beginToken {
+ if (_target != null) {
+ return _target.beginToken;
+ }
+ return operator;
+ }
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_target)..add(operator)..add(_propertyName);
+
+ @override
+ Token get endToken => _propertyName.endToken;
+
+ @override
+ bool get isAssignable => true;
+
+ @override
+ bool get isCascaded =>
+ operator != null && operator.type == TokenType.PERIOD_PERIOD;
+
+ @override
+ int get precedence => 15;
+
+ @override
+ SimpleIdentifier get propertyName => _propertyName;
+
+ @override
+ void set propertyName(SimpleIdentifier identifier) {
+ _propertyName = _becomeParentOf(identifier);
+ }
+
+ @override
+ Expression get realTarget {
+ if (isCascaded) {
+ AstNode ancestor = parent;
+ while (ancestor is! CascadeExpression) {
+ if (ancestor == null) {
+ return _target;
+ }
+ ancestor = ancestor.parent;
+ }
+ return (ancestor as CascadeExpression).target;
+ }
+ return _target;
+ }
+
+ @override
+ Expression get target => _target;
+
+ @override
+ void set target(Expression expression) {
+ _target = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitPropertyAccess(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_target, visitor);
+ _safelyVisitChild(_propertyName, visitor);
+ }
+}
+
+/**
+ * The invocation of a constructor in the same class from within a constructor's
+ * initialization list.
+ *
+ * > redirectingConstructorInvocation ::=
+ * > 'this' ('.' identifier)? arguments
+ */
+class RedirectingConstructorInvocationImpl extends ConstructorInitializerImpl
+ implements RedirectingConstructorInvocation {
+ /**
+ * The token for the 'this' keyword.
+ */
+ Token thisKeyword;
+
+ /**
+ * The token for the period before the name of the constructor that is being
+ * invoked, or `null` if the unnamed constructor is being invoked.
+ */
+ Token period;
+
+ /**
+ * The name of the constructor that is being invoked, or `null` if the unnamed
+ * constructor is being invoked.
+ */
+ SimpleIdentifier _constructorName;
+
+ /**
+ * The list of arguments to the constructor.
+ */
+ ArgumentList _argumentList;
+
+ /**
+ * The element associated with the constructor based on static type
+ * information, or `null` if the AST structure has not been resolved or if the
+ * constructor could not be resolved.
+ */
+ ConstructorElement staticElement;
+
+ /**
+ * Initialize a newly created redirecting invocation to invoke the constructor
+ * with the given name with the given arguments. The [constructorName] can be
+ * `null` if the constructor being invoked is the unnamed constructor.
+ */
+ RedirectingConstructorInvocationImpl(this.thisKeyword, this.period,
+ SimpleIdentifier constructorName, ArgumentList argumentList) {
+ _constructorName = _becomeParentOf(constructorName);
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ ArgumentList get argumentList => _argumentList;
+
+ @override
+ void set argumentList(ArgumentList argumentList) {
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ Token get beginToken => thisKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(thisKeyword)
+ ..add(period)
+ ..add(_constructorName)
+ ..add(_argumentList);
+
+ @override
+ SimpleIdentifier get constructorName => _constructorName;
+
+ @override
+ void set constructorName(SimpleIdentifier identifier) {
+ _constructorName = _becomeParentOf(identifier);
+ }
+
+ @override
+ Token get endToken => _argumentList.endToken;
+
+ @override
+ accept(AstVisitor visitor) =>
+ visitor.visitRedirectingConstructorInvocation(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_constructorName, visitor);
+ _safelyVisitChild(_argumentList, visitor);
+ }
+}
+
+/**
+ * A rethrow expression.
+ *
+ * > rethrowExpression ::=
+ * > 'rethrow'
+ */
+class RethrowExpressionImpl extends ExpressionImpl
+ implements RethrowExpression {
+ /**
+ * The token representing the 'rethrow' keyword.
+ */
+ Token rethrowKeyword;
+
+ /**
+ * Initialize a newly created rethrow expression.
+ */
+ RethrowExpressionImpl(this.rethrowKeyword);
+
+ @override
+ Token get beginToken => rethrowKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(rethrowKeyword);
+
+ @override
+ Token get endToken => rethrowKeyword;
+
+ @override
+ int get precedence => 0;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitRethrowExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A return statement.
+ *
+ * > returnStatement ::=
+ * > 'return' [Expression]? ';'
+ */
+class ReturnStatementImpl extends StatementImpl implements ReturnStatement {
+ /**
+ * The token representing the 'return' keyword.
+ */
+ Token returnKeyword;
+
+ /**
+ * The expression computing the value to be returned, or `null` if no explicit
+ * value was provided.
+ */
+ Expression _expression;
+
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created return statement. The [expression] can be `null`
+ * if no explicit value was provided.
+ */
+ ReturnStatementImpl(
+ this.returnKeyword, Expression expression, this.semicolon) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken => returnKeyword;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(returnKeyword)..add(_expression)..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitReturnStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * A script tag that can optionally occur at the beginning of a compilation unit.
+ *
+ * > scriptTag ::=
+ * > '#!' (~NEWLINE)* NEWLINE
+ */
+class ScriptTagImpl extends AstNodeImpl implements ScriptTag {
+ /**
+ * The token representing this script tag.
+ */
+ Token scriptTag;
+
+ /**
+ * Initialize a newly created script tag.
+ */
+ ScriptTagImpl(this.scriptTag);
+
+ @override
+ Token get beginToken => scriptTag;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(scriptTag);
+
+ @override
+ Token get endToken => scriptTag;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitScriptTag(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A combinator that restricts the names being imported to those in a given list.
+ *
+ * > showCombinator ::=
+ * > 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ */
+class ShowCombinatorImpl extends CombinatorImpl implements ShowCombinator {
+ /**
+ * The list of names from the library that are made visible by this combinator.
+ */
+ NodeList<SimpleIdentifier> _shownNames;
+
+ /**
+ * Initialize a newly created import show combinator.
+ */
+ ShowCombinatorImpl(Token keyword, List<SimpleIdentifier> shownNames)
+ : super(keyword) {
+ _shownNames = new NodeList<SimpleIdentifier>(this, shownNames);
+ }
+
+ @override
+ // TODO(paulberry): add commas.
+ Iterable get childEntities => new ChildEntities()
+ ..add(keyword)
+ ..addAll(_shownNames);
+
+ @override
+ Token get endToken => _shownNames.endToken;
+
+ @override
+ NodeList<SimpleIdentifier> get shownNames => _shownNames;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitShowCombinator(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _shownNames.accept(visitor);
+ }
+}
+
+/**
+ * A simple formal parameter.
+ *
+ * > simpleFormalParameter ::=
+ * > ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ */
+class SimpleFormalParameterImpl extends NormalFormalParameterImpl
+ implements SimpleFormalParameter {
+ /**
+ * The token representing either the 'final', 'const' or 'var' keyword, or
+ * `null` if no keyword was used.
+ */
+ Token keyword;
+
+ /**
+ * The name of the declared type of the parameter, or `null` if the parameter
+ * does not have a declared type.
+ */
+ TypeName _type;
+
+ /**
+ * Initialize a newly created formal parameter. Either or both of the
+ * [comment] and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [keyword] can be `null` if a type was
+ * specified. The [type] must be `null` if the keyword is 'var'.
+ */
+ SimpleFormalParameterImpl(Comment comment, List<Annotation> metadata,
+ this.keyword, TypeName type, SimpleIdentifier identifier)
+ : super(comment, metadata, identifier) {
+ _type = _becomeParentOf(type);
+ }
+
+ @override
+ Token get beginToken {
+ NodeList<Annotation> metadata = this.metadata;
+ if (!metadata.isEmpty) {
+ return metadata.beginToken;
+ } else if (keyword != null) {
+ return keyword;
+ } else if (_type != null) {
+ return _type.beginToken;
+ }
+ return identifier.beginToken;
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(keyword)..add(_type)..add(identifier);
+
+ @override
+ Token get endToken => identifier.endToken;
+
+ @override
+ bool get isConst =>
+ (keyword is KeywordToken) &&
+ (keyword as KeywordToken).keyword == Keyword.CONST;
+
+ @override
+ bool get isFinal =>
+ (keyword is KeywordToken) &&
+ (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+ @override
+ TypeName get type => _type;
+
+ @override
+ void set type(TypeName typeName) {
+ _type = _becomeParentOf(typeName);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSimpleFormalParameter(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_type, visitor);
+ _safelyVisitChild(identifier, visitor);
+ }
+}
+
+/**
+ * A simple identifier.
+ *
+ * > simpleIdentifier ::=
+ * > initialCharacter internalCharacter*
+ * >
+ * > initialCharacter ::= '_' | '$' | letter
+ * >
+ * > internalCharacter ::= '_' | '$' | letter | digit
+ */
+class SimpleIdentifierImpl extends IdentifierImpl implements SimpleIdentifier {
+ /**
+ * The token representing the identifier.
+ */
+ Token token;
+
+ /**
+ * The element associated with this identifier based on static type
+ * information, or `null` if the AST structure has not been resolved or if
+ * this identifier could not be resolved.
+ */
+ Element _staticElement;
+
+ /**
+ * The element associated with this identifier based on propagated type
+ * information, or `null` if the AST structure has not been resolved or if
+ * this identifier could not be resolved.
+ */
+ Element _propagatedElement;
+
+ /**
+ * If this expression is both in a getter and setter context, the
+ * [AuxiliaryElements] will be set to hold onto the static and propagated
+ * information. The auxiliary element will hold onto the elements from the
+ * getter context.
+ */
+ AuxiliaryElements auxiliaryElements = null;
+
+ /**
+ * Initialize a newly created identifier.
+ */
+ SimpleIdentifierImpl(this.token);
+
+ @override
+ Token get beginToken => token;
+
+ @override
+ Element get bestElement {
+ if (_propagatedElement == null) {
+ return _staticElement;
+ }
+ return _propagatedElement;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(token);
+
+ @override
+ Token get endToken => token;
+
+ @override
+ bool get isQualified {
+ AstNode parent = this.parent;
+ if (parent is PrefixedIdentifier) {
+ return identical(parent.identifier, this);
+ }
+ if (parent is PropertyAccess) {
+ return identical(parent.propertyName, this);
+ }
+ if (parent is MethodInvocation) {
+ MethodInvocation invocation = parent;
+ return identical(invocation.methodName, this) &&
+ invocation.realTarget != null;
+ }
+ return false;
+ }
+
+ @override
+ bool get isSynthetic => token.isSynthetic;
+
+ @override
+ String get name => token.lexeme;
+
+ @override
+ int get precedence => 16;
+
+ @override
+ Element get propagatedElement => _propagatedElement;
+
+ @override
+ void set propagatedElement(Element element) {
+ _propagatedElement = _validateElement(element);
+ }
+
+ @override
+ Element get staticElement => _staticElement;
+
+ @override
+ void set staticElement(Element element) {
+ _staticElement = _validateElement(element);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSimpleIdentifier(this);
+
+ @override
+ bool inDeclarationContext() {
+ // TODO(brianwilkerson) Convert this to a getter.
+ AstNode parent = this.parent;
+ if (parent is CatchClause) {
+ CatchClause clause = parent;
+ return identical(this, clause.exceptionParameter) ||
+ identical(this, clause.stackTraceParameter);
+ } else if (parent is ClassDeclaration) {
+ return identical(this, parent.name);
+ } else if (parent is ClassTypeAlias) {
+ return identical(this, parent.name);
+ } else if (parent is ConstructorDeclaration) {
+ return identical(this, parent.name);
+ } else if (parent is DeclaredIdentifier) {
+ return identical(this, parent.identifier);
+ } else if (parent is EnumDeclaration) {
+ return identical(this, parent.name);
+ } else if (parent is EnumConstantDeclaration) {
+ return identical(this, parent.name);
+ } else if (parent is FunctionDeclaration) {
+ return identical(this, parent.name);
+ } else if (parent is FunctionTypeAlias) {
+ return identical(this, parent.name);
+ } else if (parent is ImportDirective) {
+ return identical(this, parent.prefix);
+ } else if (parent is Label) {
+ return identical(this, parent.label) &&
+ (parent.parent is LabeledStatement);
+ } else if (parent is MethodDeclaration) {
+ return identical(this, parent.name);
+ } else if (parent is FunctionTypedFormalParameter ||
+ parent is SimpleFormalParameter) {
+ return identical(this, (parent as NormalFormalParameter).identifier);
+ } else if (parent is TypeParameter) {
+ return identical(this, parent.name);
+ } else if (parent is VariableDeclaration) {
+ return identical(this, parent.name);
+ }
+ return false;
+ }
+
+ @override
+ bool inGetterContext() {
+ // TODO(brianwilkerson) Convert this to a getter.
+ AstNode parent = this.parent;
+ AstNode target = this;
+ // skip prefix
+ if (parent is PrefixedIdentifier) {
+ PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
+ if (identical(prefixed.prefix, this)) {
+ return true;
+ }
+ parent = prefixed.parent;
+ target = prefixed;
+ } else if (parent is PropertyAccess) {
+ PropertyAccess access = parent as PropertyAccess;
+ if (identical(access.target, this)) {
+ return true;
+ }
+ parent = access.parent;
+ target = access;
+ }
+ // skip label
+ if (parent is Label) {
+ return false;
+ }
+ // analyze usage
+ if (parent is AssignmentExpression) {
+ if (identical(parent.leftHandSide, target) &&
+ parent.operator.type == TokenType.EQ) {
+ return false;
+ }
+ }
+ if (parent is ForEachStatement) {
+ if (identical(parent.identifier, target)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @override
+ bool inSetterContext() {
+ // TODO(brianwilkerson) Convert this to a getter.
+ AstNode parent = this.parent;
+ AstNode target = this;
+ // skip prefix
+ if (parent is PrefixedIdentifier) {
+ PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
+ // if this is the prefix, then return false
+ if (identical(prefixed.prefix, this)) {
+ return false;
+ }
+ parent = prefixed.parent;
+ target = prefixed;
+ } else if (parent is PropertyAccess) {
+ PropertyAccess access = parent as PropertyAccess;
+ if (identical(access.target, this)) {
+ return false;
+ }
+ parent = access.parent;
+ target = access;
+ }
+ // analyze usage
+ if (parent is PrefixExpression) {
+ return parent.operator.type.isIncrementOperator;
+ } else if (parent is PostfixExpression) {
+ return true;
+ } else if (parent is AssignmentExpression) {
+ return identical(parent.leftHandSide, target);
+ } else if (parent is ForEachStatement) {
+ return identical(parent.identifier, target);
+ }
+ return false;
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+
+ /**
+ * Return the given element if it is valid, or report the problem and return
+ * `null` if it is not appropriate.
+ *
+ * The [parent] is the parent of the element, used for reporting when there is
+ * a problem.
+ * The [isValid] is `true` if the element is appropriate.
+ * The [element] is the element to be associated with this identifier.
+ */
+ Element _returnOrReportElement(
+ AstNode parent, bool isValid, Element element) {
+ if (!isValid) {
+ AnalysisEngine.instance.logger.logInformation(
+ "Internal error: attempting to set the name of a ${parent.runtimeType} to a ${element.runtimeType}",
+ new CaughtException(new AnalysisException(), null));
+ return null;
+ }
+ return element;
+ }
+
+ /**
+ * Return the given [element] if it is an appropriate element based on the
+ * parent of this identifier, or `null` if it is not appropriate.
+ */
+ Element _validateElement(Element element) {
+ if (element == null) {
+ return null;
+ }
+ AstNode parent = this.parent;
+ if (parent is ClassDeclaration && identical(parent.name, this)) {
+ return _returnOrReportElement(parent, element is ClassElement, element);
+ } else if (parent is ClassTypeAlias && identical(parent.name, this)) {
+ return _returnOrReportElement(parent, element is ClassElement, element);
+ } else if (parent is DeclaredIdentifier &&
+ identical(parent.identifier, this)) {
+ return _returnOrReportElement(
+ parent, element is LocalVariableElement, element);
+ } else if (parent is FormalParameter &&
+ identical(parent.identifier, this)) {
+ return _returnOrReportElement(
+ parent, element is ParameterElement, element);
+ } else if (parent is FunctionDeclaration && identical(parent.name, this)) {
+ return _returnOrReportElement(
+ parent, element is ExecutableElement, element);
+ } else if (parent is FunctionTypeAlias && identical(parent.name, this)) {
+ return _returnOrReportElement(
+ parent, element is FunctionTypeAliasElement, element);
+ } else if (parent is MethodDeclaration && identical(parent.name, this)) {
+ return _returnOrReportElement(
+ parent, element is ExecutableElement, element);
+ } else if (parent is TypeParameter && identical(parent.name, this)) {
+ return _returnOrReportElement(
+ parent, element is TypeParameterElement, element);
+ } else if (parent is VariableDeclaration && identical(parent.name, this)) {
+ return _returnOrReportElement(
+ parent, element is VariableElement, element);
+ }
+ return element;
+ }
+}
+
+/**
+ * A string literal expression that does not contain any interpolations.
+ *
+ * > simpleStringLiteral ::=
+ * > rawStringLiteral
+ * > | basicStringLiteral
+ * >
+ * > rawStringLiteral ::=
+ * > 'r' basicStringLiteral
+ * >
+ * > simpleStringLiteral ::=
+ * > multiLineStringLiteral
+ * > | singleLineStringLiteral
+ * >
+ * > multiLineStringLiteral ::=
+ * > "'''" characters "'''"
+ * > | '"""' characters '"""'
+ * >
+ * > singleLineStringLiteral ::=
+ * > "'" characters "'"
+ * > | '"' characters '"'
+ */
+class SimpleStringLiteralImpl extends SingleStringLiteralImpl
+ implements SimpleStringLiteral {
+ /**
+ * The token representing the literal.
+ */
+ Token literal;
+
+ /**
+ * The value of the literal.
+ */
+ String _value;
+
+ /**
+ * Initialize a newly created simple string literal.
+ */
+ SimpleStringLiteralImpl(this.literal, String value) {
+ _value = StringUtilities.intern(value);
+ }
+
+ @override
+ Token get beginToken => literal;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(literal);
+
+ @override
+ int get contentsEnd => offset + _helper.end;
+
+ @override
+ int get contentsOffset => offset + _helper.start;
+
+ @override
+ Token get endToken => literal;
+
+ @override
+ bool get isMultiline => _helper.isMultiline;
+
+ @override
+ bool get isRaw => _helper.isRaw;
+
+ @override
+ bool get isSingleQuoted => _helper.isSingleQuoted;
+
+ @override
+ bool get isSynthetic => literal.isSynthetic;
+
+ @override
+ String get value => _value;
+
+ @override
+ void set value(String string) {
+ _value = StringUtilities.intern(_value);
+ }
+
+ StringLexemeHelper get _helper {
+ return new StringLexemeHelper(literal.lexeme, true, true);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSimpleStringLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+
+ @override
+ void _appendStringValue(StringBuffer buffer) {
+ buffer.write(value);
+ }
+}
+
+/**
+ * A single string literal expression.
+ *
+ * > singleStringLiteral ::=
+ * > [SimpleStringLiteral]
+ * > | [StringInterpolation]
+ */
+abstract class SingleStringLiteralImpl extends StringLiteralImpl
+ implements SingleStringLiteral {}
+
+/**
+ * A node that represents a statement.
+ *
+ * > statement ::=
+ * > [Block]
+ * > | [VariableDeclarationStatement]
+ * > | [ForStatement]
+ * > | [ForEachStatement]
+ * > | [WhileStatement]
+ * > | [DoStatement]
+ * > | [SwitchStatement]
+ * > | [IfStatement]
+ * > | [TryStatement]
+ * > | [BreakStatement]
+ * > | [ContinueStatement]
+ * > | [ReturnStatement]
+ * > | [ExpressionStatement]
+ * > | [FunctionDeclarationStatement]
+ */
+abstract class StatementImpl extends AstNodeImpl implements Statement {
+ @override
+ Statement get unlabeled => this;
+}
+
+/**
+ * A string interpolation literal.
+ *
+ * > stringInterpolation ::=
+ * > ''' [InterpolationElement]* '''
+ * > | '"' [InterpolationElement]* '"'
+ */
+class StringInterpolationImpl extends SingleStringLiteralImpl
+ implements StringInterpolation {
+ /**
+ * The elements that will be composed to produce the resulting string.
+ */
+ NodeList<InterpolationElement> _elements;
+
+ /**
+ * Initialize a newly created string interpolation expression.
+ */
+ StringInterpolationImpl(List<InterpolationElement> elements) {
+ _elements = new NodeList<InterpolationElement>(this, elements);
+ }
+
+ @override
+ Token get beginToken => _elements.beginToken;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..addAll(_elements);
+
+ @override
+ int get contentsEnd {
+ InterpolationString element = _elements.last;
+ return element.contentsEnd;
+ }
+
+ @override
+ int get contentsOffset {
+ InterpolationString element = _elements.first;
+ return element.contentsOffset;
+ }
+
+ /**
+ * Return the elements that will be composed to produce the resulting string.
+ */
+ NodeList<InterpolationElement> get elements => _elements;
+
+ @override
+ Token get endToken => _elements.endToken;
+
+ @override
+ bool get isMultiline => _firstHelper.isMultiline;
+
+ @override
+ bool get isRaw => false;
+
+ @override
+ bool get isSingleQuoted => _firstHelper.isSingleQuoted;
+
+ StringLexemeHelper get _firstHelper {
+ InterpolationString lastString = _elements.first;
+ String lexeme = lastString.contents.lexeme;
+ return new StringLexemeHelper(lexeme, true, false);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitStringInterpolation(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _elements.accept(visitor);
+ }
+
+ @override
+ void _appendStringValue(StringBuffer buffer) {
+ throw new IllegalArgumentException();
+ }
+}
+
+/**
+ * A helper for analyzing string lexemes.
+ */
+class StringLexemeHelper {
+ final String lexeme;
+ final bool isFirst;
+ final bool isLast;
+
+ bool isRaw = false;
+ bool isSingleQuoted = false;
+ bool isMultiline = false;
+ int start = 0;
+ int end;
+
+ StringLexemeHelper(this.lexeme, this.isFirst, this.isLast) {
+ if (isFirst) {
+ isRaw = StringUtilities.startsWithChar(lexeme, 0x72);
+ if (isRaw) {
+ start++;
+ }
+ if (StringUtilities.startsWith3(lexeme, start, 0x27, 0x27, 0x27)) {
+ isSingleQuoted = true;
+ isMultiline = true;
+ start += 3;
+ start = _trimInitialWhitespace(start);
+ } else if (StringUtilities.startsWith3(lexeme, start, 0x22, 0x22, 0x22)) {
+ isSingleQuoted = false;
+ isMultiline = true;
+ start += 3;
+ start = _trimInitialWhitespace(start);
+ } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x27) {
+ isSingleQuoted = true;
+ isMultiline = false;
+ start++;
+ } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x22) {
+ isSingleQuoted = false;
+ isMultiline = false;
+ start++;
+ }
+ }
+ end = lexeme.length;
+ if (isLast) {
+ if (start + 3 <= end &&
+ (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
+ StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27))) {
+ end -= 3;
+ } else if (start + 1 <= end &&
+ (StringUtilities.endsWithChar(lexeme, 0x22) ||
+ StringUtilities.endsWithChar(lexeme, 0x27))) {
+ end -= 1;
+ }
+ }
+ }
+
+ /**
+ * Given the [lexeme] for a multi-line string whose content begins at the
+ * given [start] index, return the index of the first character that is
+ * included in the value of the string. According to the specification:
+ *
+ * If the first line of a multiline string consists solely of the whitespace
+ * characters defined by the production WHITESPACE 20.1), possibly prefixed
+ * by \, then that line is ignored, including the new line at its end.
+ */
+ int _trimInitialWhitespace(int start) {
+ int length = lexeme.length;
+ int index = start;
+ while (index < length) {
+ int currentChar = lexeme.codeUnitAt(index);
+ if (currentChar == 0x0D) {
+ if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) {
+ return index + 2;
+ }
+ return index + 1;
+ } else if (currentChar == 0x0A) {
+ return index + 1;
+ } else if (currentChar == 0x5C) {
+ if (index + 1 >= length) {
+ return start;
+ }
+ currentChar = lexeme.codeUnitAt(index + 1);
+ if (currentChar != 0x0D &&
+ currentChar != 0x0A &&
+ currentChar != 0x09 &&
+ currentChar != 0x20) {
+ return start;
+ }
+ } else if (currentChar != 0x09 && currentChar != 0x20) {
+ return start;
+ }
+ index++;
+ }
+ return start;
+ }
+}
+
+/**
+ * A string literal expression.
+ *
+ * > stringLiteral ::=
+ * > [SimpleStringLiteral]
+ * > | [AdjacentStrings]
+ * > | [StringInterpolation]
+ */
+abstract class StringLiteralImpl extends LiteralImpl implements StringLiteral {
+ @override
+ String get stringValue {
+ StringBuffer buffer = new StringBuffer();
+ try {
+ _appendStringValue(buffer);
+ } on IllegalArgumentException {
+ return null;
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Append the value of this string literal to the given [buffer]. Throw an
+ * [IllegalArgumentException] if the string is not a constant string without
+ * any string interpolation.
+ */
+ void _appendStringValue(StringBuffer buffer);
+}
+
+/**
+ * The invocation of a superclass' constructor from within a constructor's
+ * initialization list.
+ *
+ * > superInvocation ::=
+ * > 'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ */
+class SuperConstructorInvocationImpl extends ConstructorInitializerImpl
+ implements SuperConstructorInvocation {
+ /**
+ * The token for the 'super' keyword.
+ */
+ Token superKeyword;
+
+ /**
+ * The token for the period before the name of the constructor that is being
+ * invoked, or `null` if the unnamed constructor is being invoked.
+ */
+ Token period;
+
+ /**
+ * The name of the constructor that is being invoked, or `null` if the unnamed
+ * constructor is being invoked.
+ */
+ SimpleIdentifier _constructorName;
+
+ /**
+ * The list of arguments to the constructor.
+ */
+ ArgumentList _argumentList;
+
+ /**
+ * The element associated with the constructor based on static type
+ * information, or `null` if the AST structure has not been resolved or if the
+ * constructor could not be resolved.
+ */
+ ConstructorElement staticElement;
+
+ /**
+ * Initialize a newly created super invocation to invoke the inherited
+ * constructor with the given name with the given arguments. The [period] and
+ * [constructorName] can be `null` if the constructor being invoked is the
+ * unnamed constructor.
+ */
+ SuperConstructorInvocationImpl(this.superKeyword, this.period,
+ SimpleIdentifier constructorName, ArgumentList argumentList) {
+ _constructorName = _becomeParentOf(constructorName);
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ ArgumentList get argumentList => _argumentList;
+
+ @override
+ void set argumentList(ArgumentList argumentList) {
+ _argumentList = _becomeParentOf(argumentList);
+ }
+
+ @override
+ Token get beginToken => superKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(superKeyword)
+ ..add(period)
+ ..add(_constructorName)
+ ..add(_argumentList);
+
+ @override
+ SimpleIdentifier get constructorName => _constructorName;
+
+ @override
+ void set constructorName(SimpleIdentifier identifier) {
+ _constructorName = _becomeParentOf(identifier);
+ }
+
+ @override
+ Token get endToken => _argumentList.endToken;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSuperConstructorInvocation(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_constructorName, visitor);
+ _safelyVisitChild(_argumentList, visitor);
+ }
+}
+
+/**
+ * A super expression.
+ *
+ * > superExpression ::=
+ * > 'super'
+ */
+class SuperExpressionImpl extends ExpressionImpl implements SuperExpression {
+ /**
+ * The token representing the 'super' keyword.
+ */
+ Token superKeyword;
+
+ /**
+ * Initialize a newly created super expression.
+ */
+ SuperExpressionImpl(this.superKeyword);
+
+ @override
+ Token get beginToken => superKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(superKeyword);
+
+ @override
+ Token get endToken => superKeyword;
+
+ @override
+ int get precedence => 16;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSuperExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A case in a switch statement.
+ *
+ * > switchCase ::=
+ * > [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ */
+class SwitchCaseImpl extends SwitchMemberImpl implements SwitchCase {
+ /**
+ * The expression controlling whether the statements will be executed.
+ */
+ Expression _expression;
+
+ /**
+ * Initialize a newly created switch case. The list of [labels] can be `null`
+ * if there are no labels.
+ */
+ SwitchCaseImpl(List<Label> labels, Token keyword, Expression expression,
+ Token colon, List<Statement> statements)
+ : super(labels, keyword, colon, statements) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..addAll(labels)
+ ..add(keyword)
+ ..add(_expression)
+ ..add(colon)
+ ..addAll(statements);
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSwitchCase(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ labels.accept(visitor);
+ _safelyVisitChild(_expression, visitor);
+ statements.accept(visitor);
+ }
+}
+
+/**
+ * The default case in a switch statement.
+ *
+ * > switchDefault ::=
+ * > [SimpleIdentifier]* 'default' ':' [Statement]*
+ */
+class SwitchDefaultImpl extends SwitchMemberImpl implements SwitchDefault {
+ /**
+ * Initialize a newly created switch default. The list of [labels] can be
+ * `null` if there are no labels.
+ */
+ SwitchDefaultImpl(List<Label> labels, Token keyword, Token colon,
+ List<Statement> statements)
+ : super(labels, keyword, colon, statements);
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..addAll(labels)
+ ..add(keyword)
+ ..add(colon)
+ ..addAll(statements);
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSwitchDefault(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ labels.accept(visitor);
+ statements.accept(visitor);
+ }
+}
+
+/**
+ * An element within a switch statement.
+ *
+ * > switchMember ::=
+ * > switchCase
+ * > | switchDefault
+ */
+abstract class SwitchMemberImpl extends AstNodeImpl implements SwitchMember {
+ /**
+ * The labels associated with the switch member.
+ */
+ NodeList<Label> _labels;
+
+ /**
+ * The token representing the 'case' or 'default' keyword.
+ */
+ Token keyword;
+
+ /**
+ * The colon separating the keyword or the expression from the statements.
+ */
+ Token colon;
+
+ /**
+ * The statements that will be executed if this switch member is selected.
+ */
+ NodeList<Statement> _statements;
+
+ /**
+ * Initialize a newly created switch member. The list of [labels] can be
+ * `null` if there are no labels.
+ */
+ SwitchMemberImpl(List<Label> labels, this.keyword, this.colon,
+ List<Statement> statements) {
+ _labels = new NodeList<Label>(this, labels);
+ _statements = new NodeList<Statement>(this, statements);
+ }
+
+ @override
+ Token get beginToken {
+ if (!_labels.isEmpty) {
+ return _labels.beginToken;
+ }
+ return keyword;
+ }
+
+ @override
+ Token get endToken {
+ if (!_statements.isEmpty) {
+ return _statements.endToken;
+ }
+ return colon;
+ }
+
+ @override
+ NodeList<Label> get labels => _labels;
+
+ @override
+ NodeList<Statement> get statements => _statements;
+}
+
+/**
+ * A switch statement.
+ *
+ * > switchStatement ::=
+ * > 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ */
+class SwitchStatementImpl extends StatementImpl implements SwitchStatement {
+ /**
+ * The token representing the 'switch' keyword.
+ */
+ Token switchKeyword;
+
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The expression used to determine which of the switch members will be
+ * selected.
+ */
+ Expression _expression;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The left curly bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The switch members that can be selected by the expression.
+ */
+ NodeList<SwitchMember> _members;
+
+ /**
+ * The right curly bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created switch statement. The list of [members] can be
+ * `null` if there are no switch members.
+ */
+ SwitchStatementImpl(
+ this.switchKeyword,
+ this.leftParenthesis,
+ Expression expression,
+ this.rightParenthesis,
+ this.leftBracket,
+ List<SwitchMember> members,
+ this.rightBracket) {
+ _expression = _becomeParentOf(expression);
+ _members = new NodeList<SwitchMember>(this, members);
+ }
+
+ @override
+ Token get beginToken => switchKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(switchKeyword)
+ ..add(leftParenthesis)
+ ..add(_expression)
+ ..add(rightParenthesis)
+ ..add(leftBracket)
+ ..addAll(_members)
+ ..add(rightBracket);
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ NodeList<SwitchMember> get members => _members;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSwitchStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ _members.accept(visitor);
+ }
+}
+
+/**
+ * A symbol literal expression.
+ *
+ * > symbolLiteral ::=
+ * > '#' (operator | (identifier ('.' identifier)*))
+ */
+class SymbolLiteralImpl extends LiteralImpl implements SymbolLiteral {
+ /**
+ * The token introducing the literal.
+ */
+ Token poundSign;
+
+ /**
+ * The components of the literal.
+ */
+ final List<Token> components;
+
+ /**
+ * Initialize a newly created symbol literal.
+ */
+ SymbolLiteralImpl(this.poundSign, this.components);
+
+ @override
+ Token get beginToken => poundSign;
+
+ @override
+ // TODO(paulberry): add "." tokens.
+ Iterable get childEntities => new ChildEntities()
+ ..add(poundSign)
+ ..addAll(components);
+
+ @override
+ Token get endToken => components[components.length - 1];
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitSymbolLiteral(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A this expression.
+ *
+ * > thisExpression ::=
+ * > 'this'
+ */
+class ThisExpressionImpl extends ExpressionImpl implements ThisExpression {
+ /**
+ * The token representing the 'this' keyword.
+ */
+ Token thisKeyword;
+
+ /**
+ * Initialize a newly created this expression.
+ */
+ ThisExpressionImpl(this.thisKeyword);
+
+ @override
+ Token get beginToken => thisKeyword;
+
+ @override
+ Iterable get childEntities => new ChildEntities()..add(thisKeyword);
+
+ @override
+ Token get endToken => thisKeyword;
+
+ @override
+ int get precedence => 16;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitThisExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ // There are no children to visit.
+ }
+}
+
+/**
+ * A throw expression.
+ *
+ * > throwExpression ::=
+ * > 'throw' [Expression]
+ */
+class ThrowExpressionImpl extends ExpressionImpl implements ThrowExpression {
+ /**
+ * The token representing the 'throw' keyword.
+ */
+ Token throwKeyword;
+
+ /**
+ * The expression computing the exception to be thrown.
+ */
+ Expression _expression;
+
+ /**
+ * Initialize a newly created throw expression.
+ */
+ ThrowExpressionImpl(this.throwKeyword, Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken => throwKeyword;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(throwKeyword)..add(_expression);
+
+ @override
+ Token get endToken {
+ if (_expression != null) {
+ return _expression.endToken;
+ }
+ return throwKeyword;
+ }
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ int get precedence => 0;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitThrowExpression(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
+
+/**
+ * The declaration of one or more top-level variables of the same type.
+ *
+ * > topLevelVariableDeclaration ::=
+ * > ('final' | 'const') type? staticFinalDeclarationList ';'
+ * > | variableDeclaration ';'
+ */
+class TopLevelVariableDeclarationImpl extends CompilationUnitMemberImpl
+ implements TopLevelVariableDeclaration {
+ /**
+ * The top-level variables being declared.
+ */
+ VariableDeclarationList _variableList;
+
+ /**
+ * The semicolon terminating the declaration.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created top-level variable declaration. Either or both
+ * of the [comment] and [metadata] can be `null` if the variable does not have
+ * the corresponding attribute.
+ */
+ TopLevelVariableDeclarationImpl(Comment comment, List<Annotation> metadata,
+ VariableDeclarationList variableList, this.semicolon)
+ : super(comment, metadata) {
+ _variableList = _becomeParentOf(variableList);
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(_variableList)..add(semicolon);
+
+ @override
+ Element get element => null;
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => _variableList.beginToken;
+
+ @override
+ VariableDeclarationList get variables => _variableList;
+
+ @override
+ void set variables(VariableDeclarationList variables) {
+ _variableList = _becomeParentOf(variables);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitTopLevelVariableDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_variableList, visitor);
+ }
+}
+
+/**
+ * A try statement.
+ *
+ * > tryStatement ::=
+ * > 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ * >
+ * > finallyClause ::=
+ * > 'finally' [Block]
+ */
+class TryStatementImpl extends StatementImpl implements TryStatement {
+ /**
+ * The token representing the 'try' keyword.
+ */
+ Token tryKeyword;
+
+ /**
+ * The body of the statement.
+ */
+ Block _body;
+
+ /**
+ * The catch clauses contained in the try statement.
+ */
+ NodeList<CatchClause> _catchClauses;
+
+ /**
+ * The token representing the 'finally' keyword, or `null` if the statement
+ * does not contain a finally clause.
+ */
+ Token finallyKeyword;
+
+ /**
+ * The finally block contained in the try statement, or `null` if the
+ * statement does not contain a finally clause.
+ */
+ Block _finallyBlock;
+
+ /**
+ * Initialize a newly created try statement. The list of [catchClauses] can be
+ * `null` if there are no catch clauses. The [finallyKeyword] and
+ * [finallyBlock] can be `null` if there is no finally clause.
+ */
+ TryStatementImpl(this.tryKeyword, Block body, List<CatchClause> catchClauses,
+ this.finallyKeyword, Block finallyBlock) {
+ _body = _becomeParentOf(body);
+ _catchClauses = new NodeList<CatchClause>(this, catchClauses);
+ _finallyBlock = _becomeParentOf(finallyBlock);
+ }
+
+ @override
+ Token get beginToken => tryKeyword;
+
+ @override
+ Block get body => _body;
+
+ @override
+ void set body(Block block) {
+ _body = _becomeParentOf(block);
+ }
+
+ @override
+ NodeList<CatchClause> get catchClauses => _catchClauses;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(tryKeyword)
+ ..add(_body)
+ ..addAll(_catchClauses)
+ ..add(finallyKeyword)
+ ..add(_finallyBlock);
+
+ @override
+ Token get endToken {
+ if (_finallyBlock != null) {
+ return _finallyBlock.endToken;
+ } else if (finallyKeyword != null) {
+ return finallyKeyword;
+ } else if (!_catchClauses.isEmpty) {
+ return _catchClauses.endToken;
+ }
+ return _body.endToken;
+ }
+
+ @override
+ Block get finallyBlock => _finallyBlock;
+
+ @override
+ void set finallyBlock(Block block) {
+ _finallyBlock = _becomeParentOf(block);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitTryStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_body, visitor);
+ _catchClauses.accept(visitor);
+ _safelyVisitChild(_finallyBlock, visitor);
+ }
+}
+
+/**
+ * The declaration of a type alias.
+ *
+ * > typeAlias ::=
+ * > 'typedef' typeAliasBody
+ * >
+ * > typeAliasBody ::=
+ * > classTypeAlias
+ * > | functionTypeAlias
+ */
+abstract class TypeAliasImpl extends NamedCompilationUnitMemberImpl
+ implements TypeAlias {
+ /**
+ * The token representing the 'typedef' keyword.
+ */
+ Token typedefKeyword;
+
+ /**
+ * The semicolon terminating the declaration.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created type alias. Either or both of the [comment] and
+ * [metadata] can be `null` if the declaration does not have the corresponding
+ * attribute.
+ */
+ TypeAliasImpl(Comment comment, List<Annotation> metadata, this.typedefKeyword,
+ SimpleIdentifier name, this.semicolon)
+ : super(comment, metadata, name);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => typedefKeyword;
+}
+
+/**
+ * A list of type arguments.
+ *
+ * > typeArguments ::=
+ * > '<' typeName (',' typeName)* '>'
+ */
+class TypeArgumentListImpl extends AstNodeImpl implements TypeArgumentList {
+ /**
+ * The left bracket.
+ */
+ Token leftBracket;
+
+ /**
+ * The type arguments associated with the type.
+ */
+ NodeList<TypeName> _arguments;
+
+ /**
+ * The right bracket.
+ */
+ Token rightBracket;
+
+ /**
+ * Initialize a newly created list of type arguments.
+ */
+ TypeArgumentListImpl(
+ this.leftBracket, List<TypeName> arguments, this.rightBracket) {
+ _arguments = new NodeList<TypeName>(this, arguments);
+ }
+
+ @override
+ NodeList<TypeName> get arguments => _arguments;
+
+ @override
+ Token get beginToken => leftBracket;
+
+ @override
+ // TODO(paulberry): Add commas.
+ Iterable get childEntities => new ChildEntities()
+ ..add(leftBracket)
+ ..addAll(_arguments)
+ ..add(rightBracket);
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitTypeArgumentList(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _arguments.accept(visitor);
+ }
+}
+
+/**
+ * A literal that has a type associated with it.
+ *
+ * > typedLiteral ::=
+ * > [ListLiteral]
+ * > | [MapLiteral]
+ */
+abstract class TypedLiteralImpl extends LiteralImpl implements TypedLiteral {
+ /**
+ * The token representing the 'const' keyword, or `null` if the literal is not
+ * a constant.
+ */
+ Token constKeyword;
+
+ /**
+ * The type argument associated with this literal, or `null` if no type
+ * arguments were declared.
+ */
+ TypeArgumentList _typeArguments;
+
+ /**
+ * Initialize a newly created typed literal. The [constKeyword] can be `null`\
+ * if the literal is not a constant. The [typeArguments] can be `null` if no
+ * type arguments were declared.
+ */
+ TypedLiteralImpl(this.constKeyword, TypeArgumentList typeArguments) {
+ _typeArguments = _becomeParentOf(typeArguments);
+ }
+
+ @override
+ TypeArgumentList get typeArguments => _typeArguments;
+
+ @override
+ void set typeArguments(TypeArgumentList typeArguments) {
+ _typeArguments = _becomeParentOf(typeArguments);
+ }
+
+ ChildEntities get _childEntities =>
+ new ChildEntities()..add(constKeyword)..add(_typeArguments);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_typeArguments, visitor);
+ }
+}
+
+/**
+ * The name of a type, which can optionally include type arguments.
+ *
+ * > typeName ::=
+ * > [Identifier] typeArguments?
+ */
+class TypeNameImpl extends AstNodeImpl implements TypeName {
+ /**
+ * The name of the type.
+ */
+ Identifier _name;
+
+ /**
+ * The type arguments associated with the type, or `null` if there are no type
+ * arguments.
+ */
+ TypeArgumentList _typeArguments;
+
+ /**
+ * The type being named, or `null` if the AST structure has not been resolved.
+ */
+ DartType type;
+
+ /**
+ * Initialize a newly created type name. The [typeArguments] can be `null` if
+ * there are no type arguments.
+ */
+ TypeNameImpl(Identifier name, TypeArgumentList typeArguments) {
+ _name = _becomeParentOf(name);
+ _typeArguments = _becomeParentOf(typeArguments);
+ }
+
+ @override
+ Token get beginToken => _name.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_name)..add(_typeArguments);
+
+ @override
+ Token get endToken {
+ if (_typeArguments != null) {
+ return _typeArguments.endToken;
+ }
+ return _name.endToken;
+ }
+
+ @override
+ bool get isDeferred {
+ Identifier identifier = name;
+ if (identifier is! PrefixedIdentifier) {
+ return false;
+ }
+ return (identifier as PrefixedIdentifier).isDeferred;
+ }
+
+ @override
+ bool get isSynthetic => _name.isSynthetic && _typeArguments == null;
+
+ @override
+ Identifier get name => _name;
+
+ @override
+ void set name(Identifier identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+
+ @override
+ TypeArgumentList get typeArguments => _typeArguments;
+
+ @override
+ void set typeArguments(TypeArgumentList typeArguments) {
+ _typeArguments = _becomeParentOf(typeArguments);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitTypeName(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_typeArguments, visitor);
+ }
+}
+
+/**
+ * A type parameter.
+ *
+ * > typeParameter ::=
+ * > [SimpleIdentifier] ('extends' [TypeName])?
+ */
+class TypeParameterImpl extends DeclarationImpl implements TypeParameter {
+ /**
+ * The name of the type parameter.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * The token representing the 'extends' keyword, or `null` if there is no
+ * explicit upper bound.
+ */
+ Token extendsKeyword;
+
+ /**
+ * The name of the upper bound for legal arguments, or `null` if there is no
+ * explicit upper bound.
+ */
+ TypeName _bound;
+
+ /**
+ * Initialize a newly created type parameter. Either or both of the [comment]
+ * and [metadata] can be `null` if the parameter does not have the
+ * corresponding attribute. The [extendsKeyword] and [bound] can be `null` if
+ * the parameter does not have an upper bound.
+ */
+ TypeParameterImpl(Comment comment, List<Annotation> metadata,
+ SimpleIdentifier name, this.extendsKeyword, TypeName bound)
+ : super(comment, metadata) {
+ _name = _becomeParentOf(name);
+ _bound = _becomeParentOf(bound);
+ }
+
+ @override
+ TypeName get bound => _bound;
+
+ @override
+ void set bound(TypeName typeName) {
+ _bound = _becomeParentOf(typeName);
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(_name)..add(extendsKeyword)..add(_bound);
+
+ @override
+ TypeParameterElement get element =>
+ _name != null ? (_name.staticElement as TypeParameterElement) : null;
+
+ @override
+ Token get endToken {
+ if (_bound == null) {
+ return _name.endToken;
+ }
+ return _bound.endToken;
+ }
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
+
+ @override
+ SimpleIdentifier get name => _name;
+
+ @override
+ void set name(SimpleIdentifier identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitTypeParameter(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_bound, visitor);
+ }
+}
+
+/**
+ * Type parameters within a declaration.
+ *
+ * > typeParameterList ::=
+ * > '<' [TypeParameter] (',' [TypeParameter])* '>'
+ */
+class TypeParameterListImpl extends AstNodeImpl implements TypeParameterList {
+ /**
+ * The left angle bracket.
+ */
+ final Token leftBracket;
+
+ /**
+ * The type parameters in the list.
+ */
+ NodeList<TypeParameter> _typeParameters;
+
+ /**
+ * The right angle bracket.
+ */
+ final Token rightBracket;
+
+ /**
+ * Initialize a newly created list of type parameters.
+ */
+ TypeParameterListImpl(
+ this.leftBracket, List<TypeParameter> typeParameters, this.rightBracket) {
+ _typeParameters = new NodeList<TypeParameter>(this, typeParameters);
+ }
+
+ @override
+ Token get beginToken => leftBracket;
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(leftBracket)
+ ..addAll(_typeParameters)
+ ..add(rightBracket);
+
+ @override
+ Token get endToken => rightBracket;
+
+ @override
+ NodeList<TypeParameter> get typeParameters => _typeParameters;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitTypeParameterList(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _typeParameters.accept(visitor);
+ }
+}
+
+/**
+ * A directive that references a URI.
+ *
+ * > uriBasedDirective ::=
+ * > [ExportDirective]
+ * > | [ImportDirective]
+ * > | [PartDirective]
+ */
+abstract class UriBasedDirectiveImpl extends DirectiveImpl
+ implements UriBasedDirective {
+ /**
+ * The prefix of a URI using the `dart-ext` scheme to reference a native code
+ * library.
+ */
+ static String _DART_EXT_SCHEME = "dart-ext:";
+
+ /**
+ * The URI referenced by this directive.
+ */
+ StringLiteral _uri;
+
+ /**
+ * The content of the URI.
+ */
+ String uriContent;
+
+ /**
+ * The source to which the URI was resolved.
+ */
+ Source source;
+
+ /**
+ * Initialize a newly create URI-based directive. Either or both of the
+ * [comment] and [metadata] can be `null` if the directive does not have the
+ * corresponding attribute.
+ */
+ UriBasedDirectiveImpl(
+ Comment comment, List<Annotation> metadata, StringLiteral uri)
+ : super(comment, metadata) {
+ _uri = _becomeParentOf(uri);
+ }
+
+ @override
+ StringLiteral get uri => _uri;
+
+ @override
+ void set uri(StringLiteral uri) {
+ _uri = _becomeParentOf(uri);
+ }
+
+ @override
+ UriValidationCode validate() {
+ StringLiteral uriLiteral = uri;
+ if (uriLiteral is StringInterpolation) {
+ return UriValidationCode.URI_WITH_INTERPOLATION;
+ }
+ String uriContent = this.uriContent;
+ if (uriContent == null) {
+ return UriValidationCode.INVALID_URI;
+ }
+ if (this is ImportDirective && uriContent.startsWith(_DART_EXT_SCHEME)) {
+ return UriValidationCode.URI_WITH_DART_EXT_SCHEME;
+ }
+ try {
+ parseUriWithException(Uri.encodeFull(uriContent));
+ } on URISyntaxException {
+ return UriValidationCode.INVALID_URI;
+ }
+ return null;
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_uri, visitor);
+ }
+}
+
+/**
+ * Validation codes returned by [UriBasedDirective.validate].
+ */
+class UriValidationCodeImpl implements UriValidationCode {
+ static const UriValidationCode INVALID_URI =
+ const UriValidationCodeImpl('INVALID_URI');
+
+ static const UriValidationCode URI_WITH_INTERPOLATION =
+ const UriValidationCodeImpl('URI_WITH_INTERPOLATION');
+
+ static const UriValidationCode URI_WITH_DART_EXT_SCHEME =
+ const UriValidationCodeImpl('URI_WITH_DART_EXT_SCHEME');
+
+ /**
+ * The name of the validation code.
+ */
+ final String name;
+
+ /**
+ * Initialize a newly created validation code to have the given [name].
+ */
+ const UriValidationCodeImpl(this.name);
+
+ @override
+ String toString() => name;
+}
+
+/**
+ * An identifier that has an initial value associated with it. Instances of this
+ * class are always children of the class [VariableDeclarationList].
+ *
+ * > variableDeclaration ::=
+ * > [SimpleIdentifier] ('=' [Expression])?
+ *
+ * TODO(paulberry): the grammar does not allow metadata to be associated with
+ * a VariableDeclaration, and currently we don't record comments for it either.
+ * Consider changing the class hierarchy so that [VariableDeclaration] does not
+ * extend [Declaration].
+ */
+class VariableDeclarationImpl extends DeclarationImpl
+ implements VariableDeclaration {
+ /**
+ * The name of the variable being declared.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * The equal sign separating the variable name from the initial value, or
+ * `null` if the initial value was not specified.
+ */
+ Token equals;
+
+ /**
+ * The expression used to compute the initial value for the variable, or
+ * `null` if the initial value was not specified.
+ */
+ Expression _initializer;
+
+ /**
+ * Initialize a newly created variable declaration. The [equals] and
+ * [initializer] can be `null` if there is no initializer.
+ */
+ VariableDeclarationImpl(
+ SimpleIdentifier name, this.equals, Expression initializer)
+ : super(null, null) {
+ _name = _becomeParentOf(name);
+ _initializer = _becomeParentOf(initializer);
+ }
+
+ @override
+ Iterable get childEntities =>
+ super._childEntities..add(_name)..add(equals)..add(_initializer);
+
+ /**
+ * This overridden implementation of getDocumentationComment() looks in the
+ * grandparent node for Dartdoc comments if no documentation is specifically
+ * available on the node.
+ */
+ @override
+ Comment get documentationComment {
+ Comment comment = super.documentationComment;
+ if (comment == null) {
+ if (parent != null && parent.parent != null) {
+ AstNode node = parent.parent;
+ if (node is AnnotatedNode) {
+ return node.documentationComment;
+ }
+ }
+ }
+ return comment;
+ }
+
+ @override
+ VariableElement get element =>
+ _name != null ? (_name.staticElement as VariableElement) : null;
+
+ @override
+ Token get endToken {
+ if (_initializer != null) {
+ return _initializer.endToken;
+ }
+ return _name.endToken;
+ }
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
+
+ @override
+ Expression get initializer => _initializer;
+
+ @override
+ void set initializer(Expression expression) {
+ _initializer = _becomeParentOf(expression);
+ }
+
+ @override
+ bool get isConst {
+ AstNode parent = this.parent;
+ return parent is VariableDeclarationList && parent.isConst;
+ }
+
+ @override
+ bool get isFinal {
+ AstNode parent = this.parent;
+ return parent is VariableDeclarationList && parent.isFinal;
+ }
+
+ @override
+ SimpleIdentifier get name => _name;
+
+ @override
+ void set name(SimpleIdentifier identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitVariableDeclaration(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_name, visitor);
+ _safelyVisitChild(_initializer, visitor);
+ }
+}
+
+/**
+ * The declaration of one or more variables of the same type.
+ *
+ * > variableDeclarationList ::=
+ * > finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ * >
+ * > finalConstVarOrType ::=
+ * > | 'final' [TypeName]?
+ * > | 'const' [TypeName]?
+ * > | 'var'
+ * > | [TypeName]
+ */
+class VariableDeclarationListImpl extends AnnotatedNodeImpl
+ implements VariableDeclarationList {
+ /**
+ * The token representing the 'final', 'const' or 'var' keyword, or `null` if
+ * no keyword was included.
+ */
+ Token keyword;
+
+ /**
+ * The type of the variables being declared, or `null` if no type was provided.
+ */
+ TypeName _type;
+
+ /**
+ * A list containing the individual variables being declared.
+ */
+ NodeList<VariableDeclaration> _variables;
+
+ /**
+ * Initialize a newly created variable declaration list. Either or both of the
+ * [comment] and [metadata] can be `null` if the variable list does not have
+ * the corresponding attribute. The [keyword] can be `null` if a type was
+ * specified. The [type] must be `null` if the keyword is 'var'.
+ */
+ VariableDeclarationListImpl(Comment comment, List<Annotation> metadata,
+ this.keyword, TypeName type, List<VariableDeclaration> variables)
+ : super(comment, metadata) {
+ _type = _becomeParentOf(type);
+ _variables = new NodeList<VariableDeclaration>(this, variables);
+ }
+
+ @override
+ // TODO(paulberry): include commas.
+ Iterable get childEntities => super._childEntities
+ ..add(keyword)
+ ..add(_type)
+ ..addAll(_variables);
+
+ @override
+ Token get endToken => _variables.endToken;
+
+ @override
+ Token get firstTokenAfterCommentAndMetadata {
+ if (keyword != null) {
+ return keyword;
+ } else if (_type != null) {
+ return _type.beginToken;
+ }
+ return _variables.beginToken;
+ }
+
+ @override
+ bool get isConst =>
+ keyword is KeywordToken &&
+ (keyword as KeywordToken).keyword == Keyword.CONST;
+
+ @override
+ bool get isFinal =>
+ keyword is KeywordToken &&
+ (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+ @override
+ TypeName get type => _type;
+
+ @override
+ void set type(TypeName typeName) {
+ _type = _becomeParentOf(typeName);
+ }
+
+ @override
+ NodeList<VariableDeclaration> get variables => _variables;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitVariableDeclarationList(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ super.visitChildren(visitor);
+ _safelyVisitChild(_type, visitor);
+ _variables.accept(visitor);
+ }
+}
+
+/**
+ * A list of variables that are being declared in a context where a statement is
+ * required.
+ *
+ * > variableDeclarationStatement ::=
+ * > [VariableDeclarationList] ';'
+ */
+class VariableDeclarationStatementImpl extends StatementImpl
+ implements VariableDeclarationStatement {
+ /**
+ * The variables being declared.
+ */
+ VariableDeclarationList _variableList;
+
+ /**
+ * The semicolon terminating the statement.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created variable declaration statement.
+ */
+ VariableDeclarationStatementImpl(
+ VariableDeclarationList variableList, this.semicolon) {
+ _variableList = _becomeParentOf(variableList);
+ }
+
+ @override
+ Token get beginToken => _variableList.beginToken;
+
+ @override
+ Iterable get childEntities =>
+ new ChildEntities()..add(_variableList)..add(semicolon);
+
+ @override
+ Token get endToken => semicolon;
+
+ @override
+ VariableDeclarationList get variables => _variableList;
+
+ @override
+ void set variables(VariableDeclarationList variables) {
+ _variableList = _becomeParentOf(variables);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitVariableDeclarationStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_variableList, visitor);
+ }
+}
+
+/**
+ * A while statement.
+ *
+ * > whileStatement ::=
+ * > 'while' '(' [Expression] ')' [Statement]
+ */
+class WhileStatementImpl extends StatementImpl implements WhileStatement {
+ /**
+ * The token representing the 'while' keyword.
+ */
+ Token whileKeyword;
+
+ /**
+ * The left parenthesis.
+ */
+ Token leftParenthesis;
+
+ /**
+ * The expression used to determine whether to execute the body of the loop.
+ */
+ Expression _condition;
+
+ /**
+ * The right parenthesis.
+ */
+ Token rightParenthesis;
+
+ /**
+ * The body of the loop.
+ */
+ Statement _body;
+
+ /**
+ * Initialize a newly created while statement.
+ */
+ WhileStatementImpl(this.whileKeyword, this.leftParenthesis,
+ Expression condition, this.rightParenthesis, Statement body) {
+ _condition = _becomeParentOf(condition);
+ _body = _becomeParentOf(body);
+ }
+
+ @override
+ Token get beginToken => whileKeyword;
+
+ @override
+ Statement get body => _body;
+
+ @override
+ void set body(Statement statement) {
+ _body = _becomeParentOf(statement);
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(whileKeyword)
+ ..add(leftParenthesis)
+ ..add(_condition)
+ ..add(rightParenthesis)
+ ..add(_body);
+
+ @override
+ Expression get condition => _condition;
+
+ @override
+ void set condition(Expression expression) {
+ _condition = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get endToken => _body.endToken;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitWhileStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_condition, visitor);
+ _safelyVisitChild(_body, visitor);
+ }
+}
+
+/**
+ * The with clause in a class declaration.
+ *
+ * > withClause ::=
+ * > 'with' [TypeName] (',' [TypeName])*
+ */
+class WithClauseImpl extends AstNodeImpl implements WithClause {
+ /**
+ * The token representing the 'with' keyword.
+ */
+ Token withKeyword;
+
+ /**
+ * The names of the mixins that were specified.
+ */
+ NodeList<TypeName> _mixinTypes;
+
+ /**
+ * Initialize a newly created with clause.
+ */
+ WithClauseImpl(this.withKeyword, List<TypeName> mixinTypes) {
+ _mixinTypes = new NodeList<TypeName>(this, mixinTypes);
+ }
+
+ @override
+ Token get beginToken => withKeyword;
+
+ @override
+ // TODO(paulberry): add commas.
+ Iterable get childEntities => new ChildEntities()
+ ..add(withKeyword)
+ ..addAll(_mixinTypes);
+
+ @override
+ Token get endToken => _mixinTypes.endToken;
+
+ @override
+ NodeList<TypeName> get mixinTypes => _mixinTypes;
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitWithClause(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _mixinTypes.accept(visitor);
+ }
+}
+
+/**
+ * A yield statement.
+ *
+ * > yieldStatement ::=
+ * > 'yield' '*'? [Expression] ‘;’
+ */
+class YieldStatementImpl extends StatementImpl implements YieldStatement {
+ /**
+ * The 'yield' keyword.
+ */
+ Token yieldKeyword;
+
+ /**
+ * The star optionally following the 'yield' keyword.
+ */
+ Token star;
+
+ /**
+ * The expression whose value will be yielded.
+ */
+ Expression _expression;
+
+ /**
+ * The semicolon following the expression.
+ */
+ Token semicolon;
+
+ /**
+ * Initialize a newly created yield expression. The [star] can be `null` if no
+ * star was provided.
+ */
+ YieldStatementImpl(
+ this.yieldKeyword, this.star, Expression expression, this.semicolon) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ Token get beginToken {
+ if (yieldKeyword != null) {
+ return yieldKeyword;
+ }
+ return _expression.beginToken;
+ }
+
+ @override
+ Iterable get childEntities => new ChildEntities()
+ ..add(yieldKeyword)
+ ..add(star)
+ ..add(_expression)
+ ..add(semicolon);
+
+ @override
+ Token get endToken {
+ if (semicolon != null) {
+ return semicolon;
+ }
+ return _expression.endToken;
+ }
+
+ @override
+ Expression get expression => _expression;
+
+ @override
+ void set expression(Expression expression) {
+ _expression = _becomeParentOf(expression);
+ }
+
+ @override
+ accept(AstVisitor visitor) => visitor.visitYieldStatement(this);
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ _safelyVisitChild(_expression, visitor);
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index f0435eb..1a21746 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -2,13 +2,13 @@
// 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 analyzer.src.generated.ast;
+library analyzer.src.dart.ast.utilities;
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/java_engine.dart';
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 71030e7..e319acf 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -7,11 +7,12 @@
import 'dart:collection';
import 'dart:math' show min;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart'
show DartObject, EvaluationResultImpl;
import 'package:analyzer/src/generated/engine.dart'
@@ -335,7 +336,22 @@
}
@override
- bool get isValidMixin => hasModifier(Modifier.MIXIN);
+ bool get isValidMixin {
+ if (!context.analysisOptions.enableSuperMixins) {
+ if (hasReferenceToSuper) {
+ return false;
+ }
+ if (!supertype.isObject) {
+ return false;
+ }
+ }
+ for (ConstructorElement constructor in constructors) {
+ if (!constructor.isSynthetic && !constructor.isFactory) {
+ return false;
+ }
+ }
+ return true;
+ }
@override
ElementKind get kind => ElementKind.CLASS;
@@ -385,13 +401,6 @@
return null;
}
- /**
- * Set whether this class is a valid mixin.
- */
- void set validMixin(bool isValidMixin) {
- setModifier(Modifier.MIXIN, isValidMixin);
- }
-
@override
accept(ElementVisitor visitor) => visitor.visitClassElement(this);
@@ -2511,6 +2520,13 @@
*/
FieldFormalParameterElementImpl(Identifier name) : super.forNode(name);
+ /**
+ * Initialize a newly created parameter element to have the given [name] and
+ * [offset].
+ */
+ FieldFormalParameterElementImpl.forNameAndOffset(String name, int nameOffset)
+ : super(name, nameOffset);
+
@override
bool get isInitializingFormal => true;
@@ -3095,6 +3111,9 @@
entryPoint != null && isOrImportsBrowserLibrary;
@override
+ bool get isDartAsync => name == "dart.async";
+
+ @override
bool get isDartCore => name == "dart.core";
@override
@@ -3641,6 +3660,148 @@
}
/**
+ * The enumeration `Modifier` defines constants for all of the modifiers defined
+ * by the Dart language and for a few additional flags that are useful.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Modifier extends Enum<Modifier> {
+ /**
+ * Indicates that the modifier 'abstract' was applied to the element.
+ */
+ static const Modifier ABSTRACT = const Modifier('ABSTRACT', 0);
+
+ /**
+ * Indicates that an executable element has a body marked as being
+ * asynchronous.
+ */
+ static const Modifier ASYNCHRONOUS = const Modifier('ASYNCHRONOUS', 1);
+
+ /**
+ * Indicates that the modifier 'const' was applied to the element.
+ */
+ static const Modifier CONST = const Modifier('CONST', 2);
+
+ /**
+ * Indicates that the import element represents a deferred library.
+ */
+ static const Modifier DEFERRED = const Modifier('DEFERRED', 3);
+
+ /**
+ * Indicates that a class element was defined by an enum declaration.
+ */
+ static const Modifier ENUM = const Modifier('ENUM', 4);
+
+ /**
+ * Indicates that a class element was defined by an enum declaration.
+ */
+ static const Modifier EXTERNAL = const Modifier('EXTERNAL', 5);
+
+ /**
+ * Indicates that the modifier 'factory' was applied to the element.
+ */
+ static const Modifier FACTORY = const Modifier('FACTORY', 6);
+
+ /**
+ * Indicates that the modifier 'final' was applied to the element.
+ */
+ static const Modifier FINAL = const Modifier('FINAL', 7);
+
+ /**
+ * Indicates that an executable element has a body marked as being a
+ * generator.
+ */
+ static const Modifier GENERATOR = const Modifier('GENERATOR', 8);
+
+ /**
+ * Indicates that the pseudo-modifier 'get' was applied to the element.
+ */
+ static const Modifier GETTER = const Modifier('GETTER', 9);
+
+ /**
+ * A flag used for libraries indicating that the defining compilation unit
+ * contains at least one import directive whose URI uses the "dart-ext"
+ * scheme.
+ */
+ static const Modifier HAS_EXT_URI = const Modifier('HAS_EXT_URI', 10);
+
+ /**
+ * Indicates that the associated element did not have an explicit type
+ * associated with it. If the element is an [ExecutableElement], then the
+ * type being referred to is the return type.
+ */
+ static const Modifier IMPLICIT_TYPE = const Modifier('IMPLICIT_TYPE', 11);
+
+ /**
+ * Indicates that a class is a mixin application.
+ */
+ static const Modifier MIXIN_APPLICATION =
+ const Modifier('MIXIN_APPLICATION', 12);
+
+ /**
+ * Indicates that the value of a parameter or local variable might be mutated
+ * within the context.
+ */
+ static const Modifier POTENTIALLY_MUTATED_IN_CONTEXT =
+ const Modifier('POTENTIALLY_MUTATED_IN_CONTEXT', 13);
+
+ /**
+ * Indicates that the value of a parameter or local variable might be mutated
+ * within the scope.
+ */
+ static const Modifier POTENTIALLY_MUTATED_IN_SCOPE =
+ const Modifier('POTENTIALLY_MUTATED_IN_SCOPE', 14);
+
+ /**
+ * Indicates that a class contains an explicit reference to 'super'.
+ */
+ static const Modifier REFERENCES_SUPER =
+ const Modifier('REFERENCES_SUPER', 15);
+
+ /**
+ * Indicates that the pseudo-modifier 'set' was applied to the element.
+ */
+ static const Modifier SETTER = const Modifier('SETTER', 16);
+
+ /**
+ * Indicates that the modifier 'static' was applied to the element.
+ */
+ static const Modifier STATIC = const Modifier('STATIC', 17);
+
+ /**
+ * Indicates that the element does not appear in the source code but was
+ * implicitly created. For example, if a class does not define any
+ * constructors, an implicit zero-argument constructor will be created and it
+ * will be marked as being synthetic.
+ */
+ static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 18);
+
+ static const List<Modifier> values = const [
+ ABSTRACT,
+ ASYNCHRONOUS,
+ CONST,
+ DEFERRED,
+ ENUM,
+ EXTERNAL,
+ FACTORY,
+ FINAL,
+ GENERATOR,
+ GETTER,
+ HAS_EXT_URI,
+ IMPLICIT_TYPE,
+ MIXIN_APPLICATION,
+ POTENTIALLY_MUTATED_IN_CONTEXT,
+ POTENTIALLY_MUTATED_IN_SCOPE,
+ REFERENCES_SUPER,
+ SETTER,
+ STATIC,
+ SYNTHETIC
+ ];
+
+ const Modifier(String name, int ordinal) : super(name, ordinal);
+}
+
+/**
* A concrete implementation of a [MultiplyDefinedElement].
*/
class MultiplyDefinedElementImpl implements MultiplyDefinedElement {
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 75dcee6..bc073d8 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -4,11 +4,11 @@
library analyzer.src.dart.element.member;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart'
show DartObject, EvaluationResultImpl;
import 'package:analyzer/src/generated/engine.dart'
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index b804339..0f8ec27 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -14,6 +14,7 @@
show AnalysisContext, AnalysisEngine, AnalysisException;
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/scanner.dart' show Keyword;
+import 'package:analyzer/src/generated/type_system.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
/**
@@ -234,15 +235,6 @@
List<TypeParameterElement> get boundTypeParameters => typeFormals;
@override
- List<TypeParameterElement> get typeFormals {
- if (_isInstantiated) {
- return TypeParameterElement.EMPTY_LIST;
- } else {
- return element?.typeParameters ?? TypeParameterElement.EMPTY_LIST;
- }
- }
-
- @override
String get displayName {
String name = this.name;
if (name == null || name.length == 0) {
@@ -496,6 +488,15 @@
}
@override
+ List<TypeParameterElement> get typeFormals {
+ if (_isInstantiated) {
+ return TypeParameterElement.EMPTY_LIST;
+ } else {
+ return element?.typeParameters ?? TypeParameterElement.EMPTY_LIST;
+ }
+ }
+
+ @override
List<TypeParameterElement> get typeParameters {
if (_typeParameters == null) {
// Combine the generic type variables from all enclosing contexts, except
@@ -1194,6 +1195,15 @@
}
@override
+ bool get isDartAsyncFuture {
+ ClassElement element = this.element;
+ if (element == null) {
+ return false;
+ }
+ return element.name == "Future" && element.library.isDartAsync;
+ }
+
+ @override
bool get isDartCoreFunction {
ClassElement element = this.element;
if (element == null) {
@@ -1280,6 +1290,35 @@
}
@override
+ DartType flattenFutures(TypeSystem typeSystem) {
+ // Implement the case: "If T = Future<S> then flatten(T) = flatten(S)."
+ if (isDartAsyncFuture && typeArguments.isNotEmpty) {
+ return typeArguments[0].flattenFutures(typeSystem);
+ }
+
+ // Implement the case: "Otherwise if T <: Future then let S be a type
+ // such that T << Future<S> and for all R, if T << Future<R> then S << R.
+ // Then flatten(T) = S."
+ //
+ // In other words, given the set of all types R such that T << Future<R>,
+ // let S be the most specific of those types, if any such S exists.
+ //
+ // Since we only care about the most specific type, it is sufficent to
+ // look at the types appearing as a parameter to Future in the type
+ // hierarchy of T. We don't need to consider the supertypes of those
+ // types, since they are by definition less specific.
+ List<DartType> candidateTypes =
+ _searchTypeHierarchyForFutureTypeParameters();
+ DartType flattenResult = _findMostSpecificType(candidateTypes, typeSystem);
+ if (flattenResult != null) {
+ return flattenResult;
+ }
+
+ // Implement the case: "In any other circumstance, flatten(T) = T."
+ return this;
+ }
+
+ @override
PropertyAccessorElement getGetter(String getterName) =>
PropertyAccessorMember.from(element.getGetter(getterName), this);
@@ -1678,6 +1717,34 @@
if (JavaArrays.equals(newTypeArguments, typeArguments)) {
return this;
}
+
+ if (isDartAsyncFuture && newTypeArguments.isNotEmpty) {
+ //
+ // In strong mode interpret Future< T > as Future< flatten(T) >
+ //
+ // For example, Future<Future<T>> will flatten to Future<T>.
+ //
+ // In the Dart 3rd edition spec, this flatten operation is used for
+ // `async` and `await`. In strong mode, we extend it to all Future<T>
+ // instantiations. This allows typing of Future-related operations
+ // in dart:async in a way that matches their runtime behavior and provides
+ // precise return types for users of these APIs.
+ //
+ // For example:
+ //
+ // abstract class Future<T> {
+ // Future<S> then<S>(S onValue(T value), ...);
+ // }
+ //
+ // Given a call where S <: Future<R> for some R, we will need to flatten
+ // the return type so it is Future< flatten(S) >, yielding Future<R>.
+ //
+ if (element.library.context.analysisOptions.strongMode) {
+ TypeImpl t = newTypeArguments[0];
+ newTypeArguments[0] = t.flattenFutures(new StrongTypeSystemImpl());
+ }
+ }
+
InterfaceTypeImpl newType = new InterfaceTypeImpl(element, prune);
newType.typeArguments = newTypeArguments;
return newType;
@@ -1688,6 +1755,31 @@
substitute2(argumentTypes, typeArguments);
/**
+ * Starting from this type, search its class hierarchy for types of the form
+ * Future<R>, and return a list of the resulting R's.
+ */
+ List<DartType> _searchTypeHierarchyForFutureTypeParameters() {
+ List<DartType> result = <DartType>[];
+ HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
+ void recurse(InterfaceTypeImpl type) {
+ if (type.isDartAsyncFuture && type.typeArguments.isNotEmpty) {
+ result.add(type.typeArguments[0]);
+ }
+ if (visitedClasses.add(type.element)) {
+ if (type.superclass != null) {
+ recurse(type.superclass);
+ }
+ for (InterfaceType interface in type.interfaces) {
+ recurse(interface);
+ }
+ visitedClasses.remove(type.element);
+ }
+ }
+ recurse(this);
+ return result;
+ }
+
+ /**
* Compute the least upper bound of types [i] and [j], both of which are
* known to be interface types.
*
@@ -1846,6 +1938,61 @@
}
/**
+ * If there is a single type which is at least as specific as all of the
+ * types in [types], return it. Otherwise return `null`.
+ */
+ static DartType _findMostSpecificType(List<DartType> types, TypeSystem typeSystem) {
+ // The << relation ("more specific than") is a partial ordering on types,
+ // so to find the most specific type of a set, we keep a bucket of the most
+ // specific types seen so far such that no type in the bucket is more
+ // specific than any other type in the bucket.
+ List<DartType> bucket = <DartType>[];
+
+ // Then we consider each type in turn.
+ for (DartType type in types) {
+ // If any existing type in the bucket is more specific than this type,
+ // then we can ignore this type.
+ if (bucket.any((DartType t) => typeSystem.isMoreSpecificThan(t, type))) {
+ continue;
+ }
+ // Otherwise, we need to add this type to the bucket and remove any types
+ // that are less specific than it.
+ bool added = false;
+ int i = 0;
+ while (i < bucket.length) {
+ if (typeSystem.isMoreSpecificThan(type, bucket[i])) {
+ if (added) {
+ if (i < bucket.length - 1) {
+ bucket[i] = bucket.removeLast();
+ } else {
+ bucket.removeLast();
+ }
+ } else {
+ bucket[i] = type;
+ i++;
+ added = true;
+ }
+ } else {
+ i++;
+ }
+ }
+ if (!added) {
+ bucket.add(type);
+ }
+ }
+
+ // Now that we are finished, if there is exactly one type left in the
+ // bucket, it is the most specific type.
+ if (bucket.length == 1) {
+ return bucket[0];
+ }
+
+ // Otherwise, there is no single type that is more specific than the
+ // others.
+ return null;
+ }
+
+ /**
* Return the intersection of the [first] and [second] sets of types, where
* intersection is based on the equality of the types themselves.
*/
@@ -1986,6 +2133,9 @@
bool get isBottom => false;
@override
+ bool get isDartAsyncFuture => false;
+
+ @override
bool get isDartCoreFunction => false;
@override
@@ -2012,6 +2162,9 @@
}
}
+ @override
+ DartType flattenFutures(TypeSystem typeSystem) => this;
+
/**
* Return `true` if this type is assignable to the given [type] (written in
* the spec as "T <=> S", where T=[this] and S=[type]).
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index 3daca75..18c14d8 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -2,12331 +2,18 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/**
+ * This library is deprecated. Please convert all references to this library to
+ * reference one of the following public libraries:
+ * * package:analyzer/dart/ast/ast.dart
+ * * package:analyzer/dart/ast/visitor.dart
+ *
+ * If your code is using APIs not available in these public libraries, please
+ * contact the analyzer team to either find an alternate API or have the API you
+ * depend on added to the public API.
+ */
library analyzer.src.generated.ast;
-import 'dart:collection';
-
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/ast/utilities.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
-import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
-import 'package:analyzer/src/generated/utilities_dart.dart';
-
+export 'package:analyzer/dart/ast/ast.dart';
export 'package:analyzer/dart/ast/visitor.dart';
export 'package:analyzer/src/dart/ast/utilities.dart';
-
-/**
- * Two or more string literals that are implicitly concatenated because of being
- * adjacent (separated only by whitespace).
- *
- * While the grammar only allows adjacent strings when all of the strings are of
- * the same kind (single line or multi-line), this class doesn't enforce that
- * restriction.
- *
- * > adjacentStrings ::=
- * > [StringLiteral] [StringLiteral]+
- */
-class AdjacentStrings extends StringLiteral {
- /**
- * The strings that are implicitly concatenated.
- */
- NodeList<StringLiteral> _strings;
-
- /**
- * Initialize a newly created list of adjacent strings. To be syntactically
- * valid, the list of [strings] must contain at least two elements.
- */
- AdjacentStrings(List<StringLiteral> strings) {
- _strings = new NodeList<StringLiteral>(this, strings);
- }
-
- @override
- Token get beginToken => _strings.beginToken;
-
- @override
- Iterable get childEntities => new ChildEntities()..addAll(_strings);
-
- @override
- Token get endToken => _strings.endToken;
-
- /**
- * Return the strings that are implicitly concatenated.
- */
- NodeList<StringLiteral> get strings => _strings;
-
- @override
- accept(AstVisitor visitor) => visitor.visitAdjacentStrings(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _strings.accept(visitor);
- }
-
- @override
- void _appendStringValue(StringBuffer buffer) {
- for (StringLiteral stringLiteral in strings) {
- stringLiteral._appendStringValue(buffer);
- }
- }
-}
-
-/**
- * An AST node that can be annotated with both a documentation comment and a
- * list of annotations.
- */
-abstract class AnnotatedNode extends AstNode {
- /**
- * The documentation comment associated with this node, or `null` if this node
- * does not have a documentation comment associated with it.
- */
- Comment _comment;
-
- /**
- * The annotations associated with this node.
- */
- NodeList<Annotation> _metadata;
-
- /**
- * Initialize a newly created annotated node. Either or both of the [comment]
- * and [metadata] can be `null` if the node does not have the corresponding
- * attribute.
- */
- AnnotatedNode(Comment comment, List<Annotation> metadata) {
- _comment = _becomeParentOf(comment);
- _metadata = new NodeList<Annotation>(this, metadata);
- }
-
- @override
- Token get beginToken {
- if (_comment == null) {
- if (_metadata.isEmpty) {
- return firstTokenAfterCommentAndMetadata;
- }
- return _metadata.beginToken;
- } else if (_metadata.isEmpty) {
- return _comment.beginToken;
- }
- Token commentToken = _comment.beginToken;
- Token metadataToken = _metadata.beginToken;
- if (commentToken.offset < metadataToken.offset) {
- return commentToken;
- }
- return metadataToken;
- }
-
- /**
- * Return the documentation comment associated with this node, or `null` if
- * this node does not have a documentation comment associated with it.
- */
- Comment get documentationComment => _comment;
-
- /**
- * Set the documentation comment associated with this node to the given
- * [comment].
- */
- void set documentationComment(Comment comment) {
- _comment = _becomeParentOf(comment);
- }
-
- /**
- * Return the first token following the comment and metadata.
- */
- Token get firstTokenAfterCommentAndMetadata;
-
- /**
- * Return the annotations associated with this node.
- */
- NodeList<Annotation> get metadata => _metadata;
-
- /**
- * Return a list containing the comment and annotations associated with this
- * node, sorted in lexical order.
- */
- List<AstNode> get sortedCommentAndAnnotations {
- return <AstNode>[]
- ..add(_comment)
- ..addAll(_metadata)
- ..sort(AstNode.LEXICAL_ORDER);
- }
-
- /**
- * Return a holder of child entities that subclasses can add to.
- */
- ChildEntities get _childEntities {
- ChildEntities result = new ChildEntities();
- if (_commentIsBeforeAnnotations()) {
- result
- ..add(_comment)
- ..addAll(_metadata);
- } else {
- result.addAll(sortedCommentAndAnnotations);
- }
- return result;
- }
-
- @override
- void visitChildren(AstVisitor visitor) {
- if (_commentIsBeforeAnnotations()) {
- _safelyVisitChild(_comment, visitor);
- _metadata.accept(visitor);
- } else {
- for (AstNode child in sortedCommentAndAnnotations) {
- child.accept(visitor);
- }
- }
- }
-
- /**
- * Return `true` if there are no annotations before the comment. Note that a
- * result of `true` does not imply that there is a comment, nor that there are
- * annotations associated with this node.
- */
- bool _commentIsBeforeAnnotations() {
- // TODO(brianwilkerson) Convert this to a getter.
- if (_comment == null || _metadata.isEmpty) {
- return true;
- }
- Annotation firstAnnotation = _metadata[0];
- return _comment.offset < firstAnnotation.offset;
- }
-}
-
-/**
- * An annotation that can be associated with an AST node.
- *
- * > metadata ::=
- * > annotation*
- * >
- * > annotation ::=
- * > '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
- */
-class Annotation extends AstNode {
- /**
- * The at sign that introduced the annotation.
- */
- Token atSign;
-
- /**
- * The name of the class defining the constructor that is being invoked or the
- * name of the field that is being referenced.
- */
- Identifier _name;
-
- /**
- * The period before the constructor name, or `null` if this annotation is not
- * the invocation of a named constructor.
- */
- Token period;
-
- /**
- * The name of the constructor being invoked, or `null` if this annotation is
- * not the invocation of a named constructor.
- */
- SimpleIdentifier _constructorName;
-
- /**
- * The arguments to the constructor being invoked, or `null` if this
- * annotation is not the invocation of a constructor.
- */
- ArgumentList _arguments;
-
- /**
- * The element associated with this annotation, or `null` if the AST structure
- * has not been resolved or if this annotation could not be resolved.
- */
- Element _element;
-
- /**
- * The element annotation representing this annotation in the element model.
- */
- ElementAnnotation elementAnnotation;
-
- /**
- * Initialize a newly created annotation. Both the [period] and the
- * [constructorName] can be `null` if the annotation is not referencing a
- * named constructor. The [arguments] can be `null` if the annotation is not
- * referencing a constructor.
- */
- Annotation(this.atSign, Identifier name, this.period,
- SimpleIdentifier constructorName, ArgumentList arguments) {
- _name = _becomeParentOf(name);
- _constructorName = _becomeParentOf(constructorName);
- _arguments = _becomeParentOf(arguments);
- }
-
- /**
- * Return the arguments to the constructor being invoked, or `null` if this
- * annotation is not the invocation of a constructor.
- */
- ArgumentList get arguments => _arguments;
-
- /**
- * Set the arguments to the constructor being invoked to the given arguments.
- */
- void set arguments(ArgumentList arguments) {
- _arguments = _becomeParentOf(arguments);
- }
-
- @override
- Token get beginToken => atSign;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(atSign)
- ..add(_name)
- ..add(period)
- ..add(_constructorName)
- ..add(_arguments);
-
- /**
- * Return the name of the constructor being invoked, or `null` if this
- * annotation is not the invocation of a named constructor.
- */
- SimpleIdentifier get constructorName => _constructorName;
-
- /**
- * Set the name of the constructor being invoked to the given [name].
- */
- void set constructorName(SimpleIdentifier name) {
- _constructorName = _becomeParentOf(name);
- }
-
- /**
- * Return the element associated with this annotation, or `null` if the AST
- * structure has not been resolved or if this annotation could not be
- * resolved.
- */
- Element get element {
- if (_element != null) {
- return _element;
- } else if (_name != null) {
- return _name.staticElement;
- }
- return null;
- }
-
- /**
- * Set the element associated with this annotation to the given [element].
- */
- void set element(Element element) {
- _element = element;
- }
-
- @override
- Token get endToken {
- if (_arguments != null) {
- return _arguments.endToken;
- } else if (_constructorName != null) {
- return _constructorName.endToken;
- }
- return _name.endToken;
- }
-
- /**
- * Return the name of the class defining the constructor that is being invoked
- * or the name of the field that is being referenced.
- */
- Identifier get name => _name;
-
- /**
- * Set the name of the class defining the constructor that is being invoked or
- * the name of the field that is being referenced to the given [name].
- */
- void set name(Identifier name) {
- _name = _becomeParentOf(name);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitAnnotation(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_constructorName, visitor);
- _safelyVisitChild(_arguments, visitor);
- }
-}
-
-/**
- * A list of arguments in the invocation of an executable element (that is, a
- * function, method, or constructor).
- *
- * > argumentList ::=
- * > '(' arguments? ')'
- * >
- * > arguments ::=
- * > [NamedExpression] (',' [NamedExpression])*
- * > | [Expression] (',' [Expression])* (',' [NamedExpression])*
- */
-class ArgumentList extends AstNode {
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The expressions producing the values of the arguments.
- */
- NodeList<Expression> _arguments;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * A list containing the elements representing the parameters corresponding to
- * each of the arguments in this list, or `null` if the AST has not been
- * resolved or if the function or method being invoked could not be determined
- * based on static type information. The list must be the same length as the
- * number of arguments, but can contain `null` entries if a given argument
- * does not correspond to a formal parameter.
- */
- List<ParameterElement> _correspondingStaticParameters;
-
- /**
- * A list containing the elements representing the parameters corresponding to
- * each of the arguments in this list, or `null` if the AST has not been
- * resolved or if the function or method being invoked could not be determined
- * based on propagated type information. The list must be the same length as
- * the number of arguments, but can contain `null` entries if a given argument
- * does not correspond to a formal parameter.
- */
- List<ParameterElement> _correspondingPropagatedParameters;
-
- /**
- * Initialize a newly created list of arguments. The list of [arguments] can
- * be `null` if there are no arguments.
- */
- ArgumentList(
- this.leftParenthesis, List<Expression> arguments, this.rightParenthesis) {
- _arguments = new NodeList<Expression>(this, arguments);
- }
-
- /**
- * Return the expressions producing the values of the arguments. Although the
- * language requires that positional arguments appear before named arguments,
- * this class allows them to be intermixed.
- */
- NodeList<Expression> get arguments => _arguments;
-
- @override
- Token get beginToken => leftParenthesis;
-
- @override
- // TODO(paulberry): Add commas.
- Iterable get childEntities => new ChildEntities()
- ..add(leftParenthesis)
- ..addAll(_arguments)
- ..add(rightParenthesis);
-
- /**
- * Set the parameter elements corresponding to each of the arguments in this
- * list to the given list of [parameters]. The list of parameters must be the
- * same length as the number of arguments, but can contain `null` entries if a
- * given argument does not correspond to a formal parameter.
- */
- void set correspondingPropagatedParameters(
- List<ParameterElement> parameters) {
- if (parameters.length != _arguments.length) {
- throw new IllegalArgumentException(
- "Expected ${_arguments.length} parameters, not ${parameters.length}");
- }
- _correspondingPropagatedParameters = parameters;
- }
-
- /**
- * Set the parameter elements corresponding to each of the arguments in this
- * list to the given list of parameters. The list of parameters must be the
- * same length as the number of arguments, but can contain `null` entries if a
- * given argument does not correspond to a formal parameter.
- */
- void set correspondingStaticParameters(List<ParameterElement> parameters) {
- if (parameters.length != _arguments.length) {
- throw new IllegalArgumentException(
- "Expected ${_arguments.length} parameters, not ${parameters.length}");
- }
- _correspondingStaticParameters = parameters;
- }
-
- @override
- Token get endToken => rightParenthesis;
-
- @override
- accept(AstVisitor visitor) => visitor.visitArgumentList(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _arguments.accept(visitor);
- }
-
- /**
- * If
- * * the given [expression] is a child of this list,
- * * the AST structure has been resolved,
- * * the function being invoked is known based on propagated type information,
- * and
- * * the expression corresponds to one of the parameters of the function being
- * invoked,
- * then return the parameter element representing the parameter to which the
- * value of the given expression will be bound. Otherwise, return `null`.
- */
- ParameterElement _getPropagatedParameterElementFor(Expression expression) {
- if (_correspondingPropagatedParameters == null ||
- _correspondingPropagatedParameters.length != _arguments.length) {
- // Either the AST structure has not been resolved, the invocation of which
- // this list is a part could not be resolved, or the argument list was
- // modified after the parameters were set.
- return null;
- }
- int index = _arguments.indexOf(expression);
- if (index < 0) {
- // The expression isn't a child of this node.
- return null;
- }
- return _correspondingPropagatedParameters[index];
- }
-
- /**
- * If
- * * the given [expression] is a child of this list,
- * * the AST structure has been resolved,
- * * the function being invoked is known based on static type information, and
- * * the expression corresponds to one of the parameters of the function being
- * invoked,
- * then return the parameter element representing the parameter to which the
- * value of the given expression will be bound. Otherwise, return `null`.
- */
- ParameterElement _getStaticParameterElementFor(Expression expression) {
- if (_correspondingStaticParameters == null ||
- _correspondingStaticParameters.length != _arguments.length) {
- // Either the AST structure has not been resolved, the invocation of which
- // this list is a part could not be resolved, or the argument list was
- // modified after the parameters were set.
- return null;
- }
- int index = _arguments.indexOf(expression);
- if (index < 0) {
- // The expression isn't a child of this node.
- return null;
- }
- return _correspondingStaticParameters[index];
- }
-}
-
-/**
- * An as expression.
- *
- * > asExpression ::=
- * > [Expression] 'as' [TypeName]
- */
-class AsExpression extends Expression {
- /**
- * The expression used to compute the value being cast.
- */
- Expression _expression;
-
- /**
- * The 'as' operator.
- */
- Token asOperator;
-
- /**
- * The name of the type being cast to.
- */
- TypeName _type;
-
- /**
- * Initialize a newly created as expression.
- */
- AsExpression(Expression expression, this.asOperator, TypeName type) {
- _expression = _becomeParentOf(expression);
- _type = _becomeParentOf(type);
- }
-
- @override
- Token get beginToken => _expression.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_expression)..add(asOperator)..add(_type);
-
- @override
- Token get endToken => _type.endToken;
-
- /**
- * Return the expression used to compute the value being cast.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression used to compute the value being cast to the given
- * [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 7;
-
- /**
- * Return the name of the type being cast to.
- */
- TypeName get type => _type;
-
- /**
- * Set the name of the type being cast to to the given [name].
- */
- void set type(TypeName name) {
- _type = _becomeParentOf(name);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitAsExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- _safelyVisitChild(_type, visitor);
- }
-}
-
-/**
- * An assert statement.
- *
- * > assertStatement ::=
- * > 'assert' '(' [Expression] ')' ';'
- */
-class AssertStatement extends Statement {
- /**
- * The token representing the 'assert' keyword.
- */
- Token assertKeyword;
-
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The condition that is being asserted to be `true`.
- */
- Expression _condition;
-
- /**
- * The comma, if a message expression was supplied. Otherwise `null`.
- */
- Token comma;
-
- /**
- * The message to report if the assertion fails. `null` if no message was
- * supplied.
- */
- Expression _message;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created assert statement.
- */
- AssertStatement(
- this.assertKeyword,
- this.leftParenthesis,
- Expression condition,
- this.comma,
- Expression message,
- this.rightParenthesis,
- this.semicolon) {
- _condition = _becomeParentOf(condition);
- _message = _becomeParentOf(message);
- }
-
- @override
- Token get beginToken => assertKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(assertKeyword)
- ..add(leftParenthesis)
- ..add(_condition)
- ..add(comma)
- ..add(_message)
- ..add(rightParenthesis)
- ..add(semicolon);
-
- /**
- * Return the condition that is being asserted to be `true`.
- */
- Expression get condition => _condition;
-
- /**
- * Set the condition that is being asserted to be `true` to the given
- * [expression].
- */
- void set condition(Expression condition) {
- _condition = _becomeParentOf(condition);
- }
-
- @override
- Token get endToken => semicolon;
-
- /**
- * Return the message to report if the assertion fails.
- */
- Expression get message => _message;
-
- /**
- * Set the message to report if the assertion fails to the given
- * [expression].
- */
- void set message(Expression expression) {
- _message = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitAssertStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_condition, visitor);
- _safelyVisitChild(message, visitor);
- }
-}
-
-/**
- * An assignment expression.
- *
- * > assignmentExpression ::=
- * > [Expression] operator [Expression]
- */
-class AssignmentExpression extends Expression {
- /**
- * The expression used to compute the left hand side.
- */
- Expression _leftHandSide;
-
- /**
- * The assignment operator being applied.
- */
- Token operator;
-
- /**
- * The expression used to compute the right hand side.
- */
- Expression _rightHandSide;
-
- /**
- * The element associated with the operator based on the static type of the
- * left-hand-side, or `null` if the AST structure has not been resolved, if
- * the operator is not a compound operator, or if the operator could not be
- * resolved.
- */
- MethodElement staticElement;
-
- /**
- * The element associated with the operator based on the propagated type of
- * the left-hand-side, or `null` if the AST structure has not been resolved,
- * if the operator is not a compound operator, or if the operator could not be
- * resolved.
- */
- MethodElement propagatedElement;
-
- /**
- * Initialize a newly created assignment expression.
- */
- AssignmentExpression(
- Expression leftHandSide, this.operator, Expression rightHandSide) {
- if (leftHandSide == null || rightHandSide == null) {
- String message;
- if (leftHandSide == null) {
- if (rightHandSide == null) {
- message = "Both the left-hand and right-hand sides are null";
- } else {
- message = "The left-hand size is null";
- }
- } else {
- message = "The right-hand size is null";
- }
- AnalysisEngine.instance.logger.logError(
- message, new CaughtException(new AnalysisException(message), null));
- }
- _leftHandSide = _becomeParentOf(leftHandSide);
- _rightHandSide = _becomeParentOf(rightHandSide);
- }
-
- @override
- Token get beginToken => _leftHandSide.beginToken;
-
- /**
- * Return the best element available for this operator. If resolution was able
- * to find a better element based on type propagation, that element will be
- * returned. Otherwise, the element found using the result of static analysis
- * will be returned. If resolution has not been performed, then `null` will be
- * returned.
- */
- MethodElement get bestElement {
- MethodElement element = propagatedElement;
- if (element == null) {
- element = staticElement;
- }
- return element;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(_leftHandSide)
- ..add(operator)
- ..add(_rightHandSide);
-
- @override
- Token get endToken => _rightHandSide.endToken;
-
- /**
- * Set the expression used to compute the left hand side to the given
- * [expression].
- */
- Expression get leftHandSide => _leftHandSide;
-
- /**
- * Return the expression used to compute the left hand side.
- */
- void set leftHandSide(Expression expression) {
- _leftHandSide = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 1;
-
- /**
- * Return the expression used to compute the right hand side.
- */
- Expression get rightHandSide => _rightHandSide;
-
- /**
- * Set the expression used to compute the left hand side to the given
- * [expression].
- */
- void set rightHandSide(Expression expression) {
- _rightHandSide = _becomeParentOf(expression);
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on propagated type information, then return the parameter
- * element representing the parameter to which the value of the right operand
- * will be bound. Otherwise, return `null`.
- */
- ParameterElement get _propagatedParameterElementForRightHandSide {
- ExecutableElement executableElement = null;
- if (propagatedElement != null) {
- executableElement = propagatedElement;
- } else {
- if (_leftHandSide is Identifier) {
- Identifier identifier = _leftHandSide as Identifier;
- Element leftElement = identifier.propagatedElement;
- if (leftElement is ExecutableElement) {
- executableElement = leftElement;
- }
- }
- if (_leftHandSide is PropertyAccess) {
- SimpleIdentifier identifier =
- (_leftHandSide as PropertyAccess).propertyName;
- Element leftElement = identifier.propagatedElement;
- if (leftElement is ExecutableElement) {
- executableElement = leftElement;
- }
- }
- }
- if (executableElement == null) {
- return null;
- }
- List<ParameterElement> parameters = executableElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on static type information, then return the parameter element
- * representing the parameter to which the value of the right operand will be
- * bound. Otherwise, return `null`.
- */
- ParameterElement get _staticParameterElementForRightHandSide {
- ExecutableElement executableElement = null;
- if (staticElement != null) {
- executableElement = staticElement;
- } else {
- if (_leftHandSide is Identifier) {
- Element leftElement = (_leftHandSide as Identifier).staticElement;
- if (leftElement is ExecutableElement) {
- executableElement = leftElement;
- }
- }
- if (_leftHandSide is PropertyAccess) {
- Element leftElement =
- (_leftHandSide as PropertyAccess).propertyName.staticElement;
- if (leftElement is ExecutableElement) {
- executableElement = leftElement;
- }
- }
- }
- if (executableElement == null) {
- return null;
- }
- List<ParameterElement> parameters = executableElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitAssignmentExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_leftHandSide, visitor);
- _safelyVisitChild(_rightHandSide, visitor);
- }
-}
-
-/**
- * A node in the AST structure for a Dart program.
- */
-abstract class AstNode {
- /**
- * An empty list of AST nodes.
- */
- static const List<AstNode> EMPTY_LIST = const <AstNode>[];
-
- /**
- * A comparator that can be used to sort AST nodes in lexical order. In other
- * words, `compare` will return a negative value if the offset of the first
- * node is less than the offset of the second node, zero (0) if the nodes have
- * the same offset, and a positive value if the offset of the first node is
- * greater than the offset of the second node.
- */
- static Comparator<AstNode> LEXICAL_ORDER =
- (AstNode first, AstNode second) => first.offset - second.offset;
-
- /**
- * The parent of the node, or `null` if the node is the root of an AST
- * structure.
- */
- AstNode _parent;
-
- /**
- * A table mapping the names of properties to their values, or `null` if this
- * node does not have any properties associated with it.
- */
- Map<String, Object> _propertyMap;
-
- /**
- * Return the first token included in this node's source range.
- */
- Token get beginToken;
-
- /**
- * Iterate through all the entities (either AST nodes or tokens) which make
- * up the contents of this node, including doc comments but excluding other
- * comments.
- */
- Iterable /*<AstNode | Token>*/ get childEntities;
-
- /**
- * Return the offset of the character immediately following the last character
- * of this node's source range. This is equivalent to
- * `node.getOffset() + node.getLength()`. For a compilation unit this will be
- * equal to the length of the unit's source. For synthetic nodes this will be
- * equivalent to the node's offset (because the length is zero (0) by
- * definition).
- */
- int get end => offset + length;
-
- /**
- * Return the last token included in this node's source range.
- */
- Token get endToken;
-
- /**
- * Return `true` if this node is a synthetic node. A synthetic node is a node
- * that was introduced by the parser in order to recover from an error in the
- * code. Synthetic nodes always have a length of zero (`0`).
- */
- bool get isSynthetic => false;
-
- /**
- * Return the number of characters in the node's source range.
- */
- int get length {
- Token beginToken = this.beginToken;
- Token endToken = this.endToken;
- if (beginToken == null || endToken == null) {
- return -1;
- }
- return endToken.offset + endToken.length - beginToken.offset;
- }
-
- /**
- * Return the offset from the beginning of the file to the first character in
- * the node's source range.
- */
- int get offset {
- Token beginToken = this.beginToken;
- if (beginToken == null) {
- return -1;
- }
- return beginToken.offset;
- }
-
- /**
- * Return this node's parent node, or `null` if this node is the root of an
- * AST structure.
- *
- * Note that the relationship between an AST node and its parent node may
- * change over the lifetime of a node.
- */
- AstNode get parent => _parent;
-
- /**
- * Return the node at the root of this node's AST structure. Note that this
- * method's performance is linear with respect to the depth of the node in the
- * AST structure (O(depth)).
- */
- AstNode get root {
- AstNode root = this;
- AstNode parent = this.parent;
- while (parent != null) {
- root = parent;
- parent = root.parent;
- }
- return root;
- }
-
- /**
- * Use the given [visitor] to visit this node. Return the value returned by
- * the visitor as a result of visiting this node.
- */
- dynamic /*=E*/ accept /*<E>*/ (AstVisitor /*<E>*/ visitor);
-
- /**
- * Return the most immediate ancestor of this node for which the [predicate]
- * returns `true`, or `null` if there is no such ancestor. Note that this node
- * will never be returned.
- */
- AstNode getAncestor(Predicate<AstNode> predicate) {
- // TODO(brianwilkerson) It is a bug that this method can return `this`.
- AstNode node = this;
- while (node != null && !predicate(node)) {
- node = node.parent;
- }
- return node;
- }
-
- /**
- * Return the value of the property with the given [name], or `null` if this
- * node does not have a property with the given name.
- */
- Object getProperty(String name) {
- if (_propertyMap == null) {
- return null;
- }
- return _propertyMap[name];
- }
-
- /**
- * Set the value of the property with the given [name] to the given [value].
- * If the value is `null`, the property will effectively be removed.
- */
- void setProperty(String name, Object value) {
- if (value == null) {
- if (_propertyMap != null) {
- _propertyMap.remove(name);
- if (_propertyMap.isEmpty) {
- _propertyMap = null;
- }
- }
- } else {
- if (_propertyMap == null) {
- _propertyMap = new HashMap<String, Object>();
- }
- _propertyMap[name] = value;
- }
- }
-
- /**
- * Return a textual description of this node in a form approximating valid
- * source. The returned string will not be valid source primarily in the case
- * where the node itself is not well-formed.
- */
- String toSource() {
- PrintStringWriter writer = new PrintStringWriter();
- accept(new ToSourceVisitor(writer));
- return writer.toString();
- }
-
- @override
- String toString() => toSource();
-
- /**
- * Use the given [visitor] to visit all of the children of this node. The
- * children will be visited in lexical order.
- */
- void visitChildren(AstVisitor visitor);
-
- /**
- * Make this node the parent of the given [child] node. Return the child node.
- */
- AstNode _becomeParentOf(AstNode child) {
- if (child != null) {
- child._parent = this;
- }
- return child;
- }
-
- /**
- * If the given [child] is not `null`, use the given [visitor] to visit it.
- */
- void _safelyVisitChild(AstNode child, AstVisitor visitor) {
- if (child != null) {
- child.accept(visitor);
- }
- }
-}
-
-/**
- * An object that can be used to visit an AST structure.
- */
-abstract class AstVisitor<R> {
- R visitAdjacentStrings(AdjacentStrings node);
-
- R visitAnnotation(Annotation node);
-
- R visitArgumentList(ArgumentList node);
-
- R visitAsExpression(AsExpression node);
-
- R visitAssertStatement(AssertStatement assertStatement);
-
- R visitAssignmentExpression(AssignmentExpression node);
-
- R visitAwaitExpression(AwaitExpression node);
-
- R visitBinaryExpression(BinaryExpression node);
-
- R visitBlock(Block node);
-
- R visitBlockFunctionBody(BlockFunctionBody node);
-
- R visitBooleanLiteral(BooleanLiteral node);
-
- R visitBreakStatement(BreakStatement node);
-
- R visitCascadeExpression(CascadeExpression node);
-
- R visitCatchClause(CatchClause node);
-
- R visitClassDeclaration(ClassDeclaration node);
-
- R visitClassTypeAlias(ClassTypeAlias node);
-
- R visitComment(Comment node);
-
- R visitCommentReference(CommentReference node);
-
- R visitCompilationUnit(CompilationUnit node);
-
- R visitConditionalExpression(ConditionalExpression node);
-
- R visitConfiguration(Configuration node);
-
- R visitConstructorDeclaration(ConstructorDeclaration node);
-
- R visitConstructorFieldInitializer(ConstructorFieldInitializer node);
-
- R visitConstructorName(ConstructorName node);
-
- R visitContinueStatement(ContinueStatement node);
-
- R visitDeclaredIdentifier(DeclaredIdentifier node);
-
- R visitDefaultFormalParameter(DefaultFormalParameter node);
-
- R visitDoStatement(DoStatement node);
-
- R visitDottedName(DottedName node);
-
- R visitDoubleLiteral(DoubleLiteral node);
-
- R visitEmptyFunctionBody(EmptyFunctionBody node);
-
- R visitEmptyStatement(EmptyStatement node);
-
- R visitEnumConstantDeclaration(EnumConstantDeclaration node);
-
- R visitEnumDeclaration(EnumDeclaration node);
-
- R visitExportDirective(ExportDirective node);
-
- R visitExpressionFunctionBody(ExpressionFunctionBody node);
-
- R visitExpressionStatement(ExpressionStatement node);
-
- R visitExtendsClause(ExtendsClause node);
-
- R visitFieldDeclaration(FieldDeclaration node);
-
- R visitFieldFormalParameter(FieldFormalParameter node);
-
- R visitForEachStatement(ForEachStatement node);
-
- R visitFormalParameterList(FormalParameterList node);
-
- R visitForStatement(ForStatement node);
-
- R visitFunctionDeclaration(FunctionDeclaration node);
-
- R visitFunctionDeclarationStatement(FunctionDeclarationStatement node);
-
- R visitFunctionExpression(FunctionExpression node);
-
- R visitFunctionExpressionInvocation(FunctionExpressionInvocation node);
-
- R visitFunctionTypeAlias(FunctionTypeAlias functionTypeAlias);
-
- R visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node);
-
- R visitHideCombinator(HideCombinator node);
-
- R visitIfStatement(IfStatement node);
-
- R visitImplementsClause(ImplementsClause node);
-
- R visitImportDirective(ImportDirective node);
-
- R visitIndexExpression(IndexExpression node);
-
- R visitInstanceCreationExpression(InstanceCreationExpression node);
-
- R visitIntegerLiteral(IntegerLiteral node);
-
- R visitInterpolationExpression(InterpolationExpression node);
-
- R visitInterpolationString(InterpolationString node);
-
- R visitIsExpression(IsExpression node);
-
- R visitLabel(Label node);
-
- R visitLabeledStatement(LabeledStatement node);
-
- R visitLibraryDirective(LibraryDirective node);
-
- R visitLibraryIdentifier(LibraryIdentifier node);
-
- R visitListLiteral(ListLiteral node);
-
- R visitMapLiteral(MapLiteral node);
-
- R visitMapLiteralEntry(MapLiteralEntry node);
-
- R visitMethodDeclaration(MethodDeclaration node);
-
- R visitMethodInvocation(MethodInvocation node);
-
- R visitNamedExpression(NamedExpression node);
-
- R visitNativeClause(NativeClause node);
-
- R visitNativeFunctionBody(NativeFunctionBody node);
-
- R visitNullLiteral(NullLiteral node);
-
- R visitParenthesizedExpression(ParenthesizedExpression node);
-
- R visitPartDirective(PartDirective node);
-
- R visitPartOfDirective(PartOfDirective node);
-
- R visitPostfixExpression(PostfixExpression node);
-
- R visitPrefixedIdentifier(PrefixedIdentifier node);
-
- R visitPrefixExpression(PrefixExpression node);
-
- R visitPropertyAccess(PropertyAccess node);
-
- R visitRedirectingConstructorInvocation(
- RedirectingConstructorInvocation node);
-
- R visitRethrowExpression(RethrowExpression node);
-
- R visitReturnStatement(ReturnStatement node);
-
- R visitScriptTag(ScriptTag node);
-
- R visitShowCombinator(ShowCombinator node);
-
- R visitSimpleFormalParameter(SimpleFormalParameter node);
-
- R visitSimpleIdentifier(SimpleIdentifier node);
-
- R visitSimpleStringLiteral(SimpleStringLiteral node);
-
- R visitStringInterpolation(StringInterpolation node);
-
- R visitSuperConstructorInvocation(SuperConstructorInvocation node);
-
- R visitSuperExpression(SuperExpression node);
-
- R visitSwitchCase(SwitchCase node);
-
- R visitSwitchDefault(SwitchDefault node);
-
- R visitSwitchStatement(SwitchStatement node);
-
- R visitSymbolLiteral(SymbolLiteral node);
-
- R visitThisExpression(ThisExpression node);
-
- R visitThrowExpression(ThrowExpression node);
-
- R visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node);
-
- R visitTryStatement(TryStatement node);
-
- R visitTypeArgumentList(TypeArgumentList node);
-
- R visitTypeName(TypeName node);
-
- R visitTypeParameter(TypeParameter node);
-
- R visitTypeParameterList(TypeParameterList node);
-
- R visitVariableDeclaration(VariableDeclaration node);
-
- R visitVariableDeclarationList(VariableDeclarationList node);
-
- R visitVariableDeclarationStatement(VariableDeclarationStatement node);
-
- R visitWhileStatement(WhileStatement node);
-
- R visitWithClause(WithClause node);
-
- R visitYieldStatement(YieldStatement node);
-}
-
-/**
- * An await expression.
- *
- * > awaitExpression ::=
- * > 'await' [Expression]
- */
-class AwaitExpression extends Expression {
- /**
- * The 'await' keyword.
- */
- Token awaitKeyword;
-
- /**
- * The expression whose value is being waited on.
- */
- Expression _expression;
-
- /**
- * Initialize a newly created await expression.
- */
- AwaitExpression(this.awaitKeyword, Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken {
- if (awaitKeyword != null) {
- return awaitKeyword;
- }
- return _expression.beginToken;
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(awaitKeyword)..add(_expression);
-
- @override
- Token get endToken => _expression.endToken;
-
- /**
- * Return the expression whose value is being waited on.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression whose value is being waited on to the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 0;
-
- @override
- accept(AstVisitor visitor) => visitor.visitAwaitExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * A binary (infix) expression.
- *
- * > binaryExpression ::=
- * > [Expression] [Token] [Expression]
- */
-class BinaryExpression extends Expression {
- /**
- * The expression used to compute the left operand.
- */
- Expression _leftOperand;
-
- /**
- * The binary operator being applied.
- */
- Token operator;
-
- /**
- * The expression used to compute the right operand.
- */
- Expression _rightOperand;
-
- /**
- * The element associated with the operator based on the static type of the
- * left operand, or `null` if the AST structure has not been resolved, if the
- * operator is not user definable, or if the operator could not be resolved.
- */
- MethodElement staticElement;
-
- /**
- * The element associated with the operator based on the propagated type of
- * the left operand, or `null` if the AST structure has not been resolved, if
- * the operator is not user definable, or if the operator could not be
- * resolved.
- */
- MethodElement propagatedElement;
-
- /**
- * Initialize a newly created binary expression.
- */
- BinaryExpression(
- Expression leftOperand, this.operator, Expression rightOperand) {
- _leftOperand = _becomeParentOf(leftOperand);
- _rightOperand = _becomeParentOf(rightOperand);
- }
-
- @override
- Token get beginToken => _leftOperand.beginToken;
-
- /**
- * Return the best element available for this operator. If resolution was able
- * to find a better element based on type propagation, that element will be
- * returned. Otherwise, the element found using the result of static analysis
- * will be returned. If resolution has not been performed, then `null` will be
- * returned.
- */
- MethodElement get bestElement {
- MethodElement element = propagatedElement;
- if (element == null) {
- element = staticElement;
- }
- return element;
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_leftOperand)..add(operator)..add(_rightOperand);
-
- @override
- Token get endToken => _rightOperand.endToken;
-
- /**
- * Return the expression used to compute the left operand.
- */
- Expression get leftOperand => _leftOperand;
-
- /**
- * Set the expression used to compute the left operand to the given
- * [expression].
- */
- void set leftOperand(Expression expression) {
- _leftOperand = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => operator.type.precedence;
-
- /**
- * Return the expression used to compute the right operand.
- */
- Expression get rightOperand => _rightOperand;
-
- /**
- * Set the expression used to compute the right operand to the given
- * [expression].
- */
- void set rightOperand(Expression expression) {
- _rightOperand = _becomeParentOf(expression);
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on propagated type information, then return the parameter
- * element representing the parameter to which the value of the right operand
- * will be bound. Otherwise, return `null`.
- */
- ParameterElement get _propagatedParameterElementForRightOperand {
- if (propagatedElement == null) {
- return null;
- }
- List<ParameterElement> parameters = propagatedElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on static type information, then return the parameter element
- * representing the parameter to which the value of the right operand will be
- * bound. Otherwise, return `null`.
- */
- ParameterElement get _staticParameterElementForRightOperand {
- if (staticElement == null) {
- return null;
- }
- List<ParameterElement> parameters = staticElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitBinaryExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_leftOperand, visitor);
- _safelyVisitChild(_rightOperand, visitor);
- }
-}
-
-/**
- * A sequence of statements.
- *
- * > block ::=
- * > '{' statement* '}'
- */
-class Block extends Statement {
- /**
- * The left curly bracket.
- */
- Token leftBracket;
-
- /**
- * The statements contained in the block.
- */
- NodeList<Statement> _statements;
-
- /**
- * The right curly bracket.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created block of code.
- */
- Block(this.leftBracket, List<Statement> statements, this.rightBracket) {
- _statements = new NodeList<Statement>(this, statements);
- }
-
- @override
- Token get beginToken => leftBracket;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(leftBracket)
- ..addAll(_statements)
- ..add(rightBracket);
-
- @override
- Token get endToken => rightBracket;
-
- /**
- * Return the statements contained in the block.
- */
- NodeList<Statement> get statements => _statements;
-
- @override
- accept(AstVisitor visitor) => visitor.visitBlock(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _statements.accept(visitor);
- }
-}
-
-/**
- * A function body that consists of a block of statements.
- *
- * > blockFunctionBody ::=
- * > ('async' | 'async' '*' | 'sync' '*')? [Block]
- */
-class BlockFunctionBody extends FunctionBody {
- /**
- * The token representing the 'async' or 'sync' keyword, or `null` if there is
- * no such keyword.
- */
- Token keyword;
-
- /**
- * The star optionally following the 'async' or 'sync' keyword, or `null` if
- * there is wither no such keyword or no star.
- */
- Token star;
-
- /**
- * The block representing the body of the function.
- */
- Block _block;
-
- /**
- * Initialize a newly created function body consisting of a block of
- * statements. The [keyword] can be `null` if there is no keyword specified
- * for the block. The [star] can be `null` if there is no star following the
- * keyword (and must be `null` if there is no keyword).
- */
- BlockFunctionBody(this.keyword, this.star, Block block) {
- _block = _becomeParentOf(block);
- }
-
- @override
- Token get beginToken {
- if (keyword != null) {
- return keyword;
- }
- return _block.beginToken;
- }
-
- /**
- * Return the block representing the body of the function.
- */
- Block get block => _block;
-
- /**
- * Set the block representing the body of the function to the given [block].
- */
- void set block(Block block) {
- _block = _becomeParentOf(block);
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(keyword)..add(star)..add(_block);
-
- @override
- Token get endToken => _block.endToken;
-
- @override
- bool get isAsynchronous => keyword != null && keyword.lexeme == Parser.ASYNC;
-
- @override
- bool get isGenerator => star != null;
-
- @override
- bool get isSynchronous => keyword == null || keyword.lexeme != Parser.ASYNC;
-
- @override
- accept(AstVisitor visitor) => visitor.visitBlockFunctionBody(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_block, visitor);
- }
-}
-
-/**
- * A boolean literal expression.
- *
- * > booleanLiteral ::=
- * > 'false' | 'true'
- */
-class BooleanLiteral extends Literal {
- /**
- * The token representing the literal.
- */
- Token literal;
-
- /**
- * The value of the literal.
- */
- bool value = false;
-
- /**
- * Initialize a newly created boolean literal.
- */
- BooleanLiteral(this.literal, this.value);
-
- @override
- Token get beginToken => literal;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(literal);
-
- @override
- Token get endToken => literal;
-
- @override
- bool get isSynthetic => literal.isSynthetic;
-
- @override
- accept(AstVisitor visitor) => visitor.visitBooleanLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A break statement.
- *
- * > breakStatement ::=
- * > 'break' [SimpleIdentifier]? ';'
- */
-class BreakStatement extends Statement {
- /**
- * The token representing the 'break' keyword.
- */
- Token breakKeyword;
-
- /**
- * The label associated with the statement, or `null` if there is no label.
- */
- SimpleIdentifier _label;
-
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * The AstNode which this break statement is breaking from. This will be
- * either a [Statement] (in the case of breaking out of a loop), a
- * [SwitchMember] (in the case of a labeled break statement whose label
- * matches a label on a switch case in an enclosing switch statement), or
- * `null` if the AST has not yet been resolved or if the target could not be
- * resolved. Note that if the source code has errors, the target might be
- * invalid (e.g. trying to break to a switch case).
- */
- AstNode target;
-
- /**
- * Initialize a newly created break statement. The [label] can be `null` if
- * there is no label associated with the statement.
- */
- BreakStatement(this.breakKeyword, SimpleIdentifier label, this.semicolon) {
- _label = _becomeParentOf(label);
- }
-
- @override
- Token get beginToken => breakKeyword;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(breakKeyword)..add(_label)..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- /**
- * Return the label associated with the statement, or `null` if there is no
- * label.
- */
- SimpleIdentifier get label => _label;
-
- /**
- * Set the label associated with the statement to the given [identifier].
- */
- void set label(SimpleIdentifier identifier) {
- _label = _becomeParentOf(identifier);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitBreakStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_label, visitor);
- }
-}
-
-/**
- * A sequence of cascaded expressions: expressions that share a common target.
- * There are three kinds of expressions that can be used in a cascade
- * expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
- *
- * > cascadeExpression ::=
- * > [Expression] cascadeSection*
- * >
- * > cascadeSection ::=
- * > '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
- * > (assignmentOperator expressionWithoutCascade)?
- * >
- * > cascadeSelector ::=
- * > '[ ' expression '] '
- * > | identifier
- */
-class CascadeExpression extends Expression {
- /**
- * The target of the cascade sections.
- */
- Expression _target;
-
- /**
- * The cascade sections sharing the common target.
- */
- NodeList<Expression> _cascadeSections;
-
- /**
- * Initialize a newly created cascade expression. The list of
- * [cascadeSections] must contain at least one element.
- */
- CascadeExpression(Expression target, List<Expression> cascadeSections) {
- _target = _becomeParentOf(target);
- _cascadeSections = new NodeList<Expression>(this, cascadeSections);
- }
-
- @override
- Token get beginToken => _target.beginToken;
-
- /**
- * Return the cascade sections sharing the common target.
- */
- NodeList<Expression> get cascadeSections => _cascadeSections;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(_target)
- ..addAll(_cascadeSections);
-
- @override
- Token get endToken => _cascadeSections.endToken;
-
- @override
- int get precedence => 2;
-
- /**
- * Return the target of the cascade sections.
- */
- Expression get target => _target;
-
- /**
- * Set the target of the cascade sections to the given [expression].
- */
- void set target(Expression target) {
- _target = _becomeParentOf(target);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitCascadeExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_target, visitor);
- _cascadeSections.accept(visitor);
- }
-}
-
-/**
- * A catch clause within a try statement.
- *
- * > onPart ::=
- * > catchPart [Block]
- * > | 'on' type catchPart? [Block]
- * >
- * > catchPart ::=
- * > 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
- */
-class CatchClause extends AstNode {
- /**
- * The token representing the 'on' keyword, or `null` if there is no 'on'
- * keyword.
- */
- Token onKeyword;
-
- /**
- * The type of exceptions caught by this catch clause, or `null` if this catch
- * clause catches every type of exception.
- */
- TypeName _exceptionType;
-
- /**
- * The token representing the 'catch' keyword, or `null` if there is no
- * 'catch' keyword.
- */
- Token catchKeyword;
-
- /**
- * The left parenthesis, or `null` if there is no 'catch' keyword.
- */
- Token leftParenthesis;
-
- /**
- * The parameter whose value will be the exception that was thrown, or `null`
- * if there is no 'catch' keyword.
- */
- SimpleIdentifier _exceptionParameter;
-
- /**
- * The comma separating the exception parameter from the stack trace
- * parameter, or `null` if there is no stack trace parameter.
- */
- Token comma;
-
- /**
- * The parameter whose value will be the stack trace associated with the
- * exception, or `null` if there is no stack trace parameter.
- */
- SimpleIdentifier _stackTraceParameter;
-
- /**
- * The right parenthesis, or `null` if there is no 'catch' keyword.
- */
- Token rightParenthesis;
-
- /**
- * The body of the catch block.
- */
- Block _body;
-
- /**
- * Initialize a newly created catch clause. The [onKeyword] and
- * [exceptionType] can be `null` if the clause will catch all exceptions. The
- * [comma] and [stackTraceParameter] can be `null` if the stack trace is not
- * referencable within the body.
- */
- CatchClause(
- this.onKeyword,
- TypeName exceptionType,
- this.catchKeyword,
- this.leftParenthesis,
- SimpleIdentifier exceptionParameter,
- this.comma,
- SimpleIdentifier stackTraceParameter,
- this.rightParenthesis,
- Block body) {
- _exceptionType = _becomeParentOf(exceptionType);
- _exceptionParameter = _becomeParentOf(exceptionParameter);
- _stackTraceParameter = _becomeParentOf(stackTraceParameter);
- _body = _becomeParentOf(body);
- }
-
- @override
- Token get beginToken {
- if (onKeyword != null) {
- return onKeyword;
- }
- return catchKeyword;
- }
-
- /**
- * Return the body of the catch block.
- */
- Block get body => _body;
-
- /**
- * Set the body of the catch block to the given [block].
- */
- void set body(Block block) {
- _body = _becomeParentOf(block);
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(onKeyword)
- ..add(_exceptionType)
- ..add(catchKeyword)
- ..add(leftParenthesis)
- ..add(_exceptionParameter)
- ..add(comma)
- ..add(_stackTraceParameter)
- ..add(rightParenthesis)
- ..add(_body);
-
- @override
- Token get endToken => _body.endToken;
-
- /**
- * Return the parameter whose value will be the exception that was thrown, or
- * `null` if there is no 'catch' keyword.
- */
- SimpleIdentifier get exceptionParameter => _exceptionParameter;
-
- /**
- * Set the parameter whose value will be the exception that was thrown to the
- * given [parameter].
- */
- void set exceptionParameter(SimpleIdentifier parameter) {
- _exceptionParameter = _becomeParentOf(parameter);
- }
-
- /**
- * Return the type of exceptions caught by this catch clause, or `null` if
- * this catch clause catches every type of exception.
- */
- TypeName get exceptionType => _exceptionType;
-
- /**
- * Set the type of exceptions caught by this catch clause to the given
- * [exceptionType].
- */
- void set exceptionType(TypeName exceptionType) {
- _exceptionType = _becomeParentOf(exceptionType);
- }
-
- /**
- * Return the parameter whose value will be the stack trace associated with
- * the exception, or `null` if there is no stack trace parameter.
- */
- SimpleIdentifier get stackTraceParameter => _stackTraceParameter;
-
- /**
- * Set the parameter whose value will be the stack trace associated with the
- * exception to the given [parameter].
- */
- void set stackTraceParameter(SimpleIdentifier parameter) {
- _stackTraceParameter = _becomeParentOf(parameter);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitCatchClause(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_exceptionType, visitor);
- _safelyVisitChild(_exceptionParameter, visitor);
- _safelyVisitChild(_stackTraceParameter, visitor);
- _safelyVisitChild(_body, visitor);
- }
-}
-
-/**
- * Helper class to allow iteration of child entities of an AST node.
- */
-class ChildEntities extends Object with IterableMixin implements Iterable {
- /**
- * The list of child entities to be iterated over.
- */
- List _entities = [];
-
- @override
- Iterator get iterator => _entities.iterator;
-
- /**
- * Add an AST node or token as the next child entity, if it is not null.
- */
- void add(entity) {
- if (entity != null) {
- assert(entity is Token || entity is AstNode);
- _entities.add(entity);
- }
- }
-
- /**
- * Add the given items as the next child entities, if [items] is not null.
- */
- void addAll(Iterable items) {
- if (items != null) {
- _entities.addAll(items);
- }
- }
-}
-
-/**
- * The declaration of a class.
- *
- * > classDeclaration ::=
- * > 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
- * > ([ExtendsClause] [WithClause]?)?
- * > [ImplementsClause]?
- * > '{' [ClassMember]* '}'
- */
-class ClassDeclaration extends NamedCompilationUnitMember {
- /**
- * The 'abstract' keyword, or `null` if the keyword was absent.
- */
- Token abstractKeyword;
-
- /**
- * The token representing the 'class' keyword.
- */
- Token classKeyword;
-
- /**
- * The type parameters for the class, or `null` if the class does not have any
- * type parameters.
- */
- TypeParameterList _typeParameters;
-
- /**
- * The extends clause for the class, or `null` if the class does not extend
- * any other class.
- */
- ExtendsClause _extendsClause;
-
- /**
- * The with clause for the class, or `null` if the class does not have a with
- * clause.
- */
- WithClause _withClause;
-
- /**
- * The implements clause for the class, or `null` if the class does not
- * implement any interfaces.
- */
- ImplementsClause _implementsClause;
-
- /**
- * The native clause for the class, or `null` if the class does not have a
- * native clause.
- */
- NativeClause _nativeClause;
-
- /**
- * The left curly bracket.
- */
- Token leftBracket;
-
- /**
- * The members defined by the class.
- */
- NodeList<ClassMember> _members;
-
- /**
- * The right curly bracket.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created class declaration. Either or both of the
- * [comment] and [metadata] can be `null` if the class does not have the
- * corresponding attribute. The [abstractKeyword] can be `null` if the class
- * is not abstract. The [typeParameters] can be `null` if the class does not
- * have any type parameters. Any or all of the [extendsClause], [withClause],
- * and [implementsClause] can be `null` if the class does not have the
- * corresponding clause. The list of [members] can be `null` if the class does
- * not have any members.
- */
- ClassDeclaration(
- Comment comment,
- List<Annotation> metadata,
- this.abstractKeyword,
- this.classKeyword,
- SimpleIdentifier name,
- TypeParameterList typeParameters,
- ExtendsClause extendsClause,
- WithClause withClause,
- ImplementsClause implementsClause,
- this.leftBracket,
- List<ClassMember> members,
- this.rightBracket)
- : super(comment, metadata, name) {
- _typeParameters = _becomeParentOf(typeParameters);
- _extendsClause = _becomeParentOf(extendsClause);
- _withClause = _becomeParentOf(withClause);
- _implementsClause = _becomeParentOf(implementsClause);
- _members = new NodeList<ClassMember>(this, members);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(abstractKeyword)
- ..add(classKeyword)
- ..add(_name)
- ..add(_typeParameters)
- ..add(_extendsClause)
- ..add(_withClause)
- ..add(_implementsClause)
- ..add(_nativeClause)
- ..add(leftBracket)
- ..addAll(members)
- ..add(rightBracket);
-
- @override
- ClassElement get element =>
- _name != null ? (_name.staticElement as ClassElement) : null;
-
- @override
- Token get endToken => rightBracket;
-
- /**
- * Return the extends clause for this class, or `null` if the class does not
- * extend any other class.
- */
- ExtendsClause get extendsClause => _extendsClause;
-
- /**
- * Set the extends clause for this class to the given [extendsClause].
- */
- void set extendsClause(ExtendsClause extendsClause) {
- _extendsClause = _becomeParentOf(extendsClause);
- }
-
- @override
- Token get firstTokenAfterCommentAndMetadata {
- if (abstractKeyword != null) {
- return abstractKeyword;
- }
- return classKeyword;
- }
-
- /**
- * Return the implements clause for the class, or `null` if the class does not
- * implement any interfaces.
- */
- ImplementsClause get implementsClause => _implementsClause;
-
- /**
- * Set the implements clause for the class to the given [implementsClause].
- */
- void set implementsClause(ImplementsClause implementsClause) {
- _implementsClause = _becomeParentOf(implementsClause);
- }
-
- /**
- * Return `true` if this class is declared to be an abstract class.
- */
- bool get isAbstract => abstractKeyword != null;
-
- /**
- * Return the members defined by the class.
- */
- NodeList<ClassMember> get members => _members;
-
- /**
- * Return the native clause for this class, or `null` if the class does not
- * have a native clause.
- */
- NativeClause get nativeClause => _nativeClause;
-
- /**
- * Set the native clause for this class to the given [nativeClause].
- */
- void set nativeClause(NativeClause nativeClause) {
- _nativeClause = _becomeParentOf(nativeClause);
- }
-
- /**
- * Return the type parameters for the class, or `null` if the class does not
- * have any type parameters.
- */
- TypeParameterList get typeParameters => _typeParameters;
-
- /**
- * Set the type parameters for the class to the given list of [typeParameters].
- */
- void set typeParameters(TypeParameterList typeParameters) {
- _typeParameters = _becomeParentOf(typeParameters);
- }
-
- /**
- * Return the with clause for the class, or `null` if the class does not have
- * a with clause.
- */
- WithClause get withClause => _withClause;
-
- /**
- * Set the with clause for the class to the given [withClause].
- */
- void set withClause(WithClause withClause) {
- _withClause = _becomeParentOf(withClause);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitClassDeclaration(this);
-
- /**
- * Return the constructor declared in the class with the given [name], or
- * `null` if there is no such constructor. If the [name] is `null` then the
- * default constructor will be searched for.
- */
- ConstructorDeclaration getConstructor(String name) {
- for (ClassMember classMember in _members) {
- if (classMember is ConstructorDeclaration) {
- ConstructorDeclaration constructor = classMember;
- SimpleIdentifier constructorName = constructor.name;
- if (name == null && constructorName == null) {
- return constructor;
- }
- if (constructorName != null && constructorName.name == name) {
- return constructor;
- }
- }
- }
- return null;
- }
-
- /**
- * Return the field declared in the class with the given [name], or `null` if
- * there is no such field.
- */
- VariableDeclaration getField(String name) {
- for (ClassMember classMember in _members) {
- if (classMember is FieldDeclaration) {
- FieldDeclaration fieldDeclaration = classMember;
- NodeList<VariableDeclaration> fields =
- fieldDeclaration.fields.variables;
- for (VariableDeclaration field in fields) {
- SimpleIdentifier fieldName = field.name;
- if (fieldName != null && name == fieldName.name) {
- return field;
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Return the method declared in the class with the given [name], or `null` if
- * there is no such method.
- */
- MethodDeclaration getMethod(String name) {
- for (ClassMember classMember in _members) {
- if (classMember is MethodDeclaration) {
- MethodDeclaration method = classMember;
- SimpleIdentifier methodName = method.name;
- if (methodName != null && name == methodName.name) {
- return method;
- }
- }
- }
- return null;
- }
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_typeParameters, visitor);
- _safelyVisitChild(_extendsClause, visitor);
- _safelyVisitChild(_withClause, visitor);
- _safelyVisitChild(_implementsClause, visitor);
- _safelyVisitChild(_nativeClause, visitor);
- members.accept(visitor);
- }
-}
-
-/**
- * A node that declares a name within the scope of a class.
- */
-abstract class ClassMember extends Declaration {
- /**
- * Initialize a newly created member of a class. Either or both of the
- * [comment] and [metadata] can be `null` if the member does not have the
- * corresponding attribute.
- */
- ClassMember(Comment comment, List<Annotation> metadata)
- : super(comment, metadata);
-}
-
-/**
- * A class type alias.
- *
- * > classTypeAlias ::=
- * > [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
- * >
- * > mixinApplication ::=
- * > [TypeName] [WithClause] [ImplementsClause]? ';'
- */
-class ClassTypeAlias extends TypeAlias {
- /**
- * The type parameters for the class, or `null` if the class does not have any
- * type parameters.
- */
- TypeParameterList _typeParameters;
-
- /**
- * The token for the '=' separating the name from the definition.
- */
- Token equals;
-
- /**
- * The token for the 'abstract' keyword, or `null` if this is not defining an
- * abstract class.
- */
- Token abstractKeyword;
-
- /**
- * The name of the superclass of the class being declared.
- */
- TypeName _superclass;
-
- /**
- * The with clause for this class.
- */
- WithClause _withClause;
-
- /**
- * The implements clause for this class, or `null` if there is no implements
- * clause.
- */
- ImplementsClause _implementsClause;
-
- /**
- * Initialize a newly created class type alias. Either or both of the
- * [comment] and [metadata] can be `null` if the class type alias does not
- * have the corresponding attribute. The [typeParameters] can be `null` if the
- * class does not have any type parameters. The [abstractKeyword] can be
- * `null` if the class is not abstract. The [implementsClause] can be `null`
- * if the class does not implement any interfaces.
- */
- ClassTypeAlias(
- Comment comment,
- List<Annotation> metadata,
- Token keyword,
- SimpleIdentifier name,
- TypeParameterList typeParameters,
- this.equals,
- this.abstractKeyword,
- TypeName superclass,
- WithClause withClause,
- ImplementsClause implementsClause,
- Token semicolon)
- : super(comment, metadata, keyword, name, semicolon) {
- _typeParameters = _becomeParentOf(typeParameters);
- _superclass = _becomeParentOf(superclass);
- _withClause = _becomeParentOf(withClause);
- _implementsClause = _becomeParentOf(implementsClause);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(typedefKeyword)
- ..add(_name)
- ..add(_typeParameters)
- ..add(equals)
- ..add(abstractKeyword)
- ..add(_superclass)
- ..add(_withClause)
- ..add(_implementsClause)
- ..add(semicolon);
-
- @override
- ClassElement get element =>
- _name != null ? (_name.staticElement as ClassElement) : null;
-
- /**
- * Return the implements clause for this class, or `null` if there is no
- * implements clause.
- */
- ImplementsClause get implementsClause => _implementsClause;
-
- /**
- * Set the implements clause for this class to the given [implementsClause].
- */
- void set implementsClause(ImplementsClause implementsClause) {
- _implementsClause = _becomeParentOf(implementsClause);
- }
-
- /**
- * Return `true` if this class is declared to be an abstract class.
- */
- bool get isAbstract => abstractKeyword != null;
-
- /**
- * Return the name of the superclass of the class being declared.
- */
- TypeName get superclass => _superclass;
-
- /**
- * Set the name of the superclass of the class being declared to the given
- * [superclass] name.
- */
- void set superclass(TypeName superclass) {
- _superclass = _becomeParentOf(superclass);
- }
-
- /**
- * Return the type parameters for the class, or `null` if the class does not
- * have any type parameters.
- */
- TypeParameterList get typeParameters => _typeParameters;
-
- /**
- * Set the type parameters for the class to the given list of [typeParameters].
- */
- void set typeParameters(TypeParameterList typeParameters) {
- _typeParameters = _becomeParentOf(typeParameters);
- }
-
- /**
- * Return the with clause for this class.
- */
- WithClause get withClause => _withClause;
-
- /**
- * Set the with clause for this class to the given with [withClause].
- */
- void set withClause(WithClause withClause) {
- _withClause = _becomeParentOf(withClause);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitClassTypeAlias(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_typeParameters, visitor);
- _safelyVisitChild(_superclass, visitor);
- _safelyVisitChild(_withClause, visitor);
- _safelyVisitChild(_implementsClause, visitor);
- }
-}
-
-/**
- * A combinator associated with an import or export directive.
- *
- * > combinator ::=
- * > [HideCombinator]
- * > | [ShowCombinator]
- */
-abstract class Combinator extends AstNode {
- /**
- * The 'hide' or 'show' keyword specifying what kind of processing is to be
- * done on the names.
- */
- Token keyword;
-
- /**
- * Initialize a newly created combinator.
- */
- Combinator(this.keyword);
-
- @override
- Token get beginToken => keyword;
-}
-
-/**
- * A comment within the source code.
- *
- * > comment ::=
- * > endOfLineComment
- * > | blockComment
- * > | documentationComment
- * >
- * > endOfLineComment ::=
- * > '//' (CHARACTER - EOL)* EOL
- * >
- * > blockComment ::=
- * > '/ *' CHARACTER* '*/'
- * >
- * > documentationComment ::=
- * > '/ **' (CHARACTER | [CommentReference])* '*/'
- * > | ('///' (CHARACTER - EOL)* EOL)+
- */
-class Comment extends AstNode {
- /**
- * The tokens representing the comment.
- */
- final List<Token> tokens;
-
- /**
- * The type of the comment.
- */
- final CommentType _type;
-
- /**
- * The references embedded within the documentation comment. This list will be
- * empty unless this is a documentation comment that has references embedded
- * within it.
- */
- NodeList<CommentReference> _references;
-
- /**
- * Initialize a newly created comment. The list of [tokens] must contain at
- * least one token. The [type] is the type of the comment. The list of
- * [references] can be empty if the comment does not contain any embedded
- * references.
- */
- Comment(this.tokens, this._type, List<CommentReference> references) {
- _references = new NodeList<CommentReference>(this, references);
- }
-
- @override
- Token get beginToken => tokens[0];
-
- @override
- Iterable get childEntities => new ChildEntities()..addAll(tokens);
-
- @override
- Token get endToken => tokens[tokens.length - 1];
-
- /**
- * Return `true` if this is a block comment.
- */
- bool get isBlock => _type == CommentType.BLOCK;
-
- /**
- * Return `true` if this is a documentation comment.
- */
- bool get isDocumentation => _type == CommentType.DOCUMENTATION;
-
- /**
- * Return `true` if this is an end-of-line comment.
- */
- bool get isEndOfLine => _type == CommentType.END_OF_LINE;
-
- /**
- * Return the references embedded within the documentation comment.
- */
- NodeList<CommentReference> get references => _references;
-
- @override
- accept(AstVisitor visitor) => visitor.visitComment(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _references.accept(visitor);
- }
-
- /**
- * Create a block comment consisting of the given [tokens].
- */
- static Comment createBlockComment(List<Token> tokens) =>
- new Comment(tokens, CommentType.BLOCK, null);
-
- /**
- * Create a documentation comment consisting of the given [tokens].
- */
- static Comment createDocumentationComment(List<Token> tokens) => new Comment(
- tokens, CommentType.DOCUMENTATION, new List<CommentReference>());
-
- /**
- * Create a documentation comment consisting of the given [tokens] and having
- * the given [references] embedded within it.
- */
- static Comment createDocumentationCommentWithReferences(
- List<Token> tokens, List<CommentReference> references) =>
- new Comment(tokens, CommentType.DOCUMENTATION, references);
-
- /**
- * Create an end-of-line comment consisting of the given [tokens].
- */
- static Comment createEndOfLineComment(List<Token> tokens) =>
- new Comment(tokens, CommentType.END_OF_LINE, null);
-}
-
-/**
- * A reference to a Dart element that is found within a documentation comment.
- *
- * > commentReference ::=
- * > '[' 'new'? [Identifier] ']'
- */
-class CommentReference extends AstNode {
- /**
- * The token representing the 'new' keyword, or `null` if there was no 'new'
- * keyword.
- */
- Token newKeyword;
-
- /**
- * The identifier being referenced.
- */
- Identifier _identifier;
-
- /**
- * Initialize a newly created reference to a Dart element. The [newKeyword]
- * can be `null` if the reference is not to a constructor.
- */
- CommentReference(this.newKeyword, Identifier identifier) {
- _identifier = _becomeParentOf(identifier);
- }
-
- @override
- Token get beginToken => _identifier.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(newKeyword)..add(_identifier);
-
- @override
- Token get endToken => _identifier.endToken;
-
- /**
- * Return the identifier being referenced.
- */
- Identifier get identifier => _identifier;
-
- /**
- * Set the identifier being referenced to the given [identifier].
- */
- void set identifier(Identifier identifier) {
- _identifier = _becomeParentOf(identifier);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitCommentReference(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_identifier, visitor);
- }
-}
-
-/**
- * The possible types of comments that are recognized by the parser.
- */
-class CommentType {
- /**
- * A block comment.
- */
- static const CommentType BLOCK = const CommentType('BLOCK');
-
- /**
- * A documentation comment.
- */
- static const CommentType DOCUMENTATION = const CommentType('DOCUMENTATION');
-
- /**
- * An end-of-line comment.
- */
- static const CommentType END_OF_LINE = const CommentType('END_OF_LINE');
-
- /**
- * The name of the comment type.
- */
- final String name;
-
- /**
- * Initialize a newly created comment type to have the given [name].
- */
- const CommentType(this.name);
-
- @override
- String toString() => name;
-}
-
-/**
- * A compilation unit.
- *
- * While the grammar restricts the order of the directives and declarations
- * within a compilation unit, this class does not enforce those restrictions.
- * In particular, the children of a compilation unit will be visited in lexical
- * order even if lexical order does not conform to the restrictions of the
- * grammar.
- *
- * > compilationUnit ::=
- * > directives declarations
- * >
- * > directives ::=
- * > [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
- * > | [PartOfDirective]
- * >
- * > namespaceDirective ::=
- * > [ImportDirective]
- * > | [ExportDirective]
- * >
- * > declarations ::=
- * > [CompilationUnitMember]*
- */
-class CompilationUnit extends AstNode {
- /**
- * The first token in the token stream that was parsed to form this
- * compilation unit.
- */
- Token beginToken;
-
- /**
- * The script tag at the beginning of the compilation unit, or `null` if there
- * is no script tag in this compilation unit.
- */
- ScriptTag _scriptTag;
-
- /**
- * The directives contained in this compilation unit.
- */
- NodeList<Directive> _directives;
-
- /**
- * The declarations contained in this compilation unit.
- */
- NodeList<CompilationUnitMember> _declarations;
-
- /**
- * The last token in the token stream that was parsed to form this compilation
- * unit. This token should always have a type of [TokenType.EOF].
- */
- Token endToken;
-
- /**
- * The element associated with this compilation unit, or `null` if the AST
- * structure has not been resolved.
- */
- CompilationUnitElement element;
-
- /**
- * The line information for this compilation unit.
- */
- LineInfo lineInfo;
-
- /**
- * Initialize a newly created compilation unit to have the given directives
- * and declarations. The [scriptTag] can be `null` if there is no script tag
- * in the compilation unit. The list of [directives] can be `null` if there
- * are no directives in the compilation unit. The list of [declarations] can
- * be `null` if there are no declarations in the compilation unit.
- */
- CompilationUnit(
- this.beginToken,
- ScriptTag scriptTag,
- List<Directive> directives,
- List<CompilationUnitMember> declarations,
- this.endToken) {
- _scriptTag = _becomeParentOf(scriptTag);
- _directives = new NodeList<Directive>(this, directives);
- _declarations = new NodeList<CompilationUnitMember>(this, declarations);
- }
-
- @override
- Iterable get childEntities {
- ChildEntities result = new ChildEntities()..add(_scriptTag);
- if (_directivesAreBeforeDeclarations) {
- result..addAll(_directives)..addAll(_declarations);
- } else {
- result.addAll(sortedDirectivesAndDeclarations);
- }
- return result;
- }
-
- /**
- * Return the declarations contained in this compilation unit.
- */
- NodeList<CompilationUnitMember> get declarations => _declarations;
-
- /**
- * Return the directives contained in this compilation unit.
- */
- NodeList<Directive> get directives => _directives;
-
- @override
- int get length {
- Token endToken = this.endToken;
- if (endToken == null) {
- return 0;
- }
- return endToken.offset + endToken.length;
- }
-
- @override
- int get offset => 0;
-
- /**
- * Return the script tag at the beginning of the compilation unit, or `null`
- * if there is no script tag in this compilation unit.
- */
- ScriptTag get scriptTag => _scriptTag;
-
- /**
- * Set the script tag at the beginning of the compilation unit to the given
- * [scriptTag].
- */
- void set scriptTag(ScriptTag scriptTag) {
- _scriptTag = _becomeParentOf(scriptTag);
- }
-
- /**
- * Return a list containing all of the directives and declarations in this
- * compilation unit, sorted in lexical order.
- */
- List<AstNode> get sortedDirectivesAndDeclarations {
- return <AstNode>[]
- ..addAll(_directives)
- ..addAll(_declarations)
- ..sort(AstNode.LEXICAL_ORDER);
- }
-
- /**
- * Return `true` if all of the directives are lexically before any
- * declarations.
- */
- bool get _directivesAreBeforeDeclarations {
- if (_directives.isEmpty || _declarations.isEmpty) {
- return true;
- }
- Directive lastDirective = _directives[_directives.length - 1];
- CompilationUnitMember firstDeclaration = _declarations[0];
- return lastDirective.offset < firstDeclaration.offset;
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitCompilationUnit(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_scriptTag, visitor);
- if (_directivesAreBeforeDeclarations) {
- _directives.accept(visitor);
- _declarations.accept(visitor);
- } else {
- for (AstNode child in sortedDirectivesAndDeclarations) {
- child.accept(visitor);
- }
- }
- }
-}
-
-/**
- * A node that declares one or more names within the scope of a compilation
- * unit.
- *
- * > compilationUnitMember ::=
- * > [ClassDeclaration]
- * > | [TypeAlias]
- * > | [FunctionDeclaration]
- * > | [MethodDeclaration]
- * > | [VariableDeclaration]
- * > | [VariableDeclaration]
- */
-abstract class CompilationUnitMember extends Declaration {
- /**
- * Initialize a newly created generic compilation unit member. Either or both
- * of the [comment] and [metadata] can be `null` if the member does not have
- * the corresponding attribute.
- */
- CompilationUnitMember(Comment comment, List<Annotation> metadata)
- : super(comment, metadata);
-}
-
-/**
- * A conditional expression.
- *
- * > conditionalExpression ::=
- * > [Expression] '?' [Expression] ':' [Expression]
- */
-class ConditionalExpression extends Expression {
- /**
- * The condition used to determine which of the expressions is executed next.
- */
- Expression _condition;
-
- /**
- * The token used to separate the condition from the then expression.
- */
- Token question;
-
- /**
- * The expression that is executed if the condition evaluates to `true`.
- */
- Expression _thenExpression;
-
- /**
- * The token used to separate the then expression from the else expression.
- */
- Token colon;
-
- /**
- * The expression that is executed if the condition evaluates to `false`.
- */
- Expression _elseExpression;
-
- /**
- * Initialize a newly created conditional expression.
- */
- ConditionalExpression(Expression condition, this.question,
- Expression thenExpression, this.colon, Expression elseExpression) {
- _condition = _becomeParentOf(condition);
- _thenExpression = _becomeParentOf(thenExpression);
- _elseExpression = _becomeParentOf(elseExpression);
- }
-
- @override
- Token get beginToken => _condition.beginToken;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(_condition)
- ..add(question)
- ..add(_thenExpression)
- ..add(colon)
- ..add(_elseExpression);
-
- /**
- * Return the condition used to determine which of the expressions is executed
- * next.
- */
- Expression get condition => _condition;
-
- /**
- * Set the condition used to determine which of the expressions is executed
- * next to the given [expression].
- */
- void set condition(Expression expression) {
- _condition = _becomeParentOf(expression);
- }
-
- /**
- * Return the expression that is executed if the condition evaluates to
- * `false`.
- */
- Expression get elseExpression => _elseExpression;
-
- /**
- * Set the expression that is executed if the condition evaluates to `false`
- * to the given [expression].
- */
- void set elseExpression(Expression expression) {
- _elseExpression = _becomeParentOf(expression);
- }
-
- @override
- Token get endToken => _elseExpression.endToken;
-
- @override
- int get precedence => 3;
-
- /**
- * Return the expression that is executed if the condition evaluates to
- * `true`.
- */
- Expression get thenExpression => _thenExpression;
-
- /**
- * Set the expression that is executed if the condition evaluates to `true` to
- * the given [expression].
- */
- void set thenExpression(Expression expression) {
- _thenExpression = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitConditionalExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_condition, visitor);
- _safelyVisitChild(_thenExpression, visitor);
- _safelyVisitChild(_elseExpression, visitor);
- }
-}
-
-/**
- * A configuration in either an import or export directive.
- *
- * configuration ::=
- * 'if' '(' test ')' uri
- *
- * test ::=
- * dottedName ('==' stringLiteral)?
- *
- * dottedName ::=
- * identifier ('.' identifier)*
- */
-class Configuration extends AstNode {
- Token ifKeyword;
- Token leftParenthesis;
- DottedName _name;
- Token equalToken;
- StringLiteral _value;
- Token rightParenthesis;
- StringLiteral _libraryUri;
-
- Configuration(
- this.ifKeyword,
- this.leftParenthesis,
- DottedName name,
- this.equalToken,
- StringLiteral value,
- this.rightParenthesis,
- StringLiteral libraryUri) {
- _name = _becomeParentOf(name);
- _value = _becomeParentOf(value);
- _libraryUri = _becomeParentOf(libraryUri);
- }
-
- @override
- Token get beginToken => ifKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(ifKeyword)
- ..add(leftParenthesis)
- ..add(_name)
- ..add(equalToken)
- ..add(_value)
- ..add(rightParenthesis)
- ..add(_libraryUri);
-
- @override
- Token get endToken => _libraryUri.endToken;
-
- StringLiteral get libraryUri => _libraryUri;
-
- void set libraryUri(StringLiteral libraryUri) {
- _libraryUri = _becomeParentOf(libraryUri);
- }
-
- DottedName get name => _name;
-
- void set name(DottedName name) {
- _name = _becomeParentOf(name);
- }
-
- StringLiteral get value => _value;
-
- void set value(StringLiteral value) {
- _value = _becomeParentOf(value);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitConfiguration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_value, visitor);
- _safelyVisitChild(_libraryUri, visitor);
- }
-}
-
-/**
- * A constructor declaration.
- *
- * > constructorDeclaration ::=
- * > constructorSignature [FunctionBody]?
- * > | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
- * >
- * > constructorSignature ::=
- * > 'external'? constructorName formalParameterList initializerList?
- * > | 'external'? 'factory' factoryName formalParameterList initializerList?
- * > | 'external'? 'const' constructorName formalParameterList initializerList?
- * >
- * > constructorName ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])?
- * >
- * > factoryName ::=
- * > [Identifier] ('.' [SimpleIdentifier])?
- * >
- * > initializerList ::=
- * > ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
- */
-class ConstructorDeclaration extends ClassMember {
- /**
- * The token for the 'external' keyword, or `null` if the constructor is not
- * external.
- */
- Token externalKeyword;
-
- /**
- * The token for the 'const' keyword, or `null` if the constructor is not a
- * const constructor.
- */
- Token constKeyword;
-
- /**
- * The token for the 'factory' keyword, or `null` if the constructor is not a
- * factory constructor.
- */
- Token factoryKeyword;
-
- /**
- * The type of object being created. This can be different than the type in
- * which the constructor is being declared if the constructor is the
- * implementation of a factory constructor.
- */
- Identifier _returnType;
-
- /**
- * The token for the period before the constructor name, or `null` if the
- * constructor being declared is unnamed.
- */
- Token period;
-
- /**
- * The name of the constructor, or `null` if the constructor being declared is
- * unnamed.
- */
- SimpleIdentifier _name;
-
- /**
- * The parameters associated with the constructor.
- */
- FormalParameterList _parameters;
-
- /**
- * The token for the separator (colon or equals) before the initializer list
- * or redirection, or `null` if there are no initializers.
- */
- Token separator;
-
- /**
- * The initializers associated with the constructor.
- */
- NodeList<ConstructorInitializer> _initializers;
-
- /**
- * The name of the constructor to which this constructor will be redirected,
- * or `null` if this is not a redirecting factory constructor.
- */
- ConstructorName _redirectedConstructor;
-
- /**
- * The body of the constructor, or `null` if the constructor does not have a
- * body.
- */
- FunctionBody _body;
-
- /**
- * The element associated with this constructor, or `null` if the AST
- * structure has not been resolved or if this constructor could not be
- * resolved.
- */
- ConstructorElement element;
-
- /**
- * Initialize a newly created constructor declaration. The [externalKeyword]
- * can be `null` if the constructor is not external. Either or both of the
- * [comment] and [metadata] can be `null` if the constructor does not have the
- * corresponding attribute. The [constKeyword] can be `null` if the
- * constructor cannot be used to create a constant. The [factoryKeyword] can
- * be `null` if the constructor is not a factory. The [period] and [name] can
- * both be `null` if the constructor is not a named constructor. The
- * [separator] can be `null` if the constructor does not have any initializers
- * and does not redirect to a different constructor. The list of
- * [initializers] can be `null` if the constructor does not have any
- * initializers. The [redirectedConstructor] can be `null` if the constructor
- * does not redirect to a different constructor. The [body] can be `null` if
- * the constructor does not have a body.
- */
- ConstructorDeclaration(
- Comment comment,
- List<Annotation> metadata,
- this.externalKeyword,
- this.constKeyword,
- this.factoryKeyword,
- Identifier returnType,
- this.period,
- SimpleIdentifier name,
- FormalParameterList parameters,
- this.separator,
- List<ConstructorInitializer> initializers,
- ConstructorName redirectedConstructor,
- FunctionBody body)
- : super(comment, metadata) {
- _returnType = _becomeParentOf(returnType);
- _name = _becomeParentOf(name);
- _parameters = _becomeParentOf(parameters);
- _initializers = new NodeList<ConstructorInitializer>(this, initializers);
- _redirectedConstructor = _becomeParentOf(redirectedConstructor);
- _body = _becomeParentOf(body);
- }
-
- /**
- * Return the body of the constructor, or `null` if the constructor does not
- * have a body.
- */
- FunctionBody get body => _body;
-
- /**
- * Set the body of the constructor to the given [functionBody].
- */
- void set body(FunctionBody functionBody) {
- _body = _becomeParentOf(functionBody);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(externalKeyword)
- ..add(constKeyword)
- ..add(factoryKeyword)
- ..add(_returnType)
- ..add(period)
- ..add(_name)
- ..add(_parameters)
- ..add(separator)
- ..addAll(initializers)
- ..add(_redirectedConstructor)
- ..add(_body);
-
- @override
- Token get endToken {
- if (_body != null) {
- return _body.endToken;
- } else if (!_initializers.isEmpty) {
- return _initializers.endToken;
- }
- return _parameters.endToken;
- }
-
- @override
- Token get firstTokenAfterCommentAndMetadata {
- Token leftMost =
- Token.lexicallyFirst([externalKeyword, constKeyword, factoryKeyword]);
- if (leftMost != null) {
- return leftMost;
- }
- return _returnType.beginToken;
- }
-
- /**
- * Return the initializers associated with the constructor.
- */
- NodeList<ConstructorInitializer> get initializers => _initializers;
-
- /**
- * Return the name of the constructor, or `null` if the constructor being
- * declared is unnamed.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the constructor to the given [identifier].
- */
- void set name(SimpleIdentifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- /**
- * Return the parameters associated with the constructor.
- */
- FormalParameterList get parameters => _parameters;
-
- /**
- * Set the parameters associated with the constructor to the given list of
- * [parameters].
- */
- void set parameters(FormalParameterList parameters) {
- _parameters = _becomeParentOf(parameters);
- }
-
- /**
- * Return the name of the constructor to which this constructor will be
- * redirected, or `null` if this is not a redirecting factory constructor.
- */
- ConstructorName get redirectedConstructor => _redirectedConstructor;
-
- /**
- * Set the name of the constructor to which this constructor will be
- * redirected to the given [redirectedConstructor] name.
- */
- void set redirectedConstructor(ConstructorName redirectedConstructor) {
- _redirectedConstructor = _becomeParentOf(redirectedConstructor);
- }
-
- /**
- * Return the type of object being created. This can be different than the
- * type in which the constructor is being declared if the constructor is the
- * implementation of a factory constructor.
- */
- Identifier get returnType => _returnType;
-
- /**
- * Set the type of object being created to the given [typeName].
- */
- void set returnType(Identifier typeName) {
- _returnType = _becomeParentOf(typeName);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitConstructorDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_returnType, visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_parameters, visitor);
- _initializers.accept(visitor);
- _safelyVisitChild(_redirectedConstructor, visitor);
- _safelyVisitChild(_body, visitor);
- }
-}
-
-/**
- * The initialization of a field within a constructor's initialization list.
- *
- * > fieldInitializer ::=
- * > ('this' '.')? [SimpleIdentifier] '=' [Expression]
- */
-class ConstructorFieldInitializer extends ConstructorInitializer {
- /**
- * The token for the 'this' keyword, or `null` if there is no 'this' keyword.
- */
- Token thisKeyword;
-
- /**
- * The token for the period after the 'this' keyword, or `null` if there is no
- * 'this' keyword.
- */
- Token period;
-
- /**
- * The name of the field being initialized.
- */
- SimpleIdentifier _fieldName;
-
- /**
- * The token for the equal sign between the field name and the expression.
- */
- Token equals;
-
- /**
- * The expression computing the value to which the field will be initialized.
- */
- Expression _expression;
-
- /**
- * Initialize a newly created field initializer to initialize the field with
- * the given name to the value of the given expression. The [thisKeyword] and
- * [period] can be `null` if the 'this' keyword was not specified.
- */
- ConstructorFieldInitializer(this.thisKeyword, this.period,
- SimpleIdentifier fieldName, this.equals, Expression expression) {
- _fieldName = _becomeParentOf(fieldName);
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken {
- if (thisKeyword != null) {
- return thisKeyword;
- }
- return _fieldName.beginToken;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(thisKeyword)
- ..add(period)
- ..add(_fieldName)
- ..add(equals)
- ..add(_expression);
-
- @override
- Token get endToken => _expression.endToken;
-
- /**
- * Return the expression computing the value to which the field will be
- * initialized.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression computing the value to which the field will be
- * initialized to the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- /**
- * Return the name of the field being initialized.
- */
- SimpleIdentifier get fieldName => _fieldName;
-
- /**
- * Set the name of the field being initialized to the given [identifier].
- */
- void set fieldName(SimpleIdentifier identifier) {
- _fieldName = _becomeParentOf(identifier);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitConstructorFieldInitializer(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_fieldName, visitor);
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * A node that can occur in the initializer list of a constructor declaration.
- *
- * > constructorInitializer ::=
- * > [SuperConstructorInvocation]
- * > | [ConstructorFieldInitializer]
- * > | [RedirectingConstructorInvocation]
- */
-abstract class ConstructorInitializer extends AstNode {}
-
-/**
- * The name of the constructor.
- *
- * > constructorName ::=
- * > type ('.' identifier)?
- */
-class ConstructorName extends AstNode {
- /**
- * The name of the type defining the constructor.
- */
- TypeName _type;
-
- /**
- * The token for the period before the constructor name, or `null` if the
- * specified constructor is the unnamed constructor.
- */
- Token period;
-
- /**
- * The name of the constructor, or `null` if the specified constructor is the
- * unnamed constructor.
- */
- SimpleIdentifier _name;
-
- /**
- * The element associated with this constructor name based on static type
- * information, or `null` if the AST structure has not been resolved or if
- * this constructor name could not be resolved.
- */
- ConstructorElement staticElement;
-
- /**
- * Initialize a newly created constructor name. The [period] and [name] can be
- * `null` if the constructor being named is the unnamed constructor.
- */
- ConstructorName(TypeName type, this.period, SimpleIdentifier name) {
- _type = _becomeParentOf(type);
- _name = _becomeParentOf(name);
- }
-
- @override
- Token get beginToken => _type.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_type)..add(period)..add(_name);
-
- @override
- Token get endToken {
- if (_name != null) {
- return _name.endToken;
- }
- return _type.endToken;
- }
-
- /**
- * Return the name of the constructor, or `null` if the specified constructor
- * is the unnamed constructor.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the constructor to the given [name].
- */
- void set name(SimpleIdentifier name) {
- _name = _becomeParentOf(name);
- }
-
- /**
- * Return the name of the type defining the constructor.
- */
- TypeName get type => _type;
-
- /**
- * Set the name of the type defining the constructor to the given [type] name.
- */
- void set type(TypeName type) {
- _type = _becomeParentOf(type);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitConstructorName(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_type, visitor);
- _safelyVisitChild(_name, visitor);
- }
-}
-
-/**
- * A continue statement.
- *
- * > continueStatement ::=
- * > 'continue' [SimpleIdentifier]? ';'
- */
-class ContinueStatement extends Statement {
- /**
- * The token representing the 'continue' keyword.
- */
- Token continueKeyword;
-
- /**
- * The label associated with the statement, or `null` if there is no label.
- */
- SimpleIdentifier _label;
-
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * The AstNode which this continue statement is continuing to. This will be
- * either a Statement (in the case of continuing a loop) or a SwitchMember
- * (in the case of continuing from one switch case to another). Null if the
- * AST has not yet been resolved or if the target could not be resolved.
- * Note that if the source code has errors, the target may be invalid (e.g.
- * the target may be in an enclosing function).
- */
- AstNode target;
-
- /**
- * Initialize a newly created continue statement. The [label] can be `null` if
- * there is no label associated with the statement.
- */
- ContinueStatement(
- this.continueKeyword, SimpleIdentifier label, this.semicolon) {
- _label = _becomeParentOf(label);
- }
-
- @override
- Token get beginToken => continueKeyword;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(continueKeyword)..add(_label)..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- /**
- * Return the label associated with the statement, or `null` if there is no
- * label.
- */
- SimpleIdentifier get label => _label;
-
- /**
- * Set the label associated with the statement to the given [identifier].
- */
- void set label(SimpleIdentifier identifier) {
- _label = _becomeParentOf(identifier);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitContinueStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_label, visitor);
- }
-}
-
-/**
- * A node that represents the declaration of one or more names. Each declared
- * name is visible within a name scope.
- */
-abstract class Declaration extends AnnotatedNode {
- /**
- * Initialize a newly created declaration. Either or both of the [comment] and
- * [metadata] can be `null` if the declaration does not have the corresponding
- * attribute.
- */
- Declaration(Comment comment, List<Annotation> metadata)
- : super(comment, metadata);
-
- /**
- * Return the element associated with this declaration, or `null` if either
- * this node corresponds to a list of declarations or if the AST structure has
- * not been resolved.
- */
- Element get element;
-}
-
-/**
- * The declaration of a single identifier.
- *
- * > declaredIdentifier ::=
- * > [Annotation] finalConstVarOrType [SimpleIdentifier]
- */
-class DeclaredIdentifier extends Declaration {
- /**
- * The token representing either the 'final', 'const' or 'var' keyword, or
- * `null` if no keyword was used.
- */
- Token keyword;
-
- /**
- * The name of the declared type of the parameter, or `null` if the parameter
- * does not have a declared type.
- */
- TypeName _type;
-
- /**
- * The name of the variable being declared.
- */
- SimpleIdentifier _identifier;
-
- /**
- * Initialize a newly created formal parameter. Either or both of the
- * [comment] and [metadata] can be `null` if the declaration does not have the
- * corresponding attribute. The [keyword] can be `null` if a type name is
- * given. The [type] must be `null` if the keyword is 'var'.
- */
- DeclaredIdentifier(Comment comment, List<Annotation> metadata, this.keyword,
- TypeName type, SimpleIdentifier identifier)
- : super(comment, metadata) {
- _type = _becomeParentOf(type);
- _identifier = _becomeParentOf(identifier);
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(keyword)..add(_type)..add(_identifier);
-
- @override
- LocalVariableElement get element {
- if (_identifier == null) {
- return null;
- }
- return _identifier.staticElement as LocalVariableElement;
- }
-
- @override
- Token get endToken => _identifier.endToken;
-
- @override
- Token get firstTokenAfterCommentAndMetadata {
- if (keyword != null) {
- return keyword;
- } else if (_type != null) {
- return _type.beginToken;
- }
- return _identifier.beginToken;
- }
-
- /**
- * Return the name of the variable being declared.
- */
- SimpleIdentifier get identifier => _identifier;
-
- /**
- * Set the name of the variable being declared to the given [identifier].
- */
- void set identifier(SimpleIdentifier identifier) {
- _identifier = _becomeParentOf(identifier);
- }
-
- /**
- * Return `true` if this variable was declared with the 'const' modifier.
- */
- bool get isConst =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
-
- /**
- * Return `true` if this variable was declared with the 'final' modifier.
- * Variables that are declared with the 'const' modifier will return `false`
- * even though they are implicitly final.
- */
- bool get isFinal =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
-
- /**
- * Return the name of the declared type of the parameter, or `null` if the
- * parameter does not have a declared type.
- */
- TypeName get type => _type;
-
- /**
- * Set the name of the declared type of the parameter to the given [typeName].
- */
- void set type(TypeName typeName) {
- _type = _becomeParentOf(typeName);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitDeclaredIdentifier(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_type, visitor);
- _safelyVisitChild(_identifier, visitor);
- }
-}
-
-/**
- * A formal parameter with a default value. There are two kinds of parameters
- * that are both represented by this class: named formal parameters and
- * positional formal parameters.
- *
- * > defaultFormalParameter ::=
- * > [NormalFormalParameter] ('=' [Expression])?
- * >
- * > defaultNamedParameter ::=
- * > [NormalFormalParameter] (':' [Expression])?
- */
-class DefaultFormalParameter extends FormalParameter {
- /**
- * The formal parameter with which the default value is associated.
- */
- NormalFormalParameter _parameter;
-
- /**
- * The kind of this parameter.
- */
- ParameterKind kind;
-
- /**
- * The token separating the parameter from the default value, or `null` if
- * there is no default value.
- */
- Token separator;
-
- /**
- * The expression computing the default value for the parameter, or `null` if
- * there is no default value.
- */
- Expression _defaultValue;
-
- /**
- * Initialize a newly created default formal parameter. The [separator] and
- * [defaultValue] can be `null` if there is no default value.
- */
- DefaultFormalParameter(NormalFormalParameter parameter, this.kind,
- this.separator, Expression defaultValue) {
- _parameter = _becomeParentOf(parameter);
- _defaultValue = _becomeParentOf(defaultValue);
- }
-
- @override
- Token get beginToken => _parameter.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_parameter)..add(separator)..add(_defaultValue);
-
- /**
- * Return the expression computing the default value for the parameter, or
- * `null` if there is no default value.
- */
- Expression get defaultValue => _defaultValue;
-
- /**
- * Set the expression computing the default value for the parameter to the
- * given [expression].
- */
- void set defaultValue(Expression expression) {
- _defaultValue = _becomeParentOf(expression);
- }
-
- @override
- Token get endToken {
- if (_defaultValue != null) {
- return _defaultValue.endToken;
- }
- return _parameter.endToken;
- }
-
- @override
- SimpleIdentifier get identifier => _parameter.identifier;
-
- @override
- bool get isConst => _parameter != null && _parameter.isConst;
-
- @override
- bool get isFinal => _parameter != null && _parameter.isFinal;
-
- @override
- NodeList<Annotation> get metadata => _parameter.metadata;
-
- /**
- * Return the formal parameter with which the default value is associated.
- */
- NormalFormalParameter get parameter => _parameter;
-
- /**
- * Set the formal parameter with which the default value is associated to the
- * given [formalParameter].
- */
- void set parameter(NormalFormalParameter formalParameter) {
- _parameter = _becomeParentOf(formalParameter);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitDefaultFormalParameter(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_parameter, visitor);
- _safelyVisitChild(_defaultValue, visitor);
- }
-}
-
-/**
- * A node that represents a directive.
- *
- * > directive ::=
- * > [ExportDirective]
- * > | [ImportDirective]
- * > | [LibraryDirective]
- * > | [PartDirective]
- * > | [PartOfDirective]
- */
-abstract class Directive extends AnnotatedNode {
- /**
- * The element associated with this directive, or `null` if the AST structure
- * has not been resolved or if this directive could not be resolved.
- */
- Element element;
-
- /**
- * Initialize a newly create directive. Either or both of the [comment] and
- * [metadata] can be `null` if the directive does not have the corresponding
- * attribute.
- */
- Directive(Comment comment, List<Annotation> metadata)
- : super(comment, metadata);
-
- /**
- * Return the token representing the keyword that introduces this directive
- * ('import', 'export', 'library' or 'part').
- */
- Token get keyword;
-}
-
-/**
- * A do statement.
- *
- * > doStatement ::=
- * > 'do' [Statement] 'while' '(' [Expression] ')' ';'
- */
-class DoStatement extends Statement {
- /**
- * The token representing the 'do' keyword.
- */
- Token doKeyword;
-
- /**
- * The body of the loop.
- */
- Statement _body;
-
- /**
- * The token representing the 'while' keyword.
- */
- Token whileKeyword;
-
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The condition that determines when the loop will terminate.
- */
- Expression _condition;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created do loop.
- */
- DoStatement(
- this.doKeyword,
- Statement body,
- this.whileKeyword,
- this.leftParenthesis,
- Expression condition,
- this.rightParenthesis,
- this.semicolon) {
- _body = _becomeParentOf(body);
- _condition = _becomeParentOf(condition);
- }
-
- @override
- Token get beginToken => doKeyword;
-
- /**
- * Return the body of the loop.
- */
- Statement get body => _body;
-
- /**
- * Set the body of the loop to the given [statement].
- */
- void set body(Statement statement) {
- _body = _becomeParentOf(statement);
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(doKeyword)
- ..add(_body)
- ..add(whileKeyword)
- ..add(leftParenthesis)
- ..add(_condition)
- ..add(rightParenthesis)
- ..add(semicolon);
-
- /**
- * Return the condition that determines when the loop will terminate.
- */
- Expression get condition => _condition;
-
- /**
- * Set the condition that determines when the loop will terminate to the given
- * [expression].
- */
- void set condition(Expression expression) {
- _condition = _becomeParentOf(expression);
- }
-
- @override
- Token get endToken => semicolon;
-
- @override
- accept(AstVisitor visitor) => visitor.visitDoStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_body, visitor);
- _safelyVisitChild(_condition, visitor);
- }
-}
-
-/**
- * A dotted name, used in a configuration within an import or export directive.
- *
- * > dottedName ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
- */
-class DottedName extends AstNode {
- /**
- * The components of the identifier.
- */
- NodeList<SimpleIdentifier> _components;
-
- /**
- * Initialize a newly created dotted name.
- */
- DottedName(List<SimpleIdentifier> components) {
- _components = new NodeList<SimpleIdentifier>(this, components);
- }
-
- @override
- Token get beginToken => _components.beginToken;
-
- @override
- // TODO(paulberry): add "." tokens.
- Iterable get childEntities => new ChildEntities()..addAll(_components);
-
- /**
- * Return the components of the identifier.
- */
- NodeList<SimpleIdentifier> get components => _components;
-
- @override
- Token get endToken => _components.endToken;
-
- @override
- accept(AstVisitor visitor) => visitor.visitDottedName(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _components.accept(visitor);
- }
-}
-
-/**
- * A floating point literal expression.
- *
- * > doubleLiteral ::=
- * > decimalDigit+ ('.' decimalDigit*)? exponent?
- * > | '.' decimalDigit+ exponent?
- * >
- * > exponent ::=
- * > ('e' | 'E') ('+' | '-')? decimalDigit+
- */
-class DoubleLiteral extends Literal {
- /**
- * The token representing the literal.
- */
- Token literal;
-
- /**
- * The value of the literal.
- */
- double value;
-
- /**
- * Initialize a newly created floating point literal.
- */
- DoubleLiteral(this.literal, this.value);
-
- @override
- Token get beginToken => literal;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(literal);
-
- @override
- Token get endToken => literal;
-
- @override
- accept(AstVisitor visitor) => visitor.visitDoubleLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * An empty function body, which can only appear in constructors or abstract
- * methods.
- *
- * > emptyFunctionBody ::=
- * > ';'
- */
-class EmptyFunctionBody extends FunctionBody {
- /**
- * The token representing the semicolon that marks the end of the function
- * body.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created function body.
- */
- EmptyFunctionBody(this.semicolon);
-
- @override
- Token get beginToken => semicolon;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- @override
- accept(AstVisitor visitor) => visitor.visitEmptyFunctionBody(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // Empty function bodies have no children.
- }
-}
-
-/**
- * An empty statement.
- *
- * > emptyStatement ::=
- * > ';'
- */
-class EmptyStatement extends Statement {
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created empty statement.
- */
- EmptyStatement(this.semicolon);
-
- @override
- Token get beginToken => semicolon;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- @override
- accept(AstVisitor visitor) => visitor.visitEmptyStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * The declaration of an enum constant.
- */
-class EnumConstantDeclaration extends Declaration {
- /**
- * The name of the constant.
- */
- SimpleIdentifier _name;
-
- /**
- * Initialize a newly created enum constant declaration. Either or both of the
- * [comment] and [metadata] can be `null` if the constant does not have the
- * corresponding attribute. (Technically, enum constants cannot have metadata,
- * but we allow it for consistency.)
- */
- EnumConstantDeclaration(
- Comment comment, List<Annotation> metadata, SimpleIdentifier name)
- : super(comment, metadata) {
- _name = _becomeParentOf(name);
- }
-
- @override
- Iterable get childEntities => super._childEntities..add(_name);
-
- @override
- FieldElement get element =>
- _name == null ? null : (_name.staticElement as FieldElement);
-
- @override
- Token get endToken => _name.endToken;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
-
- /**
- * Return the name of the constant.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the constant to the given [name].
- */
- void set name(SimpleIdentifier name) {
- _name = _becomeParentOf(name);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitEnumConstantDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_name, visitor);
- }
-}
-
-/**
- * The declaration of an enumeration.
- *
- * > enumType ::=
- * > metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
- */
-class EnumDeclaration extends NamedCompilationUnitMember {
- /**
- * The 'enum' keyword.
- */
- Token enumKeyword;
-
- /**
- * The left curly bracket.
- */
- Token leftBracket;
-
- /**
- * The enumeration constants being declared.
- */
- NodeList<EnumConstantDeclaration> _constants;
-
- /**
- * The right curly bracket.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created enumeration declaration. Either or both of the
- * [comment] and [metadata] can be `null` if the declaration does not have the
- * corresponding attribute. The list of [constants] must contain at least one
- * value.
- */
- EnumDeclaration(
- Comment comment,
- List<Annotation> metadata,
- this.enumKeyword,
- SimpleIdentifier name,
- this.leftBracket,
- List<EnumConstantDeclaration> constants,
- this.rightBracket)
- : super(comment, metadata, name) {
- _constants = new NodeList<EnumConstantDeclaration>(this, constants);
- }
-
- @override
- // TODO(brianwilkerson) Add commas?
- Iterable get childEntities => super._childEntities
- ..add(enumKeyword)
- ..add(_name)
- ..add(leftBracket)
- ..addAll(_constants)
- ..add(rightBracket);
-
- /**
- * Return the enumeration constants being declared.
- */
- NodeList<EnumConstantDeclaration> get constants => _constants;
-
- @override
- ClassElement get element =>
- _name != null ? (_name.staticElement as ClassElement) : null;
-
- @override
- Token get endToken => rightBracket;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => enumKeyword;
-
- @override
- accept(AstVisitor visitor) => visitor.visitEnumDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_name, visitor);
- _constants.accept(visitor);
- }
-}
-
-/**
- * Ephemeral identifiers are created as needed to mimic the presence of an empty
- * identifier.
- */
-class EphemeralIdentifier extends SimpleIdentifier {
- EphemeralIdentifier(AstNode parent, int location)
- : super(new StringToken(TokenType.IDENTIFIER, "", location)) {
- parent._becomeParentOf(this);
- }
-}
-
-/**
- * An export directive.
- *
- * > exportDirective ::=
- * > [Annotation] 'export' [StringLiteral] [Combinator]* ';'
- */
-class ExportDirective extends NamespaceDirective {
- /**
- * Initialize a newly created export directive. Either or both of the
- * [comment] and [metadata] can be `null` if the directive does not have the
- * corresponding attribute. The list of [combinators] can be `null` if there
- * are no combinators.
- */
- ExportDirective(
- Comment comment,
- List<Annotation> metadata,
- Token keyword,
- StringLiteral libraryUri,
- List<Configuration> configurations,
- List<Combinator> combinators,
- Token semicolon)
- : super(comment, metadata, keyword, libraryUri, configurations,
- combinators, semicolon);
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(_uri)
- ..addAll(combinators)
- ..add(semicolon);
-
- @override
- ExportElement get element => super.element as ExportElement;
-
- @override
- LibraryElement get uriElement {
- if (element != null) {
- return element.exportedLibrary;
- }
- return null;
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitExportDirective(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- combinators.accept(visitor);
- }
-}
-
-/**
- * A node that represents an expression.
- *
- * > expression ::=
- * > [AssignmentExpression]
- * > | [ConditionalExpression] cascadeSection*
- * > | [ThrowExpression]
- */
-abstract class Expression extends AstNode {
- /**
- * An empty list of expressions.
- */
- static const List<Expression> EMPTY_LIST = const <Expression>[];
-
- /**
- * The static type of this expression, or `null` if the AST structure has not
- * been resolved.
- */
- DartType staticType;
-
- /**
- * The propagated type of this expression, or `null` if type propagation has
- * not been performed on the AST structure.
- */
- DartType propagatedType;
-
- /**
- * Return the best parameter element information available for this
- * expression. If type propagation was able to find a better parameter element
- * than static analysis, that type will be returned. Otherwise, the result of
- * static analysis will be returned.
- */
- ParameterElement get bestParameterElement {
- ParameterElement propagatedElement = propagatedParameterElement;
- if (propagatedElement != null) {
- return propagatedElement;
- }
- return staticParameterElement;
- }
-
- /**
- * Return the best type information available for this expression. If type
- * propagation was able to find a better type than static analysis, that type
- * will be returned. Otherwise, the result of static analysis will be
- * returned. If no type analysis has been performed, then the type 'dynamic'
- * will be returned.
- */
- DartType get bestType {
- if (propagatedType != null) {
- return propagatedType;
- } else if (staticType != null) {
- return staticType;
- }
- return DynamicTypeImpl.instance;
- }
-
- /**
- * Return `true` if this expression is syntactically valid for the LHS of an
- * [AssignmentExpression].
- */
- bool get isAssignable => false;
-
- /**
- * Return the precedence of this expression. The precedence is a positive
- * integer value that defines how the source code is parsed into an AST. For
- * example `a * b + c` is parsed as `(a * b) + c` because the precedence of
- * `*` is greater than the precedence of `+`.
- *
- * Clients should not assume that returned values will stay the same, they
- * might change as result of specification change. Only relative order should
- * be used.
- */
- int get precedence;
-
- /**
- * If this expression is an argument to an invocation, and the AST structure
- * has been resolved, and the function being invoked is known based on
- * propagated type information, and this expression corresponds to one of the
- * parameters of the function being invoked, then return the parameter element
- * representing the parameter to which the value of this expression will be
- * bound. Otherwise, return `null`.
- */
- ParameterElement get propagatedParameterElement {
- AstNode parent = this.parent;
- if (parent is ArgumentList) {
- return parent._getPropagatedParameterElementFor(this);
- } else if (parent is IndexExpression) {
- IndexExpression indexExpression = parent;
- if (identical(indexExpression.index, this)) {
- return indexExpression._propagatedParameterElementForIndex;
- }
- } else if (parent is BinaryExpression) {
- BinaryExpression binaryExpression = parent;
- if (identical(binaryExpression.rightOperand, this)) {
- return binaryExpression._propagatedParameterElementForRightOperand;
- }
- } else if (parent is AssignmentExpression) {
- AssignmentExpression assignmentExpression = parent;
- if (identical(assignmentExpression.rightHandSide, this)) {
- return assignmentExpression._propagatedParameterElementForRightHandSide;
- }
- } else if (parent is PrefixExpression) {
- return parent._propagatedParameterElementForOperand;
- } else if (parent is PostfixExpression) {
- return parent._propagatedParameterElementForOperand;
- }
- return null;
- }
-
- /**
- * If this expression is an argument to an invocation, and the AST structure
- * has been resolved, and the function being invoked is known based on static
- * type information, and this expression corresponds to one of the parameters
- * of the function being invoked, then return the parameter element
- * representing the parameter to which the value of this expression will be
- * bound. Otherwise, return `null`.
- */
- ParameterElement get staticParameterElement {
- AstNode parent = this.parent;
- if (parent is ArgumentList) {
- return parent._getStaticParameterElementFor(this);
- } else if (parent is IndexExpression) {
- IndexExpression indexExpression = parent;
- if (identical(indexExpression.index, this)) {
- return indexExpression._staticParameterElementForIndex;
- }
- } else if (parent is BinaryExpression) {
- BinaryExpression binaryExpression = parent;
- if (identical(binaryExpression.rightOperand, this)) {
- return binaryExpression._staticParameterElementForRightOperand;
- }
- } else if (parent is AssignmentExpression) {
- AssignmentExpression assignmentExpression = parent;
- if (identical(assignmentExpression.rightHandSide, this)) {
- return assignmentExpression._staticParameterElementForRightHandSide;
- }
- } else if (parent is PrefixExpression) {
- return parent._staticParameterElementForOperand;
- } else if (parent is PostfixExpression) {
- return parent._staticParameterElementForOperand;
- }
- return null;
- }
-}
-
-/**
- * A function body consisting of a single expression.
- *
- * > expressionFunctionBody ::=
- * > 'async'? '=>' [Expression] ';'
- */
-class ExpressionFunctionBody extends FunctionBody {
- /**
- * The token representing the 'async' keyword, or `null` if there is no such
- * keyword.
- */
- Token keyword;
-
- /**
- * The token introducing the expression that represents the body of the
- * function.
- */
- Token functionDefinition;
-
- /**
- * The expression representing the body of the function.
- */
- Expression _expression;
-
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created function body consisting of a block of
- * statements. The [keyword] can be `null` if the function body is not an
- * async function body.
- */
- ExpressionFunctionBody(this.keyword, this.functionDefinition,
- Expression expression, this.semicolon) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken {
- if (keyword != null) {
- return keyword;
- }
- return functionDefinition;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(keyword)
- ..add(functionDefinition)
- ..add(_expression)
- ..add(semicolon);
-
- @override
- Token get endToken {
- if (semicolon != null) {
- return semicolon;
- }
- return _expression.endToken;
- }
-
- /**
- * Return the expression representing the body of the function.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression representing the body of the function to the given
- * [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- bool get isAsynchronous => keyword != null;
-
- @override
- bool get isSynchronous => keyword == null;
-
- @override
- accept(AstVisitor visitor) => visitor.visitExpressionFunctionBody(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * An expression used as a statement.
- *
- * > expressionStatement ::=
- * > [Expression]? ';'
- */
-class ExpressionStatement extends Statement {
- /**
- * The expression that comprises the statement.
- */
- Expression _expression;
-
- /**
- * The semicolon terminating the statement, or `null` if the expression is a
- * function expression and therefore isn't followed by a semicolon.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created expression statement.
- */
- ExpressionStatement(Expression expression, this.semicolon) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken => _expression.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_expression)..add(semicolon);
-
- @override
- Token get endToken {
- if (semicolon != null) {
- return semicolon;
- }
- return _expression.endToken;
- }
-
- /**
- * Return the expression that comprises the statement.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression that comprises the statement to the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- bool get isSynthetic => _expression.isSynthetic && semicolon.isSynthetic;
-
- @override
- accept(AstVisitor visitor) => visitor.visitExpressionStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * The "extends" clause in a class declaration.
- *
- * > extendsClause ::=
- * > 'extends' [TypeName]
- */
-class ExtendsClause extends AstNode {
- /**
- * The token representing the 'extends' keyword.
- */
- Token extendsKeyword;
-
- /**
- * The name of the class that is being extended.
- */
- TypeName _superclass;
-
- /**
- * Initialize a newly created extends clause.
- */
- ExtendsClause(this.extendsKeyword, TypeName superclass) {
- _superclass = _becomeParentOf(superclass);
- }
-
- @override
- Token get beginToken => extendsKeyword;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(extendsKeyword)..add(_superclass);
-
- @override
- Token get endToken => _superclass.endToken;
-
- /**
- * Return the name of the class that is being extended.
- */
- TypeName get superclass => _superclass;
-
- /**
- * Set the name of the class that is being extended to the given [name].
- */
- void set superclass(TypeName name) {
- _superclass = _becomeParentOf(name);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitExtendsClause(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_superclass, visitor);
- }
-}
-
-/**
- * The declaration of one or more fields of the same type.
- *
- * > fieldDeclaration ::=
- * > 'static'? [VariableDeclarationList] ';'
- */
-class FieldDeclaration extends ClassMember {
- /**
- * The token representing the 'static' keyword, or `null` if the fields are
- * not static.
- */
- Token staticKeyword;
-
- /**
- * The fields being declared.
- */
- VariableDeclarationList _fieldList;
-
- /**
- * The semicolon terminating the declaration.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created field declaration. Either or both of the
- * [comment] and [metadata] can be `null` if the declaration does not have the
- * corresponding attribute. The [staticKeyword] can be `null` if the field is
- * not a static field.
- */
- FieldDeclaration(Comment comment, List<Annotation> metadata,
- this.staticKeyword, VariableDeclarationList fieldList, this.semicolon)
- : super(comment, metadata) {
- _fieldList = _becomeParentOf(fieldList);
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(staticKeyword)..add(_fieldList)..add(semicolon);
-
- @override
- Element get element => null;
-
- @override
- Token get endToken => semicolon;
-
- /**
- * Return the fields being declared.
- */
- VariableDeclarationList get fields => _fieldList;
-
- /**
- * Set the fields being declared to the given list of [fields].
- */
- void set fields(VariableDeclarationList fields) {
- _fieldList = _becomeParentOf(fields);
- }
-
- @override
- Token get firstTokenAfterCommentAndMetadata {
- if (staticKeyword != null) {
- return staticKeyword;
- }
- return _fieldList.beginToken;
- }
-
- /**
- * Return `true` if the fields are declared to be static.
- */
- bool get isStatic => staticKeyword != null;
-
- @override
- accept(AstVisitor visitor) => visitor.visitFieldDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_fieldList, visitor);
- }
-}
-
-/**
- * A field formal parameter.
- *
- * > fieldFormalParameter ::=
- * > ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
- * > 'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
- */
-class FieldFormalParameter extends NormalFormalParameter {
- /**
- * The token representing either the 'final', 'const' or 'var' keyword, or
- * `null` if no keyword was used.
- */
- Token keyword;
-
- /**
- * The name of the declared type of the parameter, or `null` if the parameter
- * does not have a declared type.
- */
- TypeName _type;
-
- /**
- * The token representing the 'this' keyword.
- */
- Token thisKeyword;
-
- /**
- * The token representing the period.
- */
- Token period;
-
- /**
- * The type parameters associated with the method, or `null` if the method is
- * not a generic method.
- */
- TypeParameterList _typeParameters;
-
- /**
- * The parameters of the function-typed parameter, or `null` if this is not a
- * function-typed field formal parameter.
- */
- FormalParameterList _parameters;
-
- /**
- * Initialize a newly created formal parameter. Either or both of the
- * [comment] and [metadata] can be `null` if the parameter does not have the
- * corresponding attribute. The [keyword] can be `null` if there is a type.
- * The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
- * [period] can be `null` if the keyword 'this' was not provided. The
- * [parameters] can be `null` if this is not a function-typed field formal
- * parameter.
- */
- FieldFormalParameter(
- Comment comment,
- List<Annotation> metadata,
- this.keyword,
- TypeName type,
- this.thisKeyword,
- this.period,
- SimpleIdentifier identifier,
- TypeParameterList typeParameters,
- FormalParameterList parameters)
- : super(comment, metadata, identifier) {
- _type = _becomeParentOf(type);
- _typeParameters = _becomeParentOf(typeParameters);
- _parameters = _becomeParentOf(parameters);
- }
-
- @override
- Token get beginToken {
- if (keyword != null) {
- return keyword;
- } else if (_type != null) {
- return _type.beginToken;
- }
- return thisKeyword;
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(keyword)
- ..add(_type)
- ..add(thisKeyword)
- ..add(period)
- ..add(identifier)
- ..add(_parameters);
-
- @override
- Token get endToken {
- if (_parameters != null) {
- return _parameters.endToken;
- }
- return identifier.endToken;
- }
-
- @override
- bool get isConst =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
-
- @override
- bool get isFinal =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
-
- /**
- * Return the parameters of the function-typed parameter, or `null` if this is
- * not a function-typed field formal parameter.
- */
- FormalParameterList get parameters => _parameters;
-
- /**
- * Set the parameters of the function-typed parameter to the given
- * [parameters].
- */
- void set parameters(FormalParameterList parameters) {
- _parameters = _becomeParentOf(parameters);
- }
-
- /**
- * Return the name of the declared type of the parameter, or `null` if the
- * parameter does not have a declared type. Note that if this is a
- * function-typed field formal parameter this is the return type of the
- * function.
- */
- TypeName get type => _type;
-
- /**
- * Set the name of the declared type of the parameter to the given [typeName].
- */
- void set type(TypeName typeName) {
- _type = _becomeParentOf(typeName);
- }
-
- /**
- * Return the type parameters associated with this method, or `null` if this
- * method is not a generic method.
- */
- TypeParameterList get typeParameters => _typeParameters;
-
- /**
- * Set the type parameters associated with this method to the given
- * [typeParameters].
- */
- void set typeParameters(TypeParameterList typeParameters) {
- _typeParameters = _becomeParentOf(typeParameters);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitFieldFormalParameter(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_type, visitor);
- _safelyVisitChild(identifier, visitor);
- _safelyVisitChild(_typeParameters, visitor);
- _safelyVisitChild(_parameters, visitor);
- }
-}
-
-/**
- * A for-each statement.
- *
- * > forEachStatement ::=
- * > 'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
- * > | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
- */
-class ForEachStatement extends Statement {
- /**
- * The token representing the 'await' keyword, or `null` if there is no
- * 'await' keyword.
- */
- Token awaitKeyword;
-
- /**
- * The token representing the 'for' keyword.
- */
- Token forKeyword;
-
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The declaration of the loop variable, or `null` if the loop variable is a
- * simple identifier.
- */
- DeclaredIdentifier _loopVariable;
-
- /**
- * The loop variable, or `null` if the loop variable is declared in the 'for'.
- */
- SimpleIdentifier _identifier;
-
- /**
- * The token representing the 'in' keyword.
- */
- Token inKeyword;
-
- /**
- * The expression evaluated to produce the iterator.
- */
- Expression _iterable;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * The body of the loop.
- */
- Statement _body;
-
- /**
- * Initialize a newly created for-each statement whose loop control variable
- * is declared internally (in the for-loop part). The [awaitKeyword] can be
- * `null` if this is not an asynchronous for loop.
- */
- ForEachStatement.withDeclaration(
- this.awaitKeyword,
- this.forKeyword,
- this.leftParenthesis,
- DeclaredIdentifier loopVariable,
- this.inKeyword,
- Expression iterator,
- this.rightParenthesis,
- Statement body) {
- _loopVariable = _becomeParentOf(loopVariable);
- _iterable = _becomeParentOf(iterator);
- _body = _becomeParentOf(body);
- }
-
- /**
- * Initialize a newly created for-each statement whose loop control variable
- * is declared outside the for loop. The [awaitKeyword] can be `null` if this
- * is not an asynchronous for loop.
- */
- ForEachStatement.withReference(
- this.awaitKeyword,
- this.forKeyword,
- this.leftParenthesis,
- SimpleIdentifier identifier,
- this.inKeyword,
- Expression iterator,
- this.rightParenthesis,
- Statement body) {
- _identifier = _becomeParentOf(identifier);
- _iterable = _becomeParentOf(iterator);
- _body = _becomeParentOf(body);
- }
-
- @override
- Token get beginToken => forKeyword;
-
- /**
- * Return the body of the loop.
- */
- Statement get body => _body;
-
- /**
- * Set the body of the loop to the given [statement].
- */
- void set body(Statement statement) {
- _body = _becomeParentOf(statement);
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(awaitKeyword)
- ..add(forKeyword)
- ..add(leftParenthesis)
- ..add(_loopVariable)
- ..add(_identifier)
- ..add(inKeyword)
- ..add(_iterable)
- ..add(rightParenthesis)
- ..add(_body);
-
- @override
- Token get endToken => _body.endToken;
-
- /**
- * Return the loop variable, or `null` if the loop variable is declared in the
- * 'for'.
- */
- SimpleIdentifier get identifier => _identifier;
-
- /**
- * Set the loop variable to the given [identifier].
- */
- void set identifier(SimpleIdentifier identifier) {
- _identifier = _becomeParentOf(identifier);
- }
-
- /**
- * Return the expression evaluated to produce the iterator.
- */
- Expression get iterable => _iterable;
-
- /**
- * Set the expression evaluated to produce the iterator to the given
- * [expression].
- */
- void set iterable(Expression expression) {
- _iterable = _becomeParentOf(expression);
- }
-
- /**
- * Return the declaration of the loop variable, or `null` if the loop variable
- * is a simple identifier.
- */
- DeclaredIdentifier get loopVariable => _loopVariable;
-
- /**
- * Set the declaration of the loop variable to the given [variable].
- */
- void set loopVariable(DeclaredIdentifier variable) {
- _loopVariable = _becomeParentOf(variable);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitForEachStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_loopVariable, visitor);
- _safelyVisitChild(_identifier, visitor);
- _safelyVisitChild(_iterable, visitor);
- _safelyVisitChild(_body, visitor);
- }
-}
-
-/**
- * A node representing a parameter to a function.
- *
- * > formalParameter ::=
- * > [NormalFormalParameter]
- * > | [DefaultFormalParameter]
- */
-abstract class FormalParameter extends AstNode {
- /**
- * Return the element representing this parameter, or `null` if this parameter
- * has not been resolved.
- */
- ParameterElement get element {
- SimpleIdentifier identifier = this.identifier;
- if (identifier == null) {
- return null;
- }
- return identifier.staticElement as ParameterElement;
- }
-
- /**
- * Return the name of the parameter being declared.
- */
- SimpleIdentifier get identifier;
-
- /**
- * Return `true` if this parameter was declared with the 'const' modifier.
- */
- bool get isConst;
-
- /**
- * Return `true` if this parameter was declared with the 'final' modifier.
- * Parameters that are declared with the 'const' modifier will return `false`
- * even though they are implicitly final.
- */
- bool get isFinal;
-
- /**
- * Return the kind of this parameter.
- */
- ParameterKind get kind;
-
- /**
- * Return the annotations associated with this parameter.
- */
- NodeList<Annotation> get metadata;
-}
-
-/**
- * The formal parameter list of a method declaration, function declaration, or
- * function type alias.
- *
- * While the grammar requires all optional formal parameters to follow all of
- * the normal formal parameters and at most one grouping of optional formal
- * parameters, this class does not enforce those constraints. All parameters are
- * flattened into a single list, which can have any or all kinds of parameters
- * (normal, named, and positional) in any order.
- *
- * > formalParameterList ::=
- * > '(' ')'
- * > | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- * > | '(' optionalFormalParameters ')'
- * >
- * > normalFormalParameters ::=
- * > [NormalFormalParameter] (',' [NormalFormalParameter])*
- * >
- * > optionalFormalParameters ::=
- * > optionalPositionalFormalParameters
- * > | namedFormalParameters
- * >
- * > optionalPositionalFormalParameters ::=
- * > '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
- * >
- * > namedFormalParameters ::=
- * > '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
- */
-class FormalParameterList extends AstNode {
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The parameters associated with the method.
- */
- NodeList<FormalParameter> _parameters;
-
- /**
- * The left square bracket ('[') or left curly brace ('{') introducing the
- * optional parameters, or `null` if there are no optional parameters.
- */
- Token leftDelimiter;
-
- /**
- * The right square bracket (']') or right curly brace ('}') terminating the
- * optional parameters, or `null` if there are no optional parameters.
- */
- Token rightDelimiter;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * Initialize a newly created parameter list. The list of [parameters] can be
- * `null` if there are no parameters. The [leftDelimiter] and [rightDelimiter]
- * can be `null` if there are no optional parameters.
- */
- FormalParameterList(this.leftParenthesis, List<FormalParameter> parameters,
- this.leftDelimiter, this.rightDelimiter, this.rightParenthesis) {
- _parameters = new NodeList<FormalParameter>(this, parameters);
- }
-
- @override
- Token get beginToken => leftParenthesis;
-
- @override
- Iterable get childEntities {
- // TODO(paulberry): include commas.
- ChildEntities result = new ChildEntities()..add(leftParenthesis);
- bool leftDelimiterNeeded = leftDelimiter != null;
- for (FormalParameter parameter in _parameters) {
- if (leftDelimiterNeeded && leftDelimiter.offset < parameter.offset) {
- result.add(leftDelimiter);
- leftDelimiterNeeded = false;
- }
- result.add(parameter);
- }
- return result..add(rightDelimiter)..add(rightParenthesis);
- }
-
- @override
- Token get endToken => rightParenthesis;
-
- /**
- * Return a list containing the elements representing the parameters in this
- * list. The list will contain `null`s if the parameters in this list have not
- * been resolved.
- */
- List<ParameterElement> get parameterElements {
- int count = _parameters.length;
- List<ParameterElement> types = new List<ParameterElement>(count);
- for (int i = 0; i < count; i++) {
- types[i] = _parameters[i].element;
- }
- return types;
- }
-
- /**
- * Return the parameters associated with the method.
- */
- NodeList<FormalParameter> get parameters => _parameters;
-
- @override
- accept(AstVisitor visitor) => visitor.visitFormalParameterList(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _parameters.accept(visitor);
- }
-}
-
-/**
- * A for statement.
- *
- * > forStatement ::=
- * > 'for' '(' forLoopParts ')' [Statement]
- * >
- * > forLoopParts ::=
- * > forInitializerStatement ';' [Expression]? ';' [Expression]?
- * >
- * > forInitializerStatement ::=
- * > [DefaultFormalParameter]
- * > | [Expression]?
- */
-class ForStatement extends Statement {
- /**
- * The token representing the 'for' keyword.
- */
- Token forKeyword;
-
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The declaration of the loop variables, or `null` if there are no variables.
- * Note that a for statement cannot have both a variable list and an
- * initialization expression, but can validly have neither.
- */
- VariableDeclarationList _variableList;
-
- /**
- * The initialization expression, or `null` if there is no initialization
- * expression. Note that a for statement cannot have both a variable list and
- * an initialization expression, but can validly have neither.
- */
- Expression _initialization;
-
- /**
- * The semicolon separating the initializer and the condition.
- */
- Token leftSeparator;
-
- /**
- * The condition used to determine when to terminate the loop, or `null` if
- * there is no condition.
- */
- Expression _condition;
-
- /**
- * The semicolon separating the condition and the updater.
- */
- Token rightSeparator;
-
- /**
- * The list of expressions run after each execution of the loop body.
- */
- NodeList<Expression> _updaters;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * The body of the loop.
- */
- Statement _body;
-
- /**
- * Initialize a newly created for statement. Either the [variableList] or the
- * [initialization] must be `null`. Either the [condition] and the list of
- * [updaters] can be `null` if the loop does not have the corresponding
- * attribute.
- */
- ForStatement(
- this.forKeyword,
- this.leftParenthesis,
- VariableDeclarationList variableList,
- Expression initialization,
- this.leftSeparator,
- Expression condition,
- this.rightSeparator,
- List<Expression> updaters,
- this.rightParenthesis,
- Statement body) {
- _variableList = _becomeParentOf(variableList);
- _initialization = _becomeParentOf(initialization);
- _condition = _becomeParentOf(condition);
- _updaters = new NodeList<Expression>(this, updaters);
- _body = _becomeParentOf(body);
- }
-
- @override
- Token get beginToken => forKeyword;
-
- /**
- * Return the body of the loop.
- */
- Statement get body => _body;
-
- /**
- * Set the body of the loop to the given [statement].
- */
- void set body(Statement statement) {
- _body = _becomeParentOf(statement);
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(forKeyword)
- ..add(leftParenthesis)
- ..add(_variableList)
- ..add(_initialization)
- ..add(leftSeparator)
- ..add(_condition)
- ..add(rightSeparator)
- ..addAll(_updaters)
- ..add(rightParenthesis)
- ..add(_body);
-
- /**
- * Return the condition used to determine when to terminate the loop, or
- * `null` if there is no condition.
- */
- Expression get condition => _condition;
-
- /**
- * Set the condition used to determine when to terminate the loop to the given
- * [expression].
- */
- void set condition(Expression expression) {
- _condition = _becomeParentOf(expression);
- }
-
- @override
- Token get endToken => _body.endToken;
-
- /**
- * Return the initialization expression, or `null` if there is no
- * initialization expression.
- */
- Expression get initialization => _initialization;
-
- /**
- * Set the initialization expression to the given [expression].
- */
- void set initialization(Expression initialization) {
- _initialization = _becomeParentOf(initialization);
- }
-
- /**
- * Return the list of expressions run after each execution of the loop body.
- */
- NodeList<Expression> get updaters => _updaters;
-
- /**
- * Return the declaration of the loop variables, or `null` if there are no
- * variables.
- */
- VariableDeclarationList get variables => _variableList;
-
- /**
- * Set the declaration of the loop variables to the given [variableList].
- */
- void set variables(VariableDeclarationList variableList) {
- _variableList = _becomeParentOf(variableList);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitForStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_variableList, visitor);
- _safelyVisitChild(_initialization, visitor);
- _safelyVisitChild(_condition, visitor);
- _updaters.accept(visitor);
- _safelyVisitChild(_body, visitor);
- }
-}
-
-/**
- * A node representing the body of a function or method.
- *
- * > functionBody ::=
- * > [BlockFunctionBody]
- * > | [EmptyFunctionBody]
- * > | [ExpressionFunctionBody]
- */
-abstract class FunctionBody extends AstNode {
- /**
- * Return `true` if this function body is asynchronous.
- */
- bool get isAsynchronous => false;
-
- /**
- * Return `true` if this function body is a generator.
- */
- bool get isGenerator => false;
-
- /**
- * Return `true` if this function body is synchronous.
- */
- bool get isSynchronous => true;
-
- /**
- * Return the token representing the 'async' or 'sync' keyword, or `null` if
- * there is no such keyword.
- */
- Token get keyword => null;
-
- /**
- * Return the star following the 'async' or 'sync' keyword, or `null` if there
- * is no star.
- */
- Token get star => null;
-}
-
-/**
- * A top-level declaration.
- *
- * > functionDeclaration ::=
- * > 'external' functionSignature
- * > | functionSignature [FunctionBody]
- * >
- * > functionSignature ::=
- * > [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
- */
-class FunctionDeclaration extends NamedCompilationUnitMember {
- /**
- * The token representing the 'external' keyword, or `null` if this is not an
- * external function.
- */
- Token externalKeyword;
-
- /**
- * The return type of the function, or `null` if no return type was declared.
- */
- TypeName _returnType;
-
- /**
- * The token representing the 'get' or 'set' keyword, or `null` if this is a
- * function declaration rather than a property declaration.
- */
- Token propertyKeyword;
-
- /**
- * The function expression being wrapped.
- */
- FunctionExpression _functionExpression;
-
- /**
- * Initialize a newly created function declaration. Either or both of the
- * [comment] and [metadata] can be `null` if the function does not have the
- * corresponding attribute. The [externalKeyword] can be `null` if the
- * function is not an external function. The [returnType] can be `null` if no
- * return type was specified. The [propertyKeyword] can be `null` if the
- * function is neither a getter or a setter.
- */
- FunctionDeclaration(
- Comment comment,
- List<Annotation> metadata,
- this.externalKeyword,
- TypeName returnType,
- this.propertyKeyword,
- SimpleIdentifier name,
- FunctionExpression functionExpression)
- : super(comment, metadata, name) {
- _returnType = _becomeParentOf(returnType);
- _functionExpression = _becomeParentOf(functionExpression);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(externalKeyword)
- ..add(_returnType)
- ..add(propertyKeyword)
- ..add(_name)
- ..add(_functionExpression);
-
- @override
- ExecutableElement get element =>
- _name != null ? (_name.staticElement as ExecutableElement) : null;
-
- @override
- Token get endToken => _functionExpression.endToken;
-
- @override
- Token get firstTokenAfterCommentAndMetadata {
- if (externalKeyword != null) {
- return externalKeyword;
- } else if (_returnType != null) {
- return _returnType.beginToken;
- } else if (propertyKeyword != null) {
- return propertyKeyword;
- } else if (_name != null) {
- return _name.beginToken;
- }
- return _functionExpression.beginToken;
- }
-
- /**
- * Return the function expression being wrapped.
- */
- FunctionExpression get functionExpression => _functionExpression;
-
- /**
- * Set the function expression being wrapped to the given
- * [functionExpression].
- */
- void set functionExpression(FunctionExpression functionExpression) {
- _functionExpression = _becomeParentOf(functionExpression);
- }
-
- /**
- * Return `true` if this function declares a getter.
- */
- bool get isGetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.GET;
-
- /**
- * Return `true` if this function declares a setter.
- */
- bool get isSetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.SET;
-
- /**
- * Return the return type of the function, or `null` if no return type was
- * declared.
- */
- TypeName get returnType => _returnType;
-
- /**
- * Set the return type of the function to the given [returnType].
- */
- void set returnType(TypeName returnType) {
- _returnType = _becomeParentOf(returnType);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitFunctionDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_returnType, visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_functionExpression, visitor);
- }
-}
-
-/**
- * A [FunctionDeclaration] used as a statement.
- */
-class FunctionDeclarationStatement extends Statement {
- /**
- * The function declaration being wrapped.
- */
- FunctionDeclaration _functionDeclaration;
-
- /**
- * Initialize a newly created function declaration statement.
- */
- FunctionDeclarationStatement(FunctionDeclaration functionDeclaration) {
- _functionDeclaration = _becomeParentOf(functionDeclaration);
- }
-
- @override
- Token get beginToken => _functionDeclaration.beginToken;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(_functionDeclaration);
-
- @override
- Token get endToken => _functionDeclaration.endToken;
-
- /**
- * Return the function declaration being wrapped.
- */
- FunctionDeclaration get functionDeclaration => _functionDeclaration;
-
- /**
- * Set the function declaration being wrapped to the given
- * [functionDeclaration].
- */
- void set functionDeclaration(FunctionDeclaration functionDeclaration) {
- _functionDeclaration = _becomeParentOf(functionDeclaration);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitFunctionDeclarationStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_functionDeclaration, visitor);
- }
-}
-
-/**
- * A function expression.
- *
- * > functionExpression ::=
- * > [TypeParameterList]? [FormalParameterList] [FunctionBody]
- */
-class FunctionExpression extends Expression {
- /**
- * The type parameters associated with the method, or `null` if the method is
- * not a generic method.
- */
- TypeParameterList _typeParameters;
-
- /**
- * The parameters associated with the function.
- */
- FormalParameterList _parameters;
-
- /**
- * The body of the function, or `null` if this is an external function.
- */
- FunctionBody _body;
-
- /**
- * The element associated with the function, or `null` if the AST structure
- * has not been resolved.
- */
- ExecutableElement element;
-
- /**
- * Initialize a newly created function declaration.
- */
- FunctionExpression(TypeParameterList typeParameters,
- FormalParameterList parameters, FunctionBody body) {
- _typeParameters = _becomeParentOf(typeParameters);
- _parameters = _becomeParentOf(parameters);
- _body = _becomeParentOf(body);
- }
-
- @override
- Token get beginToken {
- if (_typeParameters != null) {
- return _typeParameters.beginToken;
- } else if (_parameters != null) {
- return _parameters.beginToken;
- } else if (_body != null) {
- return _body.beginToken;
- }
- // This should never be reached because external functions must be named,
- // hence either the body or the name should be non-null.
- throw new IllegalStateException("Non-external functions must have a body");
- }
-
- /**
- * Return the body of the function, or `null` if this is an external function.
- */
- FunctionBody get body => _body;
-
- /**
- * Set the body of the function to the given [functionBody].
- */
- void set body(FunctionBody functionBody) {
- _body = _becomeParentOf(functionBody);
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_parameters)..add(_body);
-
- @override
- Token get endToken {
- if (_body != null) {
- return _body.endToken;
- } else if (_parameters != null) {
- return _parameters.endToken;
- }
- // This should never be reached because external functions must be named,
- // hence either the body or the name should be non-null.
- throw new IllegalStateException("Non-external functions must have a body");
- }
-
- /**
- * Return the parameters associated with the function.
- */
- FormalParameterList get parameters => _parameters;
-
- /**
- * Set the parameters associated with the function to the given list of
- * [parameters].
- */
- void set parameters(FormalParameterList parameters) {
- _parameters = _becomeParentOf(parameters);
- }
-
- @override
- int get precedence => 16;
-
- /**
- * Return the type parameters associated with this method, or `null` if this
- * method is not a generic method.
- */
- TypeParameterList get typeParameters => _typeParameters;
-
- /**
- * Set the type parameters associated with this method to the given
- * [typeParameters].
- */
- void set typeParameters(TypeParameterList typeParameters) {
- _typeParameters = _becomeParentOf(typeParameters);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitFunctionExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_typeParameters, visitor);
- _safelyVisitChild(_parameters, visitor);
- _safelyVisitChild(_body, visitor);
- }
-}
-
-/**
- * The invocation of a function resulting from evaluating an expression.
- * Invocations of methods and other forms of functions are represented by
- * [MethodInvocation] nodes. Invocations of getters and setters are represented
- * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
- *
- * > functionExpressionInvocation ::=
- * > [Expression] [TypeArgumentList]? [ArgumentList]
- */
-class FunctionExpressionInvocation extends Expression {
- /**
- * The expression producing the function being invoked.
- */
- Expression _function;
-
- /**
- * The type arguments to be applied to the method being invoked, or `null` if
- * no type arguments were provided.
- */
- TypeArgumentList _typeArguments;
-
- /**
- * The list of arguments to the function.
- */
- ArgumentList _argumentList;
-
- /**
- * The element associated with the function being invoked based on static type
- * information, or `null` if the AST structure has not been resolved or the
- * function could not be resolved.
- */
- ExecutableElement staticElement;
-
- /**
- * The function type of the method invocation, or `null` if the AST
- * structure has not been resolved, or if the invoke could not be resolved.
- *
- * This will usually be a [FunctionType], but it can also be an
- * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
- * interface type that implements `Function`.
- */
- DartType staticInvokeType;
-
- /**
- * The element associated with the function being invoked based on propagated
- * type information, or `null` if the AST structure has not been resolved or
- * the function could not be resolved.
- */
- ExecutableElement propagatedElement;
-
- /**
- * Like [staticInvokeType], but reflects propagated type information.
- */
- DartType propagatedInvokeType;
-
- /**
- * Initialize a newly created function expression invocation.
- */
- FunctionExpressionInvocation(Expression function,
- TypeArgumentList typeArguments, ArgumentList argumentList) {
- _function = _becomeParentOf(function);
- _typeArguments = _becomeParentOf(typeArguments);
- _argumentList = _becomeParentOf(argumentList);
- }
-
- /**
- * Return the list of arguments to the method.
- */
- ArgumentList get argumentList => _argumentList;
-
- /**
- * Set the list of arguments to the method to the given [argumentList].
- */
- void set argumentList(ArgumentList argumentList) {
- _argumentList = _becomeParentOf(argumentList);
- }
-
- @override
- Token get beginToken => _function.beginToken;
-
- /**
- * Return the best element available for the function being invoked. If
- * resolution was able to find a better element based on type propagation,
- * that element will be returned. Otherwise, the element found using the
- * result of static analysis will be returned. If resolution has not been
- * performed, then `null` will be returned.
- */
- ExecutableElement get bestElement {
- ExecutableElement element = propagatedElement;
- if (element == null) {
- element = staticElement;
- }
- return element;
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_function)..add(_argumentList);
-
- @override
- Token get endToken => _argumentList.endToken;
-
- /**
- * Return the expression producing the function being invoked.
- */
- Expression get function => _function;
-
- /**
- * Set the expression producing the function being invoked to the given
- * [expression].
- */
- void set function(Expression expression) {
- _function = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 15;
-
- /**
- * Return the type arguments to be applied to the method being invoked, or
- * `null` if no type arguments were provided.
- */
- TypeArgumentList get typeArguments => _typeArguments;
-
- /**
- * Set the type arguments to be applied to the method being invoked to the
- * given [typeArguments].
- */
- void set typeArguments(TypeArgumentList typeArguments) {
- _typeArguments = _becomeParentOf(typeArguments);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitFunctionExpressionInvocation(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_function, visitor);
- _safelyVisitChild(_typeArguments, visitor);
- _safelyVisitChild(_argumentList, visitor);
- }
-}
-
-/**
- * A function type alias.
- *
- * > functionTypeAlias ::=
- * > functionPrefix [TypeParameterList]? [FormalParameterList] ';'
- * >
- * > functionPrefix ::=
- * > [TypeName]? [SimpleIdentifier]
- */
-class FunctionTypeAlias extends TypeAlias {
- /**
- * The name of the return type of the function type being defined, or `null`
- * if no return type was given.
- */
- TypeName _returnType;
-
- /**
- * The type parameters for the function type, or `null` if the function type
- * does not have any type parameters.
- */
- TypeParameterList _typeParameters;
-
- /**
- * The parameters associated with the function type.
- */
- FormalParameterList _parameters;
-
- /**
- * Initialize a newly created function type alias. Either or both of the
- * [comment] and [metadata] can be `null` if the function does not have the
- * corresponding attribute. The [returnType] can be `null` if no return type
- * was specified. The [typeParameters] can be `null` if the function has no
- * type parameters.
- */
- FunctionTypeAlias(
- Comment comment,
- List<Annotation> metadata,
- Token keyword,
- TypeName returnType,
- SimpleIdentifier name,
- TypeParameterList typeParameters,
- FormalParameterList parameters,
- Token semicolon)
- : super(comment, metadata, keyword, name, semicolon) {
- _returnType = _becomeParentOf(returnType);
- _typeParameters = _becomeParentOf(typeParameters);
- _parameters = _becomeParentOf(parameters);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(typedefKeyword)
- ..add(_returnType)
- ..add(_name)
- ..add(_typeParameters)
- ..add(_parameters)
- ..add(semicolon);
-
- @override
- FunctionTypeAliasElement get element =>
- _name != null ? (_name.staticElement as FunctionTypeAliasElement) : null;
-
- /**
- * Return the parameters associated with the function type.
- */
- FormalParameterList get parameters => _parameters;
-
- /**
- * Set the parameters associated with the function type to the given list of
- * [parameters].
- */
- void set parameters(FormalParameterList parameters) {
- _parameters = _becomeParentOf(parameters);
- }
-
- /**
- * Return the name of the return type of the function type being defined, or
- * `null` if no return type was given.
- */
- TypeName get returnType => _returnType;
-
- /**
- * Set the name of the return type of the function type being defined to the
- * given [typeName].
- */
- void set returnType(TypeName typeName) {
- _returnType = _becomeParentOf(typeName);
- }
-
- /**
- * Return the type parameters for the function type, or `null` if the function
- * type does not have any type parameters.
- */
- TypeParameterList get typeParameters => _typeParameters;
-
- /**
- * Set the type parameters for the function type to the given list of
- * [typeParameters].
- */
- void set typeParameters(TypeParameterList typeParameters) {
- _typeParameters = _becomeParentOf(typeParameters);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitFunctionTypeAlias(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_returnType, visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_typeParameters, visitor);
- _safelyVisitChild(_parameters, visitor);
- }
-}
-
-/**
- * A function-typed formal parameter.
- *
- * > functionSignature ::=
- * > [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
- */
-class FunctionTypedFormalParameter extends NormalFormalParameter {
- /**
- * The return type of the function, or `null` if the function does not have a
- * return type.
- */
- TypeName _returnType;
-
- /**
- * The type parameters associated with the function, or `null` if the function
- * is not a generic function.
- */
- TypeParameterList _typeParameters;
-
- /**
- * The parameters of the function-typed parameter.
- */
- FormalParameterList _parameters;
-
- /**
- * Initialize a newly created formal parameter. Either or both of the
- * [comment] and [metadata] can be `null` if the parameter does not have the
- * corresponding attribute. The [returnType] can be `null` if no return type
- * was specified.
- */
- FunctionTypedFormalParameter(
- Comment comment,
- List<Annotation> metadata,
- TypeName returnType,
- SimpleIdentifier identifier,
- TypeParameterList typeParameters,
- FormalParameterList parameters)
- : super(comment, metadata, identifier) {
- _returnType = _becomeParentOf(returnType);
- _typeParameters = _becomeParentOf(typeParameters);
- _parameters = _becomeParentOf(parameters);
- }
-
- @override
- Token get beginToken {
- if (_returnType != null) {
- return _returnType.beginToken;
- }
- return identifier.beginToken;
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(_returnType)..add(identifier)..add(parameters);
-
- @override
- Token get endToken => _parameters.endToken;
-
- @override
- bool get isConst => false;
-
- @override
- bool get isFinal => false;
-
- /**
- * Return the parameters of the function-typed parameter.
- */
- FormalParameterList get parameters => _parameters;
-
- /**
- * Set the parameters of the function-typed parameter to the given
- * [parameters].
- */
- void set parameters(FormalParameterList parameters) {
- _parameters = _becomeParentOf(parameters);
- }
-
- /**
- * Return the return type of the function, or `null` if the function does not
- * have a return type.
- */
- TypeName get returnType => _returnType;
-
- /**
- * Set the return type of the function to the given [type].
- */
- void set returnType(TypeName type) {
- _returnType = _becomeParentOf(type);
- }
-
- /**
- * Return the type parameters associated with this function, or `null` if
- * this function is not a generic function.
- */
- TypeParameterList get typeParameters => _typeParameters;
-
- /**
- * Set the type parameters associated with this method to the given
- * [typeParameters].
- */
- void set typeParameters(TypeParameterList typeParameters) {
- _typeParameters = _becomeParentOf(typeParameters);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitFunctionTypedFormalParameter(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_returnType, visitor);
- _safelyVisitChild(identifier, visitor);
- _safelyVisitChild(_typeParameters, visitor);
- _safelyVisitChild(_parameters, visitor);
- }
-}
-
-/**
- * A combinator that restricts the names being imported to those that are not in
- * a given list.
- *
- * > hideCombinator ::=
- * > 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
- */
-class HideCombinator extends Combinator {
- /**
- * The list of names from the library that are hidden by this combinator.
- */
- NodeList<SimpleIdentifier> _hiddenNames;
-
- /**
- * Initialize a newly created import show combinator.
- */
- HideCombinator(Token keyword, List<SimpleIdentifier> hiddenNames)
- : super(keyword) {
- _hiddenNames = new NodeList<SimpleIdentifier>(this, hiddenNames);
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(keyword)
- ..addAll(_hiddenNames);
-
- @override
- Token get endToken => _hiddenNames.endToken;
-
- /**
- * Return the list of names from the library that are hidden by this
- * combinator.
- */
- NodeList<SimpleIdentifier> get hiddenNames => _hiddenNames;
-
- @override
- accept(AstVisitor visitor) => visitor.visitHideCombinator(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _hiddenNames.accept(visitor);
- }
-}
-
-/**
- * A node that represents an identifier.
- *
- * > identifier ::=
- * > [SimpleIdentifier]
- * > | [PrefixedIdentifier]
- */
-abstract class Identifier extends Expression {
- /**
- * Return the best element available for this operator. If resolution was able
- * to find a better element based on type propagation, that element will be
- * returned. Otherwise, the element found using the result of static analysis
- * will be returned. If resolution has not been performed, then `null` will be
- * returned.
- */
- Element get bestElement;
-
- @override
- bool get isAssignable => true;
-
- /**
- * Return the lexical representation of the identifier.
- */
- String get name;
-
- /**
- * Return the element associated with this identifier based on propagated type
- * information, or `null` if the AST structure has not been resolved or if
- * this identifier could not be resolved. One example of the latter case is an
- * identifier that is not defined within the scope in which it appears.
- */
- Element get propagatedElement;
-
- /**
- * Return the element associated with this identifier based on static type
- * information, or `null` if the AST structure has not been resolved or if
- * this identifier could not be resolved. One example of the latter case is an
- * identifier that is not defined within the scope in which it appears
- */
- Element get staticElement;
-
- /**
- * Return `true` if the given [name] is visible only within the library in
- * which it is declared.
- */
- static bool isPrivateName(String name) =>
- StringUtilities.startsWithChar(name, 0x5F);
-}
-
-/**
- * An if statement.
- *
- * > ifStatement ::=
- * > 'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
- */
-class IfStatement extends Statement {
- /**
- * The token representing the 'if' keyword.
- */
- Token ifKeyword;
-
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The condition used to determine which of the statements is executed next.
- */
- Expression _condition;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * The statement that is executed if the condition evaluates to `true`.
- */
- Statement _thenStatement;
-
- /**
- * The token representing the 'else' keyword, or `null` if there is no else
- * statement.
- */
- Token elseKeyword;
-
- /**
- * The statement that is executed if the condition evaluates to `false`, or
- * `null` if there is no else statement.
- */
- Statement _elseStatement;
-
- /**
- * Initialize a newly created if statement. The [elseKeyword] and
- * [elseStatement] can be `null` if there is no else clause.
- */
- IfStatement(
- this.ifKeyword,
- this.leftParenthesis,
- Expression condition,
- this.rightParenthesis,
- Statement thenStatement,
- this.elseKeyword,
- Statement elseStatement) {
- _condition = _becomeParentOf(condition);
- _thenStatement = _becomeParentOf(thenStatement);
- _elseStatement = _becomeParentOf(elseStatement);
- }
-
- @override
- Token get beginToken => ifKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(ifKeyword)
- ..add(leftParenthesis)
- ..add(_condition)
- ..add(rightParenthesis)
- ..add(_thenStatement)
- ..add(elseKeyword)
- ..add(_elseStatement);
-
- /**
- * Return the condition used to determine which of the statements is executed
- * next.
- */
- Expression get condition => _condition;
-
- /**
- * Set the condition used to determine which of the statements is executed
- * next to the given [expression].
- */
- void set condition(Expression expression) {
- _condition = _becomeParentOf(expression);
- }
-
- /**
- * Return the statement that is executed if the condition evaluates to
- * `false`, or `null` if there is no else statement.
- */
- Statement get elseStatement => _elseStatement;
-
- /**
- * Set the statement that is executed if the condition evaluates to `false`
- * to the given [statement].
- */
- void set elseStatement(Statement statement) {
- _elseStatement = _becomeParentOf(statement);
- }
-
- @override
- Token get endToken {
- if (_elseStatement != null) {
- return _elseStatement.endToken;
- }
- return _thenStatement.endToken;
- }
-
- /**
- * Return the statement that is executed if the condition evaluates to `true`.
- */
- Statement get thenStatement => _thenStatement;
-
- /**
- * Set the statement that is executed if the condition evaluates to `true` to
- * the given [statement].
- */
- void set thenStatement(Statement statement) {
- _thenStatement = _becomeParentOf(statement);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitIfStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_condition, visitor);
- _safelyVisitChild(_thenStatement, visitor);
- _safelyVisitChild(_elseStatement, visitor);
- }
-}
-
-/**
- * The "implements" clause in an class declaration.
- *
- * > implementsClause ::=
- * > 'implements' [TypeName] (',' [TypeName])*
- */
-class ImplementsClause extends AstNode {
- /**
- * The token representing the 'implements' keyword.
- */
- Token implementsKeyword;
-
- /**
- * The interfaces that are being implemented.
- */
- NodeList<TypeName> _interfaces;
-
- /**
- * Initialize a newly created implements clause.
- */
- ImplementsClause(this.implementsKeyword, List<TypeName> interfaces) {
- _interfaces = new NodeList<TypeName>(this, interfaces);
- }
-
- @override
- Token get beginToken => implementsKeyword;
-
- @override
- // TODO(paulberry): add commas.
- Iterable get childEntities => new ChildEntities()
- ..add(implementsKeyword)
- ..addAll(interfaces);
-
- @override
- Token get endToken => _interfaces.endToken;
-
- /**
- * Return the list of the interfaces that are being implemented.
- */
- NodeList<TypeName> get interfaces => _interfaces;
-
- @override
- accept(AstVisitor visitor) => visitor.visitImplementsClause(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _interfaces.accept(visitor);
- }
-}
-
-/**
- * An import directive.
- *
- * > importDirective ::=
- * > [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
- * > | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
- */
-class ImportDirective extends NamespaceDirective {
- static Comparator<ImportDirective> COMPARATOR =
- (ImportDirective import1, ImportDirective import2) {
- //
- // uri
- //
- StringLiteral uri1 = import1.uri;
- StringLiteral uri2 = import2.uri;
- String uriStr1 = uri1.stringValue;
- String uriStr2 = uri2.stringValue;
- if (uriStr1 != null || uriStr2 != null) {
- if (uriStr1 == null) {
- return -1;
- } else if (uriStr2 == null) {
- return 1;
- } else {
- int compare = uriStr1.compareTo(uriStr2);
- if (compare != 0) {
- return compare;
- }
- }
- }
- //
- // as
- //
- SimpleIdentifier prefix1 = import1.prefix;
- SimpleIdentifier prefix2 = import2.prefix;
- String prefixStr1 = prefix1 != null ? prefix1.name : null;
- String prefixStr2 = prefix2 != null ? prefix2.name : null;
- if (prefixStr1 != null || prefixStr2 != null) {
- if (prefixStr1 == null) {
- return -1;
- } else if (prefixStr2 == null) {
- return 1;
- } else {
- int compare = prefixStr1.compareTo(prefixStr2);
- if (compare != 0) {
- return compare;
- }
- }
- }
- //
- // hides and shows
- //
- NodeList<Combinator> combinators1 = import1.combinators;
- List<String> allHides1 = new List<String>();
- List<String> allShows1 = new List<String>();
- for (Combinator combinator in combinators1) {
- if (combinator is HideCombinator) {
- NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
- for (SimpleIdentifier simpleIdentifier in hides) {
- allHides1.add(simpleIdentifier.name);
- }
- } else {
- NodeList<SimpleIdentifier> shows =
- (combinator as ShowCombinator).shownNames;
- for (SimpleIdentifier simpleIdentifier in shows) {
- allShows1.add(simpleIdentifier.name);
- }
- }
- }
- NodeList<Combinator> combinators2 = import2.combinators;
- List<String> allHides2 = new List<String>();
- List<String> allShows2 = new List<String>();
- for (Combinator combinator in combinators2) {
- if (combinator is HideCombinator) {
- NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
- for (SimpleIdentifier simpleIdentifier in hides) {
- allHides2.add(simpleIdentifier.name);
- }
- } else {
- NodeList<SimpleIdentifier> shows =
- (combinator as ShowCombinator).shownNames;
- for (SimpleIdentifier simpleIdentifier in shows) {
- allShows2.add(simpleIdentifier.name);
- }
- }
- }
- // test lengths of combinator lists first
- if (allHides1.length != allHides2.length) {
- return allHides1.length - allHides2.length;
- }
- if (allShows1.length != allShows2.length) {
- return allShows1.length - allShows2.length;
- }
- // next ensure that the lists are equivalent
- if (!javaCollectionContainsAll(allHides1, allHides2)) {
- return -1;
- }
- if (!javaCollectionContainsAll(allShows1, allShows2)) {
- return -1;
- }
- return 0;
- };
-
- /**
- * The token representing the 'deferred' keyword, or `null` if the imported is
- * not deferred.
- */
- Token deferredKeyword;
-
- /**
- * The token representing the 'as' keyword, or `null` if the imported names are
- * not prefixed.
- */
- Token asKeyword;
-
- /**
- * The prefix to be used with the imported names, or `null` if the imported
- * names are not prefixed.
- */
- SimpleIdentifier _prefix;
-
- /**
- * Initialize a newly created import directive. Either or both of the
- * [comment] and [metadata] can be `null` if the function does not have the
- * corresponding attribute. The [deferredKeyword] can be `null` if the import
- * is not deferred. The [asKeyword] and [prefix] can be `null` if the import
- * does not specify a prefix. The list of [combinators] can be `null` if there
- * are no combinators.
- */
- ImportDirective(
- Comment comment,
- List<Annotation> metadata,
- Token keyword,
- StringLiteral libraryUri,
- List<Configuration> configurations,
- this.deferredKeyword,
- this.asKeyword,
- SimpleIdentifier prefix,
- List<Combinator> combinators,
- Token semicolon)
- : super(comment, metadata, keyword, libraryUri, configurations,
- combinators, semicolon) {
- _prefix = _becomeParentOf(prefix);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(_uri)
- ..add(deferredKeyword)
- ..add(asKeyword)
- ..add(_prefix)
- ..addAll(combinators)
- ..add(semicolon);
-
- @override
- ImportElement get element => super.element as ImportElement;
-
- /**
- * Return the prefix to be used with the imported names, or `null` if the
- * imported names are not prefixed.
- */
- SimpleIdentifier get prefix => _prefix;
-
- /**
- * Set the prefix to be used with the imported names to the given [identifier].
- */
- void set prefix(SimpleIdentifier identifier) {
- _prefix = _becomeParentOf(identifier);
- }
-
- @override
- LibraryElement get uriElement {
- ImportElement element = this.element;
- if (element == null) {
- return null;
- }
- return element.importedLibrary;
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitImportDirective(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_prefix, visitor);
- combinators.accept(visitor);
- }
-}
-
-/**
- * An index expression.
- *
- * > indexExpression ::=
- * > [Expression] '[' [Expression] ']'
- */
-class IndexExpression extends Expression {
- /**
- * The expression used to compute the object being indexed, or `null` if this
- * index expression is part of a cascade expression.
- */
- Expression _target;
-
- /**
- * The period ("..") before a cascaded index expression, or `null` if this
- * index expression is not part of a cascade expression.
- */
- Token period;
-
- /**
- * The left square bracket.
- */
- Token leftBracket;
-
- /**
- * The expression used to compute the index.
- */
- Expression _index;
-
- /**
- * The right square bracket.
- */
- Token rightBracket;
-
- /**
- * The element associated with the operator based on the static type of the
- * target, or `null` if the AST structure has not been resolved or if the
- * operator could not be resolved.
- */
- MethodElement staticElement;
-
- /**
- * The element associated with the operator based on the propagated type of
- * the target, or `null` if the AST structure has not been resolved or if the
- * operator could not be resolved.
- */
- MethodElement propagatedElement;
-
- /**
- * If this expression is both in a getter and setter context, the
- * [AuxiliaryElements] will be set to hold onto the static and propagated
- * information. The auxiliary element will hold onto the elements from the
- * getter context.
- */
- AuxiliaryElements auxiliaryElements = null;
-
- /**
- * Initialize a newly created index expression.
- */
- IndexExpression.forCascade(
- this.period, this.leftBracket, Expression index, this.rightBracket) {
- _index = _becomeParentOf(index);
- }
-
- /**
- * Initialize a newly created index expression.
- */
- IndexExpression.forTarget(Expression target, this.leftBracket,
- Expression index, this.rightBracket) {
- _target = _becomeParentOf(target);
- _index = _becomeParentOf(index);
- }
-
- @override
- Token get beginToken {
- if (_target != null) {
- return _target.beginToken;
- }
- return period;
- }
-
- /**
- * Return the best element available for this operator. If resolution was able
- * to find a better element based on type propagation, that element will be
- * returned. Otherwise, the element found using the result of static analysis
- * will be returned. If resolution has not been performed, then `null` will be
- * returned.
- */
- MethodElement get bestElement {
- MethodElement element = propagatedElement;
- if (element == null) {
- element = staticElement;
- }
- return element;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(_target)
- ..add(period)
- ..add(leftBracket)
- ..add(_index)
- ..add(rightBracket);
-
- @override
- Token get endToken => rightBracket;
-
- /**
- * Return the expression used to compute the index.
- */
- Expression get index => _index;
-
- /**
- * Set the expression used to compute the index to the given [expression].
- */
- void set index(Expression expression) {
- _index = _becomeParentOf(expression);
- }
-
- @override
- bool get isAssignable => true;
-
- /**
- * Return `true` if this expression is cascaded. If it is, then the target of
- * this expression is not stored locally but is stored in the nearest ancestor
- * that is a [CascadeExpression].
- */
- bool get isCascaded => period != null;
-
- @override
- int get precedence => 15;
-
- /**
- * Return the expression used to compute the object being indexed. If this
- * index expression is not part of a cascade expression, then this is the same
- * as [target]. If this index expression is part of a cascade expression, then
- * the target expression stored with the cascade expression is returned.
- */
- Expression get realTarget {
- if (isCascaded) {
- AstNode ancestor = parent;
- while (ancestor is! CascadeExpression) {
- if (ancestor == null) {
- return _target;
- }
- ancestor = ancestor.parent;
- }
- return (ancestor as CascadeExpression).target;
- }
- return _target;
- }
-
- /**
- * Return the expression used to compute the object being indexed, or `null`
- * if this index expression is part of a cascade expression.
- *
- * Use [realTarget] to get the target independent of whether this is part of a
- * cascade expression.
- */
- Expression get target => _target;
-
- /**
- * Set the expression used to compute the object being indexed to the given
- * [expression].
- */
- void set target(Expression expression) {
- _target = _becomeParentOf(expression);
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on propagated type information, then return the parameter
- * element representing the parameter to which the value of the index
- * expression will be bound. Otherwise, return `null`.
- */
- ParameterElement get _propagatedParameterElementForIndex {
- if (propagatedElement == null) {
- return null;
- }
- List<ParameterElement> parameters = propagatedElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on static type information, then return the parameter element
- * representing the parameter to which the value of the index expression will
- * be bound. Otherwise, return `null`.
- */
- ParameterElement get _staticParameterElementForIndex {
- if (staticElement == null) {
- return null;
- }
- List<ParameterElement> parameters = staticElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitIndexExpression(this);
-
- /**
- * Return `true` if this expression is computing a right-hand value (that is,
- * if this expression is in a context where the operator '[]' will be
- * invoked).
- *
- * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
- * are they mutually exclusive. In other words, it is possible for both
- * methods to return `true` when invoked on the same node.
- */
- bool inGetterContext() {
- // TODO(brianwilkerson) Convert this to a getter.
- AstNode parent = this.parent;
- if (parent is AssignmentExpression) {
- AssignmentExpression assignment = parent;
- if (identical(assignment.leftHandSide, this) &&
- assignment.operator.type == TokenType.EQ) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return `true` if this expression is computing a left-hand value (that is,
- * if this expression is in a context where the operator '[]=' will be
- * invoked).
- *
- * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
- * are they mutually exclusive. In other words, it is possible for both
- * methods to return `true` when invoked on the same node.
- */
- bool inSetterContext() {
- // TODO(brianwilkerson) Convert this to a getter.
- AstNode parent = this.parent;
- if (parent is PrefixExpression) {
- return parent.operator.type.isIncrementOperator;
- } else if (parent is PostfixExpression) {
- return true;
- } else if (parent is AssignmentExpression) {
- return identical(parent.leftHandSide, this);
- }
- return false;
- }
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_target, visitor);
- _safelyVisitChild(_index, visitor);
- }
-}
-
-/**
- * An instance creation expression.
- *
- * > newExpression ::=
- * > ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
- */
-class InstanceCreationExpression extends Expression {
- /**
- * The 'new' or 'const' keyword used to indicate how an object should be
- * created.
- */
- Token keyword;
-
- /**
- * The name of the constructor to be invoked.
- */
- ConstructorName _constructorName;
-
- /**
- * The list of arguments to the constructor.
- */
- ArgumentList _argumentList;
-
- /**
- * The element associated with the constructor based on static type
- * information, or `null` if the AST structure has not been resolved or if the
- * constructor could not be resolved.
- */
- ConstructorElement staticElement;
-
- /**
- * Initialize a newly created instance creation expression.
- */
- InstanceCreationExpression(this.keyword, ConstructorName constructorName,
- ArgumentList argumentList) {
- _constructorName = _becomeParentOf(constructorName);
- _argumentList = _becomeParentOf(argumentList);
- }
-
- /**
- * Return the list of arguments to the constructor.
- */
- ArgumentList get argumentList => _argumentList;
-
- /**
- * Set the list of arguments to the constructor to the given [argumentList].
- */
- void set argumentList(ArgumentList argumentList) {
- _argumentList = _becomeParentOf(argumentList);
- }
-
- @override
- Token get beginToken => keyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(keyword)
- ..add(_constructorName)
- ..add(_argumentList);
-
- /**
- * Return the name of the constructor to be invoked.
- */
- ConstructorName get constructorName => _constructorName;
-
- /**
- * Set the name of the constructor to be invoked to the given [name].
- */
- void set constructorName(ConstructorName name) {
- _constructorName = _becomeParentOf(name);
- }
-
- @override
- Token get endToken => _argumentList.endToken;
-
- /**
- * Return `true` if this creation expression is used to invoke a constant
- * constructor.
- */
- bool get isConst =>
- keyword is KeywordToken &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
-
- @override
- int get precedence => 16;
-
- @override
- accept(AstVisitor visitor) => visitor.visitInstanceCreationExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_constructorName, visitor);
- _safelyVisitChild(_argumentList, visitor);
- }
-}
-
-/**
- * An integer literal expression.
- *
- * > integerLiteral ::=
- * > decimalIntegerLiteral
- * > | hexadecimalIntegerLiteral
- * >
- * > decimalIntegerLiteral ::=
- * > decimalDigit+
- * >
- * > hexadecimalIntegerLiteral ::=
- * > '0x' hexadecimalDigit+
- * > | '0X' hexadecimalDigit+
- */
-class IntegerLiteral extends Literal {
- /**
- * The token representing the literal.
- */
- Token literal;
-
- /**
- * The value of the literal.
- */
- int value = 0;
-
- /**
- * Initialize a newly created integer literal.
- */
- IntegerLiteral(this.literal, this.value);
-
- @override
- Token get beginToken => literal;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(literal);
-
- @override
- Token get endToken => literal;
-
- @override
- accept(AstVisitor visitor) => visitor.visitIntegerLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A node within a [StringInterpolation].
- *
- * > interpolationElement ::=
- * > [InterpolationExpression]
- * > | [InterpolationString]
- */
-abstract class InterpolationElement extends AstNode {}
-
-/**
- * An expression embedded in a string interpolation.
- *
- * > interpolationExpression ::=
- * > '$' [SimpleIdentifier]
- * > | '$' '{' [Expression] '}'
- */
-class InterpolationExpression extends InterpolationElement {
- /**
- * The token used to introduce the interpolation expression; either '$' if the
- * expression is a simple identifier or '${' if the expression is a full
- * expression.
- */
- Token leftBracket;
-
- /**
- * The expression to be evaluated for the value to be converted into a string.
- */
- Expression _expression;
-
- /**
- * The right curly bracket, or `null` if the expression is an identifier
- * without brackets.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created interpolation expression.
- */
- InterpolationExpression(
- this.leftBracket, Expression expression, this.rightBracket) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken => leftBracket;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(leftBracket)
- ..add(_expression)
- ..add(rightBracket);
-
- @override
- Token get endToken {
- if (rightBracket != null) {
- return rightBracket;
- }
- return _expression.endToken;
- }
-
- /**
- * Return the expression to be evaluated for the value to be converted into a
- * string.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression to be evaluated for the value to be converted into a
- * string to the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitInterpolationExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * A non-empty substring of an interpolated string.
- *
- * > interpolationString ::=
- * > characters
- */
-class InterpolationString extends InterpolationElement {
- /**
- * The characters that will be added to the string.
- */
- Token contents;
-
- /**
- * The value of the literal.
- */
- String value;
-
- /**
- * Initialize a newly created string of characters that are part of a string
- * interpolation.
- */
- InterpolationString(this.contents, this.value);
-
- @override
- Token get beginToken => contents;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(contents);
-
- /**
- * Return the offset of the after-last contents character.
- */
- int get contentsEnd {
- String lexeme = contents.lexeme;
- return offset + new StringLexemeHelper(lexeme, true, true).end;
- }
-
- /**
- * Return the offset of the first contents character.
- */
- int get contentsOffset {
- int offset = contents.offset;
- String lexeme = contents.lexeme;
- return offset + new StringLexemeHelper(lexeme, true, true).start;
- }
-
- @override
- Token get endToken => contents;
-
- @override
- accept(AstVisitor visitor) => visitor.visitInterpolationString(this);
-
- @override
- void visitChildren(AstVisitor visitor) {}
-}
-
-/**
- * An is expression.
- *
- * > isExpression ::=
- * > [Expression] 'is' '!'? [TypeName]
- */
-class IsExpression extends Expression {
- /**
- * The expression used to compute the value whose type is being tested.
- */
- Expression _expression;
-
- /**
- * The is operator.
- */
- Token isOperator;
-
- /**
- * The not operator, or `null` if the sense of the test is not negated.
- */
- Token notOperator;
-
- /**
- * The name of the type being tested for.
- */
- TypeName _type;
-
- /**
- * Initialize a newly created is expression. The [notOperator] can be `null`
- * if the sense of the test is not negated.
- */
- IsExpression(
- Expression expression, this.isOperator, this.notOperator, TypeName type) {
- _expression = _becomeParentOf(expression);
- _type = _becomeParentOf(type);
- }
-
- @override
- Token get beginToken => _expression.beginToken;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(_expression)
- ..add(isOperator)
- ..add(notOperator)
- ..add(_type);
-
- @override
- Token get endToken => _type.endToken;
-
- /**
- * Return the expression used to compute the value whose type is being tested.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression used to compute the value whose type is being tested to
- * the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 7;
-
- /**
- * Return the name of the type being tested for.
- */
- TypeName get type => _type;
-
- /**
- * Set the name of the type being tested for to the given [name].
- */
- void set type(TypeName name) {
- _type = _becomeParentOf(name);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitIsExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- _safelyVisitChild(_type, visitor);
- }
-}
-
-/**
- * A label on either a [LabeledStatement] or a [NamedExpression].
- *
- * > label ::=
- * > [SimpleIdentifier] ':'
- */
-class Label extends AstNode {
- /**
- * The label being associated with the statement.
- */
- SimpleIdentifier _label;
-
- /**
- * The colon that separates the label from the statement.
- */
- Token colon;
-
- /**
- * Initialize a newly created label.
- */
- Label(SimpleIdentifier label, this.colon) {
- _label = _becomeParentOf(label);
- }
-
- @override
- Token get beginToken => _label.beginToken;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(_label)..add(colon);
-
- @override
- Token get endToken => colon;
-
- /**
- * Return the label being associated with the statement.
- */
- SimpleIdentifier get label => _label;
-
- /**
- * Set the label being associated with the statement to the given [label].
- */
- void set label(SimpleIdentifier label) {
- _label = _becomeParentOf(label);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitLabel(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_label, visitor);
- }
-}
-
-/**
- * A statement that has a label associated with them.
- *
- * > labeledStatement ::=
- * > [Label]+ [Statement]
- */
-class LabeledStatement extends Statement {
- /**
- * The labels being associated with the statement.
- */
- NodeList<Label> _labels;
-
- /**
- * The statement with which the labels are being associated.
- */
- Statement _statement;
-
- /**
- * Initialize a newly created labeled statement.
- */
- LabeledStatement(List<Label> labels, Statement statement) {
- _labels = new NodeList<Label>(this, labels);
- _statement = _becomeParentOf(statement);
- }
-
- @override
- Token get beginToken {
- if (!_labels.isEmpty) {
- return _labels.beginToken;
- }
- return _statement.beginToken;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..addAll(_labels)
- ..add(_statement);
-
- @override
- Token get endToken => _statement.endToken;
-
- /**
- * Return the labels being associated with the statement.
- */
- NodeList<Label> get labels => _labels;
-
- /**
- * Return the statement with which the labels are being associated.
- */
- Statement get statement => _statement;
-
- /**
- * Set the statement with which the labels are being associated to the given
- * [statement].
- */
- void set statement(Statement statement) {
- _statement = _becomeParentOf(statement);
- }
-
- @override
- Statement get unlabeled => _statement.unlabeled;
-
- @override
- accept(AstVisitor visitor) => visitor.visitLabeledStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _labels.accept(visitor);
- _safelyVisitChild(_statement, visitor);
- }
-}
-
-/**
- * A library directive.
- *
- * > libraryDirective ::=
- * > [Annotation] 'library' [Identifier] ';'
- */
-class LibraryDirective extends Directive {
- /**
- * The token representing the 'library' keyword.
- */
- Token libraryKeyword;
-
- /**
- * The name of the library being defined.
- */
- LibraryIdentifier _name;
-
- /**
- * The semicolon terminating the directive.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created library directive. Either or both of the
- * [comment] and [metadata] can be `null` if the directive does not have the
- * corresponding attribute.
- */
- LibraryDirective(Comment comment, List<Annotation> metadata,
- this.libraryKeyword, LibraryIdentifier name, this.semicolon)
- : super(comment, metadata) {
- _name = _becomeParentOf(name);
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(libraryKeyword)..add(_name)..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
-
- @override
- Token get keyword => libraryKeyword;
-
- /**
- * Return the name of the library being defined.
- */
- LibraryIdentifier get name => _name;
-
- /**
- * Set the name of the library being defined to the given [name].
- */
- void set name(LibraryIdentifier name) {
- _name = _becomeParentOf(name);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitLibraryDirective(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_name, visitor);
- }
-}
-
-/**
- * The identifier for a library.
- *
- * > libraryIdentifier ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
- */
-class LibraryIdentifier extends Identifier {
- /**
- * The components of the identifier.
- */
- NodeList<SimpleIdentifier> _components;
-
- /**
- * Initialize a newly created prefixed identifier.
- */
- LibraryIdentifier(List<SimpleIdentifier> components) {
- _components = new NodeList<SimpleIdentifier>(this, components);
- }
-
- @override
- Token get beginToken => _components.beginToken;
-
- @override
- Element get bestElement => staticElement;
-
- @override
- // TODO(paulberry): add "." tokens.
- Iterable get childEntities => new ChildEntities()..addAll(_components);
-
- /**
- * Return the components of the identifier.
- */
- NodeList<SimpleIdentifier> get components => _components;
-
- @override
- Token get endToken => _components.endToken;
-
- @override
- String get name {
- StringBuffer buffer = new StringBuffer();
- bool needsPeriod = false;
- for (SimpleIdentifier identifier in _components) {
- if (needsPeriod) {
- buffer.write(".");
- } else {
- needsPeriod = true;
- }
- buffer.write(identifier.name);
- }
- return buffer.toString();
- }
-
- @override
- int get precedence => 15;
-
- @override
- Element get propagatedElement => null;
-
- @override
- Element get staticElement => null;
-
- @override
- accept(AstVisitor visitor) => visitor.visitLibraryIdentifier(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _components.accept(visitor);
- }
-}
-
-/**
- * A list literal.
- *
- * > listLiteral ::=
- * > 'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
- */
-class ListLiteral extends TypedLiteral {
- /**
- * The left square bracket.
- */
- Token leftBracket;
-
- /**
- * The expressions used to compute the elements of the list.
- */
- NodeList<Expression> _elements;
-
- /**
- * The right square bracket.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created list literal. The [constKeyword] can be `null`
- * if the literal is not a constant. The [typeArguments] can be `null` if no
- * type arguments were declared. The list of [elements] can be `null` if the
- * list is empty.
- */
- ListLiteral(Token constKeyword, TypeArgumentList typeArguments,
- this.leftBracket, List<Expression> elements, this.rightBracket)
- : super(constKeyword, typeArguments) {
- _elements = new NodeList<Expression>(this, elements);
- }
-
- @override
- Token get beginToken {
- if (constKeyword != null) {
- return constKeyword;
- }
- TypeArgumentList typeArguments = this.typeArguments;
- if (typeArguments != null) {
- return typeArguments.beginToken;
- }
- return leftBracket;
- }
-
- @override
- // TODO(paulberry): add commas.
- Iterable get childEntities => super._childEntities
- ..add(leftBracket)
- ..addAll(_elements)
- ..add(rightBracket);
-
- /**
- * Return the expressions used to compute the elements of the list.
- */
- NodeList<Expression> get elements => _elements;
-
- @override
- Token get endToken => rightBracket;
-
- @override
- accept(AstVisitor visitor) => visitor.visitListLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _elements.accept(visitor);
- }
-}
-
-/**
- * A node that represents a literal expression.
- *
- * > literal ::=
- * > [BooleanLiteral]
- * > | [DoubleLiteral]
- * > | [IntegerLiteral]
- * > | [ListLiteral]
- * > | [MapLiteral]
- * > | [NullLiteral]
- * > | [StringLiteral]
- */
-abstract class Literal extends Expression {
- @override
- int get precedence => 16;
-}
-
-/**
- * A literal map.
- *
- * > mapLiteral ::=
- * > 'const'? ('<' [TypeName] (',' [TypeName])* '>')?
- * > '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
- */
-class MapLiteral extends TypedLiteral {
- /**
- * The left curly bracket.
- */
- Token leftBracket;
-
- /**
- * The entries in the map.
- */
- NodeList<MapLiteralEntry> _entries;
-
- /**
- * The right curly bracket.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created map literal. The [constKeyword] can be `null` if
- * the literal is not a constant. The [typeArguments] can be `null` if no type
- * arguments were declared. The [entries] can be `null` if the map is empty.
- */
- MapLiteral(Token constKeyword, TypeArgumentList typeArguments,
- this.leftBracket, List<MapLiteralEntry> entries, this.rightBracket)
- : super(constKeyword, typeArguments) {
- _entries = new NodeList<MapLiteralEntry>(this, entries);
- }
-
- @override
- Token get beginToken {
- if (constKeyword != null) {
- return constKeyword;
- }
- TypeArgumentList typeArguments = this.typeArguments;
- if (typeArguments != null) {
- return typeArguments.beginToken;
- }
- return leftBracket;
- }
-
- @override
- // TODO(paulberry): add commas.
- Iterable get childEntities => super._childEntities
- ..add(leftBracket)
- ..addAll(entries)
- ..add(rightBracket);
-
- @override
- Token get endToken => rightBracket;
-
- /**
- * Return the entries in the map.
- */
- NodeList<MapLiteralEntry> get entries => _entries;
-
- @override
- accept(AstVisitor visitor) => visitor.visitMapLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _entries.accept(visitor);
- }
-}
-
-/**
- * A single key/value pair in a map literal.
- *
- * > mapLiteralEntry ::=
- * > [Expression] ':' [Expression]
- */
-class MapLiteralEntry extends AstNode {
- /**
- * The expression computing the key with which the value will be associated.
- */
- Expression _key;
-
- /**
- * The colon that separates the key from the value.
- */
- Token separator;
-
- /**
- * The expression computing the value that will be associated with the key.
- */
- Expression _value;
-
- /**
- * Initialize a newly created map literal entry.
- */
- MapLiteralEntry(Expression key, this.separator, Expression value) {
- _key = _becomeParentOf(key);
- _value = _becomeParentOf(value);
- }
-
- @override
- Token get beginToken => _key.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_key)..add(separator)..add(_value);
-
- @override
- Token get endToken => _value.endToken;
-
- /**
- * Return the expression computing the key with which the value will be
- * associated.
- */
- Expression get key => _key;
-
- /**
- * Set the expression computing the key with which the value will be
- * associated to the given [string].
- */
- void set key(Expression string) {
- _key = _becomeParentOf(string);
- }
-
- /**
- * Return the expression computing the value that will be associated with the
- * key.
- */
- Expression get value => _value;
-
- /**
- * Set the expression computing the value that will be associated with the key
- * to the given [expression].
- */
- void set value(Expression expression) {
- _value = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitMapLiteralEntry(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_key, visitor);
- _safelyVisitChild(_value, visitor);
- }
-}
-
-/**
- * A method declaration.
- *
- * > methodDeclaration ::=
- * > methodSignature [FunctionBody]
- * >
- * > methodSignature ::=
- * > 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
- * > methodName [TypeParameterList] [FormalParameterList]
- * >
- * > methodName ::=
- * > [SimpleIdentifier]
- * > | 'operator' [SimpleIdentifier]
- */
-class MethodDeclaration extends ClassMember {
- /**
- * The token for the 'external' keyword, or `null` if the constructor is not
- * external.
- */
- Token externalKeyword;
-
- /**
- * The token representing the 'abstract' or 'static' keyword, or `null` if
- * neither modifier was specified.
- */
- Token modifierKeyword;
-
- /**
- * The return type of the method, or `null` if no return type was declared.
- */
- TypeName _returnType;
-
- /**
- * The token representing the 'get' or 'set' keyword, or `null` if this is a
- * method declaration rather than a property declaration.
- */
- Token propertyKeyword;
-
- /**
- * The token representing the 'operator' keyword, or `null` if this method
- * does not declare an operator.
- */
- Token operatorKeyword;
-
- /**
- * The name of the method.
- */
- SimpleIdentifier _name;
-
- /**
- * The type parameters associated with the method, or `null` if the method is
- * not a generic method.
- */
- TypeParameterList _typeParameters;
-
- /**
- * The parameters associated with the method, or `null` if this method
- * declares a getter.
- */
- FormalParameterList _parameters;
-
- /**
- * The body of the method.
- */
- FunctionBody _body;
-
- /**
- * Initialize a newly created method declaration. Either or both of the
- * [comment] and [metadata] can be `null` if the declaration does not have the
- * corresponding attribute. The [externalKeyword] can be `null` if the method
- * is not external. The [modifierKeyword] can be `null` if the method is
- * neither abstract nor static. The [returnType] can be `null` if no return
- * type was specified. The [propertyKeyword] can be `null` if the method is
- * neither a getter or a setter. The [operatorKeyword] can be `null` if the
- * method does not implement an operator. The [parameters] must be `null` if
- * this method declares a getter.
- */
- MethodDeclaration(
- Comment comment,
- List<Annotation> metadata,
- this.externalKeyword,
- this.modifierKeyword,
- TypeName returnType,
- this.propertyKeyword,
- this.operatorKeyword,
- SimpleIdentifier name,
- TypeParameterList typeParameters,
- FormalParameterList parameters,
- FunctionBody body)
- : super(comment, metadata) {
- _returnType = _becomeParentOf(returnType);
- _name = _becomeParentOf(name);
- _typeParameters = _becomeParentOf(typeParameters);
- _parameters = _becomeParentOf(parameters);
- _body = _becomeParentOf(body);
- }
-
- /**
- * Return the body of the method.
- */
- FunctionBody get body => _body;
-
- /**
- * Set the body of the method to the given [functionBody].
- */
- void set body(FunctionBody functionBody) {
- _body = _becomeParentOf(functionBody);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(externalKeyword)
- ..add(modifierKeyword)
- ..add(_returnType)
- ..add(propertyKeyword)
- ..add(operatorKeyword)
- ..add(_name)
- ..add(_parameters)
- ..add(_body);
-
- /**
- * Return the element associated with this method, or `null` if the AST
- * structure has not been resolved. The element can either be a
- * [MethodElement], if this represents the declaration of a normal method, or
- * a [PropertyAccessorElement] if this represents the declaration of either a
- * getter or a setter.
- */
- @override
- ExecutableElement get element =>
- _name != null ? (_name.staticElement as ExecutableElement) : null;
-
- @override
- Token get endToken => _body.endToken;
-
- @override
- Token get firstTokenAfterCommentAndMetadata {
- if (modifierKeyword != null) {
- return modifierKeyword;
- } else if (_returnType != null) {
- return _returnType.beginToken;
- } else if (propertyKeyword != null) {
- return propertyKeyword;
- } else if (operatorKeyword != null) {
- return operatorKeyword;
- }
- return _name.beginToken;
- }
-
- /**
- * Return `true` if this method is declared to be an abstract method.
- */
- bool get isAbstract {
- FunctionBody body = _body;
- return externalKeyword == null &&
- (body is EmptyFunctionBody && !body.semicolon.isSynthetic);
- }
-
- /**
- * Return `true` if this method declares a getter.
- */
- bool get isGetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.GET;
-
- /**
- * Return `true` if this method declares an operator.
- */
- bool get isOperator => operatorKeyword != null;
-
- /**
- * Return `true` if this method declares a setter.
- */
- bool get isSetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.SET;
-
- /**
- * Return `true` if this method is declared to be a static method.
- */
- bool get isStatic =>
- modifierKeyword != null &&
- (modifierKeyword as KeywordToken).keyword == Keyword.STATIC;
-
- /**
- * Return the name of the method.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the method to the given [identifier].
- */
- void set name(SimpleIdentifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- /**
- * Return the parameters associated with the method, or `null` if this method
- * declares a getter.
- */
- FormalParameterList get parameters => _parameters;
-
- /**
- * Set the parameters associated with the method to the given list of
- * [parameters].
- */
- void set parameters(FormalParameterList parameters) {
- _parameters = _becomeParentOf(parameters);
- }
-
- /**
- * Return the return type of the method, or `null` if no return type was
- * declared.
- */
- TypeName get returnType => _returnType;
-
- /**
- * Set the return type of the method to the given [typeName].
- */
- void set returnType(TypeName typeName) {
- _returnType = _becomeParentOf(typeName);
- }
-
- /**
- * Return the type parameters associated with this method, or `null` if this
- * method is not a generic method.
- */
- TypeParameterList get typeParameters => _typeParameters;
-
- /**
- * Set the type parameters associated with this method to the given
- * [typeParameters].
- */
- void set typeParameters(TypeParameterList typeParameters) {
- _typeParameters = _becomeParentOf(typeParameters);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitMethodDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_returnType, visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_typeParameters, visitor);
- _safelyVisitChild(_parameters, visitor);
- _safelyVisitChild(_body, visitor);
- }
-}
-
-/**
- * The invocation of either a function or a method. Invocations of functions
- * resulting from evaluating an expression are represented by
- * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
- * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
- *
- * > methodInvocation ::=
- * > ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
- */
-class MethodInvocation extends Expression {
- /**
- * The expression producing the object on which the method is defined, or
- * `null` if there is no target (that is, the target is implicitly `this`).
- */
- Expression _target;
-
- /**
- * The operator that separates the target from the method name, or `null`
- * if there is no target. In an ordinary method invocation this will be a
- * period ('.'). In a cascade section this will be the cascade operator
- * ('..').
- */
- Token operator;
-
- /**
- * The name of the method being invoked.
- */
- SimpleIdentifier _methodName;
-
- /**
- * The type arguments to be applied to the method being invoked, or `null` if
- * no type arguments were provided.
- */
- TypeArgumentList _typeArguments;
-
- /**
- * The list of arguments to the method.
- */
- ArgumentList _argumentList;
-
- /**
- * The function type of the method invocation, or `null` if the AST
- * structure has not been resolved, or if the invoke could not be resolved.
- *
- * This will usually be a [FunctionType], but it can also be an
- * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
- * interface type that implements `Function`.
- */
- DartType staticInvokeType;
-
- /**
- * Like [staticInvokeType], but reflects propagated type information.
- */
- DartType propagatedInvokeType;
-
- /**
- * Initialize a newly created method invocation. The [target] and [operator]
- * can be `null` if there is no target.
- */
- MethodInvocation(
- Expression target,
- this.operator,
- SimpleIdentifier methodName,
- TypeArgumentList typeArguments,
- ArgumentList argumentList) {
- _target = _becomeParentOf(target);
- _methodName = _becomeParentOf(methodName);
- _typeArguments = _becomeParentOf(typeArguments);
- _argumentList = _becomeParentOf(argumentList);
- }
-
- /**
- * Return the list of arguments to the method.
- */
- ArgumentList get argumentList => _argumentList;
-
- /**
- * Set the list of arguments to the method to the given [argumentList].
- */
- void set argumentList(ArgumentList argumentList) {
- _argumentList = _becomeParentOf(argumentList);
- }
-
- @override
- Token get beginToken {
- if (_target != null) {
- return _target.beginToken;
- } else if (operator != null) {
- return operator;
- }
- return _methodName.beginToken;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(_target)
- ..add(operator)
- ..add(_methodName)
- ..add(_argumentList);
-
- @override
- Token get endToken => _argumentList.endToken;
-
- /**
- * Return `true` if this expression is cascaded. If it is, then the target of
- * this expression is not stored locally but is stored in the nearest ancestor
- * that is a [CascadeExpression].
- */
- bool get isCascaded =>
- operator != null && operator.type == TokenType.PERIOD_PERIOD;
-
- /**
- * Return the name of the method being invoked.
- */
- SimpleIdentifier get methodName => _methodName;
-
- /**
- * Set the name of the method being invoked to the given [identifier].
- */
- void set methodName(SimpleIdentifier identifier) {
- _methodName = _becomeParentOf(identifier);
- }
-
- @override
- int get precedence => 15;
-
- /**
- * Return the expression used to compute the receiver of the invocation. If
- * this invocation is not part of a cascade expression, then this is the same
- * as [target]. If this invocation is part of a cascade expression, then the
- * target stored with the cascade expression is returned.
- */
- Expression get realTarget {
- if (isCascaded) {
- AstNode ancestor = parent;
- while (ancestor is! CascadeExpression) {
- if (ancestor == null) {
- return _target;
- }
- ancestor = ancestor.parent;
- }
- return (ancestor as CascadeExpression).target;
- }
- return _target;
- }
-
- /**
- * Return the expression producing the object on which the method is defined,
- * or `null` if there is no target (that is, the target is implicitly `this`)
- * or if this method invocation is part of a cascade expression.
- *
- * Use [realTarget] to get the target independent of whether this is part of a
- * cascade expression.
- */
- Expression get target => _target;
-
- /**
- * Set the expression producing the object on which the method is defined to
- * the given [expression].
- */
- void set target(Expression expression) {
- _target = _becomeParentOf(expression);
- }
-
- /**
- * Return the type arguments to be applied to the method being invoked, or
- * `null` if no type arguments were provided.
- */
- TypeArgumentList get typeArguments => _typeArguments;
-
- /**
- * Set the type arguments to be applied to the method being invoked to the
- * given [typeArguments].
- */
- void set typeArguments(TypeArgumentList typeArguments) {
- _typeArguments = _becomeParentOf(typeArguments);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitMethodInvocation(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_target, visitor);
- _safelyVisitChild(_methodName, visitor);
- _safelyVisitChild(_typeArguments, visitor);
- _safelyVisitChild(_argumentList, visitor);
- }
-}
-
-/**
- * A node that declares a single name within the scope of a compilation unit.
- */
-abstract class NamedCompilationUnitMember extends CompilationUnitMember {
- /**
- * The name of the member being declared.
- */
- SimpleIdentifier _name;
-
- /**
- * Initialize a newly created compilation unit member with the given [name].
- * Either or both of the [comment] and [metadata] can be `null` if the member
- * does not have the corresponding attribute.
- */
- NamedCompilationUnitMember(
- Comment comment, List<Annotation> metadata, SimpleIdentifier name)
- : super(comment, metadata) {
- _name = _becomeParentOf(name);
- }
-
- /**
- * Return the name of the member being declared.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the member being declared to the given [identifier].
- */
- void set name(SimpleIdentifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-}
-
-/**
- * An expression that has a name associated with it. They are used in method
- * invocations when there are named parameters.
- *
- * > namedExpression ::=
- * > [Label] [Expression]
- */
-class NamedExpression extends Expression {
- /**
- * The name associated with the expression.
- */
- Label _name;
-
- /**
- * The expression with which the name is associated.
- */
- Expression _expression;
-
- /**
- * Initialize a newly created named expression..
- */
- NamedExpression(Label name, Expression expression) {
- _name = _becomeParentOf(name);
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken => _name.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_name)..add(_expression);
-
- /**
- * Return the element representing the parameter being named by this
- * expression, or `null` if the AST structure has not been resolved or if
- * there is no parameter with the same name as this expression.
- */
- ParameterElement get element {
- Element element = _name.label.staticElement;
- if (element is ParameterElement) {
- return element;
- }
- return null;
- }
-
- @override
- Token get endToken => _expression.endToken;
-
- /**
- * Return the expression with which the name is associated.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression with which the name is associated to the given
- * [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- /**
- * Return the name associated with the expression.
- */
- Label get name => _name;
-
- /**
- * Set the name associated with the expression to the given [identifier].
- */
- void set name(Label identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- @override
- int get precedence => 0;
-
- @override
- accept(AstVisitor visitor) => visitor.visitNamedExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * A node that represents a directive that impacts the namespace of a library.
- *
- * > directive ::=
- * > [ExportDirective]
- * > | [ImportDirective]
- */
-abstract class NamespaceDirective extends UriBasedDirective {
- /**
- * The token representing the 'import' or 'export' keyword.
- */
- Token keyword;
-
- /**
- * The configurations used to control which library will actually be loaded at
- * run-time.
- */
- NodeList<Configuration> _configurations;
-
- /**
- * The combinators used to control which names are imported or exported.
- */
- NodeList<Combinator> _combinators;
-
- /**
- * The semicolon terminating the directive.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created namespace directive. Either or both of the
- * [comment] and [metadata] can be `null` if the directive does not have the
- * corresponding attribute. The list of [combinators] can be `null` if there
- * are no combinators.
- */
- NamespaceDirective(
- Comment comment,
- List<Annotation> metadata,
- this.keyword,
- StringLiteral libraryUri,
- List<Configuration> configurations,
- List<Combinator> combinators,
- this.semicolon)
- : super(comment, metadata, libraryUri) {
- _configurations = new NodeList<Configuration>(this, configurations);
- _combinators = new NodeList<Combinator>(this, combinators);
- }
-
- /**
- * Return the combinators used to control how names are imported or exported.
- */
- NodeList<Combinator> get combinators => _combinators;
-
- /**
- * Return the configurations used to control which library will actually be
- * loaded at run-time.
- */
- NodeList<Configuration> get configurations => _configurations;
-
- @override
- Token get endToken => semicolon;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => keyword;
-
- @override
- LibraryElement get uriElement;
-}
-
-/**
- * The "native" clause in an class declaration.
- *
- * > nativeClause ::=
- * > 'native' [StringLiteral]
- */
-class NativeClause extends AstNode {
- /**
- * The token representing the 'native' keyword.
- */
- Token nativeKeyword;
-
- /**
- * The name of the native object that implements the class.
- */
- StringLiteral _name;
-
- /**
- * Initialize a newly created native clause.
- */
- NativeClause(this.nativeKeyword, StringLiteral name) {
- _name = _becomeParentOf(name);
- }
-
- @override
- Token get beginToken => nativeKeyword;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(nativeKeyword)..add(_name);
-
- @override
- Token get endToken => _name.endToken;
-
- /**
- * Return the name of the native object that implements the class.
- */
- StringLiteral get name => _name;
-
- /**
- * Set the name of the native object that implements the class to the given
- * [name].
- */
- void set name(StringLiteral name) {
- _name = _becomeParentOf(name);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitNativeClause(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_name, visitor);
- }
-}
-
-/**
- * A function body that consists of a native keyword followed by a string
- * literal.
- *
- * > nativeFunctionBody ::=
- * > 'native' [SimpleStringLiteral] ';'
- */
-class NativeFunctionBody extends FunctionBody {
- /**
- * The token representing 'native' that marks the start of the function body.
- */
- Token nativeKeyword;
-
- /**
- * The string literal, after the 'native' token.
- */
- StringLiteral _stringLiteral;
-
- /**
- * The token representing the semicolon that marks the end of the function
- * body.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created function body consisting of the 'native' token,
- * a string literal, and a semicolon.
- */
- NativeFunctionBody(
- this.nativeKeyword, StringLiteral stringLiteral, this.semicolon) {
- _stringLiteral = _becomeParentOf(stringLiteral);
- }
-
- @override
- Token get beginToken => nativeKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(nativeKeyword)
- ..add(_stringLiteral)
- ..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- /**
- * Return the string literal representing the string after the 'native' token.
- */
- StringLiteral get stringLiteral => _stringLiteral;
-
- /**
- * Set the string literal representing the string after the 'native' token to
- * the given [stringLiteral].
- */
- void set stringLiteral(StringLiteral stringLiteral) {
- _stringLiteral = _becomeParentOf(stringLiteral);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitNativeFunctionBody(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_stringLiteral, visitor);
- }
-}
-
-/**
- * A list of AST nodes that have a common parent.
- */
-class NodeList<E extends AstNode> extends Object with ListMixin<E> {
- /**
- * The node that is the parent of each of the elements in the list.
- */
- AstNode owner;
-
- /**
- * The elements contained in the list.
- */
- List<E> _elements = <E>[];
-
- /**
- * Initialize a newly created list of nodes such that all of the nodes that
- * are added to the list will have their parent set to the given [owner]. The
- * list will initially be populated with the given [elements].
- */
- NodeList(this.owner, [List<E> elements]) {
- addAll(elements);
- }
-
- /**
- * Return the first token included in this node list's source range, or `null`
- * if the list is empty.
- */
- Token get beginToken {
- if (_elements.length == 0) {
- return null;
- }
- return _elements[0].beginToken;
- }
-
- /**
- * Return the last token included in this node list's source range, or `null`
- * if the list is empty.
- */
- Token get endToken {
- int length = _elements.length;
- if (length == 0) {
- return null;
- }
- return _elements[length - 1].endToken;
- }
-
- int get length => _elements.length;
-
- @deprecated // Never intended for public use.
- @override
- void set length(int newLength) {
- throw new UnsupportedError("Cannot resize NodeList.");
- }
-
- E operator [](int index) {
- if (index < 0 || index >= _elements.length) {
- throw new RangeError("Index: $index, Size: ${_elements.length}");
- }
- return _elements[index];
- }
-
- void operator []=(int index, E node) {
- if (index < 0 || index >= _elements.length) {
- throw new RangeError("Index: $index, Size: ${_elements.length}");
- }
- owner._becomeParentOf(node);
- _elements[index] = node;
- }
-
- /**
- * Use the given [visitor] to visit each of the nodes in this list.
- */
- accept(AstVisitor visitor) {
- int length = _elements.length;
- for (var i = 0; i < length; i++) {
- _elements[i].accept(visitor);
- }
- }
-
- @override
- void add(E node) {
- insert(length, node);
- }
-
- @override
- bool addAll(Iterable<E> nodes) {
- if (nodes != null && !nodes.isEmpty) {
- _elements.addAll(nodes);
- for (E node in nodes) {
- owner._becomeParentOf(node);
- }
- return true;
- }
- return false;
- }
-
- @override
- void clear() {
- _elements = <E>[];
- }
-
- @override
- void insert(int index, E node) {
- int length = _elements.length;
- if (index < 0 || index > length) {
- throw new RangeError("Index: $index, Size: ${_elements.length}");
- }
- owner._becomeParentOf(node);
- if (length == 0) {
- _elements.add(node);
- } else {
- _elements.insert(index, node);
- }
- }
-
- @override
- E removeAt(int index) {
- if (index < 0 || index >= _elements.length) {
- throw new RangeError("Index: $index, Size: ${_elements.length}");
- }
- E removedNode = _elements[index];
- _elements.removeAt(index);
- return removedNode;
- }
-}
-
-/**
- * A formal parameter that is required (is not optional).
- *
- * > normalFormalParameter ::=
- * > [FunctionTypedFormalParameter]
- * > | [FieldFormalParameter]
- * > | [SimpleFormalParameter]
- */
-abstract class NormalFormalParameter extends FormalParameter {
- /**
- * The documentation comment associated with this parameter, or `null` if this
- * parameter does not have a documentation comment associated with it.
- */
- Comment _comment;
-
- /**
- * The annotations associated with this parameter.
- */
- NodeList<Annotation> _metadata;
-
- /**
- * The name of the parameter being declared.
- */
- SimpleIdentifier _identifier;
-
- /**
- * Initialize a newly created formal parameter. Either or both of the
- * [comment] and [metadata] can be `null` if the parameter does not have the
- * corresponding attribute.
- */
- NormalFormalParameter(
- Comment comment, List<Annotation> metadata, SimpleIdentifier identifier) {
- _comment = _becomeParentOf(comment);
- _metadata = new NodeList<Annotation>(this, metadata);
- _identifier = _becomeParentOf(identifier);
- }
-
- /**
- * Return the documentation comment associated with this parameter, or `null`
- * if this parameter does not have a documentation comment associated with it.
- */
- Comment get documentationComment => _comment;
-
- /**
- * Set the documentation comment associated with this parameter to the given
- * [comment].
- */
- void set documentationComment(Comment comment) {
- _comment = _becomeParentOf(comment);
- }
-
- @override
- SimpleIdentifier get identifier => _identifier;
-
- /**
- * Set the name of the parameter being declared to the given [identifier].
- */
- void set identifier(SimpleIdentifier identifier) {
- _identifier = _becomeParentOf(identifier);
- }
-
- @override
- ParameterKind get kind {
- AstNode parent = this.parent;
- if (parent is DefaultFormalParameter) {
- return parent.kind;
- }
- return ParameterKind.REQUIRED;
- }
-
- @override
- NodeList<Annotation> get metadata => _metadata;
-
- /**
- * Set the metadata associated with this node to the given [metadata].
- */
- void set metadata(List<Annotation> metadata) {
- _metadata.clear();
- _metadata.addAll(metadata);
- }
-
- /**
- * Return a list containing the comment and annotations associated with this
- * parameter, sorted in lexical order.
- */
- List<AstNode> get sortedCommentAndAnnotations {
- return <AstNode>[]
- ..add(_comment)
- ..addAll(_metadata)
- ..sort(AstNode.LEXICAL_ORDER);
- }
-
- ChildEntities get _childEntities {
- ChildEntities result = new ChildEntities();
- if (_commentIsBeforeAnnotations()) {
- result
- ..add(_comment)
- ..addAll(_metadata);
- } else {
- result.addAll(sortedCommentAndAnnotations);
- }
- return result;
- }
-
- @override
- void visitChildren(AstVisitor visitor) {
- //
- // Note that subclasses are responsible for visiting the identifier because
- // they often need to visit other nodes before visiting the identifier.
- //
- if (_commentIsBeforeAnnotations()) {
- _safelyVisitChild(_comment, visitor);
- _metadata.accept(visitor);
- } else {
- for (AstNode child in sortedCommentAndAnnotations) {
- child.accept(visitor);
- }
- }
- }
-
- /**
- * Return `true` if the comment is lexically before any annotations.
- */
- bool _commentIsBeforeAnnotations() {
- if (_comment == null || _metadata.isEmpty) {
- return true;
- }
- Annotation firstAnnotation = _metadata[0];
- return _comment.offset < firstAnnotation.offset;
- }
-}
-
-/**
- * A null literal expression.
- *
- * > nullLiteral ::=
- * > 'null'
- */
-class NullLiteral extends Literal {
- /**
- * The token representing the literal.
- */
- Token literal;
-
- /**
- * Initialize a newly created null literal.
- */
- NullLiteral(this.literal);
-
- @override
- Token get beginToken => literal;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(literal);
-
- @override
- Token get endToken => literal;
-
- @override
- accept(AstVisitor visitor) => visitor.visitNullLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A parenthesized expression.
- *
- * > parenthesizedExpression ::=
- * > '(' [Expression] ')'
- */
-class ParenthesizedExpression extends Expression {
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The expression within the parentheses.
- */
- Expression _expression;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * Initialize a newly created parenthesized expression.
- */
- ParenthesizedExpression(
- this.leftParenthesis, Expression expression, this.rightParenthesis) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken => leftParenthesis;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(leftParenthesis)
- ..add(_expression)
- ..add(rightParenthesis);
-
- @override
- Token get endToken => rightParenthesis;
-
- /**
- * Return the expression within the parentheses.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression within the parentheses to the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 15;
-
- @override
- accept(AstVisitor visitor) => visitor.visitParenthesizedExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * A part directive.
- *
- * > partDirective ::=
- * > [Annotation] 'part' [StringLiteral] ';'
- */
-class PartDirective extends UriBasedDirective {
- /**
- * The token representing the 'part' keyword.
- */
- Token partKeyword;
-
- /**
- * The semicolon terminating the directive.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created part directive. Either or both of the [comment]
- * and [metadata] can be `null` if the directive does not have the
- * corresponding attribute.
- */
- PartDirective(Comment comment, List<Annotation> metadata, this.partKeyword,
- StringLiteral partUri, this.semicolon)
- : super(comment, metadata, partUri);
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(partKeyword)..add(_uri)..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => partKeyword;
-
- @override
- Token get keyword => partKeyword;
-
- @override
- CompilationUnitElement get uriElement => element as CompilationUnitElement;
-
- @override
- accept(AstVisitor visitor) => visitor.visitPartDirective(this);
-}
-
-/**
- * A part-of directive.
- *
- * > partOfDirective ::=
- * > [Annotation] 'part' 'of' [Identifier] ';'
- */
-class PartOfDirective extends Directive {
- /**
- * The token representing the 'part' keyword.
- */
- Token partKeyword;
-
- /**
- * The token representing the 'of' keyword.
- */
- Token ofKeyword;
-
- /**
- * The name of the library that the containing compilation unit is part of.
- */
- LibraryIdentifier _libraryName;
-
- /**
- * The semicolon terminating the directive.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created part-of directive. Either or both of the
- * [comment] and [metadata] can be `null` if the directive does not have the
- * corresponding attribute.
- */
- PartOfDirective(Comment comment, List<Annotation> metadata, this.partKeyword,
- this.ofKeyword, LibraryIdentifier libraryName, this.semicolon)
- : super(comment, metadata) {
- _libraryName = _becomeParentOf(libraryName);
- }
-
- @override
- Iterable get childEntities => super._childEntities
- ..add(partKeyword)
- ..add(ofKeyword)
- ..add(_libraryName)
- ..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => partKeyword;
-
- @override
- Token get keyword => partKeyword;
-
- /**
- * Return the name of the library that the containing compilation unit is part
- * of.
- */
- LibraryIdentifier get libraryName => _libraryName;
-
- /**
- * Set the name of the library that the containing compilation unit is part of
- * to the given [libraryName].
- */
- void set libraryName(LibraryIdentifier libraryName) {
- _libraryName = _becomeParentOf(libraryName);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitPartOfDirective(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_libraryName, visitor);
- }
-}
-
-/**
- * A postfix unary expression.
- *
- * > postfixExpression ::=
- * > [Expression] [Token]
- */
-class PostfixExpression extends Expression {
- /**
- * The expression computing the operand for the operator.
- */
- Expression _operand;
-
- /**
- * The postfix operator being applied to the operand.
- */
- Token operator;
-
- /**
- * The element associated with this the operator based on the propagated type
- * of the operand, or `null` if the AST structure has not been resolved, if
- * the operator is not user definable, or if the operator could not be
- * resolved.
- */
- MethodElement propagatedElement;
-
- /**
- * The element associated with the operator based on the static type of the
- * operand, or `null` if the AST structure has not been resolved, if the
- * operator is not user definable, or if the operator could not be resolved.
- */
- MethodElement staticElement;
-
- /**
- * Initialize a newly created postfix expression.
- */
- PostfixExpression(Expression operand, this.operator) {
- _operand = _becomeParentOf(operand);
- }
-
- @override
- Token get beginToken => _operand.beginToken;
-
- /**
- * Return the best element available for this operator. If resolution was able
- * to find a better element based on type propagation, that element will be
- * returned. Otherwise, the element found using the result of static analysis
- * will be returned. If resolution has not been performed, then `null` will be
- * returned.
- */
- MethodElement get bestElement {
- MethodElement element = propagatedElement;
- if (element == null) {
- element = staticElement;
- }
- return element;
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_operand)..add(operator);
-
- @override
- Token get endToken => operator;
-
- /**
- * Return the expression computing the operand for the operator.
- */
- Expression get operand => _operand;
-
- /**
- * Set the expression computing the operand for the operator to the given
- * [expression].
- */
- void set operand(Expression expression) {
- _operand = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 15;
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on propagated type information, then return the parameter
- * element representing the parameter to which the value of the operand will
- * be bound. Otherwise, return `null`.
- */
- ParameterElement get _propagatedParameterElementForOperand {
- if (propagatedElement == null) {
- return null;
- }
- List<ParameterElement> parameters = propagatedElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on static type information, then return the parameter element
- * representing the parameter to which the value of the operand will be bound.
- * Otherwise, return `null`.
- */
- ParameterElement get _staticParameterElementForOperand {
- if (staticElement == null) {
- return null;
- }
- List<ParameterElement> parameters = staticElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitPostfixExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_operand, visitor);
- }
-}
-
-/**
- * An identifier that is prefixed or an access to an object property where the
- * target of the property access is a simple identifier.
- *
- * > prefixedIdentifier ::=
- * > [SimpleIdentifier] '.' [SimpleIdentifier]
- */
-class PrefixedIdentifier extends Identifier {
- /**
- * The prefix associated with the library in which the identifier is defined.
- */
- SimpleIdentifier _prefix;
-
- /**
- * The period used to separate the prefix from the identifier.
- */
- Token period;
-
- /**
- * The identifier being prefixed.
- */
- SimpleIdentifier _identifier;
-
- /**
- * Initialize a newly created prefixed identifier.
- */
- PrefixedIdentifier(
- SimpleIdentifier prefix, this.period, SimpleIdentifier identifier) {
- _prefix = _becomeParentOf(prefix);
- _identifier = _becomeParentOf(identifier);
- }
-
- @override
- Token get beginToken => _prefix.beginToken;
-
- @override
- Element get bestElement {
- if (_identifier == null) {
- return null;
- }
- return _identifier.bestElement;
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_prefix)..add(period)..add(_identifier);
-
- @override
- Token get endToken => _identifier.endToken;
-
- /**
- * Return the identifier being prefixed.
- */
- SimpleIdentifier get identifier => _identifier;
-
- /**
- * Set the identifier being prefixed to the given [identifier].
- */
- void set identifier(SimpleIdentifier identifier) {
- _identifier = _becomeParentOf(identifier);
- }
-
- /**
- * Return `true` if this type is a deferred type. If the AST structure has not
- * been resolved, then return `false`.
- *
- * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
- * </i>p.T</i> where <i>p</i> is a deferred prefix.
- */
- bool get isDeferred {
- Element element = _prefix.staticElement;
- if (element is! PrefixElement) {
- return false;
- }
- PrefixElement prefixElement = element as PrefixElement;
- List<ImportElement> imports =
- prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
- if (imports.length != 1) {
- return false;
- }
- return imports[0].isDeferred;
- }
-
- @override
- String get name => "${_prefix.name}.${_identifier.name}";
-
- @override
- int get precedence => 15;
-
- /**
- * Return the prefix associated with the library in which the identifier is
- * defined.
- */
- SimpleIdentifier get prefix => _prefix;
-
- /**
- * Set the prefix associated with the library in which the identifier is
- * defined to the given [identifier].
- */
- void set prefix(SimpleIdentifier identifier) {
- _prefix = _becomeParentOf(identifier);
- }
-
- @override
- Element get propagatedElement {
- if (_identifier == null) {
- return null;
- }
- return _identifier.propagatedElement;
- }
-
- @override
- Element get staticElement {
- if (_identifier == null) {
- return null;
- }
- return _identifier.staticElement;
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitPrefixedIdentifier(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_prefix, visitor);
- _safelyVisitChild(_identifier, visitor);
- }
-}
-
-/**
- * A prefix unary expression.
- *
- * > prefixExpression ::=
- * > [Token] [Expression]
- */
-class PrefixExpression extends Expression {
- /**
- * The prefix operator being applied to the operand.
- */
- Token operator;
-
- /**
- * The expression computing the operand for the operator.
- */
- Expression _operand;
-
- /**
- * The element associated with the operator based on the static type of the
- * operand, or `null` if the AST structure has not been resolved, if the
- * operator is not user definable, or if the operator could not be resolved.
- */
- MethodElement staticElement;
-
- /**
- * The element associated with the operator based on the propagated type of
- * the operand, or `null` if the AST structure has not been resolved, if the
- * operator is not user definable, or if the operator could not be resolved.
- */
- MethodElement propagatedElement;
-
- /**
- * Initialize a newly created prefix expression.
- */
- PrefixExpression(this.operator, Expression operand) {
- _operand = _becomeParentOf(operand);
- }
-
- @override
- Token get beginToken => operator;
-
- /**
- * Return the best element available for this operator. If resolution was able
- * to find a better element based on type propagation, that element will be
- * returned. Otherwise, the element found using the result of static analysis
- * will be returned. If resolution has not been performed, then `null` will be
- * returned.
- */
- MethodElement get bestElement {
- MethodElement element = propagatedElement;
- if (element == null) {
- element = staticElement;
- }
- return element;
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(operator)..add(_operand);
-
- @override
- Token get endToken => _operand.endToken;
-
- /**
- * Return the expression computing the operand for the operator.
- */
- Expression get operand => _operand;
-
- /**
- * Set the expression computing the operand for the operator to the given
- * [expression].
- */
- void set operand(Expression expression) {
- _operand = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 14;
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on propagated type information, then return the parameter
- * element representing the parameter to which the value of the operand will
- * be bound. Otherwise, return `null`.
- */
- ParameterElement get _propagatedParameterElementForOperand {
- if (propagatedElement == null) {
- return null;
- }
- List<ParameterElement> parameters = propagatedElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- /**
- * If the AST structure has been resolved, and the function being invoked is
- * known based on static type information, then return the parameter element
- * representing the parameter to which the value of the operand will be bound.
- * Otherwise, return `null`.
- */
- ParameterElement get _staticParameterElementForOperand {
- if (staticElement == null) {
- return null;
- }
- List<ParameterElement> parameters = staticElement.parameters;
- if (parameters.length < 1) {
- return null;
- }
- return parameters[0];
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitPrefixExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_operand, visitor);
- }
-}
-
-/**
- * The access of a property of an object.
- *
- * Note, however, that accesses to properties of objects can also be represented
- * as [PrefixedIdentifier] nodes in cases where the target is also a simple
- * identifier.
- *
- * > propertyAccess ::=
- * > [Expression] '.' [SimpleIdentifier]
- */
-class PropertyAccess extends Expression {
- /**
- * The expression computing the object defining the property being accessed.
- */
- Expression _target;
-
- /**
- * The property access operator.
- */
- Token operator;
-
- /**
- * The name of the property being accessed.
- */
- SimpleIdentifier _propertyName;
-
- /**
- * Initialize a newly created property access expression.
- */
- PropertyAccess(
- Expression target, this.operator, SimpleIdentifier propertyName) {
- _target = _becomeParentOf(target);
- _propertyName = _becomeParentOf(propertyName);
- }
-
- @override
- Token get beginToken {
- if (_target != null) {
- return _target.beginToken;
- }
- return operator;
- }
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_target)..add(operator)..add(_propertyName);
-
- @override
- Token get endToken => _propertyName.endToken;
-
- @override
- bool get isAssignable => true;
-
- /**
- * Return `true` if this expression is cascaded. If it is, then the target of
- * this expression is not stored locally but is stored in the nearest ancestor
- * that is a [CascadeExpression].
- */
- bool get isCascaded =>
- operator != null && operator.type == TokenType.PERIOD_PERIOD;
-
- @override
- int get precedence => 15;
-
- /**
- * Return the name of the property being accessed.
- */
- SimpleIdentifier get propertyName => _propertyName;
-
- /**
- * Set the name of the property being accessed to the given [identifier].
- */
- void set propertyName(SimpleIdentifier identifier) {
- _propertyName = _becomeParentOf(identifier);
- }
-
- /**
- * Return the expression used to compute the receiver of the invocation. If
- * this invocation is not part of a cascade expression, then this is the same
- * as [target]. If this invocation is part of a cascade expression, then the
- * target stored with the cascade expression is returned.
- */
- Expression get realTarget {
- if (isCascaded) {
- AstNode ancestor = parent;
- while (ancestor is! CascadeExpression) {
- if (ancestor == null) {
- return _target;
- }
- ancestor = ancestor.parent;
- }
- return (ancestor as CascadeExpression).target;
- }
- return _target;
- }
-
- /**
- * Return the expression computing the object defining the property being
- * accessed, or `null` if this property access is part of a cascade expression.
- *
- * Use [realTarget] to get the target independent of whether this is part of a
- * cascade expression.
- */
- Expression get target => _target;
-
- /**
- * Set the expression computing the object defining the property being
- * accessed to the given [expression].
- */
- void set target(Expression expression) {
- _target = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitPropertyAccess(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_target, visitor);
- _safelyVisitChild(_propertyName, visitor);
- }
-}
-
-/**
- * The invocation of a constructor in the same class from within a constructor's
- * initialization list.
- *
- * > redirectingConstructorInvocation ::=
- * > 'this' ('.' identifier)? arguments
- */
-class RedirectingConstructorInvocation extends ConstructorInitializer {
- /**
- * The token for the 'this' keyword.
- */
- Token thisKeyword;
-
- /**
- * The token for the period before the name of the constructor that is being
- * invoked, or `null` if the unnamed constructor is being invoked.
- */
- Token period;
-
- /**
- * The name of the constructor that is being invoked, or `null` if the unnamed
- * constructor is being invoked.
- */
- SimpleIdentifier _constructorName;
-
- /**
- * The list of arguments to the constructor.
- */
- ArgumentList _argumentList;
-
- /**
- * The element associated with the constructor based on static type
- * information, or `null` if the AST structure has not been resolved or if the
- * constructor could not be resolved.
- */
- ConstructorElement staticElement;
-
- /**
- * Initialize a newly created redirecting invocation to invoke the constructor
- * with the given name with the given arguments. The [constructorName] can be
- * `null` if the constructor being invoked is the unnamed constructor.
- */
- RedirectingConstructorInvocation(this.thisKeyword, this.period,
- SimpleIdentifier constructorName, ArgumentList argumentList) {
- _constructorName = _becomeParentOf(constructorName);
- _argumentList = _becomeParentOf(argumentList);
- }
-
- /**
- * Return the list of arguments to the constructor.
- */
- ArgumentList get argumentList => _argumentList;
-
- /**
- * Set the list of arguments to the constructor to the given [argumentList].
- */
- void set argumentList(ArgumentList argumentList) {
- _argumentList = _becomeParentOf(argumentList);
- }
-
- @override
- Token get beginToken => thisKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(thisKeyword)
- ..add(period)
- ..add(_constructorName)
- ..add(_argumentList);
-
- /**
- * Return the name of the constructor that is being invoked, or `null` if the
- * unnamed constructor is being invoked.
- */
- SimpleIdentifier get constructorName => _constructorName;
-
- /**
- * Set the name of the constructor that is being invoked to the given
- * [identifier].
- */
- void set constructorName(SimpleIdentifier identifier) {
- _constructorName = _becomeParentOf(identifier);
- }
-
- @override
- Token get endToken => _argumentList.endToken;
-
- @override
- accept(AstVisitor visitor) =>
- visitor.visitRedirectingConstructorInvocation(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_constructorName, visitor);
- _safelyVisitChild(_argumentList, visitor);
- }
-}
-
-/**
- * A rethrow expression.
- *
- * > rethrowExpression ::=
- * > 'rethrow'
- */
-class RethrowExpression extends Expression {
- /**
- * The token representing the 'rethrow' keyword.
- */
- Token rethrowKeyword;
-
- /**
- * Initialize a newly created rethrow expression.
- */
- RethrowExpression(this.rethrowKeyword);
-
- @override
- Token get beginToken => rethrowKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(rethrowKeyword);
-
- @override
- Token get endToken => rethrowKeyword;
-
- @override
- int get precedence => 0;
-
- @override
- accept(AstVisitor visitor) => visitor.visitRethrowExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A return statement.
- *
- * > returnStatement ::=
- * > 'return' [Expression]? ';'
- */
-class ReturnStatement extends Statement {
- /**
- * The token representing the 'return' keyword.
- */
- Token returnKeyword;
-
- /**
- * The expression computing the value to be returned, or `null` if no explicit
- * value was provided.
- */
- Expression _expression;
-
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created return statement. The [expression] can be `null`
- * if no explicit value was provided.
- */
- ReturnStatement(this.returnKeyword, Expression expression, this.semicolon) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken => returnKeyword;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(returnKeyword)..add(_expression)..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- /**
- * Return the expression computing the value to be returned, or `null` if no
- * explicit value was provided.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression computing the value to be returned to the given
- * [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitReturnStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * A script tag that can optionally occur at the beginning of a compilation unit.
- *
- * > scriptTag ::=
- * > '#!' (~NEWLINE)* NEWLINE
- */
-class ScriptTag extends AstNode {
- /**
- * The token representing this script tag.
- */
- Token scriptTag;
-
- /**
- * Initialize a newly created script tag.
- */
- ScriptTag(this.scriptTag);
-
- @override
- Token get beginToken => scriptTag;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(scriptTag);
-
- @override
- Token get endToken => scriptTag;
-
- @override
- accept(AstVisitor visitor) => visitor.visitScriptTag(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A combinator that restricts the names being imported to those in a given list.
- *
- * > showCombinator ::=
- * > 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
- */
-class ShowCombinator extends Combinator {
- /**
- * The list of names from the library that are made visible by this combinator.
- */
- NodeList<SimpleIdentifier> _shownNames;
-
- /**
- * Initialize a newly created import show combinator.
- */
- ShowCombinator(Token keyword, List<SimpleIdentifier> shownNames)
- : super(keyword) {
- _shownNames = new NodeList<SimpleIdentifier>(this, shownNames);
- }
-
- @override
- // TODO(paulberry): add commas.
- Iterable get childEntities => new ChildEntities()
- ..add(keyword)
- ..addAll(_shownNames);
-
- @override
- Token get endToken => _shownNames.endToken;
-
- /**
- * Return the list of names from the library that are made visible by this
- * combinator.
- */
- NodeList<SimpleIdentifier> get shownNames => _shownNames;
-
- @override
- accept(AstVisitor visitor) => visitor.visitShowCombinator(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _shownNames.accept(visitor);
- }
-}
-
-/**
- * A simple formal parameter.
- *
- * > simpleFormalParameter ::=
- * > ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
- */
-class SimpleFormalParameter extends NormalFormalParameter {
- /**
- * The token representing either the 'final', 'const' or 'var' keyword, or
- * `null` if no keyword was used.
- */
- Token keyword;
-
- /**
- * The name of the declared type of the parameter, or `null` if the parameter
- * does not have a declared type.
- */
- TypeName _type;
-
- /**
- * Initialize a newly created formal parameter. Either or both of the
- * [comment] and [metadata] can be `null` if the parameter does not have the
- * corresponding attribute. The [keyword] can be `null` if a type was
- * specified. The [type] must be `null` if the keyword is 'var'.
- */
- SimpleFormalParameter(Comment comment, List<Annotation> metadata,
- this.keyword, TypeName type, SimpleIdentifier identifier)
- : super(comment, metadata, identifier) {
- _type = _becomeParentOf(type);
- }
-
- @override
- Token get beginToken {
- NodeList<Annotation> metadata = this.metadata;
- if (!metadata.isEmpty) {
- return metadata.beginToken;
- } else if (keyword != null) {
- return keyword;
- } else if (_type != null) {
- return _type.beginToken;
- }
- return identifier.beginToken;
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(keyword)..add(_type)..add(identifier);
-
- @override
- Token get endToken => identifier.endToken;
-
- @override
- bool get isConst =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
-
- @override
- bool get isFinal =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
-
- /**
- * Return the name of the declared type of the parameter, or `null` if the
- * parameter does not have a declared type.
- */
- TypeName get type => _type;
-
- /**
- * Set the name of the declared type of the parameter to the given [typeName].
- */
- void set type(TypeName typeName) {
- _type = _becomeParentOf(typeName);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitSimpleFormalParameter(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_type, visitor);
- _safelyVisitChild(identifier, visitor);
- }
-}
-
-/**
- * A simple identifier.
- *
- * > simpleIdentifier ::=
- * > initialCharacter internalCharacter*
- * >
- * > initialCharacter ::= '_' | '$' | letter
- * >
- * > internalCharacter ::= '_' | '$' | letter | digit
- */
-class SimpleIdentifier extends Identifier {
- /**
- * The token representing the identifier.
- */
- Token token;
-
- /**
- * The element associated with this identifier based on static type
- * information, or `null` if the AST structure has not been resolved or if
- * this identifier could not be resolved.
- */
- Element _staticElement;
-
- /**
- * The element associated with this identifier based on propagated type
- * information, or `null` if the AST structure has not been resolved or if
- * this identifier could not be resolved.
- */
- Element _propagatedElement;
-
- /**
- * If this expression is both in a getter and setter context, the
- * [AuxiliaryElements] will be set to hold onto the static and propagated
- * information. The auxiliary element will hold onto the elements from the
- * getter context.
- */
- AuxiliaryElements auxiliaryElements = null;
-
- /**
- * Initialize a newly created identifier.
- */
- SimpleIdentifier(this.token);
-
- @override
- Token get beginToken => token;
-
- @override
- Element get bestElement {
- if (_propagatedElement == null) {
- return _staticElement;
- }
- return _propagatedElement;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()..add(token);
-
- @override
- Token get endToken => token;
-
- /**
- * Return `true` if this identifier is the "name" part of a prefixed
- * identifier or a method invocation.
- */
- bool get isQualified {
- AstNode parent = this.parent;
- if (parent is PrefixedIdentifier) {
- return identical(parent.identifier, this);
- }
- if (parent is PropertyAccess) {
- return identical(parent.propertyName, this);
- }
- if (parent is MethodInvocation) {
- MethodInvocation invocation = parent;
- return identical(invocation.methodName, this) &&
- invocation.realTarget != null;
- }
- return false;
- }
-
- @override
- bool get isSynthetic => token.isSynthetic;
-
- @override
- String get name => token.lexeme;
-
- @override
- int get precedence => 16;
-
- @override
- Element get propagatedElement => _propagatedElement;
-
- /**
- * Set the element associated with this identifier based on propagated type
- * information to the given [element].
- */
- void set propagatedElement(Element element) {
- _propagatedElement = _validateElement(element);
- }
-
- @override
- Element get staticElement => _staticElement;
-
- /**
- * Set the element associated with this identifier based on static type
- * information to the given [element].
- */
- void set staticElement(Element element) {
- _staticElement = _validateElement(element);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitSimpleIdentifier(this);
-
- /**
- * Return `true` if this identifier is the name being declared in a
- * declaration.
- */
- bool inDeclarationContext() {
- // TODO(brianwilkerson) Convert this to a getter.
- AstNode parent = this.parent;
- if (parent is CatchClause) {
- CatchClause clause = parent;
- return identical(this, clause.exceptionParameter) ||
- identical(this, clause.stackTraceParameter);
- } else if (parent is ClassDeclaration) {
- return identical(this, parent.name);
- } else if (parent is ClassTypeAlias) {
- return identical(this, parent.name);
- } else if (parent is ConstructorDeclaration) {
- return identical(this, parent.name);
- } else if (parent is DeclaredIdentifier) {
- return identical(this, parent.identifier);
- } else if (parent is EnumDeclaration) {
- return identical(this, parent.name);
- } else if (parent is EnumConstantDeclaration) {
- return identical(this, parent.name);
- } else if (parent is FunctionDeclaration) {
- return identical(this, parent.name);
- } else if (parent is FunctionTypeAlias) {
- return identical(this, parent.name);
- } else if (parent is ImportDirective) {
- return identical(this, parent.prefix);
- } else if (parent is Label) {
- return identical(this, parent.label) &&
- (parent.parent is LabeledStatement);
- } else if (parent is MethodDeclaration) {
- return identical(this, parent.name);
- } else if (parent is FunctionTypedFormalParameter ||
- parent is SimpleFormalParameter) {
- return identical(this, (parent as NormalFormalParameter).identifier);
- } else if (parent is TypeParameter) {
- return identical(this, parent.name);
- } else if (parent is VariableDeclaration) {
- return identical(this, parent.name);
- }
- return false;
- }
-
- /**
- * Return `true` if this expression is computing a right-hand value.
- *
- * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
- * are they mutually exclusive. In other words, it is possible for both
- * methods to return `true` when invoked on the same node.
- */
- bool inGetterContext() {
- // TODO(brianwilkerson) Convert this to a getter.
- AstNode parent = this.parent;
- AstNode target = this;
- // skip prefix
- if (parent is PrefixedIdentifier) {
- PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
- if (identical(prefixed.prefix, this)) {
- return true;
- }
- parent = prefixed.parent;
- target = prefixed;
- } else if (parent is PropertyAccess) {
- PropertyAccess access = parent as PropertyAccess;
- if (identical(access.target, this)) {
- return true;
- }
- parent = access.parent;
- target = access;
- }
- // skip label
- if (parent is Label) {
- return false;
- }
- // analyze usage
- if (parent is AssignmentExpression) {
- if (identical(parent.leftHandSide, target) &&
- parent.operator.type == TokenType.EQ) {
- return false;
- }
- }
- if (parent is ForEachStatement) {
- if (identical(parent.identifier, target)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return `true` if this expression is computing a left-hand value.
- *
- * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
- * are they mutually exclusive. In other words, it is possible for both
- * methods to return `true` when invoked on the same node.
- */
- bool inSetterContext() {
- // TODO(brianwilkerson) Convert this to a getter.
- AstNode parent = this.parent;
- AstNode target = this;
- // skip prefix
- if (parent is PrefixedIdentifier) {
- PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
- // if this is the prefix, then return false
- if (identical(prefixed.prefix, this)) {
- return false;
- }
- parent = prefixed.parent;
- target = prefixed;
- } else if (parent is PropertyAccess) {
- PropertyAccess access = parent as PropertyAccess;
- if (identical(access.target, this)) {
- return false;
- }
- parent = access.parent;
- target = access;
- }
- // analyze usage
- if (parent is PrefixExpression) {
- return parent.operator.type.isIncrementOperator;
- } else if (parent is PostfixExpression) {
- return true;
- } else if (parent is AssignmentExpression) {
- return identical(parent.leftHandSide, target);
- } else if (parent is ForEachStatement) {
- return identical(parent.identifier, target);
- }
- return false;
- }
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-
- /**
- * Return the given element if it is valid, or report the problem and return
- * `null` if it is not appropriate.
- *
- * The [parent] is the parent of the element, used for reporting when there is
- * a problem.
- * The [isValid] is `true` if the element is appropriate.
- * The [element] is the element to be associated with this identifier.
- */
- Element _returnOrReportElement(
- AstNode parent, bool isValid, Element element) {
- if (!isValid) {
- AnalysisEngine.instance.logger.logInformation(
- "Internal error: attempting to set the name of a ${parent.runtimeType} to a ${element.runtimeType}",
- new CaughtException(new AnalysisException(), null));
- return null;
- }
- return element;
- }
-
- /**
- * Return the given [element] if it is an appropriate element based on the
- * parent of this identifier, or `null` if it is not appropriate.
- */
- Element _validateElement(Element element) {
- if (element == null) {
- return null;
- }
- AstNode parent = this.parent;
- if (parent is ClassDeclaration && identical(parent.name, this)) {
- return _returnOrReportElement(parent, element is ClassElement, element);
- } else if (parent is ClassTypeAlias && identical(parent.name, this)) {
- return _returnOrReportElement(parent, element is ClassElement, element);
- } else if (parent is DeclaredIdentifier &&
- identical(parent.identifier, this)) {
- return _returnOrReportElement(
- parent, element is LocalVariableElement, element);
- } else if (parent is FormalParameter &&
- identical(parent.identifier, this)) {
- return _returnOrReportElement(
- parent, element is ParameterElement, element);
- } else if (parent is FunctionDeclaration && identical(parent.name, this)) {
- return _returnOrReportElement(
- parent, element is ExecutableElement, element);
- } else if (parent is FunctionTypeAlias && identical(parent.name, this)) {
- return _returnOrReportElement(
- parent, element is FunctionTypeAliasElement, element);
- } else if (parent is MethodDeclaration && identical(parent.name, this)) {
- return _returnOrReportElement(
- parent, element is ExecutableElement, element);
- } else if (parent is TypeParameter && identical(parent.name, this)) {
- return _returnOrReportElement(
- parent, element is TypeParameterElement, element);
- } else if (parent is VariableDeclaration && identical(parent.name, this)) {
- return _returnOrReportElement(
- parent, element is VariableElement, element);
- }
- return element;
- }
-}
-
-/**
- * A string literal expression that does not contain any interpolations.
- *
- * > simpleStringLiteral ::=
- * > rawStringLiteral
- * > | basicStringLiteral
- * >
- * > rawStringLiteral ::=
- * > 'r' basicStringLiteral
- * >
- * > simpleStringLiteral ::=
- * > multiLineStringLiteral
- * > | singleLineStringLiteral
- * >
- * > multiLineStringLiteral ::=
- * > "'''" characters "'''"
- * > | '"""' characters '"""'
- * >
- * > singleLineStringLiteral ::=
- * > "'" characters "'"
- * > | '"' characters '"'
- */
-class SimpleStringLiteral extends SingleStringLiteral {
- /**
- * The token representing the literal.
- */
- Token literal;
-
- /**
- * The value of the literal.
- */
- String _value;
-
- /**
- * Initialize a newly created simple string literal.
- */
- SimpleStringLiteral(this.literal, String value) {
- _value = StringUtilities.intern(value);
- }
-
- @override
- Token get beginToken => literal;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(literal);
-
- @override
- int get contentsEnd => offset + _helper.end;
-
- @override
- int get contentsOffset => offset + _helper.start;
-
- @override
- Token get endToken => literal;
-
- @override
- bool get isMultiline => _helper.isMultiline;
-
- @override
- bool get isRaw => _helper.isRaw;
-
- @override
- bool get isSingleQuoted => _helper.isSingleQuoted;
-
- @override
- bool get isSynthetic => literal.isSynthetic;
-
- /**
- * Return the value of the literal.
- */
- String get value => _value;
-
- /**
- * Set the value of the literal to the given [string].
- */
- void set value(String string) {
- _value = StringUtilities.intern(_value);
- }
-
- StringLexemeHelper get _helper {
- return new StringLexemeHelper(literal.lexeme, true, true);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitSimpleStringLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-
- @override
- void _appendStringValue(StringBuffer buffer) {
- buffer.write(value);
- }
-}
-
-/**
- * A single string literal expression.
- *
- * > singleStringLiteral ::=
- * > [SimpleStringLiteral]
- * > | [StringInterpolation]
- */
-abstract class SingleStringLiteral extends StringLiteral {
- /**
- * Return the offset of the after-last contents character.
- */
- int get contentsEnd;
-
- /**
- * Return the offset of the first contents character.
- * If the string is multiline, then leading whitespaces are skipped.
- */
- int get contentsOffset;
-
- /**
- * Return `true` if this string literal is a multi-line string.
- */
- bool get isMultiline;
-
- /**
- * Return `true` if this string literal is a raw string.
- */
- bool get isRaw;
-
- /**
- * Return `true` if this string literal uses single quotes (' or ''').
- * Return `false` if this string literal uses double quotes (" or """).
- */
- bool get isSingleQuoted;
-}
-
-/**
- * A node that represents a statement.
- *
- * > statement ::=
- * > [Block]
- * > | [VariableDeclarationStatement]
- * > | [ForStatement]
- * > | [ForEachStatement]
- * > | [WhileStatement]
- * > | [DoStatement]
- * > | [SwitchStatement]
- * > | [IfStatement]
- * > | [TryStatement]
- * > | [BreakStatement]
- * > | [ContinueStatement]
- * > | [ReturnStatement]
- * > | [ExpressionStatement]
- * > | [FunctionDeclarationStatement]
- */
-abstract class Statement extends AstNode {
- /**
- * If this is a labeled statement, return the unlabeled portion of the
- * statement. Otherwise return the statement itself.
- */
- Statement get unlabeled => this;
-}
-
-/**
- * A string interpolation literal.
- *
- * > stringInterpolation ::=
- * > ''' [InterpolationElement]* '''
- * > | '"' [InterpolationElement]* '"'
- */
-class StringInterpolation extends SingleStringLiteral {
- /**
- * The elements that will be composed to produce the resulting string.
- */
- NodeList<InterpolationElement> _elements;
-
- /**
- * Initialize a newly created string interpolation expression.
- */
- StringInterpolation(List<InterpolationElement> elements) {
- _elements = new NodeList<InterpolationElement>(this, elements);
- }
-
- @override
- Token get beginToken => _elements.beginToken;
-
- @override
- Iterable get childEntities => new ChildEntities()..addAll(_elements);
-
- @override
- int get contentsEnd {
- InterpolationString element = _elements.last;
- return element.contentsEnd;
- }
-
- @override
- int get contentsOffset {
- InterpolationString element = _elements.first;
- return element.contentsOffset;
- }
-
- /**
- * Return the elements that will be composed to produce the resulting string.
- */
- NodeList<InterpolationElement> get elements => _elements;
-
- @override
- Token get endToken => _elements.endToken;
-
- @override
- bool get isMultiline => _firstHelper.isMultiline;
-
- @override
- bool get isRaw => false;
-
- @override
- bool get isSingleQuoted => _firstHelper.isSingleQuoted;
-
- StringLexemeHelper get _firstHelper {
- InterpolationString lastString = _elements.first;
- String lexeme = lastString.contents.lexeme;
- return new StringLexemeHelper(lexeme, true, false);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitStringInterpolation(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _elements.accept(visitor);
- }
-
- @override
- void _appendStringValue(StringBuffer buffer) {
- throw new IllegalArgumentException();
- }
-}
-
-/**
- * A helper for analyzing string lexemes.
- */
-class StringLexemeHelper {
- final String lexeme;
- final bool isFirst;
- final bool isLast;
-
- bool isRaw = false;
- bool isSingleQuoted = false;
- bool isMultiline = false;
- int start = 0;
- int end;
-
- StringLexemeHelper(this.lexeme, this.isFirst, this.isLast) {
- if (isFirst) {
- isRaw = StringUtilities.startsWithChar(lexeme, 0x72);
- if (isRaw) {
- start++;
- }
- if (StringUtilities.startsWith3(lexeme, start, 0x27, 0x27, 0x27)) {
- isSingleQuoted = true;
- isMultiline = true;
- start += 3;
- start = _trimInitialWhitespace(start);
- } else if (StringUtilities.startsWith3(lexeme, start, 0x22, 0x22, 0x22)) {
- isSingleQuoted = false;
- isMultiline = true;
- start += 3;
- start = _trimInitialWhitespace(start);
- } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x27) {
- isSingleQuoted = true;
- isMultiline = false;
- start++;
- } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x22) {
- isSingleQuoted = false;
- isMultiline = false;
- start++;
- }
- }
- end = lexeme.length;
- if (isLast) {
- if (start + 3 <= end &&
- (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
- StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27))) {
- end -= 3;
- } else if (start + 1 <= end &&
- (StringUtilities.endsWithChar(lexeme, 0x22) ||
- StringUtilities.endsWithChar(lexeme, 0x27))) {
- end -= 1;
- }
- }
- }
-
- /**
- * Given the [lexeme] for a multi-line string whose content begins at the
- * given [start] index, return the index of the first character that is
- * included in the value of the string. According to the specification:
- *
- * If the first line of a multiline string consists solely of the whitespace
- * characters defined by the production WHITESPACE 20.1), possibly prefixed
- * by \, then that line is ignored, including the new line at its end.
- */
- int _trimInitialWhitespace(int start) {
- int length = lexeme.length;
- int index = start;
- while (index < length) {
- int currentChar = lexeme.codeUnitAt(index);
- if (currentChar == 0x0D) {
- if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) {
- return index + 2;
- }
- return index + 1;
- } else if (currentChar == 0x0A) {
- return index + 1;
- } else if (currentChar == 0x5C) {
- if (index + 1 >= length) {
- return start;
- }
- currentChar = lexeme.codeUnitAt(index + 1);
- if (currentChar != 0x0D &&
- currentChar != 0x0A &&
- currentChar != 0x09 &&
- currentChar != 0x20) {
- return start;
- }
- } else if (currentChar != 0x09 && currentChar != 0x20) {
- return start;
- }
- index++;
- }
- return start;
- }
-}
-
-/**
- * A string literal expression.
- *
- * > stringLiteral ::=
- * > [SimpleStringLiteral]
- * > | [AdjacentStrings]
- * > | [StringInterpolation]
- */
-abstract class StringLiteral extends Literal {
- /**
- * Return the value of the string literal, or `null` if the string is not a
- * constant string without any string interpolation.
- */
- String get stringValue {
- StringBuffer buffer = new StringBuffer();
- try {
- _appendStringValue(buffer);
- } on IllegalArgumentException {
- return null;
- }
- return buffer.toString();
- }
-
- /**
- * Append the value of this string literal to the given [buffer]. Throw an
- * [IllegalArgumentException] if the string is not a constant string without
- * any string interpolation.
- */
- void _appendStringValue(StringBuffer buffer);
-}
-
-/**
- * The invocation of a superclass' constructor from within a constructor's
- * initialization list.
- *
- * > superInvocation ::=
- * > 'super' ('.' [SimpleIdentifier])? [ArgumentList]
- */
-class SuperConstructorInvocation extends ConstructorInitializer {
- /**
- * The token for the 'super' keyword.
- */
- Token superKeyword;
-
- /**
- * The token for the period before the name of the constructor that is being
- * invoked, or `null` if the unnamed constructor is being invoked.
- */
- Token period;
-
- /**
- * The name of the constructor that is being invoked, or `null` if the unnamed
- * constructor is being invoked.
- */
- SimpleIdentifier _constructorName;
-
- /**
- * The list of arguments to the constructor.
- */
- ArgumentList _argumentList;
-
- /**
- * The element associated with the constructor based on static type
- * information, or `null` if the AST structure has not been resolved or if the
- * constructor could not be resolved.
- */
- ConstructorElement staticElement;
-
- /**
- * Initialize a newly created super invocation to invoke the inherited
- * constructor with the given name with the given arguments. The [period] and
- * [constructorName] can be `null` if the constructor being invoked is the
- * unnamed constructor.
- */
- SuperConstructorInvocation(this.superKeyword, this.period,
- SimpleIdentifier constructorName, ArgumentList argumentList) {
- _constructorName = _becomeParentOf(constructorName);
- _argumentList = _becomeParentOf(argumentList);
- }
-
- /**
- * Return the list of arguments to the constructor.
- */
- ArgumentList get argumentList => _argumentList;
-
- /**
- * Set the list of arguments to the constructor to the given [argumentList].
- */
- void set argumentList(ArgumentList argumentList) {
- _argumentList = _becomeParentOf(argumentList);
- }
-
- @override
- Token get beginToken => superKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(superKeyword)
- ..add(period)
- ..add(_constructorName)
- ..add(_argumentList);
-
- /**
- * Return the name of the constructor that is being invoked, or `null` if the
- * unnamed constructor is being invoked.
- */
- SimpleIdentifier get constructorName => _constructorName;
-
- /**
- * Set the name of the constructor that is being invoked to the given
- * [identifier].
- */
- void set constructorName(SimpleIdentifier identifier) {
- _constructorName = _becomeParentOf(identifier);
- }
-
- @override
- Token get endToken => _argumentList.endToken;
-
- @override
- accept(AstVisitor visitor) => visitor.visitSuperConstructorInvocation(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_constructorName, visitor);
- _safelyVisitChild(_argumentList, visitor);
- }
-}
-
-/**
- * A super expression.
- *
- * > superExpression ::=
- * > 'super'
- */
-class SuperExpression extends Expression {
- /**
- * The token representing the 'super' keyword.
- */
- Token superKeyword;
-
- /**
- * Initialize a newly created super expression.
- */
- SuperExpression(this.superKeyword);
-
- @override
- Token get beginToken => superKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(superKeyword);
-
- @override
- Token get endToken => superKeyword;
-
- @override
- int get precedence => 16;
-
- @override
- accept(AstVisitor visitor) => visitor.visitSuperExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A case in a switch statement.
- *
- * > switchCase ::=
- * > [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
- */
-class SwitchCase extends SwitchMember {
- /**
- * The expression controlling whether the statements will be executed.
- */
- Expression _expression;
-
- /**
- * Initialize a newly created switch case. The list of [labels] can be `null`
- * if there are no labels.
- */
- SwitchCase(List<Label> labels, Token keyword, Expression expression,
- Token colon, List<Statement> statements)
- : super(labels, keyword, colon, statements) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..addAll(labels)
- ..add(keyword)
- ..add(_expression)
- ..add(colon)
- ..addAll(statements);
-
- /**
- * Return the expression controlling whether the statements will be executed.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression controlling whether the statements will be executed to
- * the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitSwitchCase(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- labels.accept(visitor);
- _safelyVisitChild(_expression, visitor);
- statements.accept(visitor);
- }
-}
-
-/**
- * The default case in a switch statement.
- *
- * > switchDefault ::=
- * > [SimpleIdentifier]* 'default' ':' [Statement]*
- */
-class SwitchDefault extends SwitchMember {
- /**
- * Initialize a newly created switch default. The list of [labels] can be
- * `null` if there are no labels.
- */
- SwitchDefault(List<Label> labels, Token keyword, Token colon,
- List<Statement> statements)
- : super(labels, keyword, colon, statements);
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..addAll(labels)
- ..add(keyword)
- ..add(colon)
- ..addAll(statements);
-
- @override
- accept(AstVisitor visitor) => visitor.visitSwitchDefault(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- labels.accept(visitor);
- statements.accept(visitor);
- }
-}
-
-/**
- * An element within a switch statement.
- *
- * > switchMember ::=
- * > switchCase
- * > | switchDefault
- */
-abstract class SwitchMember extends AstNode {
- /**
- * The labels associated with the switch member.
- */
- NodeList<Label> _labels;
-
- /**
- * The token representing the 'case' or 'default' keyword.
- */
- Token keyword;
-
- /**
- * The colon separating the keyword or the expression from the statements.
- */
- Token colon;
-
- /**
- * The statements that will be executed if this switch member is selected.
- */
- NodeList<Statement> _statements;
-
- /**
- * Initialize a newly created switch member. The list of [labels] can be
- * `null` if there are no labels.
- */
- SwitchMember(List<Label> labels, this.keyword, this.colon,
- List<Statement> statements) {
- _labels = new NodeList<Label>(this, labels);
- _statements = new NodeList<Statement>(this, statements);
- }
-
- @override
- Token get beginToken {
- if (!_labels.isEmpty) {
- return _labels.beginToken;
- }
- return keyword;
- }
-
- @override
- Token get endToken {
- if (!_statements.isEmpty) {
- return _statements.endToken;
- }
- return colon;
- }
-
- /**
- * Return the labels associated with the switch member.
- */
- NodeList<Label> get labels => _labels;
-
- /**
- * Return the statements that will be executed if this switch member is
- * selected.
- */
- NodeList<Statement> get statements => _statements;
-}
-
-/**
- * A switch statement.
- *
- * > switchStatement ::=
- * > 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
- */
-class SwitchStatement extends Statement {
- /**
- * The token representing the 'switch' keyword.
- */
- Token switchKeyword;
-
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The expression used to determine which of the switch members will be
- * selected.
- */
- Expression _expression;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * The left curly bracket.
- */
- Token leftBracket;
-
- /**
- * The switch members that can be selected by the expression.
- */
- NodeList<SwitchMember> _members;
-
- /**
- * The right curly bracket.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created switch statement. The list of [members] can be
- * `null` if there are no switch members.
- */
- SwitchStatement(
- this.switchKeyword,
- this.leftParenthesis,
- Expression expression,
- this.rightParenthesis,
- this.leftBracket,
- List<SwitchMember> members,
- this.rightBracket) {
- _expression = _becomeParentOf(expression);
- _members = new NodeList<SwitchMember>(this, members);
- }
-
- @override
- Token get beginToken => switchKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(switchKeyword)
- ..add(leftParenthesis)
- ..add(_expression)
- ..add(rightParenthesis)
- ..add(leftBracket)
- ..addAll(_members)
- ..add(rightBracket);
-
- @override
- Token get endToken => rightBracket;
-
- /**
- * Return the expression used to determine which of the switch members will be
- * selected.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression used to determine which of the switch members will be
- * selected to the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- /**
- * Return the switch members that can be selected by the expression.
- */
- NodeList<SwitchMember> get members => _members;
-
- @override
- accept(AstVisitor visitor) => visitor.visitSwitchStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- _members.accept(visitor);
- }
-}
-
-/**
- * A symbol literal expression.
- *
- * > symbolLiteral ::=
- * > '#' (operator | (identifier ('.' identifier)*))
- */
-class SymbolLiteral extends Literal {
- /**
- * The token introducing the literal.
- */
- Token poundSign;
-
- /**
- * The components of the literal.
- */
- final List<Token> components;
-
- /**
- * Initialize a newly created symbol literal.
- */
- SymbolLiteral(this.poundSign, this.components);
-
- @override
- Token get beginToken => poundSign;
-
- @override
- // TODO(paulberry): add "." tokens.
- Iterable get childEntities => new ChildEntities()
- ..add(poundSign)
- ..addAll(components);
-
- @override
- Token get endToken => components[components.length - 1];
-
- @override
- accept(AstVisitor visitor) => visitor.visitSymbolLiteral(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A this expression.
- *
- * > thisExpression ::=
- * > 'this'
- */
-class ThisExpression extends Expression {
- /**
- * The token representing the 'this' keyword.
- */
- Token thisKeyword;
-
- /**
- * Initialize a newly created this expression.
- */
- ThisExpression(this.thisKeyword);
-
- @override
- Token get beginToken => thisKeyword;
-
- @override
- Iterable get childEntities => new ChildEntities()..add(thisKeyword);
-
- @override
- Token get endToken => thisKeyword;
-
- @override
- int get precedence => 16;
-
- @override
- accept(AstVisitor visitor) => visitor.visitThisExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- // There are no children to visit.
- }
-}
-
-/**
- * A throw expression.
- *
- * > throwExpression ::=
- * > 'throw' [Expression]
- */
-class ThrowExpression extends Expression {
- /**
- * The token representing the 'throw' keyword.
- */
- Token throwKeyword;
-
- /**
- * The expression computing the exception to be thrown.
- */
- Expression _expression;
-
- /**
- * Initialize a newly created throw expression.
- */
- ThrowExpression(this.throwKeyword, Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken => throwKeyword;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(throwKeyword)..add(_expression);
-
- @override
- Token get endToken {
- if (_expression != null) {
- return _expression.endToken;
- }
- return throwKeyword;
- }
-
- /**
- * Return the expression computing the exception to be thrown.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression computing the exception to be thrown to the given
- * [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- int get precedence => 0;
-
- @override
- accept(AstVisitor visitor) => visitor.visitThrowExpression(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
-
-/**
- * The declaration of one or more top-level variables of the same type.
- *
- * > topLevelVariableDeclaration ::=
- * > ('final' | 'const') type? staticFinalDeclarationList ';'
- * > | variableDeclaration ';'
- */
-class TopLevelVariableDeclaration extends CompilationUnitMember {
- /**
- * The top-level variables being declared.
- */
- VariableDeclarationList _variableList;
-
- /**
- * The semicolon terminating the declaration.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created top-level variable declaration. Either or both
- * of the [comment] and [metadata] can be `null` if the variable does not have
- * the corresponding attribute.
- */
- TopLevelVariableDeclaration(Comment comment, List<Annotation> metadata,
- VariableDeclarationList variableList, this.semicolon)
- : super(comment, metadata) {
- _variableList = _becomeParentOf(variableList);
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(_variableList)..add(semicolon);
-
- @override
- Element get element => null;
-
- @override
- Token get endToken => semicolon;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => _variableList.beginToken;
-
- /**
- * Return the top-level variables being declared.
- */
- VariableDeclarationList get variables => _variableList;
-
- /**
- * Set the top-level variables being declared to the given list of
- * [variables].
- */
- void set variables(VariableDeclarationList variables) {
- _variableList = _becomeParentOf(variables);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitTopLevelVariableDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_variableList, visitor);
- }
-}
-
-/**
- * A try statement.
- *
- * > tryStatement ::=
- * > 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
- * >
- * > finallyClause ::=
- * > 'finally' [Block]
- */
-class TryStatement extends Statement {
- /**
- * The token representing the 'try' keyword.
- */
- Token tryKeyword;
-
- /**
- * The body of the statement.
- */
- Block _body;
-
- /**
- * The catch clauses contained in the try statement.
- */
- NodeList<CatchClause> _catchClauses;
-
- /**
- * The token representing the 'finally' keyword, or `null` if the statement
- * does not contain a finally clause.
- */
- Token finallyKeyword;
-
- /**
- * The finally block contained in the try statement, or `null` if the
- * statement does not contain a finally clause.
- */
- Block _finallyBlock;
-
- /**
- * Initialize a newly created try statement. The list of [catchClauses] can be
- * `null` if there are no catch clauses. The [finallyKeyword] and
- * [finallyBlock] can be `null` if there is no finally clause.
- */
- TryStatement(this.tryKeyword, Block body, List<CatchClause> catchClauses,
- this.finallyKeyword, Block finallyBlock) {
- _body = _becomeParentOf(body);
- _catchClauses = new NodeList<CatchClause>(this, catchClauses);
- _finallyBlock = _becomeParentOf(finallyBlock);
- }
-
- @override
- Token get beginToken => tryKeyword;
-
- /**
- * Return the body of the statement.
- */
- Block get body => _body;
-
- /**
- * Set the body of the statement to the given [block].
- */
- void set body(Block block) {
- _body = _becomeParentOf(block);
- }
-
- /**
- * Return the catch clauses contained in the try statement.
- */
- NodeList<CatchClause> get catchClauses => _catchClauses;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(tryKeyword)
- ..add(_body)
- ..addAll(_catchClauses)
- ..add(finallyKeyword)
- ..add(_finallyBlock);
-
- @override
- Token get endToken {
- if (_finallyBlock != null) {
- return _finallyBlock.endToken;
- } else if (finallyKeyword != null) {
- return finallyKeyword;
- } else if (!_catchClauses.isEmpty) {
- return _catchClauses.endToken;
- }
- return _body.endToken;
- }
-
- /**
- * Return the finally block contained in the try statement, or `null` if the
- * statement does not contain a finally clause.
- */
- Block get finallyBlock => _finallyBlock;
-
- /**
- * Set the finally block contained in the try statement to the given [block].
- */
- void set finallyBlock(Block block) {
- _finallyBlock = _becomeParentOf(block);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitTryStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_body, visitor);
- _catchClauses.accept(visitor);
- _safelyVisitChild(_finallyBlock, visitor);
- }
-}
-
-/**
- * The declaration of a type alias.
- *
- * > typeAlias ::=
- * > 'typedef' typeAliasBody
- * >
- * > typeAliasBody ::=
- * > classTypeAlias
- * > | functionTypeAlias
- */
-abstract class TypeAlias extends NamedCompilationUnitMember {
- /**
- * The token representing the 'typedef' keyword.
- */
- Token typedefKeyword;
-
- /**
- * The semicolon terminating the declaration.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created type alias. Either or both of the [comment] and
- * [metadata] can be `null` if the declaration does not have the corresponding
- * attribute.
- */
- TypeAlias(Comment comment, List<Annotation> metadata, this.typedefKeyword,
- SimpleIdentifier name, this.semicolon)
- : super(comment, metadata, name);
-
- @override
- Token get endToken => semicolon;
-
- @override
- Token get firstTokenAfterCommentAndMetadata => typedefKeyword;
-}
-
-/**
- * A list of type arguments.
- *
- * > typeArguments ::=
- * > '<' typeName (',' typeName)* '>'
- */
-class TypeArgumentList extends AstNode {
- /**
- * The left bracket.
- */
- Token leftBracket;
-
- /**
- * The type arguments associated with the type.
- */
- NodeList<TypeName> _arguments;
-
- /**
- * The right bracket.
- */
- Token rightBracket;
-
- /**
- * Initialize a newly created list of type arguments.
- */
- TypeArgumentList(
- this.leftBracket, List<TypeName> arguments, this.rightBracket) {
- _arguments = new NodeList<TypeName>(this, arguments);
- }
-
- /**
- * Return the type arguments associated with the type.
- */
- NodeList<TypeName> get arguments => _arguments;
-
- @override
- Token get beginToken => leftBracket;
-
- @override
- // TODO(paulberry): Add commas.
- Iterable get childEntities => new ChildEntities()
- ..add(leftBracket)
- ..addAll(_arguments)
- ..add(rightBracket);
-
- @override
- Token get endToken => rightBracket;
-
- @override
- accept(AstVisitor visitor) => visitor.visitTypeArgumentList(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _arguments.accept(visitor);
- }
-}
-
-/**
- * A literal that has a type associated with it.
- *
- * > typedLiteral ::=
- * > [ListLiteral]
- * > | [MapLiteral]
- */
-abstract class TypedLiteral extends Literal {
- /**
- * The token representing the 'const' keyword, or `null` if the literal is not
- * a constant.
- */
- Token constKeyword;
-
- /**
- * The type argument associated with this literal, or `null` if no type
- * arguments were declared.
- */
- TypeArgumentList _typeArguments;
-
- /**
- * Initialize a newly created typed literal. The [constKeyword] can be `null`\
- * if the literal is not a constant. The [typeArguments] can be `null` if no
- * type arguments were declared.
- */
- TypedLiteral(this.constKeyword, TypeArgumentList typeArguments) {
- _typeArguments = _becomeParentOf(typeArguments);
- }
-
- /**
- * Return the type argument associated with this literal, or `null` if no type
- * arguments were declared.
- */
- TypeArgumentList get typeArguments => _typeArguments;
-
- /**
- * Set the type argument associated with this literal to the given
- * [typeArguments].
- */
- void set typeArguments(TypeArgumentList typeArguments) {
- _typeArguments = _becomeParentOf(typeArguments);
- }
-
- ChildEntities get _childEntities =>
- new ChildEntities()..add(constKeyword)..add(_typeArguments);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_typeArguments, visitor);
- }
-}
-
-/**
- * The name of a type, which can optionally include type arguments.
- *
- * > typeName ::=
- * > [Identifier] typeArguments?
- */
-class TypeName extends AstNode {
- /**
- * The name of the type.
- */
- Identifier _name;
-
- /**
- * The type arguments associated with the type, or `null` if there are no type
- * arguments.
- */
- TypeArgumentList _typeArguments;
-
- /**
- * The type being named, or `null` if the AST structure has not been resolved.
- */
- DartType type;
-
- /**
- * Initialize a newly created type name. The [typeArguments] can be `null` if
- * there are no type arguments.
- */
- TypeName(Identifier name, TypeArgumentList typeArguments) {
- _name = _becomeParentOf(name);
- _typeArguments = _becomeParentOf(typeArguments);
- }
-
- @override
- Token get beginToken => _name.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_name)..add(_typeArguments);
-
- @override
- Token get endToken {
- if (_typeArguments != null) {
- return _typeArguments.endToken;
- }
- return _name.endToken;
- }
-
- /**
- * Return `true` if this type is a deferred type.
- *
- * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
- * </i>p.T</i> where <i>p</i> is a deferred prefix.
- */
- bool get isDeferred {
- Identifier identifier = name;
- if (identifier is! PrefixedIdentifier) {
- return false;
- }
- return (identifier as PrefixedIdentifier).isDeferred;
- }
-
- @override
- bool get isSynthetic => _name.isSynthetic && _typeArguments == null;
-
- /**
- * Return the name of the type.
- */
- Identifier get name => _name;
-
- /**
- * Set the name of the type to the given [identifier].
- */
- void set name(Identifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- /**
- * Return the type arguments associated with the type, or `null` if there are
- * no type arguments.
- */
- TypeArgumentList get typeArguments => _typeArguments;
-
- /**
- * Set the type arguments associated with the type to the given
- * [typeArguments].
- */
- void set typeArguments(TypeArgumentList typeArguments) {
- _typeArguments = _becomeParentOf(typeArguments);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitTypeName(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_typeArguments, visitor);
- }
-}
-
-/**
- * A type parameter.
- *
- * > typeParameter ::=
- * > [SimpleIdentifier] ('extends' [TypeName])?
- */
-class TypeParameter extends Declaration {
- /**
- * The name of the type parameter.
- */
- SimpleIdentifier _name;
-
- /**
- * The token representing the 'extends' keyword, or `null` if there is no
- * explicit upper bound.
- */
- Token extendsKeyword;
-
- /**
- * The name of the upper bound for legal arguments, or `null` if there is no
- * explicit upper bound.
- */
- TypeName _bound;
-
- /**
- * Initialize a newly created type parameter. Either or both of the [comment]
- * and [metadata] can be `null` if the parameter does not have the
- * corresponding attribute. The [extendsKeyword] and [bound] can be `null` if
- * the parameter does not have an upper bound.
- */
- TypeParameter(Comment comment, List<Annotation> metadata,
- SimpleIdentifier name, this.extendsKeyword, TypeName bound)
- : super(comment, metadata) {
- _name = _becomeParentOf(name);
- _bound = _becomeParentOf(bound);
- }
-
- /**
- * Return the name of the upper bound for legal arguments, or `null` if there
- * is no explicit upper bound.
- */
- TypeName get bound => _bound;
-
- /**
- * Set the name of the upper bound for legal arguments to the given
- * [typeName].
- */
- void set bound(TypeName typeName) {
- _bound = _becomeParentOf(typeName);
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(_name)..add(extendsKeyword)..add(_bound);
-
- @override
- TypeParameterElement get element =>
- _name != null ? (_name.staticElement as TypeParameterElement) : null;
-
- @override
- Token get endToken {
- if (_bound == null) {
- return _name.endToken;
- }
- return _bound.endToken;
- }
-
- @override
- Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
-
- /**
- * Return the name of the type parameter.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the type parameter to the given [identifier].
- */
- void set name(SimpleIdentifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitTypeParameter(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_bound, visitor);
- }
-}
-
-/**
- * Type parameters within a declaration.
- *
- * > typeParameterList ::=
- * > '<' [TypeParameter] (',' [TypeParameter])* '>'
- */
-class TypeParameterList extends AstNode {
- /**
- * The left angle bracket.
- */
- final Token leftBracket;
-
- /**
- * The type parameters in the list.
- */
- NodeList<TypeParameter> _typeParameters;
-
- /**
- * The right angle bracket.
- */
- final Token rightBracket;
-
- /**
- * Initialize a newly created list of type parameters.
- */
- TypeParameterList(
- this.leftBracket, List<TypeParameter> typeParameters, this.rightBracket) {
- _typeParameters = new NodeList<TypeParameter>(this, typeParameters);
- }
-
- @override
- Token get beginToken => leftBracket;
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(leftBracket)
- ..addAll(_typeParameters)
- ..add(rightBracket);
-
- @override
- Token get endToken => rightBracket;
-
- /**
- * Return the type parameters for the type.
- */
- NodeList<TypeParameter> get typeParameters => _typeParameters;
-
- @override
- accept(AstVisitor visitor) => visitor.visitTypeParameterList(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _typeParameters.accept(visitor);
- }
-}
-
-/**
- * A directive that references a URI.
- *
- * > uriBasedDirective ::=
- * > [ExportDirective]
- * > | [ImportDirective]
- * > | [PartDirective]
- */
-abstract class UriBasedDirective extends Directive {
- /**
- * The prefix of a URI using the `dart-ext` scheme to reference a native code
- * library.
- */
- static String _DART_EXT_SCHEME = "dart-ext:";
-
- /**
- * The URI referenced by this directive.
- */
- StringLiteral _uri;
-
- /**
- * The content of the URI.
- */
- String uriContent;
-
- /**
- * The source to which the URI was resolved.
- */
- Source source;
-
- /**
- * Initialize a newly create URI-based directive. Either or both of the
- * [comment] and [metadata] can be `null` if the directive does not have the
- * corresponding attribute.
- */
- UriBasedDirective(
- Comment comment, List<Annotation> metadata, StringLiteral uri)
- : super(comment, metadata) {
- _uri = _becomeParentOf(uri);
- }
-
- /**
- * Return the URI referenced by this directive.
- */
- StringLiteral get uri => _uri;
-
- /**
- * Set the URI referenced by this directive to the given [uri].
- */
- void set uri(StringLiteral uri) {
- _uri = _becomeParentOf(uri);
- }
-
- /**
- * Return the element associated with the URI of this directive, or `null` if
- * the AST structure has not been resolved or if the URI could not be
- * resolved. Examples of the latter case include a directive that contains an
- * invalid URL or a URL that does not exist.
- */
- Element get uriElement;
-
- /**
- * Validate this directive, but do not check for existence. Return a code
- * indicating the problem if there is one, or `null` no problem
- */
- UriValidationCode validate() {
- StringLiteral uriLiteral = uri;
- if (uriLiteral is StringInterpolation) {
- return UriValidationCode.URI_WITH_INTERPOLATION;
- }
- String uriContent = this.uriContent;
- if (uriContent == null) {
- return UriValidationCode.INVALID_URI;
- }
- if (this is ImportDirective && uriContent.startsWith(_DART_EXT_SCHEME)) {
- return UriValidationCode.URI_WITH_DART_EXT_SCHEME;
- }
- try {
- parseUriWithException(Uri.encodeFull(uriContent));
- } on URISyntaxException {
- return UriValidationCode.INVALID_URI;
- }
- return null;
- }
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_uri, visitor);
- }
-}
-
-/**
- * Validation codes returned by [UriBasedDirective.validate].
- */
-class UriValidationCode {
- static const UriValidationCode INVALID_URI =
- const UriValidationCode('INVALID_URI');
-
- static const UriValidationCode URI_WITH_INTERPOLATION =
- const UriValidationCode('URI_WITH_INTERPOLATION');
-
- static const UriValidationCode URI_WITH_DART_EXT_SCHEME =
- const UriValidationCode('URI_WITH_DART_EXT_SCHEME');
-
- /**
- * The name of the validation code.
- */
- final String name;
-
- /**
- * Initialize a newly created validation code to have the given [name].
- */
- const UriValidationCode(this.name);
-
- @override
- String toString() => name;
-}
-
-/**
- * An identifier that has an initial value associated with it. Instances of this
- * class are always children of the class [VariableDeclarationList].
- *
- * > variableDeclaration ::=
- * > [SimpleIdentifier] ('=' [Expression])?
- *
- * TODO(paulberry): the grammar does not allow metadata to be associated with
- * a VariableDeclaration, and currently we don't record comments for it either.
- * Consider changing the class hierarchy so that [VariableDeclaration] does not
- * extend [Declaration].
- */
-class VariableDeclaration extends Declaration {
- /**
- * The name of the variable being declared.
- */
- SimpleIdentifier _name;
-
- /**
- * The equal sign separating the variable name from the initial value, or
- * `null` if the initial value was not specified.
- */
- Token equals;
-
- /**
- * The expression used to compute the initial value for the variable, or
- * `null` if the initial value was not specified.
- */
- Expression _initializer;
-
- /**
- * Initialize a newly created variable declaration. The [equals] and
- * [initializer] can be `null` if there is no initializer.
- */
- VariableDeclaration(
- SimpleIdentifier name, this.equals, Expression initializer)
- : super(null, null) {
- _name = _becomeParentOf(name);
- _initializer = _becomeParentOf(initializer);
- }
-
- @override
- Iterable get childEntities =>
- super._childEntities..add(_name)..add(equals)..add(_initializer);
-
- /**
- * This overridden implementation of getDocumentationComment() looks in the
- * grandparent node for Dartdoc comments if no documentation is specifically
- * available on the node.
- */
- @override
- Comment get documentationComment {
- Comment comment = super.documentationComment;
- if (comment == null) {
- if (parent != null && parent.parent != null) {
- AstNode node = parent.parent;
- if (node is AnnotatedNode) {
- return node.documentationComment;
- }
- }
- }
- return comment;
- }
-
- @override
- VariableElement get element =>
- _name != null ? (_name.staticElement as VariableElement) : null;
-
- @override
- Token get endToken {
- if (_initializer != null) {
- return _initializer.endToken;
- }
- return _name.endToken;
- }
-
- @override
- Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
-
- /**
- * Return the expression used to compute the initial value for the variable,
- * or `null` if the initial value was not specified.
- */
- Expression get initializer => _initializer;
-
- /**
- * Set the expression used to compute the initial value for the variable to
- * the given [expression].
- */
- void set initializer(Expression expression) {
- _initializer = _becomeParentOf(expression);
- }
-
- /**
- * Return `true` if this variable was declared with the 'const' modifier.
- */
- bool get isConst {
- AstNode parent = this.parent;
- return parent is VariableDeclarationList && parent.isConst;
- }
-
- /**
- * Return `true` if this variable was declared with the 'final' modifier.
- * Variables that are declared with the 'const' modifier will return `false`
- * even though they are implicitly final.
- */
- bool get isFinal {
- AstNode parent = this.parent;
- return parent is VariableDeclarationList && parent.isFinal;
- }
-
- /**
- * Return the name of the variable being declared.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the variable being declared to the given [identifier].
- */
- void set name(SimpleIdentifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitVariableDeclaration(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_name, visitor);
- _safelyVisitChild(_initializer, visitor);
- }
-}
-
-/**
- * The declaration of one or more variables of the same type.
- *
- * > variableDeclarationList ::=
- * > finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
- * >
- * > finalConstVarOrType ::=
- * > | 'final' [TypeName]?
- * > | 'const' [TypeName]?
- * > | 'var'
- * > | [TypeName]
- */
-class VariableDeclarationList extends AnnotatedNode {
- /**
- * The token representing the 'final', 'const' or 'var' keyword, or `null` if
- * no keyword was included.
- */
- Token keyword;
-
- /**
- * The type of the variables being declared, or `null` if no type was provided.
- */
- TypeName _type;
-
- /**
- * A list containing the individual variables being declared.
- */
- NodeList<VariableDeclaration> _variables;
-
- /**
- * Initialize a newly created variable declaration list. Either or both of the
- * [comment] and [metadata] can be `null` if the variable list does not have
- * the corresponding attribute. The [keyword] can be `null` if a type was
- * specified. The [type] must be `null` if the keyword is 'var'.
- */
- VariableDeclarationList(Comment comment, List<Annotation> metadata,
- this.keyword, TypeName type, List<VariableDeclaration> variables)
- : super(comment, metadata) {
- _type = _becomeParentOf(type);
- _variables = new NodeList<VariableDeclaration>(this, variables);
- }
-
- @override
- // TODO(paulberry): include commas.
- Iterable get childEntities => super._childEntities
- ..add(keyword)
- ..add(_type)
- ..addAll(_variables);
-
- @override
- Token get endToken => _variables.endToken;
-
- @override
- Token get firstTokenAfterCommentAndMetadata {
- if (keyword != null) {
- return keyword;
- } else if (_type != null) {
- return _type.beginToken;
- }
- return _variables.beginToken;
- }
-
- /**
- * Return `true` if the variables in this list were declared with the 'const'
- * modifier.
- */
- bool get isConst =>
- keyword is KeywordToken &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
-
- /**
- * Return `true` if the variables in this list were declared with the 'final'
- * modifier. Variables that are declared with the 'const' modifier will return
- * `false` even though they are implicitly final. (In other words, this is a
- * syntactic check rather than a semantic check.)
- */
- bool get isFinal =>
- keyword is KeywordToken &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
-
- /**
- * Return the type of the variables being declared, or `null` if no type was
- * provided.
- */
- TypeName get type => _type;
-
- /**
- * Set the type of the variables being declared to the given [typeName].
- */
- void set type(TypeName typeName) {
- _type = _becomeParentOf(typeName);
- }
-
- /**
- * Return a list containing the individual variables being declared.
- */
- NodeList<VariableDeclaration> get variables => _variables;
-
- @override
- accept(AstVisitor visitor) => visitor.visitVariableDeclarationList(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- super.visitChildren(visitor);
- _safelyVisitChild(_type, visitor);
- _variables.accept(visitor);
- }
-}
-
-/**
- * A list of variables that are being declared in a context where a statement is
- * required.
- *
- * > variableDeclarationStatement ::=
- * > [VariableDeclarationList] ';'
- */
-class VariableDeclarationStatement extends Statement {
- /**
- * The variables being declared.
- */
- VariableDeclarationList _variableList;
-
- /**
- * The semicolon terminating the statement.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created variable declaration statement.
- */
- VariableDeclarationStatement(
- VariableDeclarationList variableList, this.semicolon) {
- _variableList = _becomeParentOf(variableList);
- }
-
- @override
- Token get beginToken => _variableList.beginToken;
-
- @override
- Iterable get childEntities =>
- new ChildEntities()..add(_variableList)..add(semicolon);
-
- @override
- Token get endToken => semicolon;
-
- /**
- * Return the variables being declared.
- */
- VariableDeclarationList get variables => _variableList;
-
- /**
- * Set the variables being declared to the given list of [variables].
- */
- void set variables(VariableDeclarationList variables) {
- _variableList = _becomeParentOf(variables);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitVariableDeclarationStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_variableList, visitor);
- }
-}
-
-/**
- * A while statement.
- *
- * > whileStatement ::=
- * > 'while' '(' [Expression] ')' [Statement]
- */
-class WhileStatement extends Statement {
- /**
- * The token representing the 'while' keyword.
- */
- Token whileKeyword;
-
- /**
- * The left parenthesis.
- */
- Token leftParenthesis;
-
- /**
- * The expression used to determine whether to execute the body of the loop.
- */
- Expression _condition;
-
- /**
- * The right parenthesis.
- */
- Token rightParenthesis;
-
- /**
- * The body of the loop.
- */
- Statement _body;
-
- /**
- * Initialize a newly created while statement.
- */
- WhileStatement(this.whileKeyword, this.leftParenthesis, Expression condition,
- this.rightParenthesis, Statement body) {
- _condition = _becomeParentOf(condition);
- _body = _becomeParentOf(body);
- }
-
- @override
- Token get beginToken => whileKeyword;
-
- /**
- * Return the body of the loop.
- */
- Statement get body => _body;
-
- /**
- * Set the body of the loop to the given [statement].
- */
- void set body(Statement statement) {
- _body = _becomeParentOf(statement);
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(whileKeyword)
- ..add(leftParenthesis)
- ..add(_condition)
- ..add(rightParenthesis)
- ..add(_body);
-
- /**
- * Return the expression used to determine whether to execute the body of the
- * loop.
- */
- Expression get condition => _condition;
-
- /**
- * Set the expression used to determine whether to execute the body of the
- * loop to the given [expression].
- */
- void set condition(Expression expression) {
- _condition = _becomeParentOf(expression);
- }
-
- @override
- Token get endToken => _body.endToken;
-
- @override
- accept(AstVisitor visitor) => visitor.visitWhileStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_condition, visitor);
- _safelyVisitChild(_body, visitor);
- }
-}
-
-/**
- * The with clause in a class declaration.
- *
- * > withClause ::=
- * > 'with' [TypeName] (',' [TypeName])*
- */
-class WithClause extends AstNode {
- /**
- * The token representing the 'with' keyword.
- */
- Token withKeyword;
-
- /**
- * The names of the mixins that were specified.
- */
- NodeList<TypeName> _mixinTypes;
-
- /**
- * Initialize a newly created with clause.
- */
- WithClause(this.withKeyword, List<TypeName> mixinTypes) {
- _mixinTypes = new NodeList<TypeName>(this, mixinTypes);
- }
-
- @override
- Token get beginToken => withKeyword;
-
- @override
- // TODO(paulberry): add commas.
- Iterable get childEntities => new ChildEntities()
- ..add(withKeyword)
- ..addAll(_mixinTypes);
-
- @override
- Token get endToken => _mixinTypes.endToken;
-
- /**
- * Return the names of the mixins that were specified.
- */
- NodeList<TypeName> get mixinTypes => _mixinTypes;
-
- @override
- accept(AstVisitor visitor) => visitor.visitWithClause(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _mixinTypes.accept(visitor);
- }
-}
-
-/**
- * A yield statement.
- *
- * > yieldStatement ::=
- * > 'yield' '*'? [Expression] ‘;’
- */
-class YieldStatement extends Statement {
- /**
- * The 'yield' keyword.
- */
- Token yieldKeyword;
-
- /**
- * The star optionally following the 'yield' keyword.
- */
- Token star;
-
- /**
- * The expression whose value will be yielded.
- */
- Expression _expression;
-
- /**
- * The semicolon following the expression.
- */
- Token semicolon;
-
- /**
- * Initialize a newly created yield expression. The [star] can be `null` if no
- * star was provided.
- */
- YieldStatement(
- this.yieldKeyword, this.star, Expression expression, this.semicolon) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- Token get beginToken {
- if (yieldKeyword != null) {
- return yieldKeyword;
- }
- return _expression.beginToken;
- }
-
- @override
- Iterable get childEntities => new ChildEntities()
- ..add(yieldKeyword)
- ..add(star)
- ..add(_expression)
- ..add(semicolon);
-
- @override
- Token get endToken {
- if (semicolon != null) {
- return semicolon;
- }
- return _expression.endToken;
- }
-
- /**
- * Return the expression whose value will be yielded.
- */
- Expression get expression => _expression;
-
- /**
- * Set the expression whose value will be yielded to the given [expression].
- */
- void set expression(Expression expression) {
- _expression = _becomeParentOf(expression);
- }
-
- @override
- accept(AstVisitor visitor) => visitor.visitYieldStatement(this);
-
- @override
- void visitChildren(AstVisitor visitor) {
- _safelyVisitChild(_expression, visitor);
- }
-}
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index a561978..efb81e3 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -6,11 +6,13 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisEngine, RecordingErrorListener;
@@ -157,6 +159,13 @@
ConstantAstCloner() : super(true);
@override
+ ConstructorName visitConstructorName(ConstructorName node) {
+ ConstructorName name = super.visitConstructorName(node);
+ name.staticElement = node.staticElement;
+ return name;
+ }
+
+ @override
InstanceCreationExpression visitInstanceCreationExpression(
InstanceCreationExpression node) {
InstanceCreationExpression expression =
@@ -441,13 +450,6 @@
* Determine which constant elements need to have their values computed
* prior to computing the value of [constant], and report them using
* [callback].
- *
- * Note that it's possible (in erroneous code) for a constant to depend on a
- * non-constant. When this happens, we report the dependency anyhow so that
- * if the non-constant changes to a constant, we will know to recompute the
- * thing that depends on it. [computeDependencies] and
- * [computeConstantValue] are responsible for ignoring the request if they
- * are asked to act on a non-constant target.
*/
void computeDependencies(
ConstantEvaluationTarget constant, ReferenceFinderCallback callback) {
@@ -1616,7 +1618,9 @@
DartObjectImpl rightResult = node.rightOperand.accept(this);
TokenType operatorType = node.operator.type;
// 'null' is almost never good operand
- if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) {
+ if (operatorType != TokenType.BANG_EQ &&
+ operatorType != TokenType.EQ_EQ &&
+ operatorType != TokenType.QUESTION_QUESTION) {
if (leftResult != null && leftResult.isNull ||
rightResult != null && rightResult.isNull) {
_error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
@@ -1665,6 +1669,9 @@
return _dartObjectComputer.divide(node, leftResult, rightResult);
} else if (operatorType == TokenType.TILDE_SLASH) {
return _dartObjectComputer.integerDivide(node, leftResult, rightResult);
+ } else if (operatorType == TokenType.QUESTION_QUESTION) {
+ return _dartObjectComputer.questionQuestion(
+ node, leftResult, rightResult);
} else {
// TODO(brianwilkerson) Figure out which error to report.
_error(node, null);
@@ -2461,6 +2468,17 @@
return null;
}
+ DartObjectImpl questionQuestion(Expression node, DartObjectImpl leftOperand,
+ DartObjectImpl rightOperand) {
+ if (leftOperand != null && rightOperand != null) {
+ if (leftOperand.isNull) {
+ return rightOperand;
+ }
+ return leftOperand;
+ }
+ return null;
+ }
+
DartObjectImpl remainder(BinaryExpression node, DartObjectImpl leftOperand,
DartObjectImpl rightOperand) {
if (leftOperand != null && rightOperand != null) {
@@ -5232,7 +5250,7 @@
if (element is PropertyAccessorElement) {
element = (element as PropertyAccessorElement).variable;
}
- if (element is VariableElement) {
+ if (element is VariableElement && element.isConst) {
_callback(element);
}
return null;
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 968d797..4ff96d5 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -9,7 +9,7 @@
* * package:analyzer/dart/element/type.dart
* * package:analyzer/dart/element/visitor.dart
*
- * If your code is using API's not available in these public libraries, please
+ * If your code is using APIs not available in these public libraries, please
* contact the analyzer team to either find an alternate API or have the API you
* depend on added to the public API.
*/
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 0a29cfb..03f9137 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -7,7 +7,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
@@ -754,6 +754,9 @@
bool get isBrowserApplication => actualElement.isBrowserApplication;
@override
+ bool get isDartAsync => actualElement.isDartAsync;
+
+ @override
bool get isDartCore => actualElement.isDartCore;
@override
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 368da2a..5bf9630 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -6,11 +6,14 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart'
+ show ChildEntities, IdentifierImpl;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -427,9 +430,9 @@
@override
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
Expression function = node.function;
- DartType staticInvokeType =
- _resolveGenericMethod(function.staticType, node.typeArguments, node);
- DartType propagatedInvokeType = _resolveGenericMethod(
+ DartType staticInvokeType = _instantiateGenericMethod(
+ function.staticType, node.typeArguments, node);
+ DartType propagatedInvokeType = _instantiateGenericMethod(
function.propagatedType, node.typeArguments, node);
node.staticInvokeType = staticInvokeType;
@@ -616,7 +619,9 @@
[(target as SimpleIdentifier).name]);
}
LibraryElement importedLibrary = _getImportedLibrary(target);
- methodName.staticElement = importedLibrary.loadLibraryFunction;
+ FunctionElement loadLibraryFunction = importedLibrary.loadLibraryFunction;
+ methodName.staticElement = loadLibraryFunction;
+ node.staticInvokeType = loadLibraryFunction.type;
return null;
} else {
//
@@ -650,9 +655,23 @@
staticElement = _convertSetterToGetter(staticElement);
propagatedElement = _convertSetterToGetter(propagatedElement);
- DartType staticInvokeType = _computeMethodInvokeType(node, staticElement);
- DartType propagatedInvokeType =
- _computeMethodInvokeType(node, propagatedElement);
+ //
+ // Given the elements, determine the type of the function we are invoking
+ //
+ DartType staticInvokeType = _getInvokeType(staticElement);
+ methodName.staticType = staticInvokeType;
+
+ DartType propagatedInvokeType = _getInvokeType(propagatedElement);
+ methodName.propagatedType =
+ _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType);
+
+ //
+ // Instantiate generic function or method if needed.
+ //
+ staticInvokeType = _instantiateGenericMethod(
+ staticInvokeType, node.typeArguments, node.methodName);
+ propagatedInvokeType = _instantiateGenericMethod(
+ propagatedInvokeType, node.typeArguments, node.methodName);
//
// Record the results.
@@ -1336,30 +1355,6 @@
return null;
}
- DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
- if (element == null) {
- // TODO(jmesserly): should we return `dynamic` in this case?
- // Otherwise we have to guard against `null` every time we use
- // `staticInvokeType`.
- // If we do return `dynamic` we need to be careful that this doesn't
- // adversely affect propagatedType code path. But it shouldn't because
- // we'll discard `dynamic` anyway (see _propagatedInvokeTypeIfBetter).
- return null;
- }
-
- DartType invokeType;
- if (element is PropertyAccessorElement) {
- invokeType = element.returnType;
- } else if (element is ExecutableElement) {
- invokeType = element.type;
- } else if (element is VariableElement) {
- invokeType = _promoteManager.getStaticType(element);
- }
-
- return _resolveGenericMethod(
- invokeType, node.typeArguments, node.methodName);
- }
-
/**
* If the given [element] is a setter, return the getter associated with it.
* Otherwise, return the element unchanged.
@@ -1437,6 +1432,28 @@
}
/**
+ * Given an element, computes the type of the invocation.
+ *
+ * For executable elements (like methods, functions) this is just their type.
+ *
+ * For variables it is their type taking into account any type promotion.
+ *
+ * For calls to getters in Dart, we invoke the function that is returned by
+ * the getter, so the invoke type is the getter's returnType.
+ */
+ DartType _getInvokeType(Element element) {
+ DartType invokeType;
+ if (element is PropertyAccessorElement) {
+ invokeType = element.returnType;
+ } else if (element is ExecutableElement) {
+ invokeType = element.type;
+ } else if (element is VariableElement) {
+ invokeType = _promoteManager.getStaticType(element);
+ }
+ return invokeType ?? DynamicTypeImpl.instance;
+ }
+
+ /**
* Return the name of the method invoked by the given postfix [expression].
*/
String _getPostfixOperator(PostfixExpression expression) =>
@@ -1497,6 +1514,36 @@
}
/**
+ * Check for a generic method & apply type arguments if any were passed.
+ */
+ DartType _instantiateGenericMethod(
+ DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
+ // TODO(jmesserly): support generic "call" methods on InterfaceType.
+ if (invokeType is FunctionType) {
+ FunctionType type = invokeType;
+ List<TypeParameterElement> parameters = type.typeFormals;
+
+ NodeList<TypeName> arguments = typeArguments?.arguments;
+ if (arguments != null && arguments.length != parameters.length) {
+ // Wrong number of type arguments. Ignore them
+ arguments = null;
+ _resolver.reportErrorForNode(
+ StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
+ node,
+ [type, parameters.length, arguments?.length ?? 0]);
+ }
+ if (parameters.isNotEmpty) {
+ if (arguments == null) {
+ invokeType = _resolver.typeSystem.instantiateToBounds(type);
+ } else {
+ invokeType = type.instantiate(arguments.map((n) => n.type).toList());
+ }
+ }
+ }
+ return invokeType;
+ }
+
+ /**
* Return `true` if the given [expression] is a prefix for a deferred import.
*/
bool _isDeferredPrefix(Expression expression) {
@@ -2081,36 +2128,6 @@
}
/**
- * Check for a generic method & apply type arguments if any were passed.
- */
- DartType _resolveGenericMethod(
- DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
- // TODO(jmesserly): support generic "call" methods on InterfaceType.
- if (invokeType is FunctionType) {
- FunctionType type = invokeType;
- List<TypeParameterElement> parameters = type.typeFormals;
-
- NodeList<TypeName> arguments = typeArguments?.arguments;
- if (arguments != null && arguments.length != parameters.length) {
- // Wrong number of type arguments. Ignore them
- arguments = null;
- _resolver.reportErrorForNode(
- StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
- node,
- [type, parameters.length, arguments?.length ?? 0]);
- }
- if (parameters.isNotEmpty) {
- if (arguments == null) {
- invokeType = _resolver.typeSystem.instantiateToBounds(type);
- } else {
- invokeType = type.instantiate(arguments.map((n) => n.type).toList());
- }
- }
- }
- return invokeType;
- }
-
- /**
* Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the
* element being invoked. If the returned element is a method, then the method
* will be invoked. If the returned element is a getter, the getter will be
@@ -2559,7 +2576,7 @@
* AST when the parser could not distinguish between a method invocation and an
* invocation of a top-level function imported with a prefix.
*/
-class SyntheticIdentifier extends Identifier {
+class SyntheticIdentifier extends IdentifierImpl {
/**
* The name of the synthetic identifier.
*/
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 4f8d664..b27c42e 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -7,13 +7,14 @@
import 'dart:async';
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/source/embedder.dart';
import 'package:analyzer/src/cancelable_future.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -312,8 +313,8 @@
* Perform work until the given [result] has been computed for the given
* [target]. Return the computed value.
*/
- Object /*=V*/ computeResult /*<V>*/ (
- AnalysisTarget target, ResultDescriptor /*<V>*/ result);
+ Object/*=V*/ computeResult/*<V>*/(
+ AnalysisTarget target, ResultDescriptor/*<V>*/ result);
/**
* Notifies the context that the client is going to stop using this context.
@@ -474,8 +475,8 @@
* If the corresponding [target] does not exist, or the [result] is not
* computed yet, then the default value is returned.
*/
- Object /*=V*/ getResult /*<V>*/ (
- AnalysisTarget target, ResultDescriptor /*<V>*/ result);
+ Object/*=V*/ getResult/*<V>*/(
+ AnalysisTarget target, ResultDescriptor/*<V>*/ result);
/**
* Return a list of the sources being analyzed in this context whose full path
@@ -1589,6 +1590,7 @@
/**
* A list containing the sources that have been deleted.
*/
+ @deprecated
final List<Source> deletedSources = new List<Source>();
/**
@@ -1651,6 +1653,7 @@
/**
* Record that the specified [source] has been deleted.
*/
+ @deprecated
void deletedSource(Source source) {
deletedSources.add(source);
}
@@ -1850,6 +1853,11 @@
*/
abstract class InternalAnalysisContext implements AnalysisContext {
/**
+ * The result provider for [aboutToComputeResult].
+ */
+ ResultProvider resultProvider;
+
+ /**
* A table mapping the sources known to the context to the information known
* about the source.
*/
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index aa43a7e..777e5bc 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -6,10 +6,10 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart' show AstNode;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/error_processor.dart';
-import 'package:analyzer/src/generated/ast.dart' show AstNode;
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/scanner.dart'
@@ -19,6 +19,8 @@
import 'package:analyzer/task/model.dart';
import 'package:source_span/source_span.dart';
+import 'generated/shared_messages.dart' as shared_messages;
+
/**
* The descriptor used to associate error processors with analysis contexts in
* configuration data.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index d644fcd..20462bb 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -7,13 +7,14 @@
import 'dart:collection';
import "dart:math" as math;
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -23,7 +24,6 @@
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart' as sc;
import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary;
-import 'package:analyzer/src/generated/static_type_analyzer.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
/**
@@ -1285,27 +1285,27 @@
}
}
});
+
if (notInitFinalFields.isNotEmpty) {
foundError = true;
AnalysisErrorWithProperties analysisError;
- if (notInitFinalFields.length == 1) {
+ List<String> names = notInitFinalFields.map((item) => item.name).toList();
+ names.sort();
+ if (names.length == 1) {
analysisError = _errorReporter.newErrorWithProperties(
StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1,
constructor.returnType,
- [notInitFinalFields[0].name]);
- } else if (notInitFinalFields.length == 2) {
+ names);
+ } else if (names.length == 2) {
analysisError = _errorReporter.newErrorWithProperties(
StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
constructor.returnType,
- [notInitFinalFields[0].name, notInitFinalFields[1].name]);
+ names);
} else {
analysisError = _errorReporter.newErrorWithProperties(
StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS,
- constructor.returnType, [
- notInitFinalFields[0].name,
- notInitFinalFields[1].name,
- notInitFinalFields.length - 2
- ]);
+ constructor.returnType,
+ [names[0], names[1], names.length - 2]);
}
analysisError.setProperty(
ErrorProperty.NOT_INITIALIZED_FIELDS, notInitFinalFields);
@@ -5771,9 +5771,8 @@
}
DartType staticReturnType = getStaticType(returnExpression);
if (staticReturnType != null && _enclosingFunction.isAsynchronous) {
- return _typeProvider.futureType.substitute4(<DartType>[
- StaticTypeAnalyzer.flattenFutures(_typeProvider, staticReturnType)
- ]);
+ return _typeProvider.futureType.substitute4(
+ <DartType>[staticReturnType.flattenFutures(_typeSystem)]);
}
return staticReturnType;
}
diff --git a/pkg/analyzer/lib/src/generated/generated/shared_messages.dart b/pkg/analyzer/lib/src/generated/generated/shared_messages.dart
new file mode 100644
index 0000000..2c1465c
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/generated/shared_messages.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+/*
+DON'T EDIT. GENERATED. DON'T EDIT.
+This file has been generated by 'publish.dart' in the dart_messages package.
+
+Messages are maintained in `lib/shared_messages.dart` of that same package.
+After any change to that file, run `bin/publish.dart` to generate a new version
+of the json, dart2js and analyzer representations.
+*/
+import 'package:analyzer/src/generated/error.dart';
+
+const AnalysisOptionsErrorCode exampleMessage = const AnalysisOptionsErrorCode(
+ 'exampleMessage',
+ "{2} {1} {0}",
+ "an explanation on how to fix things"); // Generated. Don't edit.
diff --git a/pkg/analyzer/lib/src/generated/incremental_logger.dart b/pkg/analyzer/lib/src/generated/incremental_logger.dart
index d942aba..1de2534 100644
--- a/pkg/analyzer/lib/src/generated/incremental_logger.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_logger.dart
@@ -40,6 +40,11 @@
void log(Object obj);
/**
+ * Logs the given [exception] and [stackTrace].
+ */
+ void logException(Object exception, [Object stackTrace]);
+
+ /**
* Starts a new timer.
*/
LoggingTimer startTimer();
@@ -102,6 +107,16 @@
}
@override
+ void logException(Object exception, [Object stackTrace]) {
+ if (exception != null) {
+ log(exception);
+ }
+ if (stackTrace != null) {
+ log(stackTrace);
+ }
+ }
+
+ @override
LoggingTimer startTimer() {
return new LoggingTimer(this);
}
@@ -147,6 +162,9 @@
void log(Object obj) {}
@override
+ void logException(Object exception, [Object stackTrace]) {}
+
+ @override
LoggingTimer startTimer() {
return new LoggingTimer(this);
}
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart b/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart
index 36d8784..f0f7a4c7 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart
@@ -4,11 +4,11 @@
library analyzer.src.generated.incremental_resolution_validator;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
-import 'package:analyzer/src/generated/ast.dart';
/**
* Validates that the [actual] and the [expected] units have the same structure
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index b67b905..542e721 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -7,12 +7,14 @@
import 'dart:collection';
import 'dart:math' as math;
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -474,7 +476,8 @@
void _assertCompatibleParameter(
FormalParameter node, ParameterElement element) {
_assertEquals(node.kind, element.parameterKind);
- if (node.kind == ParameterKind.NAMED) {
+ if (node.kind == ParameterKind.NAMED ||
+ element.enclosingElement is ConstructorElement) {
_assertEquals(node.identifier.name, element.name);
}
// check parameter type specific properties
@@ -597,12 +600,12 @@
}
void _assertSameAnnotations(AnnotatedNode node, Element element) {
- List<Annotation> nodeAnnotaitons = node.metadata;
+ List<Annotation> nodeAnnotations = node.metadata;
List<ElementAnnotation> elementAnnotations = element.metadata;
- int length = nodeAnnotaitons.length;
+ int length = nodeAnnotations.length;
_assertEquals(elementAnnotations.length, length);
for (int i = 0; i < length; i++) {
- _assertSameAnnotation(nodeAnnotaitons[i], elementAnnotations[i]);
+ _assertSameAnnotation(nodeAnnotations[i], elementAnnotations[i]);
}
}
@@ -1468,37 +1471,67 @@
{
List<AstNode> oldParents = _getParents(oldNode);
List<AstNode> newParents = _getParents(newNode);
+ // fail if an initializer change
+ if (oldParents.any((n) => n is ConstructorInitializer) ||
+ newParents.any((n) => n is ConstructorInitializer)) {
+ logger.log('Failure: a change in a constructor initializer');
+ return false;
+ }
+ // find matching methods / bodies
int length = math.min(oldParents.length, newParents.length);
bool found = false;
for (int i = 0; i < length; i++) {
AstNode oldParent = oldParents[i];
AstNode newParent = newParents[i];
- if (oldParent is ConstructorInitializer ||
- newParent is ConstructorInitializer) {
- logger.log('Failure: changes in constant constructor initializers'
- ' may cause external changes in constant objects.');
- return false;
- }
- if (oldParent is FunctionDeclaration &&
+ if (oldParent is CompilationUnit && newParent is CompilationUnit) {
+ int oldLength = oldParent.declarations.length;
+ int newLength = newParent.declarations.length;
+ if (oldLength != newLength) {
+ logger.log(
+ 'Failure: unit declarations mismatch $oldLength vs. $newLength');
+ return false;
+ }
+ } else if (oldParent is ClassDeclaration &&
+ newParent is ClassDeclaration) {
+ int oldLength = oldParent.members.length;
+ int newLength = newParent.members.length;
+ if (oldLength != newLength) {
+ logger.log(
+ 'Failure: class declarations mismatch $oldLength vs. $newLength');
+ return false;
+ }
+ } else if (oldParent is FunctionDeclaration &&
newParent is FunctionDeclaration ||
- oldParent is MethodDeclaration &&
- newParent is MethodDeclaration ||
oldParent is ConstructorDeclaration &&
- newParent is ConstructorDeclaration) {
+ newParent is ConstructorDeclaration ||
+ oldParent is MethodDeclaration &&
+ newParent is MethodDeclaration) {
Element oldElement = (oldParent as Declaration).element;
if (new DeclarationMatcher().matches(newParent, oldElement) ==
DeclarationMatchKind.MATCH) {
oldNode = oldParent;
newNode = newParent;
found = true;
+ } else {
+ return false;
}
- }
- if (oldParent is BlockFunctionBody &&
- newParent is BlockFunctionBody) {
- oldNode = oldParent;
- newNode = newParent;
- found = true;
- break;
+ } else if (oldParent is FunctionBody && newParent is FunctionBody) {
+ if (oldParent is BlockFunctionBody &&
+ newParent is BlockFunctionBody) {
+ oldNode = oldParent;
+ newNode = newParent;
+ found = true;
+ break;
+ }
+ logger.log('Failure: not a block function body.');
+ return false;
+ } else if (oldParent is FunctionExpression &&
+ newParent is FunctionExpression) {
+ // skip
+ } else {
+ logger.log('Failure: old and new parent mismatch'
+ ' ${oldParent.runtimeType} vs. ${newParent.runtimeType}');
+ return false;
}
}
if (!found) {
@@ -1555,9 +1588,12 @@
return true;
}
} catch (e, st) {
- logger.log(e);
- logger.log(st);
+ logger.logException(e, st);
logger.log('Failure: exception.');
+ // The incremental resolver log is usually turned off,
+ // so also log the exception to the instrumentation log.
+ AnalysisEngine.instance.logger.logError(
+ 'Failure in incremental resolver', new CaughtException(e, st));
} finally {
logger.exit();
}
@@ -1595,8 +1631,13 @@
// find nodes
int offset = oldComments.offset;
logger.log('offset: $offset');
- Comment oldComment = _findNodeCovering(_oldUnit, offset, offset);
- Comment newComment = _findNodeCovering(newUnit, offset, offset);
+ AstNode oldNode = _findNodeCovering(_oldUnit, offset, offset);
+ AstNode newNode = _findNodeCovering(newUnit, offset, offset);
+ if (oldNode is! Comment || newNode is! Comment) {
+ return false;
+ }
+ Comment oldComment = oldNode;
+ Comment newComment = newNode;
logger.log('oldComment.beginToken: ${oldComment.beginToken}');
logger.log('newComment.beginToken: ${newComment.beginToken}');
_updateOffset = oldToken.offset - 1;
@@ -1733,7 +1774,7 @@
Token newComment = newToken.precedingComments;
if (_compareToken(oldComment, newComment, 0, true) != null) {
_TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
- if (oldComment is DocumentationCommentToken ||
+ if (oldComment is DocumentationCommentToken &&
newComment is DocumentationCommentToken) {
diffKind = _TokenDifferenceKind.COMMENT_DOC;
}
@@ -1769,7 +1810,7 @@
Token newComment = newToken.precedingComments;
if (_compareToken(oldComment, newComment, delta, true) != null) {
_TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
- if (oldComment is DocumentationCommentToken ||
+ if (oldComment is DocumentationCommentToken &&
newComment is DocumentationCommentToken) {
diffKind = _TokenDifferenceKind.COMMENT_DOC;
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index de0306f..4f249be 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -7,7 +7,10 @@
import 'dart:collection';
import "dart:math" as math;
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisEngine, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/error.dart';
@@ -3798,8 +3801,7 @@
/**
* If the current token has the type [TokenType.GT], return it after advancing
- * to the next token. Otherwise report an error and return the current token
- * without advancing.
+ * to the next token. Otherwise report an error and create a synthetic token.
*/
Token _expectGt() {
if (_matchesGt()) {
@@ -3807,7 +3809,7 @@
}
_reportErrorForCurrentToken(
ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
- return _currentToken;
+ return _createSyntheticToken(TokenType.GT);
}
/**
@@ -5369,12 +5371,13 @@
*/
Expression _parseConstExpression() {
Token keyword = _expectKeyword(Keyword.CONST);
- if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) {
+ if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) {
+ return _parseListOrMapLiteral(keyword);
+ } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
+ _matches(TokenType.INDEX)) {
return _parseListLiteral(keyword, null);
} else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
return _parseMapLiteral(keyword, null);
- } else if (_matches(TokenType.LT)) {
- return _parseListOrMapLiteral(keyword);
}
return _parseInstanceCreationExpression(keyword);
}
@@ -7394,11 +7397,6 @@
return new IntegerLiteral(token, value);
} else if (_matches(TokenType.STRING)) {
return parseStringLiteral();
- } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
- return _parseMapLiteral(null, null);
- } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
- _matches(TokenType.INDEX)) {
- return _parseListLiteral(null, null);
} else if (_matchesIdentifier()) {
// TODO(brianwilkerson) The code below was an attempt to recover from an
// error case, but it needs to be applied as a recovery only after we
@@ -7431,8 +7429,13 @@
} finally {
_inInitializer = wasInInitializer;
}
- } else if (_matches(TokenType.LT)) {
+ } else if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) {
return _parseListOrMapLiteral(null);
+ } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
+ return _parseMapLiteral(null, null);
+ } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
+ _matches(TokenType.INDEX)) {
+ return _parseListLiteral(null, null);
} else if (_matches(TokenType.QUESTION) &&
_tokenMatches(_peek(), TokenType.IDENTIFIER)) {
_reportErrorForCurrentToken(
@@ -9381,9 +9384,9 @@
/**
* Some environments, such as Fletch, do not support async.
*/
- static const CompileTimeErrorCode ASYNC_NOT_SUPPORTED =
- const CompileTimeErrorCode('ASYNC_NOT_SUPPORTED',
- "Async and sync are not supported in this environment.");
+ static const ParserErrorCode ASYNC_NOT_SUPPORTED = const ParserErrorCode(
+ 'ASYNC_NOT_SUPPORTED',
+ "Async and sync are not supported in this environment.");
static const ParserErrorCode BREAK_OUTSIDE_OF_LOOP = const ParserErrorCode(
'BREAK_OUTSIDE_OF_LOOP',
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 0d856c8..4ed3deb 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -6,13 +6,15 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -517,6 +519,8 @@
}
AstNode parent = identifier.parent;
if ((parent is ConstructorName && identical(identifier, parent.name)) ||
+ (parent is ConstructorDeclaration &&
+ identical(identifier, parent.returnType)) ||
(parent is SuperConstructorInvocation &&
identical(identifier, parent.constructorName)) ||
parent is HideCombinator) {
@@ -906,6 +910,63 @@
}
/**
+ * Utilities for [LibraryElementImpl] building.
+ */
+class BuildLibraryElementUtils {
+ /**
+ * Look through all of the compilation units defined for the given [library],
+ * looking for getters and setters that are defined in different compilation
+ * units but that have the same names. If any are found, make sure that they
+ * have the same variable element.
+ */
+ static void patchTopLevelAccessors(LibraryElementImpl library) {
+ // Without parts getters/setters already share the same variable element.
+ if (library.parts.isEmpty) {
+ return;
+ }
+ // Collect getters and setters.
+ HashMap<String, PropertyAccessorElement> getters =
+ new HashMap<String, PropertyAccessorElement>();
+ List<PropertyAccessorElement> setters = <PropertyAccessorElement>[];
+ _collectAccessors(getters, setters, library.definingCompilationUnit);
+ for (CompilationUnitElement unit in library.parts) {
+ _collectAccessors(getters, setters, unit);
+ }
+ // Move every setter to the corresponding getter's variable (if exists).
+ for (PropertyAccessorElement setter in setters) {
+ PropertyAccessorElement getter = getters[setter.displayName];
+ if (getter != null) {
+ TopLevelVariableElementImpl variable = getter.variable;
+ TopLevelVariableElementImpl setterVariable = setter.variable;
+ CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement;
+ setterUnit.replaceTopLevelVariable(setterVariable, variable);
+ variable.setter = setter;
+ (setter as PropertyAccessorElementImpl).variable = variable;
+ }
+ }
+ }
+
+ /**
+ * Add all of the non-synthetic [getters] and [setters] defined in the given
+ * [unit] that have no corresponding accessor to one of the given collections.
+ */
+ static void _collectAccessors(Map<String, PropertyAccessorElement> getters,
+ List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
+ for (PropertyAccessorElement accessor in unit.accessors) {
+ if (accessor.isGetter) {
+ if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
+ getters[accessor.displayName] = accessor;
+ }
+ } else {
+ if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
+ setters.add(accessor);
+ }
+ }
+ }
+ }
+}
+
+/**
* Instances of the class `ClassScope` implement the scope defined by a class.
*/
class ClassScope extends EnclosedScope {
@@ -2610,11 +2671,6 @@
bool _inFunction = false;
/**
- * A flag indicating whether the class currently being visited can be used as a mixin.
- */
- bool _isValidMixin = false;
-
- /**
* A collection holding the elements defined in a class that need to have
* their function type fixed to take into account type parameters of the
* enclosing class, or `null` if we are not currently processing nodes within
@@ -2676,7 +2732,6 @@
@override
Object visitClassDeclaration(ClassDeclaration node) {
ElementHolder holder = new ElementHolder();
- _isValidMixin = true;
_functionTypesToFix = new List<ExecutableElementImpl>();
//
// Process field declarations before constructors and methods so that field
@@ -2714,7 +2769,6 @@
element.constructors = constructors;
element.fields = holder.fields;
element.methods = holder.methods;
- element.validMixin = _isValidMixin;
// Function types must be initialized after the enclosing element has been
// set, for them to pick up the type parameters.
for (ExecutableElementImpl e in _functionTypesToFix) {
@@ -2764,7 +2818,6 @@
@override
Object visitConstructorDeclaration(ConstructorDeclaration node) {
- _isValidMixin = false;
ElementHolder holder = new ElementHolder();
bool wasInFunction = _inFunction;
_inFunction = true;
@@ -3337,12 +3390,6 @@
}
@override
- Object visitSuperExpression(SuperExpression node) {
- _isValidMixin = false;
- return super.visitSuperExpression(node);
- }
-
- @override
Object visitSwitchCase(SwitchCase node) {
for (Label label in node.labels) {
SimpleIdentifier labelName = label.label;
@@ -6938,16 +6985,6 @@
}
/**
- * Instances of the class `LibraryResolver` are used to resolve one or more mutually dependent
- * libraries within a single context.
- */
-
-/**
- * Instances of the class `LibraryResolver` are used to resolve one or more mutually dependent
- * libraries within a single context.
- */
-
-/**
* Instances of the class `LibraryScope` implement a scope containing all of the names defined
* in a given library.
*/
@@ -8380,11 +8417,10 @@
Object visitAwaitExpression(AwaitExpression node) {
// TODO(leafp): Handle the implicit union type here
// https://github.com/dart-lang/sdk/issues/25322
- DartType contextType = StaticTypeAnalyzer.flattenFutures(
- typeProvider, InferenceContext.getType(node));
+ DartType contextType = InferenceContext.getType(node);
if (contextType != null) {
- InterfaceType futureT =
- typeProvider.futureType.substitute4([contextType]);
+ InterfaceType futureT = typeProvider.futureType
+ .substitute4([contextType.flattenFutures(typeSystem)]);
InferenceContext.setType(node.expression, futureT);
}
return super.visitAwaitExpression(node);
@@ -9165,105 +9201,6 @@
return null;
}
- /**
- * Given an [argumentList] and the [parameters] related to the element that
- * will be invoked using those arguments, compute the list of parameters that
- * correspond to the list of arguments.
- *
- * An error will be reported to [onError] if any of the arguments cannot be
- * matched to a parameter. onError can be null to ignore the error.
- *
- * The flag [reportAsError] should be `true` if a compile-time error should be
- * reported; or `false` if a compile-time warning should be reported
- *
- * Returns the parameters that correspond to the arguments.
- */
- static List<ParameterElement> resolveArgumentsToParameters(
- ArgumentList argumentList,
- List<ParameterElement> parameters,
- void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
- {bool reportAsError: false}) {
- List<ParameterElement> requiredParameters = new List<ParameterElement>();
- List<ParameterElement> positionalParameters = new List<ParameterElement>();
- HashMap<String, ParameterElement> namedParameters =
- new HashMap<String, ParameterElement>();
- for (ParameterElement parameter in parameters) {
- ParameterKind kind = parameter.parameterKind;
- if (kind == ParameterKind.REQUIRED) {
- requiredParameters.add(parameter);
- } else if (kind == ParameterKind.POSITIONAL) {
- positionalParameters.add(parameter);
- } else {
- namedParameters[parameter.name] = parameter;
- }
- }
- List<ParameterElement> unnamedParameters =
- new List<ParameterElement>.from(requiredParameters);
- unnamedParameters.addAll(positionalParameters);
- int unnamedParameterCount = unnamedParameters.length;
- int unnamedIndex = 0;
- NodeList<Expression> arguments = argumentList.arguments;
- int argumentCount = arguments.length;
- List<ParameterElement> resolvedParameters =
- new List<ParameterElement>(argumentCount);
- int positionalArgumentCount = 0;
- HashSet<String> usedNames = new HashSet<String>();
- bool noBlankArguments = true;
- for (int i = 0; i < argumentCount; i++) {
- Expression argument = arguments[i];
- if (argument is NamedExpression) {
- SimpleIdentifier nameNode = argument.name.label;
- String name = nameNode.name;
- ParameterElement element = namedParameters[name];
- if (element == null) {
- ErrorCode errorCode = (reportAsError
- ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
- : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
- if (onError != null) {
- onError(errorCode, nameNode, [name]);
- }
- } else {
- resolvedParameters[i] = element;
- nameNode.staticElement = element;
- }
- if (!usedNames.add(name)) {
- if (onError != null) {
- onError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode,
- [name]);
- }
- }
- } else {
- if (argument is SimpleIdentifier && argument.name.isEmpty) {
- noBlankArguments = false;
- }
- positionalArgumentCount++;
- if (unnamedIndex < unnamedParameterCount) {
- resolvedParameters[i] = unnamedParameters[unnamedIndex++];
- }
- }
- }
- if (positionalArgumentCount < requiredParameters.length &&
- noBlankArguments) {
- ErrorCode errorCode = (reportAsError
- ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
- : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
- if (onError != null) {
- onError(errorCode, argumentList,
- [requiredParameters.length, positionalArgumentCount]);
- }
- } else if (positionalArgumentCount > unnamedParameterCount &&
- noBlankArguments) {
- ErrorCode errorCode = (reportAsError
- ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
- : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
- if (onError != null) {
- onError(errorCode, argumentList,
- [unnamedParameterCount, positionalArgumentCount]);
- }
- }
- return resolvedParameters;
- }
-
@override
Object visitNamedExpression(NamedExpression node) {
InferenceContext.setType(node.expression, InferenceContext.getType(node));
@@ -9409,7 +9346,8 @@
return null;
}
- @override visitVariableDeclarationList(VariableDeclarationList node) {
+ @override
+ visitVariableDeclarationList(VariableDeclarationList node) {
for (VariableDeclaration decl in node.variables) {
InferenceContext.setType(decl, node.type?.type);
}
@@ -9525,7 +9463,7 @@
return (typeArgs?.length == 1) ? typeArgs[0] : null;
}
// Must be asynchronous to reach here, so strip off any layers of Future
- return StaticTypeAnalyzer.flattenFutures(typeProvider, declaredType);
+ return declaredType.flattenFutures(typeSystem);
}
/**
@@ -9775,24 +9713,17 @@
return;
}
// prepare current variable type
- DartType type = _promoteManager.getType(element);
- if (type == null) {
- type = expression.staticType;
+ DartType type = _promoteManager.getType(element) ??
+ expression.staticType ??
+ DynamicTypeImpl.instance;
+
+ potentialType ??= DynamicTypeImpl.instance;
+
+ // Check if we can promote to potentialType from type.
+ if (typeSystem.canPromoteToType(potentialType, type)) {
+ // Do promote type of variable.
+ _promoteManager.setType(element, potentialType);
}
- // Declared type should not be "dynamic".
- if (type == null || type.isDynamic) {
- return;
- }
- // Promoted type should not be "dynamic".
- if (potentialType == null || potentialType.isDynamic) {
- return;
- }
- // Promoted type should be more specific than declared.
- if (!potentialType.isMoreSpecificThan(type)) {
- return;
- }
- // Do promote type of variable.
- _promoteManager.setType(element, potentialType);
}
}
@@ -9890,6 +9821,106 @@
_propagateTrueState(condition.expression);
}
}
+
+ /**
+ * Given an [argumentList] and the [parameters] related to the element that
+ * will be invoked using those arguments, compute the list of parameters that
+ * correspond to the list of arguments.
+ *
+ * An error will be reported to [onError] if any of the arguments cannot be
+ * matched to a parameter. onError can be null to ignore the error.
+ *
+ * The flag [reportAsError] should be `true` if a compile-time error should be
+ * reported; or `false` if a compile-time warning should be reported.
+ *
+ * Returns the parameters that correspond to the arguments. If no parameter
+ * matched an argument, that position will be `null` in the list.
+ */
+ static List<ParameterElement> resolveArgumentsToParameters(
+ ArgumentList argumentList,
+ List<ParameterElement> parameters,
+ void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
+ {bool reportAsError: false}) {
+ List<ParameterElement> requiredParameters = new List<ParameterElement>();
+ List<ParameterElement> positionalParameters = new List<ParameterElement>();
+ HashMap<String, ParameterElement> namedParameters =
+ new HashMap<String, ParameterElement>();
+ for (ParameterElement parameter in parameters) {
+ ParameterKind kind = parameter.parameterKind;
+ if (kind == ParameterKind.REQUIRED) {
+ requiredParameters.add(parameter);
+ } else if (kind == ParameterKind.POSITIONAL) {
+ positionalParameters.add(parameter);
+ } else {
+ namedParameters[parameter.name] = parameter;
+ }
+ }
+ List<ParameterElement> unnamedParameters =
+ new List<ParameterElement>.from(requiredParameters);
+ unnamedParameters.addAll(positionalParameters);
+ int unnamedParameterCount = unnamedParameters.length;
+ int unnamedIndex = 0;
+ NodeList<Expression> arguments = argumentList.arguments;
+ int argumentCount = arguments.length;
+ List<ParameterElement> resolvedParameters =
+ new List<ParameterElement>(argumentCount);
+ int positionalArgumentCount = 0;
+ HashSet<String> usedNames = new HashSet<String>();
+ bool noBlankArguments = true;
+ for (int i = 0; i < argumentCount; i++) {
+ Expression argument = arguments[i];
+ if (argument is NamedExpression) {
+ SimpleIdentifier nameNode = argument.name.label;
+ String name = nameNode.name;
+ ParameterElement element = namedParameters[name];
+ if (element == null) {
+ ErrorCode errorCode = (reportAsError
+ ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
+ : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
+ if (onError != null) {
+ onError(errorCode, nameNode, [name]);
+ }
+ } else {
+ resolvedParameters[i] = element;
+ nameNode.staticElement = element;
+ }
+ if (!usedNames.add(name)) {
+ if (onError != null) {
+ onError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode,
+ [name]);
+ }
+ }
+ } else {
+ if (argument is SimpleIdentifier && argument.name.isEmpty) {
+ noBlankArguments = false;
+ }
+ positionalArgumentCount++;
+ if (unnamedIndex < unnamedParameterCount) {
+ resolvedParameters[i] = unnamedParameters[unnamedIndex++];
+ }
+ }
+ }
+ if (positionalArgumentCount < requiredParameters.length &&
+ noBlankArguments) {
+ ErrorCode errorCode = (reportAsError
+ ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
+ : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
+ if (onError != null) {
+ onError(errorCode, argumentList,
+ [requiredParameters.length, positionalArgumentCount]);
+ }
+ } else if (positionalArgumentCount > unnamedParameterCount &&
+ noBlankArguments) {
+ ErrorCode errorCode = (reportAsError
+ ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
+ : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
+ if (onError != null) {
+ onError(errorCode, argumentList,
+ [unnamedParameterCount, positionalArgumentCount]);
+ }
+ }
+ return resolvedParameters;
+ }
}
/**
@@ -11981,9 +12012,6 @@
: CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
superclassType = _resolveType(extendsClause.superclass, errorCode,
CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
- if (!identical(superclassType, typeProvider.objectType)) {
- classElement.validMixin = false;
- }
}
if (classElement != null) {
if (superclassType == null) {
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index 4c756e2..a2b6325 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -6,7 +6,8 @@
import 'dart:collection';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/source.dart'
show ContentCache, Source, UriKind;
@@ -184,16 +185,20 @@
*/
LibraryMap get librariesMap => _librariesMap;
-
// To be backwards-compatible the new categories field is translated to
// an old approximation.
String convertCategories(String categories) {
switch (categories) {
- case "": return "Internal";
- case "Client": return "Client";
- case "Server": return "Server";
- case "Client,Server": return "Shared";
- case "Client,Server,Embedded": return "Shared";
+ case "":
+ return "Internal";
+ case "Client":
+ return "Client";
+ case "Server":
+ return "Server";
+ case "Client,Server":
+ return "Shared";
+ case "Client,Server,Embedded":
+ return "Shared";
}
return "Shared";
}
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index 863a3d4..a50eb95 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -7,8 +7,8 @@
import 'dart:collection';
import 'dart:io';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -255,20 +255,15 @@
@override
AnalysisContext get context {
if (_analysisContext == null) {
- SdkBundle sdkBundle = _getSummarySdkBundle();
- if (sdkBundle != null) {
- _analysisContext = new SummarySdkAnalysisContext(sdkBundle);
- } else {
- _analysisContext = new SdkAnalysisContext();
- }
+ _analysisContext = new SdkAnalysisContext();
SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
_analysisContext.sourceFactory = factory;
- List<String> uris = this.uris;
- ChangeSet changeSet = new ChangeSet();
- for (String uri in uris) {
- changeSet.addedSource(factory.forUri(uri));
+ // Try to use summaries.
+ SdkBundle sdkBundle = _getSummarySdkBundle();
+ if (sdkBundle != null) {
+ _analysisContext.resultProvider =
+ new SdkSummaryResultProvider(_analysisContext, sdkBundle);
}
- _analysisContext.applyChanges(changeSet);
}
return _analysisContext;
}
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 950f36e0..a3662f9 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -178,12 +178,12 @@
}
/**
- * Instances of the class `LineInfo` encapsulate information about line and column information
- * within a source file.
+ * Information about line and column information within a source file.
*/
class LineInfo {
/**
- * An array containing the offsets of the first character of each line in the source code.
+ * A list containing the offsets of the first character of each line in the
+ * source code.
*/
final List<int> _lineStarts;
@@ -194,12 +194,23 @@
int _previousLine = 0;
/**
- * Initialize a newly created set of line information to represent the data encoded in the given
- * array.
- *
- * @param lineStarts the offsets of the first character of each line in the source code
+ * Initialize a newly created set of line information to represent the data
+ * encoded in the given list of [_lineStarts].
*/
- LineInfo(this._lineStarts) {
+ factory LineInfo(List<int> _lineStarts) => new LineInfoWithCount(_lineStarts);
+
+ /**
+ * Initialize a newly created set of line information corresponding to the
+ * given file [content].
+ */
+ factory LineInfo.fromContent(String content) =>
+ new LineInfoWithCount(StringUtilities.computeLineStarts(content));
+
+ /**
+ * Initialize a newly created set of line information to represent the data
+ * encoded in the given list of [_lineStarts].
+ */
+ LineInfo._(this._lineStarts) {
if (_lineStarts == null) {
throw new IllegalArgumentException("lineStarts must be non-null");
} else if (_lineStarts.length < 1) {
@@ -208,10 +219,7 @@
}
/**
- * Return the location information for the character at the given offset.
- *
- * @param offset the offset of the character for which location information is to be returned
- * @return the location information for the character at the given offset
+ * Return the location information for the character at the given [offset].
*/
LineInfo_Location getLocation(int offset) {
var min = 0;
@@ -288,6 +296,26 @@
}
/**
+ * Information about line and column information within a source file,
+ * including a count of the total number of lines.
+ *
+ * TODO(paulberry): in the next major version roll of analyzer, merge this
+ * class into [LineInfo].
+ */
+class LineInfoWithCount extends LineInfo {
+ /**
+ * Initialize a newly created set of line information to represent the data
+ * encoded in the given list of [_lineStarts].
+ */
+ LineInfoWithCount(List<int> _lineStarts) : super._(_lineStarts);
+
+ /**
+ * Return the number of lines in the file.
+ */
+ int get lineCount => _lineStarts.length;
+}
+
+/**
* Instances of interface `LocalSourcePredicate` are used to determine if the given
* [Source] is "local" in some sense, so can be updated.
*/
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 28f42f7..e67d096 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -6,11 +6,12 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart';
@@ -281,11 +282,11 @@
// TODO(brianwilkerson) Determine whether this can still happen.
staticExpressionType = _dynamicType;
}
- DartType staticType = flattenFutures(_typeProvider, staticExpressionType);
+ DartType staticType = staticExpressionType.flattenFutures(_typeSystem);
_recordStaticType(node, staticType);
DartType propagatedExpressionType = node.expression.propagatedType;
DartType propagatedType =
- flattenFutures(_typeProvider, propagatedExpressionType);
+ propagatedExpressionType?.flattenFutures(_typeSystem);
_resolver.recordPropagatedTypeIfBetter(node, propagatedType);
return null;
}
@@ -495,6 +496,9 @@
*/
@override
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+ if (_strongMode) {
+ _inferFunctionInvocationGeneric(node);
+ }
DartType staticType = _computeInvokeReturnType(node.staticInvokeType);
_recordStaticType(node, staticType);
DartType functionPropagatedType = node.propagatedInvokeType;
@@ -713,12 +717,12 @@
Object visitMethodInvocation(MethodInvocation node) {
SimpleIdentifier methodNameNode = node.methodName;
Element staticMethodElement = methodNameNode.staticElement;
+ if (_strongMode) {
+ _inferMethodInvocation(node);
+ }
// Record types of the variable invoked as a function.
if (staticMethodElement is VariableElement) {
- VariableElement variable = staticMethodElement;
- DartType staticType = variable.type;
- _recordStaticType(methodNameNode, staticType);
- DartType propagatedType = _overrideManager.getType(variable);
+ DartType propagatedType = _overrideManager.getType(staticMethodElement);
_resolver.recordPropagatedTypeIfBetter(methodNameNode, propagatedType);
}
// Record static return type of the static element.
@@ -731,10 +735,7 @@
// Check for special cases.
bool needPropagatedType = true;
String methodName = methodNameNode.name;
- if (_strongMode) {
- _inferMethodInvocation(node);
- }
- if (methodName == "then") {
+ if (!_strongMode && methodName == "then") {
Expression target = node.realTarget;
if (target != null) {
DartType targetType = target.bestType;
@@ -753,16 +754,10 @@
_computePropagatedReturnType(closureExpr.element);
if (returnType != null) {
// prepare the type of the returned Future
- InterfaceTypeImpl newFutureType;
- if (_isAsyncFutureType(returnType)) {
- newFutureType = returnType as InterfaceTypeImpl;
- } else {
- InterfaceType futureType = targetType as InterfaceType;
- newFutureType = new InterfaceTypeImpl(futureType.element);
- newFutureType.typeArguments = <DartType>[returnType];
- }
+ InterfaceType newFutureType = _typeProvider.futureType
+ .substitute4([returnType.flattenFutures(_typeSystem)]);
// set the 'then' invocation type
- _recordPropagatedType(node, newFutureType);
+ _resolver.recordPropagatedTypeIfBetter(node, newFutureType);
needPropagatedType = false;
return null;
}
@@ -873,16 +868,21 @@
}
if (needPropagatedType) {
Element propagatedElement = methodNameNode.propagatedElement;
+ DartType propagatedInvokeType = node.propagatedInvokeType;
// HACK: special case for object methods ([toString]) on dynamic
// expressions. More special cases in [visitPrefixedIdentfier].
if (propagatedElement == null) {
- propagatedElement =
+ MethodElement objMethod =
_typeProvider.objectType.getMethod(methodNameNode.name);
+ if (objMethod != null) {
+ propagatedElement = objMethod;
+ propagatedInvokeType = objMethod.type;
+ }
}
if (!identical(propagatedElement, staticMethodElement)) {
// Record static return type of the propagated element.
DartType propagatedStaticType =
- _computeStaticReturnType(propagatedElement);
+ _computeInvokeReturnType(propagatedInvokeType);
_resolver.recordPropagatedTypeIfBetter(
node, propagatedStaticType, true);
// Record propagated return type of the propagated element.
@@ -1379,6 +1379,21 @@
}
/**
+ * Compute the return type of the method or function represented by the given
+ * type that is being invoked.
+ */
+ DartType _computeInvokeReturnType(DartType type) {
+ if (type is InterfaceType) {
+ MethodElement callMethod = type.lookUpMethod(
+ FunctionElement.CALL_METHOD_NAME, _resolver.definingLibrary);
+ return callMethod?.type?.returnType ?? _dynamicType;
+ } else if (type is FunctionType) {
+ return type.returnType ?? _dynamicType;
+ }
+ return _dynamicType;
+ }
+
+ /**
* Compute the propagated return type of the method or function represented by the given element.
*
* @param element the element representing the method or function invoked by the given node
@@ -1440,21 +1455,6 @@
}
/**
- * Compute the return type of the method or function represented by the given
- * type that is being invoked.
- */
- DartType _computeInvokeReturnType(DartType type) {
- if (type is InterfaceType) {
- MethodElement callMethod = type.lookUpMethod(
- FunctionElement.CALL_METHOD_NAME, _resolver.definingLibrary);
- return callMethod?.type?.returnType ?? _dynamicType;
- } else if (type is FunctionType) {
- return type.returnType ?? _dynamicType;
- }
- return _dynamicType;
- }
-
- /**
* Given a function declaration, compute the return static type of the function. The return type
* of functions with a block body is `dynamicType`, with an expression body it is the type
* of the expression.
@@ -1497,7 +1497,7 @@
}
if (body.isAsynchronous) {
return _typeProvider.futureType
- .substitute4(<DartType>[flattenFutures(_typeProvider, type)]);
+ .substitute4(<DartType>[type.flattenFutures(_typeSystem)]);
} else {
return type;
}
@@ -1769,6 +1769,63 @@
}
/**
+ * Similar to [_inferMethodInvocationGeneric] but for function expression
+ * invocations.
+ */
+ // TODO(jmesserly): if we had a common AST interface between these two nodes,
+ // we could remove this duplicated code.
+ bool _inferFunctionInvocationGeneric(FunctionExpressionInvocation node) {
+ DartType instantiatedType = node.staticInvokeType;
+ DartType originalType = node.function.staticType;
+ if (instantiatedType is FunctionType && originalType is FunctionType) {
+ FunctionType inferred = _inferGenericInvoke(instantiatedType,
+ originalType, node.typeArguments, node.argumentList);
+ if (inferred != null) {
+ node.staticInvokeType = inferred;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ FunctionType _inferGenericInvoke(FunctionType invokeType, FunctionType fnType,
+ TypeArgumentList typeArguments, ArgumentList argumentList) {
+ TypeSystem ts = _typeSystem;
+ if (typeArguments == null && ts is StrongTypeSystemImpl) {
+ if (fnType.typeFormals.isNotEmpty &&
+ ts.instantiateToBounds(fnType) == invokeType) {
+ // Get the parameters that correspond to the uninstantiated generic.
+ List<ParameterElement> rawParameters =
+ ResolverVisitor.resolveArgumentsToParameters(
+ argumentList, fnType.parameters, null);
+
+ List<DartType> paramTypes = <DartType>[];
+ List<DartType> argTypes = <DartType>[];
+ for (int i = 0, length = rawParameters.length; i < length; i++) {
+ ParameterElement parameter = rawParameters[i];
+ if (parameter != null) {
+ paramTypes.add(parameter.type);
+ argTypes.add(argumentList.arguments[i].staticType);
+ }
+ }
+
+ FunctionType inferred = ts.inferCallFromArguments(
+ _typeProvider, fnType, paramTypes, argTypes);
+
+ if (inferred != fnType) {
+ // Fix up the parameter elements based on inferred method.
+ List<ParameterElement> inferredParameters =
+ ResolverVisitor.resolveArgumentsToParameters(
+ argumentList, inferred.parameters, null);
+ argumentList.correspondingStaticParameters = inferredParameters;
+ return inferred;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Given a local variable declaration and its initializer, attempt to infer
* a type for the local variable declaration based on the initializer.
* Inference is only done if an explicit type is not present, and if
@@ -1802,42 +1859,17 @@
* type variables, using the actual types of the arguments.
*/
bool _inferMethodInvocationGeneric(MethodInvocation node) {
- Element element = node.methodName.staticElement;
- DartType invokeType = node.staticInvokeType;
-
- TypeSystem ts = _typeSystem;
- if (node.typeArguments == null &&
- element is ExecutableElement &&
- ts is StrongTypeSystemImpl) {
- FunctionType fnType = element.type;
- if (fnType.typeFormals.isNotEmpty &&
- ts.instantiateToBounds(fnType) == invokeType) {
- // Get the parameters that correspond to the uninstantiated generic.
- List<ParameterElement> genericParameters =
- ResolverVisitor.resolveArgumentsToParameters(
- node.argumentList, fnType.parameters, null);
-
- int length = genericParameters.length;
- List<DartType> argTypes = new List<DartType>(length);
- List<DartType> paramTypes = new List<DartType>(length);
- for (int i = 0; i < length; i++) {
- argTypes[i] = node.argumentList.arguments[i].staticType;
- paramTypes[i] = genericParameters[i].type;
- }
-
- FunctionType inferred = ts.inferCallFromArguments(
- _typeProvider, fnType, paramTypes, argTypes);
-
- if (inferred != fnType) {
- // Fix up the parameter elements based on inferred method.
- List<ParameterElement> inferredParameters =
- ResolverVisitor.resolveArgumentsToParameters(
- node.argumentList, inferred.parameters, null);
- node.argumentList.correspondingStaticParameters = inferredParameters;
- node.staticInvokeType = inferred;
- _recordStaticType(node, inferred.returnType);
- return true;
- }
+ DartType instantiatedType = node.staticInvokeType;
+ DartType originalType = node.methodName.staticType;
+ // TODO(jmesserly): support generic `call` methods.
+ // Perhaps we should always record a FunctionType in staticInvokeType
+ // and the methodName's staticType.
+ if (instantiatedType is FunctionType && originalType is FunctionType) {
+ FunctionType inferred = _inferGenericInvoke(instantiatedType,
+ originalType, node.typeArguments, node.argumentList);
+ if (inferred != null) {
+ node.staticInvokeType = inferred;
+ return true;
}
}
return false;
@@ -1890,7 +1922,7 @@
return false;
}
DartType inferredType = inferredElement.type;
- DartType nodeType = node.staticType;
+ DartType nodeType = node.staticInvokeType;
if (nodeType != null &&
nodeType.isDynamic &&
inferredType is FunctionType &&
@@ -2082,47 +2114,6 @@
}
/**
- * Implements the function "flatten" defined in the spec:
- *
- * If T = Future<S> then flatten(T) = flatten(S).
- *
- * Otherwise if T <: Future then let S be a type such that T << Future<S>
- * and for all R, if T << Future<R> then S << R. Then flatten(T) = S.
- *
- * In any other circumstance, flatten(T) = T.
- */
- static DartType flattenFutures(TypeProvider typeProvider, DartType type) {
- if (type is InterfaceType) {
- // Implement the case: "If T = Future<S> then flatten(T) = flatten(S)."
- if (type.element == typeProvider.futureType.element &&
- type.typeArguments.length > 0) {
- return flattenFutures(typeProvider, type.typeArguments[0]);
- }
-
- // Implement the case: "Otherwise if T <: Future then let S be a type
- // such that T << Future<S> and for all R, if T << Future<R> then S << R.
- // Then flatten(T) = S."
- //
- // In other words, given the set of all types R such that T << Future<R>,
- // let S be the most specific of those types, if any such S exists.
- //
- // Since we only care about the most specific type, it is sufficent to
- // look at the types appearing as a parameter to Future in the type
- // hierarchy of T. We don't need to consider the supertypes of those
- // types, since they are by definition less specific.
- List<DartType> candidateTypes =
- _searchTypeHierarchyForFutureParameters(typeProvider, type);
- DartType flattenResult = _findMostSpecificType(candidateTypes);
- if (flattenResult != null) {
- return flattenResult;
- }
- }
-
- // Implement the case: "In any other circumstance, flatten(T) = T."
- return type;
- }
-
- /**
* Create a table mapping HTML tag names to the names of the classes (in 'dart:html') that
* implement those tags.
*
@@ -2190,88 +2181,6 @@
map["video"] = "VideoElement";
return map;
}
-
- /**
- * If there is a single type which is at least as specific as all of the
- * types in [types], return it. Otherwise return `null`.
- */
- static DartType _findMostSpecificType(List<DartType> types) {
- // The << relation ("more specific than") is a partial ordering on types,
- // so to find the most specific type of a set, we keep a bucket of the most
- // specific types seen so far such that no type in the bucket is more
- // specific than any other type in the bucket.
- List<DartType> bucket = <DartType>[];
-
- // Then we consider each type in turn.
- for (DartType type in types) {
- // If any existing type in the bucket is more specific than this type,
- // then we can ignore this type.
- if (bucket.any((DartType t) => t.isMoreSpecificThan(type))) {
- continue;
- }
- // Otherwise, we need to add this type to the bucket and remove any types
- // that are less specific than it.
- bool added = false;
- int i = 0;
- while (i < bucket.length) {
- if (type.isMoreSpecificThan(bucket[i])) {
- if (added) {
- if (i < bucket.length - 1) {
- bucket[i] = bucket.removeLast();
- } else {
- bucket.removeLast();
- }
- } else {
- bucket[i] = type;
- i++;
- added = true;
- }
- } else {
- i++;
- }
- }
- if (!added) {
- bucket.add(type);
- }
- }
-
- // Now that we are finished, if there is exactly one type left in the
- // bucket, it is the most specific type.
- if (bucket.length == 1) {
- return bucket[0];
- }
-
- // Otherwise, there is no single type that is more specific than the
- // others.
- return null;
- }
-
- /**
- * Given a seed type [type], search its class hierarchy for types of the form
- * Future<R>, and return a list of the resulting R's.
- */
- static List<DartType> _searchTypeHierarchyForFutureParameters(
- TypeProvider typeProvider, InterfaceType type) {
- List<DartType> result = <DartType>[];
- HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
- void recurse(InterfaceType type) {
- if (type.element == typeProvider.futureType.element &&
- type.typeArguments.length > 0) {
- result.add(type.typeArguments[0]);
- }
- if (visitedClasses.add(type.element)) {
- if (type.superclass != null) {
- recurse(type.superclass);
- }
- for (InterfaceType interface in type.interfaces) {
- recurse(interface);
- }
- visitedClasses.remove(type.element);
- }
- }
- recurse(type);
- return result;
- }
}
class _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
index c6892c2..c77192c 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
@@ -4,8 +4,9 @@
library analyzer.src.generated.testing.ast_factory;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 0dc3c7b..38c322e 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -6,11 +6,11 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -100,6 +100,7 @@
ConstructorElementImpl constructor = name == null
? new ConstructorElementImpl("", -1)
: new ConstructorElementImpl(name, 0);
+ constructor.synthetic = name == null;
constructor.const2 = isConst;
if (argumentTypes != null) {
int count = argumentTypes.length;
@@ -405,11 +406,12 @@
field.type = type;
field.final2 = true;
PropertyAccessorElementImpl getter =
- new PropertyAccessorElementImpl.forVariable(field);
+ new PropertyAccessorElementImpl(name, 0);
getter.synthetic = false;
getter.getter = true;
getter.variable = field;
getter.returnType = type;
+ getter.static = isStatic;
field.getter = getter;
FunctionTypeImpl getterType = new FunctionTypeImpl(getter);
getter.type = getterType;
@@ -559,8 +561,14 @@
if (isConst) {
ConstTopLevelVariableElementImpl constant =
new ConstTopLevelVariableElementImpl(AstFactory.identifier3(name));
- constant.constantInitializer = AstFactory.instanceCreationExpression2(
+ InstanceCreationExpression initializer = AstFactory.instanceCreationExpression2(
Keyword.CONST, AstFactory.typeName(type.element));
+ if (type is InterfaceType) {
+ ConstructorElement element = type.element.unnamedConstructor;
+ initializer.staticElement = element;
+ initializer.constructorName.staticElement = element;
+ }
+ constant.constantInitializer = initializer;
variable = constant;
} else {
variable = new TopLevelVariableElementImpl(name, -1);
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index 5f1a49b..4bf5cc9 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -4,14 +4,17 @@
library analyzer.src.generated.testing.test_type_provider;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
+import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/generated/testing/ast_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
@@ -150,6 +153,14 @@
*/
DartType _undefinedType;
+ /**
+ * The analysis context, if any. Used to create an appropriate 'dart:async'
+ * library to back `Future<T>`.
+ */
+ AnalysisContext _context;
+
+ TestTypeProvider([this._context]);
+
@override
InterfaceType get boolType {
if (_boolType == null) {
@@ -181,8 +192,8 @@
if (_deprecatedType == null) {
ClassElementImpl deprecatedElement =
ElementFactory.classElement2("Deprecated");
- ConstructorElementImpl constructor = ElementFactory.constructorElement(
- deprecatedElement, null, true, [stringType]);
+ ConstructorElementImpl constructor = ElementFactory
+ .constructorElement(deprecatedElement, '', true, [stringType]);
constructor.constantInitializers = <ConstructorInitializer>[
AstFactory.constructorFieldInitializer(
true, 'expires', AstFactory.identifier3('expires'))
@@ -240,7 +251,18 @@
@override
InterfaceType get futureType {
if (_futureType == null) {
- _futureType = ElementFactory.classElement2("Future", ["T"]).type;
+ Source asyncSource = _context.sourceFactory.forUri(DartSdk.DART_ASYNC);
+ _context.setContents(asyncSource, "");
+ CompilationUnitElementImpl asyncUnit =
+ new CompilationUnitElementImpl("async.dart");
+ LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
+ _context, AstFactory.libraryIdentifier2(["dart.async"]));
+ asyncLibrary.definingCompilationUnit = asyncUnit;
+ asyncUnit.librarySource = asyncUnit.source = asyncSource;
+
+ ClassElementImpl future = ElementFactory.classElement2("Future", ["T"]);
+ _futureType = future.type;
+ asyncUnit.types = <ClassElement>[future];
}
return _futureType;
}
@@ -274,7 +296,7 @@
ElementFactory.getterElement("last", false, eType)
]);
iterableElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(iterableElement, null, true)
+ ElementFactory.constructorElement(iterableElement, '', true)
..isCycleFree = true
];
_propagateTypeArguments(iterableElement);
@@ -317,8 +339,8 @@
]);
listElement.methods = <MethodElement>[
ElementFactory.methodElement("[]", eType, [intType]),
- ElementFactory.methodElement(
- "[]=", VoidTypeImpl.instance, [intType, eType]),
+ ElementFactory
+ .methodElement("[]=", VoidTypeImpl.instance, [intType, eType]),
ElementFactory.methodElement("add", VoidTypeImpl.instance, [eType])
];
_propagateTypeArguments(listElement);
@@ -339,11 +361,11 @@
]);
mapElement.methods = <MethodElement>[
ElementFactory.methodElement("[]", vType, [objectType]),
- ElementFactory.methodElement(
- "[]=", VoidTypeImpl.instance, [kType, vType])
+ ElementFactory
+ .methodElement("[]=", VoidTypeImpl.instance, [kType, vType])
];
mapElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(mapElement, null, false)
+ ElementFactory.constructorElement(mapElement, '', false)
..external = true
..factory = true
];
@@ -397,7 +419,7 @@
ClassElementImpl objectElement = ElementFactory.object;
_objectType = objectElement.type;
ConstructorElementImpl constructor =
- ElementFactory.constructorElement(objectElement, null, true);
+ ElementFactory.constructorElement(objectElement, '', true);
constructor.constantInitializers = <ConstructorInitializer>[];
objectElement.constructors = <ConstructorElement>[constructor];
objectElement.methods = <MethodElement>[
@@ -475,8 +497,8 @@
InterfaceType get symbolType {
if (_symbolType == null) {
ClassElementImpl symbolClass = ElementFactory.classElement2("Symbol");
- ConstructorElementImpl constructor = ElementFactory.constructorElement(
- symbolClass, null, true, [stringType]);
+ ConstructorElementImpl constructor = ElementFactory
+ .constructorElement(symbolClass, '', true, [stringType]);
constructor.factory = true;
constructor.isCycleFree = true;
symbolClass.constructors = <ConstructorElement>[constructor];
@@ -555,10 +577,10 @@
ElementFactory.methodElement("toInt", _intType),
ElementFactory.methodElement("toDouble", _doubleType),
ElementFactory.methodElement("toStringAsFixed", _stringType, [_intType]),
- ElementFactory.methodElement(
- "toStringAsExponential", _stringType, [_intType]),
- ElementFactory.methodElement(
- "toStringAsPrecision", _stringType, [_intType]),
+ ElementFactory
+ .methodElement("toStringAsExponential", _stringType, [_intType]),
+ ElementFactory
+ .methodElement("toStringAsPrecision", _stringType, [_intType]),
ElementFactory.methodElement("toRadixString", _stringType, [_intType])
];
intElement.methods = <MethodElement>[
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 911dfa9..b85205c 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -29,6 +29,12 @@
return ft.parameters.any((p) => predicate(p.type));
}
+ @override
+ bool canPromoteToType(DartType to, DartType from) => isSubtypeOf(to, from);
+
+ @override
+ bool isMoreSpecificThan(DartType t1, DartType t2) => isSubtypeOf(t1, t2);
+
/**
* Given a type t, if t is an interface type with a call method
* defined, return the function type for the call method, otherwise
@@ -563,6 +569,25 @@
*/
abstract class TypeSystem {
/**
+ * Returns `true` if we can promote to the first type from the second type.
+ *
+ * In the standard Dart type system, it is not possible to promote from or to
+ * `dynamic`, and we must be promoting to a more specific type, see
+ * [isMoreSpecificThan].
+ *
+ * In strong mode, this is equivalent to [isSubtypeOf].
+ */
+ bool canPromoteToType(DartType to, DartType from);
+
+ /**
+ * Return `true` if the [leftType] is more specific than the [rightType]
+ * (that is, if leftType << rightType), as defined in the Dart language spec.
+ *
+ * In strong mode, this is equivalent to [isSubtypeOf].
+ */
+ bool isMoreSpecificThan(DartType leftType, DartType rightType);
+
+ /**
* Compute the least upper bound of two types.
*/
DartType getLeastUpperBound(
@@ -606,6 +631,18 @@
TypeSystemImpl();
@override
+ bool isMoreSpecificThan(DartType t1, DartType t2) =>
+ t1.isMoreSpecificThan(t2);
+
+ @override
+ bool canPromoteToType(DartType to, DartType from) {
+ // Declared type should not be "dynamic".
+ // Promoted type should not be "dynamic".
+ // Promoted type should be more specific than declared.
+ return !from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from);
+ }
+
+ @override
DartType getLeastUpperBound(
TypeProvider typeProvider, DartType type1, DartType type2) {
// The least upper bound relation is reflexive.
diff --git a/pkg/analyzer/lib/src/generated/visitors.dart b/pkg/analyzer/lib/src/generated/visitors.dart
index 46e2a41..31e5ddc 100644
--- a/pkg/analyzer/lib/src/generated/visitors.dart
+++ b/pkg/analyzer/lib/src/generated/visitors.dart
@@ -4,7 +4,7 @@
library analyzer.src.generated.visitors;
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
/// An [AstVisitor] that delegates calls to visit methods to all [delegates]
/// before calling [visitChildren].
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 07b0def..c2ad576 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -14,6 +14,7 @@
import 'package:analyzer/src/task/html.dart';
import 'package:analyzer/src/task/html_work_manager.dart';
import 'package:analyzer/src/task/options_work_manager.dart';
+import 'package:analyzer/src/task/yaml.dart';
import 'package:analyzer/task/model.dart';
import 'package:plugin/plugin.dart';
@@ -240,6 +241,10 @@
registerExtension(taskId, DartScriptsTask.DESCRIPTOR);
registerExtension(taskId, HtmlErrorsTask.DESCRIPTOR);
registerExtension(taskId, ParseHtmlTask.DESCRIPTOR);
+ //
+ // Register YAML tasks.
+ //
+ registerExtension(taskId, ParseYamlTask.DESCRIPTOR);
}
void _registerWorkManagerFactoryExtensions(
diff --git a/pkg/analyzer/lib/src/services/lint.dart b/pkg/analyzer/lib/src/services/lint.dart
index 91d72a2..953741b 100644
--- a/pkg/analyzer/lib/src/services/lint.dart
+++ b/pkg/analyzer/lib/src/services/lint.dart
@@ -4,7 +4,7 @@
library analyzer.src.services.lint;
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/lib/src/summary/flat_buffers.dart b/pkg/analyzer/lib/src/summary/flat_buffers.dart
index 3c7de13..c56b298 100644
--- a/pkg/analyzer/lib/src/summary/flat_buffers.dart
+++ b/pkg/analyzer/lib/src/summary/flat_buffers.dart
@@ -49,6 +49,9 @@
return new BufferPointer._(_buffer, _offset + delta);
}
+ double _getFloat64([int delta = 0]) =>
+ _buffer.getFloat64(_offset + delta, Endianness.LITTLE_ENDIAN);
+
int _getInt32([int delta = 0]) =>
_buffer.getInt32(_offset + delta, Endianness.LITTLE_ENDIAN);
@@ -175,6 +178,22 @@
}
/**
+ * Add the [field] with the given 32-bit unsigned integer [value]. The field
+ * is not added if the [value] is equal to [def].
+ */
+ void addUint32(int field, int value, [int def]) {
+ if (_currentVTable == null) {
+ throw new StateError('Start a table before adding values.');
+ }
+ if (value != null && value != def) {
+ int size = 4;
+ _prepare(size, 1);
+ _trackField(field);
+ _setUint32AtTail(_buf, _tail, value);
+ }
+ }
+
+ /**
* End the current table and return its offset.
*/
Offset endTable() {
@@ -299,6 +318,26 @@
}
/**
+ * Write the given list of 64-bit float [values].
+ */
+ Offset writeListFloat64(List<double> values) {
+ if (_currentVTable != null) {
+ throw new StateError(
+ 'Cannot write a non-scalar value while writing a table.');
+ }
+ _prepare(8, 1 + values.length);
+ Offset result = new Offset(_tail);
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= 8;
+ for (double value in values) {
+ _setFloat64AtTail(_buf, tail, value);
+ tail -= 8;
+ }
+ return result;
+ }
+
+ /**
* Write the given list of signed 32-bit integer [values].
*/
Offset writeListInt32(List<int> values) {
@@ -319,6 +358,26 @@
}
/**
+ * Write the given list of unsigned 32-bit integer [values].
+ */
+ Offset writeListUint32(List<int> values) {
+ if (_currentVTable != null) {
+ throw new StateError(
+ 'Cannot write a non-scalar value while writing a table.');
+ }
+ _prepare(4, 1 + values.length);
+ Offset result = new Offset(_tail);
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= 4;
+ for (int value in values) {
+ _setUint32AtTail(_buf, tail, value);
+ tail -= 4;
+ }
+ return result;
+ }
+
+ /**
* Write the given string [value] and return its [Offset], or `null` if
* the [value] is equal to [def].
*/
@@ -383,6 +442,10 @@
_currentVTable.addField(field, _tail);
}
+ static void _setFloat64AtTail(ByteData _buf, int tail, double x) {
+ _buf.setFloat64(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
static void _setInt32AtTail(ByteData _buf, int tail, int x) {
_buf.setInt32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
}
@@ -393,7 +456,22 @@
}
/**
- * The reader of 32-bit signed integers.
+ * The reader of lists of 64-bit float values.
+ *
+ * The returned unmodifiable lists lazily read values on access.
+ */
+class Float64ListReader extends Reader<List<double>> {
+ const Float64ListReader();
+
+ @override
+ int get size => 4;
+
+ @override
+ List<double> read(BufferPointer bp) => new _FbFloat64List(bp.derefObject());
+}
+
+/**
+ * The reader of signed 32-bit integers.
*/
class Int32Reader extends Reader<int> {
const Int32Reader() : super();
@@ -433,7 +511,7 @@
@override
List<E> read(BufferPointer bp) =>
- new _FbList<E>(_elementReader, bp.derefObject());
+ new _FbInt32List<E>(_elementReader, bp.derefObject());
}
/**
@@ -519,14 +597,29 @@
}
}
-class _FbList<E> extends Object with ListMixin<E> implements List<E> {
- final Reader<E> elementReader;
+/**
+ * The reader of unsigned 32-bit integers.
+ */
+class Uint32Reader extends Reader<int> {
+ const Uint32Reader() : super();
+
+ @override
+ int get size => 4;
+
+ @override
+ int read(BufferPointer bp) => bp._getUint32();
+}
+
+/**
+ * The list backed by 64-bit values - Uint64 length and Float64.
+ */
+class _FbFloat64List extends _FbList<double> {
final BufferPointer bp;
int _length;
- List<E> _items;
+ List<double> _items;
- _FbList(this.elementReader, this.bp);
+ _FbFloat64List(this.bp);
@override
int get length {
@@ -535,20 +628,56 @@
}
@override
- void set length(int i) =>
- throw new StateError('Attempt to modify immutable list');
+ double operator [](int i) {
+ _items ??= new List<double>(length);
+ double item = _items[i];
+ if (item == null) {
+ BufferPointer ref = bp._advance(8 + 8 * i);
+ item = ref._getFloat64();
+ _items[i] = item;
+ }
+ return item;
+ }
+}
+
+/**
+ * The list backed by 32-bit values - offsets or integers.
+ */
+class _FbInt32List<E> extends _FbList<E> {
+ final Reader<E> elementReader;
+ final BufferPointer bp;
+
+ int _length;
+ List<E> _items;
+
+ _FbInt32List(this.elementReader, this.bp);
+
+ @override
+ int get length {
+ _length ??= bp._getUint32();
+ return _length;
+ }
@override
E operator [](int i) {
_items ??= new List<E>(length);
E item = _items[i];
if (item == null) {
- BufferPointer ref = bp._advance(4 + elementReader.size * i);
+ BufferPointer ref = bp._advance(4 + 4 * i);
item = elementReader.read(ref);
_items[i] = item;
}
return item;
}
+}
+
+/**
+ * The base class for immutable lists read from flat buffers.
+ */
+abstract class _FbList<E> extends Object with ListMixin<E> implements List<E> {
+ @override
+ void set length(int i) =>
+ throw new StateError('Attempt to modify immutable list');
@override
void operator []=(int i, E e) =>
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 97f9db6..4a0424b 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -12,42 +12,661 @@
/**
* Enum used to indicate the kind of entity referred to by a
- * [PrelinkedReference].
+ * [LinkedReference].
*/
-enum PrelinkedReferenceKind {
+enum ReferenceKind {
+ /**
+ * The entity is a class or enum.
+ */
classOrEnum,
+
+ /**
+ * The entity is a constructor.
+ */
+ constructor,
+
+ /**
+ * The entity is a static const field.
+ */
+ constField,
+
+ /**
+ * The entity is a static method.
+ */
+ staticMethod,
+
+ /**
+ * The `length` property access.
+ */
+ length,
+
+ /**
+ * The entity is a typedef.
+ */
typedef,
- other,
+
+ /**
+ * The entity is a top level function.
+ */
+ topLevelFunction,
+
+ /**
+ * The entity is a top level getter or setter.
+ */
+ topLevelPropertyAccessor,
+
+ /**
+ * The entity is a prefix.
+ */
prefix,
- unresolved,
+
+ /**
+ * The entity being referred to does not exist.
+ */
+ unresolved
+}
+
+class _ReferenceKindReader extends fb.Reader<ReferenceKind> {
+ const _ReferenceKindReader() : super();
+
+ @override
+ int get size => 4;
+
+ @override
+ ReferenceKind read(fb.BufferPointer bp) {
+ int index = const fb.Uint32Reader().read(bp);
+ return ReferenceKind.values[index];
+ }
+}
+
+/**
+ * Enum representing the various kinds of operations which may be performed to
+ * produce a constant value. These options are assumed to execute in the
+ * context of a stack which is initially empty.
+ */
+enum UnlinkedConstOperation {
+ /**
+ * Push the value of the n-th constructor argument (where n is obtained from
+ * [UnlinkedConst.ints]) onto the stack.
+ */
+ pushArgument,
+
+ /**
+ * Push the next value from [UnlinkedConst.ints] (a 32-bit unsigned integer)
+ * onto the stack.
+ *
+ * Note that Dart supports integers larger than 32 bits; these are
+ * represented by composing 32 bit values using the [shiftOr] operation.
+ */
+ pushInt,
+
+ /**
+ * Pop the top value off the stack, which should be an integer. Multiply it
+ * by 2^32, "or" in the next value from [UnlinkedConst.ints] (which is
+ * interpreted as a 32-bit unsigned integer), and push the result back onto
+ * the stack.
+ */
+ shiftOr,
+
+ /**
+ * Push the next value from [UnlinkedConst.doubles] (a double precision
+ * floating point value) onto the stack.
+ */
+ pushDouble,
+
+ /**
+ * Push the constant `true` onto the stack.
+ */
+ pushTrue,
+
+ /**
+ * Push the constant `false` onto the stack.
+ */
+ pushFalse,
+
+ /**
+ * Push the next value from [UnlinkedConst.strings] onto the stack.
+ */
+ pushString,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), convert them to strings (if they aren't already),
+ * concatenate them into a single string, and push it back onto the stack.
+ *
+ * This operation is used to represent constants whose value is a literal
+ * string containing string interpolations.
+ */
+ concatenate,
+
+ /**
+ * Pop the top value from the stack which should be string, convert it to
+ * a symbol, and push it back onto the stack.
+ */
+ makeSymbol,
+
+ /**
+ * Push the constant `null` onto the stack.
+ */
+ pushNull,
+
+ /**
+ * Evaluate a (potentially qualified) identifier expression and push the
+ * resulting value onto the stack. The identifier to be evaluated is
+ * obtained from [UnlinkedConst.references].
+ *
+ * This operation is used to represent the following kinds of constants
+ * (which are indistinguishable from an unresolved AST alone):
+ *
+ * - A qualified reference to a static constant variable (e.g. `C.v`, where
+ * C is a class and `v` is a constant static variable in `C`).
+ * - An identifier expression referring to a constant variable.
+ * - A simple or qualified identifier denoting a class or type alias.
+ * - A simple or qualified identifier denoting a top-level function or a
+ * static method.
+ */
+ pushReference,
+
+ /**
+ * Pop the top `n` values from the stack (where `n` is obtained from
+ * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
+ * `n` values from [UnlinkedConst.strings] and use the lists of names and
+ * values to create named arguments. Then pop the top `m` values from the
+ * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
+ * from the end) and use them as positional arguments. Use the lists of
+ * positional and names arguments to invoke a constant constructor obtained
+ * from [UnlinkedConst.references], and push the resulting value back onto the
+ * stack.
+ *
+ * Note that for an invocation of the form `const a.b(...)` (where no type
+ * arguments are specified), it is impossible to tell from the unresolved AST
+ * alone whether `a` is a class name and `b` is a constructor name, or `a` is
+ * a prefix name and `b` is a class name. For consistency between AST based
+ * and elements based summaries, references to default constructors are always
+ * recorded as references to corresponding classes.
+ */
+ invokeConstructor,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), place them in a [List], and push the result back
+ * onto the stack. The type parameter for the [List] is implicitly `dynamic`.
+ */
+ makeUntypedList,
+
+ /**
+ * Pop the top 2*n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+ * [Map], and push the result back onto the stack. The two type parameters
+ * for the [Map] are implicitly `dynamic`.
+ */
+ makeUntypedMap,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), place them in a [List], and push the result back
+ * onto the stack. The type parameter for the [List] is obtained from
+ * [UnlinkedConst.references].
+ */
+ makeTypedList,
+
+ /**
+ * Pop the top 2*n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+ * [Map], and push the result back onto the stack. The two type parameters for
+ * the [Map] are obtained from [UnlinkedConst.references].
+ */
+ makeTypedMap,
+
+ /**
+ * Pop the top 2 values from the stack, pass them to the predefined Dart
+ * function `identical`, and push the result back onto the stack.
+ */
+ identical,
+
+ /**
+ * Pop the top 2 values from the stack, evaluate `v1 == v2`, and push the
+ * result back onto the stack.
+ *
+ * This is also used to represent `v1 != v2`, by composition with [not].
+ */
+ equal,
+
+ /**
+ * Pop the top value from the stack, compute its boolean negation, and push
+ * the result back onto the stack.
+ */
+ not,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 && v2`, and push the
+ * result back onto the stack.
+ */
+ and,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 || v2`, and push the
+ * result back onto the stack.
+ */
+ or,
+
+ /**
+ * Pop the top value from the stack, compute its integer complement, and push
+ * the result back onto the stack.
+ */
+ complement,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 ^ v2`, and push the
+ * result back onto the stack.
+ */
+ bitXor,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 & v2`, and push the
+ * result back onto the stack.
+ */
+ bitAnd,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 | v2`, and push the
+ * result back onto the stack.
+ */
+ bitOr,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 >> v2`, and push the
+ * result back onto the stack.
+ */
+ bitShiftRight,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 << v2`, and push the
+ * result back onto the stack.
+ */
+ bitShiftLeft,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 + v2`, and push the
+ * result back onto the stack.
+ */
+ add,
+
+ /**
+ * Pop the top value from the stack, compute its integer negation, and push
+ * the result back onto the stack.
+ */
+ negate,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 - v2`, and push the
+ * result back onto the stack.
+ */
+ subtract,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 * v2`, and push the
+ * result back onto the stack.
+ */
+ multiply,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 / v2`, and push the
+ * result back onto the stack.
+ */
+ divide,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 ~/ v2`, and push the
+ * result back onto the stack.
+ */
+ floorDivide,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 > v2`, and push the
+ * result back onto the stack.
+ */
+ greater,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 < v2`, and push the
+ * result back onto the stack.
+ */
+ less,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 >= v2`, and push the
+ * result back onto the stack.
+ */
+ greaterEqual,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 <= v2`, and push the
+ * result back onto the stack.
+ */
+ lessEqual,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 % v2`, and push the
+ * result back onto the stack.
+ */
+ modulo,
+
+ /**
+ * Pop the top 3 values from the stack, compute `v1 ? v2 : v3`, and push the
+ * result back onto the stack.
+ */
+ conditional,
+
+ /**
+ * Pop the top value from the stack, evaluate `v.length`, and push the result
+ * back onto the stack.
+ */
+ length
+}
+
+class _UnlinkedConstOperationReader extends fb.Reader<UnlinkedConstOperation> {
+ const _UnlinkedConstOperationReader() : super();
+
+ @override
+ int get size => 4;
+
+ @override
+ UnlinkedConstOperation read(fb.BufferPointer bp) {
+ int index = const fb.Uint32Reader().read(bp);
+ return UnlinkedConstOperation.values[index];
+ }
}
/**
* Enum used to indicate the kind of an executable.
*/
enum UnlinkedExecutableKind {
+ /**
+ * Executable is a function or method.
+ */
functionOrMethod,
+
+ /**
+ * Executable is a getter.
+ */
getter,
+
+ /**
+ * Executable is a setter.
+ */
setter,
- constructor,
+
+ /**
+ * Executable is a constructor.
+ */
+ constructor
+}
+
+class _UnlinkedExecutableKindReader extends fb.Reader<UnlinkedExecutableKind> {
+ const _UnlinkedExecutableKindReader() : super();
+
+ @override
+ int get size => 4;
+
+ @override
+ UnlinkedExecutableKind read(fb.BufferPointer bp) {
+ int index = const fb.Uint32Reader().read(bp);
+ return UnlinkedExecutableKind.values[index];
+ }
}
/**
* Enum used to indicate the kind of a parameter.
*/
enum UnlinkedParamKind {
+ /**
+ * Parameter is required.
+ */
required,
+
+ /**
+ * Parameter is positional optional (enclosed in `[]`)
+ */
positional,
- named,
+
+ /**
+ * Parameter is named optional (enclosed in `{}`)
+ */
+ named
}
-class PrelinkedDependencyBuilder {
+class _UnlinkedParamKindReader extends fb.Reader<UnlinkedParamKind> {
+ const _UnlinkedParamKindReader() : super();
+
+ @override
+ int get size => 4;
+
+ @override
+ UnlinkedParamKind read(fb.BufferPointer bp) {
+ int index = const fb.Uint32Reader().read(bp);
+ return UnlinkedParamKind.values[index];
+ }
+}
+
+class EntityRefBuilder extends Object with _EntityRefMixin implements EntityRef {
+ bool _finished = false;
+
+ int _slot;
+ int _reference;
+ int _paramReference;
+ List<EntityRefBuilder> _typeArguments;
+
+ @override
+ int get slot => _slot ??= 0;
+
+ /**
+ * If this [EntityRef] is contained within [LinkedUnit.types], slot id (which
+ * is unique within the compilation unit) identifying the target of type
+ * propagation or type inference with which this [EntityRef] is associated.
+ *
+ * Otherwise zero.
+ */
+ void set slot(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _slot = _value;
+ }
+
+ @override
+ int get reference => _reference ??= 0;
+
+ /**
+ * Index into [UnlinkedUnit.references] for the entity being referred to, or
+ * zero if this is a reference to a type parameter.
+ */
+ void set reference(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _reference = _value;
+ }
+
+ @override
+ int get paramReference => _paramReference ??= 0;
+
+ /**
+ * If this is a reference to a type parameter, one-based index into the list
+ * of [UnlinkedTypeParam]s currently in effect. Indexing is done using De
+ * Bruijn index conventions; that is, innermost parameters come first, and
+ * if a class or method has multiple parameters, they are indexed from right
+ * to left. So for instance, if the enclosing declaration is
+ *
+ * class C<T,U> {
+ * m<V,W> {
+ * ...
+ * }
+ * }
+ *
+ * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
+ * respectively.
+ *
+ * If the type being referred to is not a type parameter, [paramReference] is
+ * zero.
+ */
+ void set paramReference(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _paramReference = _value;
+ }
+
+ @override
+ List<EntityRefBuilder> get typeArguments => _typeArguments ??= <EntityRefBuilder>[];
+
+ /**
+ * If this is an instantiation of a generic type or generic executable, the
+ * type arguments used to instantiate it. Trailing type arguments of type
+ * `dynamic` are omitted.
+ */
+ void set typeArguments(List<EntityRefBuilder> _value) {
+ assert(!_finished);
+ _typeArguments = _value;
+ }
+
+ EntityRefBuilder({int slot, int reference, int paramReference, List<EntityRefBuilder> typeArguments})
+ : _slot = slot,
+ _reference = reference,
+ _paramReference = paramReference,
+ _typeArguments = typeArguments;
+
+ fb.Offset finish(fb.Builder fbBuilder) {
+ assert(!_finished);
+ _finished = true;
+ fb.Offset offset_typeArguments;
+ if (!(_typeArguments == null || _typeArguments.isEmpty)) {
+ offset_typeArguments = fbBuilder.writeList(_typeArguments.map((b) => b.finish(fbBuilder)).toList());
+ }
+ fbBuilder.startTable();
+ if (_slot != null && _slot != 0) {
+ fbBuilder.addUint32(0, _slot);
+ }
+ if (_reference != null && _reference != 0) {
+ fbBuilder.addUint32(1, _reference);
+ }
+ if (_paramReference != null && _paramReference != 0) {
+ fbBuilder.addUint32(2, _paramReference);
+ }
+ if (offset_typeArguments != null) {
+ fbBuilder.addOffset(3, offset_typeArguments);
+ }
+ return fbBuilder.endTable();
+ }
+}
+
+/**
+ * Summary information about a reference to a an entity such as a type, top
+ * level executable, or executable within a class.
+ */
+abstract class EntityRef extends base.SummaryClass {
+
+ /**
+ * If this [EntityRef] is contained within [LinkedUnit.types], slot id (which
+ * is unique within the compilation unit) identifying the target of type
+ * propagation or type inference with which this [EntityRef] is associated.
+ *
+ * Otherwise zero.
+ */
+ int get slot;
+
+ /**
+ * Index into [UnlinkedUnit.references] for the entity being referred to, or
+ * zero if this is a reference to a type parameter.
+ */
+ int get reference;
+
+ /**
+ * If this is a reference to a type parameter, one-based index into the list
+ * of [UnlinkedTypeParam]s currently in effect. Indexing is done using De
+ * Bruijn index conventions; that is, innermost parameters come first, and
+ * if a class or method has multiple parameters, they are indexed from right
+ * to left. So for instance, if the enclosing declaration is
+ *
+ * class C<T,U> {
+ * m<V,W> {
+ * ...
+ * }
+ * }
+ *
+ * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
+ * respectively.
+ *
+ * If the type being referred to is not a type parameter, [paramReference] is
+ * zero.
+ */
+ int get paramReference;
+
+ /**
+ * If this is an instantiation of a generic type or generic executable, the
+ * type arguments used to instantiate it. Trailing type arguments of type
+ * `dynamic` are omitted.
+ */
+ List<EntityRef> get typeArguments;
+}
+
+class _EntityRefReader extends fb.TableReader<_EntityRefImpl> {
+ const _EntityRefReader();
+
+ @override
+ _EntityRefImpl createObject(fb.BufferPointer bp) => new _EntityRefImpl(bp);
+}
+
+class _EntityRefImpl extends Object with _EntityRefMixin implements EntityRef {
+ final fb.BufferPointer _bp;
+
+ _EntityRefImpl(this._bp);
+
+ int _slot;
+ int _reference;
+ int _paramReference;
+ List<EntityRef> _typeArguments;
+
+ @override
+ int get slot {
+ _slot ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+ return _slot;
+ }
+
+ @override
+ int get reference {
+ _reference ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+ return _reference;
+ }
+
+ @override
+ int get paramReference {
+ _paramReference ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+ return _paramReference;
+ }
+
+ @override
+ List<EntityRef> get typeArguments {
+ _typeArguments ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 3, const <EntityRef>[]);
+ return _typeArguments;
+ }
+}
+
+abstract class _EntityRefMixin implements EntityRef {
+ @override
+ Map<String, Object> toMap() => {
+ "slot": slot,
+ "reference": reference,
+ "paramReference": paramReference,
+ "typeArguments": typeArguments,
+ };
+}
+
+class LinkedDependencyBuilder extends Object with _LinkedDependencyMixin implements LinkedDependency {
bool _finished = false;
String _uri;
List<String> _parts;
- PrelinkedDependencyBuilder();
+ @override
+ String get uri => _uri ??= '';
/**
* The relative URI of the dependent library. This URI is relative to the
@@ -61,6 +680,9 @@
_uri = _value;
}
+ @override
+ List<String> get parts => _parts ??= <String>[];
+
/**
* URI for the compilation units listed in the library's `part` declarations.
* These URIs are relative to the importing library.
@@ -70,6 +692,10 @@
_parts = _value;
}
+ LinkedDependencyBuilder({String uri, List<String> parts})
+ : _uri = uri,
+ _parts = parts;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -92,18 +718,11 @@
}
}
-PrelinkedDependencyBuilder encodePrelinkedDependency({String uri, List<String> parts}) {
- PrelinkedDependencyBuilder builder = new PrelinkedDependencyBuilder();
- builder.uri = uri;
- builder.parts = parts;
- return builder;
-}
-
/**
* Information about a dependency that exists between one library and another
* due to an "import" declaration.
*/
-abstract class PrelinkedDependency extends base.SummaryClass {
+abstract class LinkedDependency extends base.SummaryClass {
/**
* The relative URI of the dependent library. This URI is relative to the
@@ -121,28 +740,22 @@
List<String> get parts;
}
-class _PrelinkedDependencyReader extends fb.TableReader<_PrelinkedDependencyImpl> {
- const _PrelinkedDependencyReader();
+class _LinkedDependencyReader extends fb.TableReader<_LinkedDependencyImpl> {
+ const _LinkedDependencyReader();
@override
- _PrelinkedDependencyImpl createObject(fb.BufferPointer bp) => new _PrelinkedDependencyImpl(bp);
+ _LinkedDependencyImpl createObject(fb.BufferPointer bp) => new _LinkedDependencyImpl(bp);
}
-class _PrelinkedDependencyImpl implements PrelinkedDependency {
+class _LinkedDependencyImpl extends Object with _LinkedDependencyMixin implements LinkedDependency {
final fb.BufferPointer _bp;
- _PrelinkedDependencyImpl(this._bp);
+ _LinkedDependencyImpl(this._bp);
String _uri;
List<String> _parts;
@override
- Map<String, Object> toMap() => {
- "uri": uri,
- "parts": parts,
- };
-
- @override
String get uri {
_uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _uri;
@@ -155,52 +768,283 @@
}
}
-class PrelinkedLibraryBuilder {
+abstract class _LinkedDependencyMixin implements LinkedDependency {
+ @override
+ Map<String, Object> toMap() => {
+ "uri": uri,
+ "parts": parts,
+ };
+}
+
+class LinkedExportNameBuilder extends Object with _LinkedExportNameMixin implements LinkedExportName {
bool _finished = false;
- List<PrelinkedUnitBuilder> _units;
- List<PrelinkedDependencyBuilder> _dependencies;
- List<int> _importDependencies;
+ String _name;
+ int _dependency;
+ int _unit;
+ ReferenceKind _kind;
- PrelinkedLibraryBuilder();
+ @override
+ String get name => _name ??= '';
/**
- * The pre-linked summary of all the compilation units constituting the
+ * Name of the exported entity. TODO(paulberry): do we include the trailing
+ * '=' for a setter?
+ */
+ void set name(String _value) {
+ assert(!_finished);
+ _name = _value;
+ }
+
+ @override
+ int get dependency => _dependency ??= 0;
+
+ /**
+ * Index into [LinkedLibrary.dependencies] for the library in which the
+ * entity is defined.
+ */
+ void set dependency(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _dependency = _value;
+ }
+
+ @override
+ int get unit => _unit ??= 0;
+
+ /**
+ * Integer index indicating which unit in the exported library contains the
+ * definition of the entity. As with indices into [LinkedLibrary.units],
+ * zero represents the defining compilation unit, and nonzero values
+ * represent parts in the order of the corresponding `part` declarations.
+ */
+ void set unit(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _unit = _value;
+ }
+
+ @override
+ ReferenceKind get kind => _kind ??= ReferenceKind.classOrEnum;
+
+ /**
+ * The kind of the entity being referred to.
+ */
+ void set kind(ReferenceKind _value) {
+ assert(!_finished);
+ _kind = _value;
+ }
+
+ LinkedExportNameBuilder({String name, int dependency, int unit, ReferenceKind kind})
+ : _name = name,
+ _dependency = dependency,
+ _unit = unit,
+ _kind = kind;
+
+ fb.Offset finish(fb.Builder fbBuilder) {
+ assert(!_finished);
+ _finished = true;
+ fb.Offset offset_name;
+ if (_name != null) {
+ offset_name = fbBuilder.writeString(_name);
+ }
+ fbBuilder.startTable();
+ if (offset_name != null) {
+ fbBuilder.addOffset(0, offset_name);
+ }
+ if (_dependency != null && _dependency != 0) {
+ fbBuilder.addUint32(1, _dependency);
+ }
+ if (_unit != null && _unit != 0) {
+ fbBuilder.addUint32(2, _unit);
+ }
+ if (_kind != null && _kind != ReferenceKind.classOrEnum) {
+ fbBuilder.addUint32(3, _kind.index);
+ }
+ return fbBuilder.endTable();
+ }
+}
+
+/**
+ * Information about a single name in the export namespace of the library that
+ * is not in the public namespace.
+ */
+abstract class LinkedExportName extends base.SummaryClass {
+
+ /**
+ * Name of the exported entity. TODO(paulberry): do we include the trailing
+ * '=' for a setter?
+ */
+ String get name;
+
+ /**
+ * Index into [LinkedLibrary.dependencies] for the library in which the
+ * entity is defined.
+ */
+ int get dependency;
+
+ /**
+ * Integer index indicating which unit in the exported library contains the
+ * definition of the entity. As with indices into [LinkedLibrary.units],
+ * zero represents the defining compilation unit, and nonzero values
+ * represent parts in the order of the corresponding `part` declarations.
+ */
+ int get unit;
+
+ /**
+ * The kind of the entity being referred to.
+ */
+ ReferenceKind get kind;
+}
+
+class _LinkedExportNameReader extends fb.TableReader<_LinkedExportNameImpl> {
+ const _LinkedExportNameReader();
+
+ @override
+ _LinkedExportNameImpl createObject(fb.BufferPointer bp) => new _LinkedExportNameImpl(bp);
+}
+
+class _LinkedExportNameImpl extends Object with _LinkedExportNameMixin implements LinkedExportName {
+ final fb.BufferPointer _bp;
+
+ _LinkedExportNameImpl(this._bp);
+
+ String _name;
+ int _dependency;
+ int _unit;
+ ReferenceKind _kind;
+
+ @override
+ String get name {
+ _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+ return _name;
+ }
+
+ @override
+ int get dependency {
+ _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+ return _dependency;
+ }
+
+ @override
+ int get unit {
+ _unit ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+ return _unit;
+ }
+
+ @override
+ ReferenceKind get kind {
+ _kind ??= const _ReferenceKindReader().vTableGet(_bp, 3, ReferenceKind.classOrEnum);
+ return _kind;
+ }
+}
+
+abstract class _LinkedExportNameMixin implements LinkedExportName {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "dependency": dependency,
+ "unit": unit,
+ "kind": kind,
+ };
+}
+
+class LinkedLibraryBuilder extends Object with _LinkedLibraryMixin implements LinkedLibrary {
+ bool _finished = false;
+
+ List<LinkedUnitBuilder> _units;
+ List<LinkedDependencyBuilder> _dependencies;
+ List<int> _importDependencies;
+ List<LinkedExportNameBuilder> _exportNames;
+ int _numPrelinkedDependencies;
+
+ @override
+ List<LinkedUnitBuilder> get units => _units ??= <LinkedUnitBuilder>[];
+
+ /**
+ * The linked summary of all the compilation units constituting the
* library. The summary of the defining compilation unit is listed first,
* followed by the summary of each part, in the order of the `part`
* declarations in the defining compilation unit.
*/
- void set units(List<PrelinkedUnitBuilder> _value) {
+ void set units(List<LinkedUnitBuilder> _value) {
assert(!_finished);
_units = _value;
}
+ @override
+ List<LinkedDependencyBuilder> get dependencies => _dependencies ??= <LinkedDependencyBuilder>[];
+
/**
* The libraries that this library depends on (either via an explicit import
* statement or via the implicit dependencies on `dart:core` and
* `dart:async`). The first element of this array is a pseudo-dependency
- * representing the library itself (it is also used for "dynamic").
+ * representing the library itself (it is also used for `dynamic` and
+ * `void`). This is followed by elements representing "prelinked"
+ * dependencies (direct imports and the transitive closure of exports).
+ * After the prelinked dependencies are elements representing "linked"
+ * dependencies.
*
- * TODO(paulberry): consider removing this entirely and just using
- * [UnlinkedLibrary.imports].
+ * A library is only included as a "linked" dependency if it is a true
+ * dependency (e.g. a propagated or inferred type or constant value
+ * implicitly refers to an element declared in the library) or
+ * anti-dependency (e.g. the result of type propagation or type inference
+ * depends on the lack of a certain declaration in the library).
*/
- void set dependencies(List<PrelinkedDependencyBuilder> _value) {
+ void set dependencies(List<LinkedDependencyBuilder> _value) {
assert(!_finished);
_dependencies = _value;
}
+ @override
+ List<int> get importDependencies => _importDependencies ??= <int>[];
+
/**
* For each import in [UnlinkedUnit.imports], an index into [dependencies]
* of the library being imported.
- *
- * TODO(paulberry): if [dependencies] is removed, this can be removed as
- * well, since there will effectively be a one-to-one mapping.
*/
void set importDependencies(List<int> _value) {
assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
_importDependencies = _value;
}
+ @override
+ List<LinkedExportNameBuilder> get exportNames => _exportNames ??= <LinkedExportNameBuilder>[];
+
+ /**
+ * Information about entities in the export namespace of the library that are
+ * not in the public namespace of the library (that is, entities that are
+ * brought into the namespace via `export` directives).
+ *
+ * Sorted by name.
+ */
+ void set exportNames(List<LinkedExportNameBuilder> _value) {
+ assert(!_finished);
+ _exportNames = _value;
+ }
+
+ @override
+ int get numPrelinkedDependencies => _numPrelinkedDependencies ??= 0;
+
+ /**
+ * The number of elements in [dependencies] which are not "linked"
+ * dependencies (that is, the number of libraries in the direct imports plus
+ * the transitive closure of exports, plus the library itself).
+ */
+ void set numPrelinkedDependencies(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _numPrelinkedDependencies = _value;
+ }
+
+ LinkedLibraryBuilder({List<LinkedUnitBuilder> units, List<LinkedDependencyBuilder> dependencies, List<int> importDependencies, List<LinkedExportNameBuilder> exportNames, int numPrelinkedDependencies})
+ : _units = units,
+ _dependencies = dependencies,
+ _importDependencies = importDependencies,
+ _exportNames = exportNames,
+ _numPrelinkedDependencies = numPrelinkedDependencies;
+
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
return fbBuilder.finish(finish(fbBuilder));
@@ -212,6 +1056,7 @@
fb.Offset offset_units;
fb.Offset offset_dependencies;
fb.Offset offset_importDependencies;
+ fb.Offset offset_exportNames;
if (!(_units == null || _units.isEmpty)) {
offset_units = fbBuilder.writeList(_units.map((b) => b.finish(fbBuilder)).toList());
}
@@ -219,7 +1064,10 @@
offset_dependencies = fbBuilder.writeList(_dependencies.map((b) => b.finish(fbBuilder)).toList());
}
if (!(_importDependencies == null || _importDependencies.isEmpty)) {
- offset_importDependencies = fbBuilder.writeListInt32(_importDependencies);
+ offset_importDependencies = fbBuilder.writeListUint32(_importDependencies);
+ }
+ if (!(_exportNames == null || _exportNames.isEmpty)) {
+ offset_exportNames = fbBuilder.writeList(_exportNames.map((b) => b.finish(fbBuilder)).toList());
}
fbBuilder.startTable();
if (offset_units != null) {
@@ -231,195 +1079,263 @@
if (offset_importDependencies != null) {
fbBuilder.addOffset(2, offset_importDependencies);
}
+ if (offset_exportNames != null) {
+ fbBuilder.addOffset(3, offset_exportNames);
+ }
+ if (_numPrelinkedDependencies != null && _numPrelinkedDependencies != 0) {
+ fbBuilder.addUint32(4, _numPrelinkedDependencies);
+ }
return fbBuilder.endTable();
}
}
-PrelinkedLibraryBuilder encodePrelinkedLibrary({List<PrelinkedUnitBuilder> units, List<PrelinkedDependencyBuilder> dependencies, List<int> importDependencies}) {
- PrelinkedLibraryBuilder builder = new PrelinkedLibraryBuilder();
- builder.units = units;
- builder.dependencies = dependencies;
- builder.importDependencies = importDependencies;
- return builder;
-}
-
/**
- * Pre-linked summary of a library.
+ * Linked summary of a library.
*/
-abstract class PrelinkedLibrary extends base.SummaryClass {
- factory PrelinkedLibrary.fromBuffer(List<int> buffer) {
+abstract class LinkedLibrary extends base.SummaryClass {
+ factory LinkedLibrary.fromBuffer(List<int> buffer) {
fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
- return const _PrelinkedLibraryReader().read(rootRef);
+ return const _LinkedLibraryReader().read(rootRef);
}
/**
- * The pre-linked summary of all the compilation units constituting the
+ * The linked summary of all the compilation units constituting the
* library. The summary of the defining compilation unit is listed first,
* followed by the summary of each part, in the order of the `part`
* declarations in the defining compilation unit.
*/
- List<PrelinkedUnit> get units;
+ List<LinkedUnit> get units;
/**
* The libraries that this library depends on (either via an explicit import
* statement or via the implicit dependencies on `dart:core` and
* `dart:async`). The first element of this array is a pseudo-dependency
- * representing the library itself (it is also used for "dynamic").
+ * representing the library itself (it is also used for `dynamic` and
+ * `void`). This is followed by elements representing "prelinked"
+ * dependencies (direct imports and the transitive closure of exports).
+ * After the prelinked dependencies are elements representing "linked"
+ * dependencies.
*
- * TODO(paulberry): consider removing this entirely and just using
- * [UnlinkedLibrary.imports].
+ * A library is only included as a "linked" dependency if it is a true
+ * dependency (e.g. a propagated or inferred type or constant value
+ * implicitly refers to an element declared in the library) or
+ * anti-dependency (e.g. the result of type propagation or type inference
+ * depends on the lack of a certain declaration in the library).
*/
- List<PrelinkedDependency> get dependencies;
+ List<LinkedDependency> get dependencies;
/**
* For each import in [UnlinkedUnit.imports], an index into [dependencies]
* of the library being imported.
- *
- * TODO(paulberry): if [dependencies] is removed, this can be removed as
- * well, since there will effectively be a one-to-one mapping.
*/
List<int> get importDependencies;
+
+ /**
+ * Information about entities in the export namespace of the library that are
+ * not in the public namespace of the library (that is, entities that are
+ * brought into the namespace via `export` directives).
+ *
+ * Sorted by name.
+ */
+ List<LinkedExportName> get exportNames;
+
+ /**
+ * The number of elements in [dependencies] which are not "linked"
+ * dependencies (that is, the number of libraries in the direct imports plus
+ * the transitive closure of exports, plus the library itself).
+ */
+ int get numPrelinkedDependencies;
}
-class _PrelinkedLibraryReader extends fb.TableReader<_PrelinkedLibraryImpl> {
- const _PrelinkedLibraryReader();
+class _LinkedLibraryReader extends fb.TableReader<_LinkedLibraryImpl> {
+ const _LinkedLibraryReader();
@override
- _PrelinkedLibraryImpl createObject(fb.BufferPointer bp) => new _PrelinkedLibraryImpl(bp);
+ _LinkedLibraryImpl createObject(fb.BufferPointer bp) => new _LinkedLibraryImpl(bp);
}
-class _PrelinkedLibraryImpl implements PrelinkedLibrary {
+class _LinkedLibraryImpl extends Object with _LinkedLibraryMixin implements LinkedLibrary {
final fb.BufferPointer _bp;
- _PrelinkedLibraryImpl(this._bp);
+ _LinkedLibraryImpl(this._bp);
- List<PrelinkedUnit> _units;
- List<PrelinkedDependency> _dependencies;
+ List<LinkedUnit> _units;
+ List<LinkedDependency> _dependencies;
List<int> _importDependencies;
+ List<LinkedExportName> _exportNames;
+ int _numPrelinkedDependencies;
@override
- Map<String, Object> toMap() => {
- "units": units,
- "dependencies": dependencies,
- "importDependencies": importDependencies,
- };
-
- @override
- List<PrelinkedUnit> get units {
- _units ??= const fb.ListReader<PrelinkedUnit>(const _PrelinkedUnitReader()).vTableGet(_bp, 0, const <PrelinkedUnit>[]);
+ List<LinkedUnit> get units {
+ _units ??= const fb.ListReader<LinkedUnit>(const _LinkedUnitReader()).vTableGet(_bp, 0, const <LinkedUnit>[]);
return _units;
}
@override
- List<PrelinkedDependency> get dependencies {
- _dependencies ??= const fb.ListReader<PrelinkedDependency>(const _PrelinkedDependencyReader()).vTableGet(_bp, 1, const <PrelinkedDependency>[]);
+ List<LinkedDependency> get dependencies {
+ _dependencies ??= const fb.ListReader<LinkedDependency>(const _LinkedDependencyReader()).vTableGet(_bp, 1, const <LinkedDependency>[]);
return _dependencies;
}
@override
List<int> get importDependencies {
- _importDependencies ??= const fb.ListReader<int>(const fb.Int32Reader()).vTableGet(_bp, 2, const <int>[]);
+ _importDependencies ??= const fb.ListReader<int>(const fb.Uint32Reader()).vTableGet(_bp, 2, const <int>[]);
return _importDependencies;
}
+
+ @override
+ List<LinkedExportName> get exportNames {
+ _exportNames ??= const fb.ListReader<LinkedExportName>(const _LinkedExportNameReader()).vTableGet(_bp, 3, const <LinkedExportName>[]);
+ return _exportNames;
+ }
+
+ @override
+ int get numPrelinkedDependencies {
+ _numPrelinkedDependencies ??= const fb.Uint32Reader().vTableGet(_bp, 4, 0);
+ return _numPrelinkedDependencies;
+ }
}
-class PrelinkedReferenceBuilder {
+abstract class _LinkedLibraryMixin implements LinkedLibrary {
+ @override
+ Map<String, Object> toMap() => {
+ "units": units,
+ "dependencies": dependencies,
+ "importDependencies": importDependencies,
+ "exportNames": exportNames,
+ "numPrelinkedDependencies": numPrelinkedDependencies,
+ };
+}
+
+class LinkedReferenceBuilder extends Object with _LinkedReferenceMixin implements LinkedReference {
bool _finished = false;
int _dependency;
- PrelinkedReferenceKind _kind;
+ ReferenceKind _kind;
int _unit;
int _numTypeParameters;
+ String _name;
- PrelinkedReferenceBuilder();
+ @override
+ int get dependency => _dependency ??= 0;
/**
- * Index into [PrelinkedLibrary.dependencies] indicating which imported library
+ * Index into [LinkedLibrary.dependencies] indicating which imported library
* declares the entity being referred to.
*/
void set dependency(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_dependency = _value;
}
+ @override
+ ReferenceKind get kind => _kind ??= ReferenceKind.classOrEnum;
+
/**
- * The kind of the entity being referred to. For the pseudo-type `dynamic`,
- * the kind is [PrelinkedReferenceKind.classOrEnum].
+ * The kind of the entity being referred to. For the pseudo-types `dynamic`
+ * and `void`, the kind is [ReferenceKind.classOrEnum].
*/
- void set kind(PrelinkedReferenceKind _value) {
+ void set kind(ReferenceKind _value) {
assert(!_finished);
_kind = _value;
}
+ @override
+ int get unit => _unit ??= 0;
+
/**
* Integer index indicating which unit in the imported library contains the
- * definition of the entity. As with indices into [PrelinkedLibrary.units],
+ * definition of the entity. As with indices into [LinkedLibrary.units],
* zero represents the defining compilation unit, and nonzero values
* represent parts in the order of the corresponding `part` declarations.
*/
void set unit(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_unit = _value;
}
+ @override
+ int get numTypeParameters => _numTypeParameters ??= 0;
+
/**
* If the entity being referred to is generic, the number of type parameters
* it accepts. Otherwise zero.
*/
void set numTypeParameters(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_numTypeParameters = _value;
}
+ @override
+ String get name => _name ??= '';
+
+ /**
+ * If this [LinkedReference] doesn't have an associated [UnlinkedReference],
+ * name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
+ */
+ void set name(String _value) {
+ assert(!_finished);
+ _name = _value;
+ }
+
+ LinkedReferenceBuilder({int dependency, ReferenceKind kind, int unit, int numTypeParameters, String name})
+ : _dependency = dependency,
+ _kind = kind,
+ _unit = unit,
+ _numTypeParameters = numTypeParameters,
+ _name = name;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
+ fb.Offset offset_name;
+ if (_name != null) {
+ offset_name = fbBuilder.writeString(_name);
+ }
fbBuilder.startTable();
if (_dependency != null && _dependency != 0) {
- fbBuilder.addInt32(0, _dependency);
+ fbBuilder.addUint32(0, _dependency);
}
- if (_kind != null && _kind != PrelinkedReferenceKind.classOrEnum) {
- fbBuilder.addInt32(1, _kind.index);
+ if (_kind != null && _kind != ReferenceKind.classOrEnum) {
+ fbBuilder.addUint32(1, _kind.index);
}
if (_unit != null && _unit != 0) {
- fbBuilder.addInt32(2, _unit);
+ fbBuilder.addUint32(2, _unit);
}
if (_numTypeParameters != null && _numTypeParameters != 0) {
- fbBuilder.addInt32(3, _numTypeParameters);
+ fbBuilder.addUint32(3, _numTypeParameters);
+ }
+ if (offset_name != null) {
+ fbBuilder.addOffset(4, offset_name);
}
return fbBuilder.endTable();
}
}
-PrelinkedReferenceBuilder encodePrelinkedReference({int dependency, PrelinkedReferenceKind kind, int unit, int numTypeParameters}) {
- PrelinkedReferenceBuilder builder = new PrelinkedReferenceBuilder();
- builder.dependency = dependency;
- builder.kind = kind;
- builder.unit = unit;
- builder.numTypeParameters = numTypeParameters;
- return builder;
-}
-
/**
* Information about the resolution of an [UnlinkedReference].
*/
-abstract class PrelinkedReference extends base.SummaryClass {
+abstract class LinkedReference extends base.SummaryClass {
/**
- * Index into [PrelinkedLibrary.dependencies] indicating which imported library
+ * Index into [LinkedLibrary.dependencies] indicating which imported library
* declares the entity being referred to.
*/
int get dependency;
/**
- * The kind of the entity being referred to. For the pseudo-type `dynamic`,
- * the kind is [PrelinkedReferenceKind.classOrEnum].
+ * The kind of the entity being referred to. For the pseudo-types `dynamic`
+ * and `void`, the kind is [ReferenceKind.classOrEnum].
*/
- PrelinkedReferenceKind get kind;
+ ReferenceKind get kind;
/**
* Integer index indicating which unit in the imported library contains the
- * definition of the entity. As with indices into [PrelinkedLibrary.units],
+ * definition of the entity. As with indices into [LinkedLibrary.units],
* zero represents the defining compilation unit, and nonzero values
* represent parts in the order of the corresponding `part` declarations.
*/
@@ -430,159 +1346,226 @@
* it accepts. Otherwise zero.
*/
int get numTypeParameters;
+
+ /**
+ * If this [LinkedReference] doesn't have an associated [UnlinkedReference],
+ * name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
+ */
+ String get name;
}
-class _PrelinkedReferenceReader extends fb.TableReader<_PrelinkedReferenceImpl> {
- const _PrelinkedReferenceReader();
+class _LinkedReferenceReader extends fb.TableReader<_LinkedReferenceImpl> {
+ const _LinkedReferenceReader();
@override
- _PrelinkedReferenceImpl createObject(fb.BufferPointer bp) => new _PrelinkedReferenceImpl(bp);
+ _LinkedReferenceImpl createObject(fb.BufferPointer bp) => new _LinkedReferenceImpl(bp);
}
-class _PrelinkedReferenceImpl implements PrelinkedReference {
+class _LinkedReferenceImpl extends Object with _LinkedReferenceMixin implements LinkedReference {
final fb.BufferPointer _bp;
- _PrelinkedReferenceImpl(this._bp);
+ _LinkedReferenceImpl(this._bp);
int _dependency;
- PrelinkedReferenceKind _kind;
+ ReferenceKind _kind;
int _unit;
int _numTypeParameters;
+ String _name;
@override
+ int get dependency {
+ _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+ return _dependency;
+ }
+
+ @override
+ ReferenceKind get kind {
+ _kind ??= const _ReferenceKindReader().vTableGet(_bp, 1, ReferenceKind.classOrEnum);
+ return _kind;
+ }
+
+ @override
+ int get unit {
+ _unit ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+ return _unit;
+ }
+
+ @override
+ int get numTypeParameters {
+ _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+ return _numTypeParameters;
+ }
+
+ @override
+ String get name {
+ _name ??= const fb.StringReader().vTableGet(_bp, 4, '');
+ return _name;
+ }
+}
+
+abstract class _LinkedReferenceMixin implements LinkedReference {
+ @override
Map<String, Object> toMap() => {
"dependency": dependency,
"kind": kind,
"unit": unit,
"numTypeParameters": numTypeParameters,
+ "name": name,
};
-
- @override
- int get dependency {
- _dependency ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
- return _dependency;
- }
-
- @override
- PrelinkedReferenceKind get kind {
- _kind ??= PrelinkedReferenceKind.values[const fb.Int32Reader().vTableGet(_bp, 1, 0)];
- return _kind;
- }
-
- @override
- int get unit {
- _unit ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
- return _unit;
- }
-
- @override
- int get numTypeParameters {
- _numTypeParameters ??= const fb.Int32Reader().vTableGet(_bp, 3, 0);
- return _numTypeParameters;
- }
}
-class PrelinkedUnitBuilder {
+class LinkedUnitBuilder extends Object with _LinkedUnitMixin implements LinkedUnit {
bool _finished = false;
- List<PrelinkedReferenceBuilder> _references;
+ List<LinkedReferenceBuilder> _references;
+ List<EntityRefBuilder> _types;
- PrelinkedUnitBuilder();
+ @override
+ List<LinkedReferenceBuilder> get references => _references ??= <LinkedReferenceBuilder>[];
/**
- * For each reference in [UnlinkedUnit.references], information about how
- * that reference is resolved.
+ * Information about the resolution of references within the compilation
+ * unit. Each element of [UnlinkedUnit.references] has a corresponding
+ * element in this list (at the same index). If this list has additional
+ * elements beyond the number of elements in [UnlinkedUnit.references], those
+ * additional elements are references that are only referred to implicitly
+ * (e.g. elements involved in inferred or propagated types).
*/
- void set references(List<PrelinkedReferenceBuilder> _value) {
+ void set references(List<LinkedReferenceBuilder> _value) {
assert(!_finished);
_references = _value;
}
+ @override
+ List<EntityRefBuilder> get types => _types ??= <EntityRefBuilder>[];
+
+ /**
+ * List associating slot ids found inside the unlinked summary for the
+ * compilation unit with propagated and inferred types.
+ */
+ void set types(List<EntityRefBuilder> _value) {
+ assert(!_finished);
+ _types = _value;
+ }
+
+ LinkedUnitBuilder({List<LinkedReferenceBuilder> references, List<EntityRefBuilder> types})
+ : _references = references,
+ _types = types;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
fb.Offset offset_references;
+ fb.Offset offset_types;
if (!(_references == null || _references.isEmpty)) {
offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
}
+ if (!(_types == null || _types.isEmpty)) {
+ offset_types = fbBuilder.writeList(_types.map((b) => b.finish(fbBuilder)).toList());
+ }
fbBuilder.startTable();
if (offset_references != null) {
fbBuilder.addOffset(0, offset_references);
}
+ if (offset_types != null) {
+ fbBuilder.addOffset(1, offset_types);
+ }
return fbBuilder.endTable();
}
}
-PrelinkedUnitBuilder encodePrelinkedUnit({List<PrelinkedReferenceBuilder> references}) {
- PrelinkedUnitBuilder builder = new PrelinkedUnitBuilder();
- builder.references = references;
- return builder;
-}
-
/**
- * Pre-linked summary of a compilation unit.
+ * Linked summary of a compilation unit.
*/
-abstract class PrelinkedUnit extends base.SummaryClass {
+abstract class LinkedUnit extends base.SummaryClass {
/**
- * For each reference in [UnlinkedUnit.references], information about how
- * that reference is resolved.
+ * Information about the resolution of references within the compilation
+ * unit. Each element of [UnlinkedUnit.references] has a corresponding
+ * element in this list (at the same index). If this list has additional
+ * elements beyond the number of elements in [UnlinkedUnit.references], those
+ * additional elements are references that are only referred to implicitly
+ * (e.g. elements involved in inferred or propagated types).
*/
- List<PrelinkedReference> get references;
+ List<LinkedReference> get references;
+
+ /**
+ * List associating slot ids found inside the unlinked summary for the
+ * compilation unit with propagated and inferred types.
+ */
+ List<EntityRef> get types;
}
-class _PrelinkedUnitReader extends fb.TableReader<_PrelinkedUnitImpl> {
- const _PrelinkedUnitReader();
+class _LinkedUnitReader extends fb.TableReader<_LinkedUnitImpl> {
+ const _LinkedUnitReader();
@override
- _PrelinkedUnitImpl createObject(fb.BufferPointer bp) => new _PrelinkedUnitImpl(bp);
+ _LinkedUnitImpl createObject(fb.BufferPointer bp) => new _LinkedUnitImpl(bp);
}
-class _PrelinkedUnitImpl implements PrelinkedUnit {
+class _LinkedUnitImpl extends Object with _LinkedUnitMixin implements LinkedUnit {
final fb.BufferPointer _bp;
- _PrelinkedUnitImpl(this._bp);
+ _LinkedUnitImpl(this._bp);
- List<PrelinkedReference> _references;
+ List<LinkedReference> _references;
+ List<EntityRef> _types;
@override
+ List<LinkedReference> get references {
+ _references ??= const fb.ListReader<LinkedReference>(const _LinkedReferenceReader()).vTableGet(_bp, 0, const <LinkedReference>[]);
+ return _references;
+ }
+
+ @override
+ List<EntityRef> get types {
+ _types ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 1, const <EntityRef>[]);
+ return _types;
+ }
+}
+
+abstract class _LinkedUnitMixin implements LinkedUnit {
+ @override
Map<String, Object> toMap() => {
"references": references,
+ "types": types,
};
-
- @override
- List<PrelinkedReference> get references {
- _references ??= const fb.ListReader<PrelinkedReference>(const _PrelinkedReferenceReader()).vTableGet(_bp, 0, const <PrelinkedReference>[]);
- return _references;
- }
}
-class SdkBundleBuilder {
+class SdkBundleBuilder extends Object with _SdkBundleMixin implements SdkBundle {
bool _finished = false;
- List<String> _prelinkedLibraryUris;
- List<PrelinkedLibraryBuilder> _prelinkedLibraries;
+ List<String> _linkedLibraryUris;
+ List<LinkedLibraryBuilder> _linkedLibraries;
List<String> _unlinkedUnitUris;
List<UnlinkedUnitBuilder> _unlinkedUnits;
- SdkBundleBuilder();
+ @override
+ List<String> get linkedLibraryUris => _linkedLibraryUris ??= <String>[];
/**
- * The list of URIs of items in [prelinkedLibraries], e.g. `dart:core`.
+ * The list of URIs of items in [linkedLibraries], e.g. `dart:core`.
*/
- void set prelinkedLibraryUris(List<String> _value) {
+ void set linkedLibraryUris(List<String> _value) {
assert(!_finished);
- _prelinkedLibraryUris = _value;
+ _linkedLibraryUris = _value;
}
+ @override
+ List<LinkedLibraryBuilder> get linkedLibraries => _linkedLibraries ??= <LinkedLibraryBuilder>[];
+
/**
- * Pre-linked libraries.
+ * Linked libraries.
*/
- void set prelinkedLibraries(List<PrelinkedLibraryBuilder> _value) {
+ void set linkedLibraries(List<LinkedLibraryBuilder> _value) {
assert(!_finished);
- _prelinkedLibraries = _value;
+ _linkedLibraries = _value;
}
+ @override
+ List<String> get unlinkedUnitUris => _unlinkedUnitUris ??= <String>[];
+
/**
* The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
*/
@@ -591,6 +1574,9 @@
_unlinkedUnitUris = _value;
}
+ @override
+ List<UnlinkedUnitBuilder> get unlinkedUnits => _unlinkedUnits ??= <UnlinkedUnitBuilder>[];
+
/**
* Unlinked information for the compilation units constituting the SDK.
*/
@@ -599,6 +1585,12 @@
_unlinkedUnits = _value;
}
+ SdkBundleBuilder({List<String> linkedLibraryUris, List<LinkedLibraryBuilder> linkedLibraries, List<String> unlinkedUnitUris, List<UnlinkedUnitBuilder> unlinkedUnits})
+ : _linkedLibraryUris = linkedLibraryUris,
+ _linkedLibraries = linkedLibraries,
+ _unlinkedUnitUris = unlinkedUnitUris,
+ _unlinkedUnits = unlinkedUnits;
+
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
return fbBuilder.finish(finish(fbBuilder));
@@ -607,15 +1599,15 @@
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
- fb.Offset offset_prelinkedLibraryUris;
- fb.Offset offset_prelinkedLibraries;
+ fb.Offset offset_linkedLibraryUris;
+ fb.Offset offset_linkedLibraries;
fb.Offset offset_unlinkedUnitUris;
fb.Offset offset_unlinkedUnits;
- if (!(_prelinkedLibraryUris == null || _prelinkedLibraryUris.isEmpty)) {
- offset_prelinkedLibraryUris = fbBuilder.writeList(_prelinkedLibraryUris.map((b) => fbBuilder.writeString(b)).toList());
+ if (!(_linkedLibraryUris == null || _linkedLibraryUris.isEmpty)) {
+ offset_linkedLibraryUris = fbBuilder.writeList(_linkedLibraryUris.map((b) => fbBuilder.writeString(b)).toList());
}
- if (!(_prelinkedLibraries == null || _prelinkedLibraries.isEmpty)) {
- offset_prelinkedLibraries = fbBuilder.writeList(_prelinkedLibraries.map((b) => b.finish(fbBuilder)).toList());
+ if (!(_linkedLibraries == null || _linkedLibraries.isEmpty)) {
+ offset_linkedLibraries = fbBuilder.writeList(_linkedLibraries.map((b) => b.finish(fbBuilder)).toList());
}
if (!(_unlinkedUnitUris == null || _unlinkedUnitUris.isEmpty)) {
offset_unlinkedUnitUris = fbBuilder.writeList(_unlinkedUnitUris.map((b) => fbBuilder.writeString(b)).toList());
@@ -624,11 +1616,11 @@
offset_unlinkedUnits = fbBuilder.writeList(_unlinkedUnits.map((b) => b.finish(fbBuilder)).toList());
}
fbBuilder.startTable();
- if (offset_prelinkedLibraryUris != null) {
- fbBuilder.addOffset(0, offset_prelinkedLibraryUris);
+ if (offset_linkedLibraryUris != null) {
+ fbBuilder.addOffset(0, offset_linkedLibraryUris);
}
- if (offset_prelinkedLibraries != null) {
- fbBuilder.addOffset(1, offset_prelinkedLibraries);
+ if (offset_linkedLibraries != null) {
+ fbBuilder.addOffset(1, offset_linkedLibraries);
}
if (offset_unlinkedUnitUris != null) {
fbBuilder.addOffset(2, offset_unlinkedUnitUris);
@@ -640,15 +1632,6 @@
}
}
-SdkBundleBuilder encodeSdkBundle({List<String> prelinkedLibraryUris, List<PrelinkedLibraryBuilder> prelinkedLibraries, List<String> unlinkedUnitUris, List<UnlinkedUnitBuilder> unlinkedUnits}) {
- SdkBundleBuilder builder = new SdkBundleBuilder();
- builder.prelinkedLibraryUris = prelinkedLibraryUris;
- builder.prelinkedLibraries = prelinkedLibraries;
- builder.unlinkedUnitUris = unlinkedUnitUris;
- builder.unlinkedUnits = unlinkedUnits;
- return builder;
-}
-
/**
* Information about SDK.
*/
@@ -659,14 +1642,14 @@
}
/**
- * The list of URIs of items in [prelinkedLibraries], e.g. `dart:core`.
+ * The list of URIs of items in [linkedLibraries], e.g. `dart:core`.
*/
- List<String> get prelinkedLibraryUris;
+ List<String> get linkedLibraryUris;
/**
- * Pre-linked libraries.
+ * Linked libraries.
*/
- List<PrelinkedLibrary> get prelinkedLibraries;
+ List<LinkedLibrary> get linkedLibraries;
/**
* The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
@@ -686,34 +1669,26 @@
_SdkBundleImpl createObject(fb.BufferPointer bp) => new _SdkBundleImpl(bp);
}
-class _SdkBundleImpl implements SdkBundle {
+class _SdkBundleImpl extends Object with _SdkBundleMixin implements SdkBundle {
final fb.BufferPointer _bp;
_SdkBundleImpl(this._bp);
- List<String> _prelinkedLibraryUris;
- List<PrelinkedLibrary> _prelinkedLibraries;
+ List<String> _linkedLibraryUris;
+ List<LinkedLibrary> _linkedLibraries;
List<String> _unlinkedUnitUris;
List<UnlinkedUnit> _unlinkedUnits;
@override
- Map<String, Object> toMap() => {
- "prelinkedLibraryUris": prelinkedLibraryUris,
- "prelinkedLibraries": prelinkedLibraries,
- "unlinkedUnitUris": unlinkedUnitUris,
- "unlinkedUnits": unlinkedUnits,
- };
-
- @override
- List<String> get prelinkedLibraryUris {
- _prelinkedLibraryUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
- return _prelinkedLibraryUris;
+ List<String> get linkedLibraryUris {
+ _linkedLibraryUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
+ return _linkedLibraryUris;
}
@override
- List<PrelinkedLibrary> get prelinkedLibraries {
- _prelinkedLibraries ??= const fb.ListReader<PrelinkedLibrary>(const _PrelinkedLibraryReader()).vTableGet(_bp, 1, const <PrelinkedLibrary>[]);
- return _prelinkedLibraries;
+ List<LinkedLibrary> get linkedLibraries {
+ _linkedLibraries ??= const fb.ListReader<LinkedLibrary>(const _LinkedLibraryReader()).vTableGet(_bp, 1, const <LinkedLibrary>[]);
+ return _linkedLibraries;
}
@override
@@ -729,23 +1704,34 @@
}
}
-class UnlinkedClassBuilder {
+abstract class _SdkBundleMixin implements SdkBundle {
+ @override
+ Map<String, Object> toMap() => {
+ "linkedLibraryUris": linkedLibraryUris,
+ "linkedLibraries": linkedLibraries,
+ "unlinkedUnitUris": unlinkedUnitUris,
+ "unlinkedUnits": unlinkedUnits,
+ };
+}
+
+class UnlinkedClassBuilder extends Object with _UnlinkedClassMixin implements UnlinkedClass {
bool _finished = false;
String _name;
int _nameOffset;
UnlinkedDocumentationCommentBuilder _documentationComment;
List<UnlinkedTypeParamBuilder> _typeParameters;
- UnlinkedTypeRefBuilder _supertype;
- List<UnlinkedTypeRefBuilder> _mixins;
- List<UnlinkedTypeRefBuilder> _interfaces;
+ EntityRefBuilder _supertype;
+ List<EntityRefBuilder> _mixins;
+ List<EntityRefBuilder> _interfaces;
List<UnlinkedVariableBuilder> _fields;
List<UnlinkedExecutableBuilder> _executables;
bool _isAbstract;
bool _isMixinApplication;
bool _hasNoSupertype;
- UnlinkedClassBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the class.
@@ -755,14 +1741,21 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the class name relative to the beginning of the file.
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
/**
* Documentation comment for the class, or `null` if there is no
* documentation comment.
@@ -772,6 +1765,9 @@
_documentationComment = _value;
}
+ @override
+ List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+
/**
* Type parameters of the class, if any.
*/
@@ -780,32 +1776,44 @@
_typeParameters = _value;
}
+ @override
+ EntityRefBuilder get supertype => _supertype;
+
/**
* Supertype of the class, or `null` if either (a) the class doesn't
* explicitly declare a supertype (and hence has supertype `Object`), or (b)
* the class *is* `Object` (and hence has no supertype).
*/
- void set supertype(UnlinkedTypeRefBuilder _value) {
+ void set supertype(EntityRefBuilder _value) {
assert(!_finished);
_supertype = _value;
}
+ @override
+ List<EntityRefBuilder> get mixins => _mixins ??= <EntityRefBuilder>[];
+
/**
* Mixins appearing in a `with` clause, if any.
*/
- void set mixins(List<UnlinkedTypeRefBuilder> _value) {
+ void set mixins(List<EntityRefBuilder> _value) {
assert(!_finished);
_mixins = _value;
}
+ @override
+ List<EntityRefBuilder> get interfaces => _interfaces ??= <EntityRefBuilder>[];
+
/**
* Interfaces appearing in an `implements` clause, if any.
*/
- void set interfaces(List<UnlinkedTypeRefBuilder> _value) {
+ void set interfaces(List<EntityRefBuilder> _value) {
assert(!_finished);
_interfaces = _value;
}
+ @override
+ List<UnlinkedVariableBuilder> get fields => _fields ??= <UnlinkedVariableBuilder>[];
+
/**
* Field declarations contained in the class.
*/
@@ -814,6 +1822,9 @@
_fields = _value;
}
+ @override
+ List<UnlinkedExecutableBuilder> get executables => _executables ??= <UnlinkedExecutableBuilder>[];
+
/**
* Executable objects (methods, getters, and setters) contained in the class.
*/
@@ -822,6 +1833,9 @@
_executables = _value;
}
+ @override
+ bool get isAbstract => _isAbstract ??= false;
+
/**
* Indicates whether the class is declared with the `abstract` keyword.
*/
@@ -830,6 +1844,9 @@
_isAbstract = _value;
}
+ @override
+ bool get isMixinApplication => _isMixinApplication ??= false;
+
/**
* Indicates whether the class is declared using mixin application syntax.
*/
@@ -838,6 +1855,9 @@
_isMixinApplication = _value;
}
+ @override
+ bool get hasNoSupertype => _hasNoSupertype ??= false;
+
/**
* Indicates whether this class is the core "Object" class (and hence has no
* supertype)
@@ -847,6 +1867,20 @@
_hasNoSupertype = _value;
}
+ UnlinkedClassBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, EntityRefBuilder supertype, List<EntityRefBuilder> mixins, List<EntityRefBuilder> interfaces, List<UnlinkedVariableBuilder> fields, List<UnlinkedExecutableBuilder> executables, bool isAbstract, bool isMixinApplication, bool hasNoSupertype})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _documentationComment = documentationComment,
+ _typeParameters = typeParameters,
+ _supertype = supertype,
+ _mixins = mixins,
+ _interfaces = interfaces,
+ _fields = fields,
+ _executables = executables,
+ _isAbstract = isAbstract,
+ _isMixinApplication = isMixinApplication,
+ _hasNoSupertype = hasNoSupertype;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -887,7 +1921,7 @@
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_documentationComment != null) {
fbBuilder.addOffset(2, offset_documentationComment);
@@ -923,23 +1957,6 @@
}
}
-UnlinkedClassBuilder encodeUnlinkedClass({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, UnlinkedTypeRefBuilder supertype, List<UnlinkedTypeRefBuilder> mixins, List<UnlinkedTypeRefBuilder> interfaces, List<UnlinkedVariableBuilder> fields, List<UnlinkedExecutableBuilder> executables, bool isAbstract, bool isMixinApplication, bool hasNoSupertype}) {
- UnlinkedClassBuilder builder = new UnlinkedClassBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.documentationComment = documentationComment;
- builder.typeParameters = typeParameters;
- builder.supertype = supertype;
- builder.mixins = mixins;
- builder.interfaces = interfaces;
- builder.fields = fields;
- builder.executables = executables;
- builder.isAbstract = isAbstract;
- builder.isMixinApplication = isMixinApplication;
- builder.hasNoSupertype = hasNoSupertype;
- return builder;
-}
-
/**
* Unlinked summary information about a class declaration.
*/
@@ -971,17 +1988,17 @@
* explicitly declare a supertype (and hence has supertype `Object`), or (b)
* the class *is* `Object` (and hence has no supertype).
*/
- UnlinkedTypeRef get supertype;
+ EntityRef get supertype;
/**
* Mixins appearing in a `with` clause, if any.
*/
- List<UnlinkedTypeRef> get mixins;
+ List<EntityRef> get mixins;
/**
* Interfaces appearing in an `implements` clause, if any.
*/
- List<UnlinkedTypeRef> get interfaces;
+ List<EntityRef> get interfaces;
/**
* Field declarations contained in the class.
@@ -1017,7 +2034,7 @@
_UnlinkedClassImpl createObject(fb.BufferPointer bp) => new _UnlinkedClassImpl(bp);
}
-class _UnlinkedClassImpl implements UnlinkedClass {
+class _UnlinkedClassImpl extends Object with _UnlinkedClassMixin implements UnlinkedClass {
final fb.BufferPointer _bp;
_UnlinkedClassImpl(this._bp);
@@ -1026,9 +2043,9 @@
int _nameOffset;
UnlinkedDocumentationComment _documentationComment;
List<UnlinkedTypeParam> _typeParameters;
- UnlinkedTypeRef _supertype;
- List<UnlinkedTypeRef> _mixins;
- List<UnlinkedTypeRef> _interfaces;
+ EntityRef _supertype;
+ List<EntityRef> _mixins;
+ List<EntityRef> _interfaces;
List<UnlinkedVariable> _fields;
List<UnlinkedExecutable> _executables;
bool _isAbstract;
@@ -1036,22 +2053,6 @@
bool _hasNoSupertype;
@override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "documentationComment": documentationComment,
- "typeParameters": typeParameters,
- "supertype": supertype,
- "mixins": mixins,
- "interfaces": interfaces,
- "fields": fields,
- "executables": executables,
- "isAbstract": isAbstract,
- "isMixinApplication": isMixinApplication,
- "hasNoSupertype": hasNoSupertype,
- };
-
- @override
String get name {
_name ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _name;
@@ -1059,7 +2060,7 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@@ -1076,20 +2077,20 @@
}
@override
- UnlinkedTypeRef get supertype {
- _supertype ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 4, null);
+ EntityRef get supertype {
+ _supertype ??= const _EntityRefReader().vTableGet(_bp, 4, null);
return _supertype;
}
@override
- List<UnlinkedTypeRef> get mixins {
- _mixins ??= const fb.ListReader<UnlinkedTypeRef>(const _UnlinkedTypeRefReader()).vTableGet(_bp, 5, const <UnlinkedTypeRef>[]);
+ List<EntityRef> get mixins {
+ _mixins ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 5, const <EntityRef>[]);
return _mixins;
}
@override
- List<UnlinkedTypeRef> get interfaces {
- _interfaces ??= const fb.ListReader<UnlinkedTypeRef>(const _UnlinkedTypeRefReader()).vTableGet(_bp, 6, const <UnlinkedTypeRef>[]);
+ List<EntityRef> get interfaces {
+ _interfaces ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 6, const <EntityRef>[]);
return _interfaces;
}
@@ -1124,13 +2125,32 @@
}
}
-class UnlinkedCombinatorBuilder {
+abstract class _UnlinkedClassMixin implements UnlinkedClass {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "nameOffset": nameOffset,
+ "documentationComment": documentationComment,
+ "typeParameters": typeParameters,
+ "supertype": supertype,
+ "mixins": mixins,
+ "interfaces": interfaces,
+ "fields": fields,
+ "executables": executables,
+ "isAbstract": isAbstract,
+ "isMixinApplication": isMixinApplication,
+ "hasNoSupertype": hasNoSupertype,
+ };
+}
+
+class UnlinkedCombinatorBuilder extends Object with _UnlinkedCombinatorMixin implements UnlinkedCombinator {
bool _finished = false;
List<String> _shows;
List<String> _hides;
- UnlinkedCombinatorBuilder();
+ @override
+ List<String> get shows => _shows ??= <String>[];
/**
* List of names which are shown. Empty if this is a `hide` combinator.
@@ -1140,6 +2160,9 @@
_shows = _value;
}
+ @override
+ List<String> get hides => _hides ??= <String>[];
+
/**
* List of names which are hidden. Empty if this is a `show` combinator.
*/
@@ -1148,6 +2171,10 @@
_hides = _value;
}
+ UnlinkedCombinatorBuilder({List<String> shows, List<String> hides})
+ : _shows = shows,
+ _hides = hides;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -1170,13 +2197,6 @@
}
}
-UnlinkedCombinatorBuilder encodeUnlinkedCombinator({List<String> shows, List<String> hides}) {
- UnlinkedCombinatorBuilder builder = new UnlinkedCombinatorBuilder();
- builder.shows = shows;
- builder.hides = hides;
- return builder;
-}
-
/**
* Unlinked summary information about a `show` or `hide` combinator in an
* import or export declaration.
@@ -1201,7 +2221,7 @@
_UnlinkedCombinatorImpl createObject(fb.BufferPointer bp) => new _UnlinkedCombinatorImpl(bp);
}
-class _UnlinkedCombinatorImpl implements UnlinkedCombinator {
+class _UnlinkedCombinatorImpl extends Object with _UnlinkedCombinatorMixin implements UnlinkedCombinator {
final fb.BufferPointer _bp;
_UnlinkedCombinatorImpl(this._bp);
@@ -1210,12 +2230,6 @@
List<String> _hides;
@override
- Map<String, Object> toMap() => {
- "shows": shows,
- "hides": hides,
- };
-
- @override
List<String> get shows {
_shows ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
return _shows;
@@ -1228,14 +2242,250 @@
}
}
-class UnlinkedDocumentationCommentBuilder {
+abstract class _UnlinkedCombinatorMixin implements UnlinkedCombinator {
+ @override
+ Map<String, Object> toMap() => {
+ "shows": shows,
+ "hides": hides,
+ };
+}
+
+class UnlinkedConstBuilder extends Object with _UnlinkedConstMixin implements UnlinkedConst {
+ bool _finished = false;
+
+ List<UnlinkedConstOperation> _operations;
+ List<int> _ints;
+ List<double> _doubles;
+ List<String> _strings;
+ List<EntityRefBuilder> _references;
+
+ @override
+ List<UnlinkedConstOperation> get operations => _operations ??= <UnlinkedConstOperation>[];
+
+ /**
+ * Sequence of operations to execute (starting with an empty stack) to form
+ * the constant value.
+ */
+ void set operations(List<UnlinkedConstOperation> _value) {
+ assert(!_finished);
+ _operations = _value;
+ }
+
+ @override
+ List<int> get ints => _ints ??= <int>[];
+
+ /**
+ * Sequence of unsigned 32-bit integers consumed by the operations
+ * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+ * `makeList`, and `makeMap`.
+ */
+ void set ints(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _ints = _value;
+ }
+
+ @override
+ List<double> get doubles => _doubles ??= <double>[];
+
+ /**
+ * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+ */
+ void set doubles(List<double> _value) {
+ assert(!_finished);
+ _doubles = _value;
+ }
+
+ @override
+ List<String> get strings => _strings ??= <String>[];
+
+ /**
+ * Sequence of strings consumed by the operations `pushString` and
+ * `invokeConstructor`.
+ */
+ void set strings(List<String> _value) {
+ assert(!_finished);
+ _strings = _value;
+ }
+
+ @override
+ List<EntityRefBuilder> get references => _references ??= <EntityRefBuilder>[];
+
+ /**
+ * Sequence of language constructs consumed by the operations
+ * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`. Note
+ * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+ * actual entity being referred to may be something other than a type.
+ */
+ void set references(List<EntityRefBuilder> _value) {
+ assert(!_finished);
+ _references = _value;
+ }
+
+ UnlinkedConstBuilder({List<UnlinkedConstOperation> operations, List<int> ints, List<double> doubles, List<String> strings, List<EntityRefBuilder> references})
+ : _operations = operations,
+ _ints = ints,
+ _doubles = doubles,
+ _strings = strings,
+ _references = references;
+
+ fb.Offset finish(fb.Builder fbBuilder) {
+ assert(!_finished);
+ _finished = true;
+ fb.Offset offset_operations;
+ fb.Offset offset_ints;
+ fb.Offset offset_doubles;
+ fb.Offset offset_strings;
+ fb.Offset offset_references;
+ if (!(_operations == null || _operations.isEmpty)) {
+ offset_operations = fbBuilder.writeListUint32(_operations.map((b) => b.index).toList());
+ }
+ if (!(_ints == null || _ints.isEmpty)) {
+ offset_ints = fbBuilder.writeListUint32(_ints);
+ }
+ if (!(_doubles == null || _doubles.isEmpty)) {
+ offset_doubles = fbBuilder.writeListFloat64(_doubles);
+ }
+ if (!(_strings == null || _strings.isEmpty)) {
+ offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
+ }
+ if (!(_references == null || _references.isEmpty)) {
+ offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
+ }
+ fbBuilder.startTable();
+ if (offset_operations != null) {
+ fbBuilder.addOffset(0, offset_operations);
+ }
+ if (offset_ints != null) {
+ fbBuilder.addOffset(1, offset_ints);
+ }
+ if (offset_doubles != null) {
+ fbBuilder.addOffset(2, offset_doubles);
+ }
+ if (offset_strings != null) {
+ fbBuilder.addOffset(3, offset_strings);
+ }
+ if (offset_references != null) {
+ fbBuilder.addOffset(4, offset_references);
+ }
+ return fbBuilder.endTable();
+ }
+}
+
+/**
+ * Unlinked summary information about a compile-time constant expression, or a
+ * potentially constant expression.
+ *
+ * Constant expressions are represented using a simple stack-based language
+ * where [operations] is a sequence of operations to execute starting with an
+ * empty stack. Once all operations have been executed, the stack should
+ * contain a single value which is the value of the constant. Note that some
+ * operations consume additional data from the other fields of this class.
+ */
+abstract class UnlinkedConst extends base.SummaryClass {
+
+ /**
+ * Sequence of operations to execute (starting with an empty stack) to form
+ * the constant value.
+ */
+ List<UnlinkedConstOperation> get operations;
+
+ /**
+ * Sequence of unsigned 32-bit integers consumed by the operations
+ * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+ * `makeList`, and `makeMap`.
+ */
+ List<int> get ints;
+
+ /**
+ * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+ */
+ List<double> get doubles;
+
+ /**
+ * Sequence of strings consumed by the operations `pushString` and
+ * `invokeConstructor`.
+ */
+ List<String> get strings;
+
+ /**
+ * Sequence of language constructs consumed by the operations
+ * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`. Note
+ * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+ * actual entity being referred to may be something other than a type.
+ */
+ List<EntityRef> get references;
+}
+
+class _UnlinkedConstReader extends fb.TableReader<_UnlinkedConstImpl> {
+ const _UnlinkedConstReader();
+
+ @override
+ _UnlinkedConstImpl createObject(fb.BufferPointer bp) => new _UnlinkedConstImpl(bp);
+}
+
+class _UnlinkedConstImpl extends Object with _UnlinkedConstMixin implements UnlinkedConst {
+ final fb.BufferPointer _bp;
+
+ _UnlinkedConstImpl(this._bp);
+
+ List<UnlinkedConstOperation> _operations;
+ List<int> _ints;
+ List<double> _doubles;
+ List<String> _strings;
+ List<EntityRef> _references;
+
+ @override
+ List<UnlinkedConstOperation> get operations {
+ _operations ??= const fb.ListReader<UnlinkedConstOperation>(const _UnlinkedConstOperationReader()).vTableGet(_bp, 0, const <UnlinkedConstOperation>[]);
+ return _operations;
+ }
+
+ @override
+ List<int> get ints {
+ _ints ??= const fb.ListReader<int>(const fb.Uint32Reader()).vTableGet(_bp, 1, const <int>[]);
+ return _ints;
+ }
+
+ @override
+ List<double> get doubles {
+ _doubles ??= const fb.Float64ListReader().vTableGet(_bp, 2, const <double>[]);
+ return _doubles;
+ }
+
+ @override
+ List<String> get strings {
+ _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 3, const <String>[]);
+ return _strings;
+ }
+
+ @override
+ List<EntityRef> get references {
+ _references ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 4, const <EntityRef>[]);
+ return _references;
+ }
+}
+
+abstract class _UnlinkedConstMixin implements UnlinkedConst {
+ @override
+ Map<String, Object> toMap() => {
+ "operations": operations,
+ "ints": ints,
+ "doubles": doubles,
+ "strings": strings,
+ "references": references,
+ };
+}
+
+class UnlinkedDocumentationCommentBuilder extends Object with _UnlinkedDocumentationCommentMixin implements UnlinkedDocumentationComment {
bool _finished = false;
String _text;
int _offset;
int _length;
- UnlinkedDocumentationCommentBuilder();
+ @override
+ String get text => _text ??= '';
/**
* Text of the documentation comment, with '\r\n' replaced by '\n'.
@@ -1248,23 +2498,36 @@
_text = _value;
}
+ @override
+ int get offset => _offset ??= 0;
+
/**
* Offset of the beginning of the documentation comment relative to the
* beginning of the file.
*/
void set offset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_offset = _value;
}
+ @override
+ int get length => _length ??= 0;
+
/**
* Length of the documentation comment (prior to replacing '\r\n' with '\n').
*/
void set length(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_length = _value;
}
+ UnlinkedDocumentationCommentBuilder({String text, int offset, int length})
+ : _text = text,
+ _offset = offset,
+ _length = length;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -1277,23 +2540,15 @@
fbBuilder.addOffset(0, offset_text);
}
if (_offset != null && _offset != 0) {
- fbBuilder.addInt32(1, _offset);
+ fbBuilder.addUint32(1, _offset);
}
if (_length != null && _length != 0) {
- fbBuilder.addInt32(2, _length);
+ fbBuilder.addUint32(2, _length);
}
return fbBuilder.endTable();
}
}
-UnlinkedDocumentationCommentBuilder encodeUnlinkedDocumentationComment({String text, int offset, int length}) {
- UnlinkedDocumentationCommentBuilder builder = new UnlinkedDocumentationCommentBuilder();
- builder.text = text;
- builder.offset = offset;
- builder.length = length;
- return builder;
-}
-
/**
* Unlinked summary information about a documentation comment.
*/
@@ -1326,7 +2581,7 @@
_UnlinkedDocumentationCommentImpl createObject(fb.BufferPointer bp) => new _UnlinkedDocumentationCommentImpl(bp);
}
-class _UnlinkedDocumentationCommentImpl implements UnlinkedDocumentationComment {
+class _UnlinkedDocumentationCommentImpl extends Object with _UnlinkedDocumentationCommentMixin implements UnlinkedDocumentationComment {
final fb.BufferPointer _bp;
_UnlinkedDocumentationCommentImpl(this._bp);
@@ -1336,13 +2591,6 @@
int _length;
@override
- Map<String, Object> toMap() => {
- "text": text,
- "offset": offset,
- "length": length,
- };
-
- @override
String get text {
_text ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _text;
@@ -1350,18 +2598,27 @@
@override
int get offset {
- _offset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _offset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _offset;
}
@override
int get length {
- _length ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
+ _length ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
return _length;
}
}
-class UnlinkedEnumBuilder {
+abstract class _UnlinkedDocumentationCommentMixin implements UnlinkedDocumentationComment {
+ @override
+ Map<String, Object> toMap() => {
+ "text": text,
+ "offset": offset,
+ "length": length,
+ };
+}
+
+class UnlinkedEnumBuilder extends Object with _UnlinkedEnumMixin implements UnlinkedEnum {
bool _finished = false;
String _name;
@@ -1369,7 +2626,8 @@
UnlinkedDocumentationCommentBuilder _documentationComment;
List<UnlinkedEnumValueBuilder> _values;
- UnlinkedEnumBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the enum type.
@@ -1379,14 +2637,21 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the enum name relative to the beginning of the file.
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
/**
* Documentation comment for the enum, or `null` if there is no documentation
* comment.
@@ -1396,6 +2661,9 @@
_documentationComment = _value;
}
+ @override
+ List<UnlinkedEnumValueBuilder> get values => _values ??= <UnlinkedEnumValueBuilder>[];
+
/**
* Values listed in the enum declaration, in declaration order.
*/
@@ -1404,6 +2672,12 @@
_values = _value;
}
+ UnlinkedEnumBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedEnumValueBuilder> values})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _documentationComment = documentationComment,
+ _values = values;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -1424,7 +2698,7 @@
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_documentationComment != null) {
fbBuilder.addOffset(2, offset_documentationComment);
@@ -1436,15 +2710,6 @@
}
}
-UnlinkedEnumBuilder encodeUnlinkedEnum({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedEnumValueBuilder> values}) {
- UnlinkedEnumBuilder builder = new UnlinkedEnumBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.documentationComment = documentationComment;
- builder.values = values;
- return builder;
-}
-
/**
* Unlinked summary information about an enum declaration.
*/
@@ -1479,7 +2744,7 @@
_UnlinkedEnumImpl createObject(fb.BufferPointer bp) => new _UnlinkedEnumImpl(bp);
}
-class _UnlinkedEnumImpl implements UnlinkedEnum {
+class _UnlinkedEnumImpl extends Object with _UnlinkedEnumMixin implements UnlinkedEnum {
final fb.BufferPointer _bp;
_UnlinkedEnumImpl(this._bp);
@@ -1490,14 +2755,6 @@
List<UnlinkedEnumValue> _values;
@override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "documentationComment": documentationComment,
- "values": values,
- };
-
- @override
String get name {
_name ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _name;
@@ -1505,7 +2762,7 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@@ -1522,14 +2779,25 @@
}
}
-class UnlinkedEnumValueBuilder {
+abstract class _UnlinkedEnumMixin implements UnlinkedEnum {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "nameOffset": nameOffset,
+ "documentationComment": documentationComment,
+ "values": values,
+ };
+}
+
+class UnlinkedEnumValueBuilder extends Object with _UnlinkedEnumValueMixin implements UnlinkedEnumValue {
bool _finished = false;
String _name;
int _nameOffset;
UnlinkedDocumentationCommentBuilder _documentationComment;
- UnlinkedEnumValueBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the enumerated value.
@@ -1539,14 +2807,21 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the enum value name relative to the beginning of the file.
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
/**
* Documentation comment for the enum value, or `null` if there is no
* documentation comment.
@@ -1556,6 +2831,11 @@
_documentationComment = _value;
}
+ UnlinkedEnumValueBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _documentationComment = documentationComment;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -1572,7 +2852,7 @@
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_documentationComment != null) {
fbBuilder.addOffset(2, offset_documentationComment);
@@ -1581,14 +2861,6 @@
}
}
-UnlinkedEnumValueBuilder encodeUnlinkedEnumValue({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment}) {
- UnlinkedEnumValueBuilder builder = new UnlinkedEnumValueBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.documentationComment = documentationComment;
- return builder;
-}
-
/**
* Unlinked summary information about a single enumerated value in an enum
* declaration.
@@ -1619,7 +2891,7 @@
_UnlinkedEnumValueImpl createObject(fb.BufferPointer bp) => new _UnlinkedEnumValueImpl(bp);
}
-class _UnlinkedEnumValueImpl implements UnlinkedEnumValue {
+class _UnlinkedEnumValueImpl extends Object with _UnlinkedEnumValueMixin implements UnlinkedEnumValue {
final fb.BufferPointer _bp;
_UnlinkedEnumValueImpl(this._bp);
@@ -1629,13 +2901,6 @@
UnlinkedDocumentationComment _documentationComment;
@override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "documentationComment": documentationComment,
- };
-
- @override
String get name {
_name ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _name;
@@ -1643,7 +2908,7 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@@ -1654,24 +2919,34 @@
}
}
-class UnlinkedExecutableBuilder {
+abstract class _UnlinkedEnumValueMixin implements UnlinkedEnumValue {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "nameOffset": nameOffset,
+ "documentationComment": documentationComment,
+ };
+}
+
+class UnlinkedExecutableBuilder extends Object with _UnlinkedExecutableMixin implements UnlinkedExecutable {
bool _finished = false;
String _name;
int _nameOffset;
UnlinkedDocumentationCommentBuilder _documentationComment;
List<UnlinkedTypeParamBuilder> _typeParameters;
- UnlinkedTypeRefBuilder _returnType;
+ EntityRefBuilder _returnType;
List<UnlinkedParamBuilder> _parameters;
UnlinkedExecutableKind _kind;
bool _isAbstract;
bool _isStatic;
bool _isConst;
bool _isFactory;
- bool _hasImplicitReturnType;
bool _isExternal;
+ int _inferredReturnTypeSlot;
- UnlinkedExecutableBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the executable. For setters, this includes the trailing "=". For
@@ -1683,6 +2958,9 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the executable name relative to the beginning of the file. For
* named constructors, this excludes the class name and excludes the ".".
@@ -1691,9 +2969,13 @@
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
/**
* Documentation comment for the executable, or `null` if there is no
* documentation comment.
@@ -1703,6 +2985,9 @@
_documentationComment = _value;
}
+ @override
+ List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+
/**
* Type parameters of the executable, if any. Empty if support for generic
* method syntax is disabled.
@@ -1712,16 +2997,21 @@
_typeParameters = _value;
}
+ @override
+ EntityRefBuilder get returnType => _returnType;
+
/**
- * Declared return type of the executable. Absent if the return type is
- * `void` or the executable is a constructor. Note that when strong mode is
- * enabled, the actual return type may be different due to type inference.
+ * Declared return type of the executable. Absent if the executable is a
+ * constructor or the return type is implicit.
*/
- void set returnType(UnlinkedTypeRefBuilder _value) {
+ void set returnType(EntityRefBuilder _value) {
assert(!_finished);
_returnType = _value;
}
+ @override
+ List<UnlinkedParamBuilder> get parameters => _parameters ??= <UnlinkedParamBuilder>[];
+
/**
* Parameters of the executable, if any. Note that getters have no
* parameters (hence this will be the empty list), and setters have a single
@@ -1732,6 +3022,9 @@
_parameters = _value;
}
+ @override
+ UnlinkedExecutableKind get kind => _kind ??= UnlinkedExecutableKind.functionOrMethod;
+
/**
* The kind of the executable (function/method, getter, setter, or
* constructor).
@@ -1741,6 +3034,9 @@
_kind = _value;
}
+ @override
+ bool get isAbstract => _isAbstract ??= false;
+
/**
* Indicates whether the executable is declared using the `abstract` keyword.
*/
@@ -1749,6 +3045,9 @@
_isAbstract = _value;
}
+ @override
+ bool get isStatic => _isStatic ??= false;
+
/**
* Indicates whether the executable is declared using the `static` keyword.
*
@@ -1761,6 +3060,9 @@
_isStatic = _value;
}
+ @override
+ bool get isConst => _isConst ??= false;
+
/**
* Indicates whether the executable is declared using the `const` keyword.
*/
@@ -1769,6 +3071,9 @@
_isConst = _value;
}
+ @override
+ bool get isFactory => _isFactory ??= false;
+
/**
* Indicates whether the executable is declared using the `factory` keyword.
*/
@@ -1777,14 +3082,8 @@
_isFactory = _value;
}
- /**
- * Indicates whether the executable lacks an explicit return type
- * declaration. False for constructors and setters.
- */
- void set hasImplicitReturnType(bool _value) {
- assert(!_finished);
- _hasImplicitReturnType = _value;
- }
+ @override
+ bool get isExternal => _isExternal ??= false;
/**
* Indicates whether the executable is declared using the `external` keyword.
@@ -1794,6 +3093,37 @@
_isExternal = _value;
}
+ @override
+ int get inferredReturnTypeSlot => _inferredReturnTypeSlot ??= 0;
+
+ /**
+ * If this executable's return type is inferrable, nonzero slot id
+ * identifying which entry in [LinkedLibrary.types] contains the inferred
+ * return type. If there is no matching entry in [LinkedLibrary.types], then
+ * no return type was inferred for this variable, so its static type is
+ * `dynamic`.
+ */
+ void set inferredReturnTypeSlot(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _inferredReturnTypeSlot = _value;
+ }
+
+ UnlinkedExecutableBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, EntityRefBuilder returnType, List<UnlinkedParamBuilder> parameters, UnlinkedExecutableKind kind, bool isAbstract, bool isStatic, bool isConst, bool isFactory, bool isExternal, int inferredReturnTypeSlot})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _documentationComment = documentationComment,
+ _typeParameters = typeParameters,
+ _returnType = returnType,
+ _parameters = parameters,
+ _kind = kind,
+ _isAbstract = isAbstract,
+ _isStatic = isStatic,
+ _isConst = isConst,
+ _isFactory = isFactory,
+ _isExternal = isExternal,
+ _inferredReturnTypeSlot = inferredReturnTypeSlot;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -1822,7 +3152,7 @@
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_documentationComment != null) {
fbBuilder.addOffset(2, offset_documentationComment);
@@ -1837,7 +3167,7 @@
fbBuilder.addOffset(5, offset_parameters);
}
if (_kind != null && _kind != UnlinkedExecutableKind.functionOrMethod) {
- fbBuilder.addInt32(6, _kind.index);
+ fbBuilder.addUint32(6, _kind.index);
}
if (_isAbstract == true) {
fbBuilder.addBool(7, true);
@@ -1851,34 +3181,16 @@
if (_isFactory == true) {
fbBuilder.addBool(10, true);
}
- if (_hasImplicitReturnType == true) {
+ if (_isExternal == true) {
fbBuilder.addBool(11, true);
}
- if (_isExternal == true) {
- fbBuilder.addBool(12, true);
+ if (_inferredReturnTypeSlot != null && _inferredReturnTypeSlot != 0) {
+ fbBuilder.addUint32(12, _inferredReturnTypeSlot);
}
return fbBuilder.endTable();
}
}
-UnlinkedExecutableBuilder encodeUnlinkedExecutable({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, UnlinkedTypeRefBuilder returnType, List<UnlinkedParamBuilder> parameters, UnlinkedExecutableKind kind, bool isAbstract, bool isStatic, bool isConst, bool isFactory, bool hasImplicitReturnType, bool isExternal}) {
- UnlinkedExecutableBuilder builder = new UnlinkedExecutableBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.documentationComment = documentationComment;
- builder.typeParameters = typeParameters;
- builder.returnType = returnType;
- builder.parameters = parameters;
- builder.kind = kind;
- builder.isAbstract = isAbstract;
- builder.isStatic = isStatic;
- builder.isConst = isConst;
- builder.isFactory = isFactory;
- builder.hasImplicitReturnType = hasImplicitReturnType;
- builder.isExternal = isExternal;
- return builder;
-}
-
/**
* Unlinked summary information about a function, method, getter, or setter
* declaration.
@@ -1913,11 +3225,10 @@
List<UnlinkedTypeParam> get typeParameters;
/**
- * Declared return type of the executable. Absent if the return type is
- * `void` or the executable is a constructor. Note that when strong mode is
- * enabled, the actual return type may be different due to type inference.
+ * Declared return type of the executable. Absent if the executable is a
+ * constructor or the return type is implicit.
*/
- UnlinkedTypeRef get returnType;
+ EntityRef get returnType;
/**
* Parameters of the executable, if any. Note that getters have no
@@ -1957,15 +3268,18 @@
bool get isFactory;
/**
- * Indicates whether the executable lacks an explicit return type
- * declaration. False for constructors and setters.
- */
- bool get hasImplicitReturnType;
-
- /**
* Indicates whether the executable is declared using the `external` keyword.
*/
bool get isExternal;
+
+ /**
+ * If this executable's return type is inferrable, nonzero slot id
+ * identifying which entry in [LinkedLibrary.types] contains the inferred
+ * return type. If there is no matching entry in [LinkedLibrary.types], then
+ * no return type was inferred for this variable, so its static type is
+ * `dynamic`.
+ */
+ int get inferredReturnTypeSlot;
}
class _UnlinkedExecutableReader extends fb.TableReader<_UnlinkedExecutableImpl> {
@@ -1975,7 +3289,7 @@
_UnlinkedExecutableImpl createObject(fb.BufferPointer bp) => new _UnlinkedExecutableImpl(bp);
}
-class _UnlinkedExecutableImpl implements UnlinkedExecutable {
+class _UnlinkedExecutableImpl extends Object with _UnlinkedExecutableMixin implements UnlinkedExecutable {
final fb.BufferPointer _bp;
_UnlinkedExecutableImpl(this._bp);
@@ -1984,32 +3298,15 @@
int _nameOffset;
UnlinkedDocumentationComment _documentationComment;
List<UnlinkedTypeParam> _typeParameters;
- UnlinkedTypeRef _returnType;
+ EntityRef _returnType;
List<UnlinkedParam> _parameters;
UnlinkedExecutableKind _kind;
bool _isAbstract;
bool _isStatic;
bool _isConst;
bool _isFactory;
- bool _hasImplicitReturnType;
bool _isExternal;
-
- @override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "documentationComment": documentationComment,
- "typeParameters": typeParameters,
- "returnType": returnType,
- "parameters": parameters,
- "kind": kind,
- "isAbstract": isAbstract,
- "isStatic": isStatic,
- "isConst": isConst,
- "isFactory": isFactory,
- "hasImplicitReturnType": hasImplicitReturnType,
- "isExternal": isExternal,
- };
+ int _inferredReturnTypeSlot;
@override
String get name {
@@ -2019,7 +3316,7 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@@ -2036,8 +3333,8 @@
}
@override
- UnlinkedTypeRef get returnType {
- _returnType ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 4, null);
+ EntityRef get returnType {
+ _returnType ??= const _EntityRefReader().vTableGet(_bp, 4, null);
return _returnType;
}
@@ -2049,7 +3346,7 @@
@override
UnlinkedExecutableKind get kind {
- _kind ??= UnlinkedExecutableKind.values[const fb.Int32Reader().vTableGet(_bp, 6, 0)];
+ _kind ??= const _UnlinkedExecutableKindReader().vTableGet(_bp, 6, UnlinkedExecutableKind.functionOrMethod);
return _kind;
}
@@ -2078,78 +3375,104 @@
}
@override
- bool get hasImplicitReturnType {
- _hasImplicitReturnType ??= const fb.BoolReader().vTableGet(_bp, 11, false);
- return _hasImplicitReturnType;
+ bool get isExternal {
+ _isExternal ??= const fb.BoolReader().vTableGet(_bp, 11, false);
+ return _isExternal;
}
@override
- bool get isExternal {
- _isExternal ??= const fb.BoolReader().vTableGet(_bp, 12, false);
- return _isExternal;
+ int get inferredReturnTypeSlot {
+ _inferredReturnTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 12, 0);
+ return _inferredReturnTypeSlot;
}
}
-class UnlinkedExportNonPublicBuilder {
+abstract class _UnlinkedExecutableMixin implements UnlinkedExecutable {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "nameOffset": nameOffset,
+ "documentationComment": documentationComment,
+ "typeParameters": typeParameters,
+ "returnType": returnType,
+ "parameters": parameters,
+ "kind": kind,
+ "isAbstract": isAbstract,
+ "isStatic": isStatic,
+ "isConst": isConst,
+ "isFactory": isFactory,
+ "isExternal": isExternal,
+ "inferredReturnTypeSlot": inferredReturnTypeSlot,
+ };
+}
+
+class UnlinkedExportNonPublicBuilder extends Object with _UnlinkedExportNonPublicMixin implements UnlinkedExportNonPublic {
bool _finished = false;
int _offset;
int _uriOffset;
int _uriEnd;
- UnlinkedExportNonPublicBuilder();
+ @override
+ int get offset => _offset ??= 0;
/**
* Offset of the "export" keyword.
*/
void set offset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_offset = _value;
}
+ @override
+ int get uriOffset => _uriOffset ??= 0;
+
/**
* Offset of the URI string (including quotes) relative to the beginning of
* the file.
*/
void set uriOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_uriOffset = _value;
}
+ @override
+ int get uriEnd => _uriEnd ??= 0;
+
/**
* End of the URI string (including quotes) relative to the beginning of the
* file.
*/
void set uriEnd(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_uriEnd = _value;
}
+ UnlinkedExportNonPublicBuilder({int offset, int uriOffset, int uriEnd})
+ : _offset = offset,
+ _uriOffset = uriOffset,
+ _uriEnd = uriEnd;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
fbBuilder.startTable();
if (_offset != null && _offset != 0) {
- fbBuilder.addInt32(0, _offset);
+ fbBuilder.addUint32(0, _offset);
}
if (_uriOffset != null && _uriOffset != 0) {
- fbBuilder.addInt32(1, _uriOffset);
+ fbBuilder.addUint32(1, _uriOffset);
}
if (_uriEnd != null && _uriEnd != 0) {
- fbBuilder.addInt32(2, _uriEnd);
+ fbBuilder.addUint32(2, _uriEnd);
}
return fbBuilder.endTable();
}
}
-UnlinkedExportNonPublicBuilder encodeUnlinkedExportNonPublic({int offset, int uriOffset, int uriEnd}) {
- UnlinkedExportNonPublicBuilder builder = new UnlinkedExportNonPublicBuilder();
- builder.offset = offset;
- builder.uriOffset = uriOffset;
- builder.uriEnd = uriEnd;
- return builder;
-}
-
/**
* Unlinked summary information about an export declaration (stored outside
* [UnlinkedPublicNamespace]).
@@ -2181,7 +3504,7 @@
_UnlinkedExportNonPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportNonPublicImpl(bp);
}
-class _UnlinkedExportNonPublicImpl implements UnlinkedExportNonPublic {
+class _UnlinkedExportNonPublicImpl extends Object with _UnlinkedExportNonPublicMixin implements UnlinkedExportNonPublic {
final fb.BufferPointer _bp;
_UnlinkedExportNonPublicImpl(this._bp);
@@ -2191,38 +3514,41 @@
int _uriEnd;
@override
- Map<String, Object> toMap() => {
- "offset": offset,
- "uriOffset": uriOffset,
- "uriEnd": uriEnd,
- };
-
- @override
int get offset {
- _offset ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
+ _offset ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
return _offset;
}
@override
int get uriOffset {
- _uriOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _uriOffset;
}
@override
int get uriEnd {
- _uriEnd ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
+ _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
return _uriEnd;
}
}
-class UnlinkedExportPublicBuilder {
+abstract class _UnlinkedExportNonPublicMixin implements UnlinkedExportNonPublic {
+ @override
+ Map<String, Object> toMap() => {
+ "offset": offset,
+ "uriOffset": uriOffset,
+ "uriEnd": uriEnd,
+ };
+}
+
+class UnlinkedExportPublicBuilder extends Object with _UnlinkedExportPublicMixin implements UnlinkedExportPublic {
bool _finished = false;
String _uri;
List<UnlinkedCombinatorBuilder> _combinators;
- UnlinkedExportPublicBuilder();
+ @override
+ String get uri => _uri ??= '';
/**
* URI used in the source code to reference the exported library.
@@ -2232,6 +3558,9 @@
_uri = _value;
}
+ @override
+ List<UnlinkedCombinatorBuilder> get combinators => _combinators ??= <UnlinkedCombinatorBuilder>[];
+
/**
* Combinators contained in this import declaration.
*/
@@ -2240,6 +3569,10 @@
_combinators = _value;
}
+ UnlinkedExportPublicBuilder({String uri, List<UnlinkedCombinatorBuilder> combinators})
+ : _uri = uri,
+ _combinators = combinators;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -2262,13 +3595,6 @@
}
}
-UnlinkedExportPublicBuilder encodeUnlinkedExportPublic({String uri, List<UnlinkedCombinatorBuilder> combinators}) {
- UnlinkedExportPublicBuilder builder = new UnlinkedExportPublicBuilder();
- builder.uri = uri;
- builder.combinators = combinators;
- return builder;
-}
-
/**
* Unlinked summary information about an export declaration (stored inside
* [UnlinkedPublicNamespace]).
@@ -2293,7 +3619,7 @@
_UnlinkedExportPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportPublicImpl(bp);
}
-class _UnlinkedExportPublicImpl implements UnlinkedExportPublic {
+class _UnlinkedExportPublicImpl extends Object with _UnlinkedExportPublicMixin implements UnlinkedExportPublic {
final fb.BufferPointer _bp;
_UnlinkedExportPublicImpl(this._bp);
@@ -2302,12 +3628,6 @@
List<UnlinkedCombinator> _combinators;
@override
- Map<String, Object> toMap() => {
- "uri": uri,
- "combinators": combinators,
- };
-
- @override
String get uri {
_uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _uri;
@@ -2320,7 +3640,15 @@
}
}
-class UnlinkedImportBuilder {
+abstract class _UnlinkedExportPublicMixin implements UnlinkedExportPublic {
+ @override
+ Map<String, Object> toMap() => {
+ "uri": uri,
+ "combinators": combinators,
+ };
+}
+
+class UnlinkedImportBuilder extends Object with _UnlinkedImportMixin implements UnlinkedImport {
bool _finished = false;
String _uri;
@@ -2333,7 +3661,8 @@
int _uriEnd;
int _prefixOffset;
- UnlinkedImportBuilder();
+ @override
+ String get uri => _uri ??= '';
/**
* URI used in the source code to reference the imported library.
@@ -2343,15 +3672,22 @@
_uri = _value;
}
+ @override
+ int get offset => _offset ??= 0;
+
/**
* If [isImplicit] is false, offset of the "import" keyword. If [isImplicit]
* is true, zero.
*/
void set offset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_offset = _value;
}
+ @override
+ int get prefixReference => _prefixReference ??= 0;
+
/**
* Index into [UnlinkedUnit.references] of the prefix declared by this
* import declaration, or zero if this import declaration declares no prefix.
@@ -2360,9 +3696,13 @@
*/
void set prefixReference(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_prefixReference = _value;
}
+ @override
+ List<UnlinkedCombinatorBuilder> get combinators => _combinators ??= <UnlinkedCombinatorBuilder>[];
+
/**
* Combinators contained in this import declaration.
*/
@@ -2371,6 +3711,9 @@
_combinators = _value;
}
+ @override
+ bool get isDeferred => _isDeferred ??= false;
+
/**
* Indicates whether the import declaration uses the `deferred` keyword.
*/
@@ -2379,6 +3722,9 @@
_isDeferred = _value;
}
+ @override
+ bool get isImplicit => _isImplicit ??= false;
+
/**
* Indicates whether the import declaration is implicit.
*/
@@ -2387,33 +3733,56 @@
_isImplicit = _value;
}
+ @override
+ int get uriOffset => _uriOffset ??= 0;
+
/**
* Offset of the URI string (including quotes) relative to the beginning of
* the file. If [isImplicit] is true, zero.
*/
void set uriOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_uriOffset = _value;
}
+ @override
+ int get uriEnd => _uriEnd ??= 0;
+
/**
* End of the URI string (including quotes) relative to the beginning of the
* file. If [isImplicit] is true, zero.
*/
void set uriEnd(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_uriEnd = _value;
}
+ @override
+ int get prefixOffset => _prefixOffset ??= 0;
+
/**
* Offset of the prefix name relative to the beginning of the file, or zero
* if there is no prefix.
*/
void set prefixOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_prefixOffset = _value;
}
+ UnlinkedImportBuilder({String uri, int offset, int prefixReference, List<UnlinkedCombinatorBuilder> combinators, bool isDeferred, bool isImplicit, int uriOffset, int uriEnd, int prefixOffset})
+ : _uri = uri,
+ _offset = offset,
+ _prefixReference = prefixReference,
+ _combinators = combinators,
+ _isDeferred = isDeferred,
+ _isImplicit = isImplicit,
+ _uriOffset = uriOffset,
+ _uriEnd = uriEnd,
+ _prefixOffset = prefixOffset;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -2430,10 +3799,10 @@
fbBuilder.addOffset(0, offset_uri);
}
if (_offset != null && _offset != 0) {
- fbBuilder.addInt32(1, _offset);
+ fbBuilder.addUint32(1, _offset);
}
if (_prefixReference != null && _prefixReference != 0) {
- fbBuilder.addInt32(2, _prefixReference);
+ fbBuilder.addUint32(2, _prefixReference);
}
if (offset_combinators != null) {
fbBuilder.addOffset(3, offset_combinators);
@@ -2445,32 +3814,18 @@
fbBuilder.addBool(5, true);
}
if (_uriOffset != null && _uriOffset != 0) {
- fbBuilder.addInt32(6, _uriOffset);
+ fbBuilder.addUint32(6, _uriOffset);
}
if (_uriEnd != null && _uriEnd != 0) {
- fbBuilder.addInt32(7, _uriEnd);
+ fbBuilder.addUint32(7, _uriEnd);
}
if (_prefixOffset != null && _prefixOffset != 0) {
- fbBuilder.addInt32(8, _prefixOffset);
+ fbBuilder.addUint32(8, _prefixOffset);
}
return fbBuilder.endTable();
}
}
-UnlinkedImportBuilder encodeUnlinkedImport({String uri, int offset, int prefixReference, List<UnlinkedCombinatorBuilder> combinators, bool isDeferred, bool isImplicit, int uriOffset, int uriEnd, int prefixOffset}) {
- UnlinkedImportBuilder builder = new UnlinkedImportBuilder();
- builder.uri = uri;
- builder.offset = offset;
- builder.prefixReference = prefixReference;
- builder.combinators = combinators;
- builder.isDeferred = isDeferred;
- builder.isImplicit = isImplicit;
- builder.uriOffset = uriOffset;
- builder.uriEnd = uriEnd;
- builder.prefixOffset = prefixOffset;
- return builder;
-}
-
/**
* Unlinked summary information about an import declaration.
*/
@@ -2536,7 +3891,7 @@
_UnlinkedImportImpl createObject(fb.BufferPointer bp) => new _UnlinkedImportImpl(bp);
}
-class _UnlinkedImportImpl implements UnlinkedImport {
+class _UnlinkedImportImpl extends Object with _UnlinkedImportMixin implements UnlinkedImport {
final fb.BufferPointer _bp;
_UnlinkedImportImpl(this._bp);
@@ -2552,19 +3907,6 @@
int _prefixOffset;
@override
- Map<String, Object> toMap() => {
- "uri": uri,
- "offset": offset,
- "prefixReference": prefixReference,
- "combinators": combinators,
- "isDeferred": isDeferred,
- "isImplicit": isImplicit,
- "uriOffset": uriOffset,
- "uriEnd": uriEnd,
- "prefixOffset": prefixOffset,
- };
-
- @override
String get uri {
_uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _uri;
@@ -2572,13 +3914,13 @@
@override
int get offset {
- _offset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _offset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _offset;
}
@override
int get prefixReference {
- _prefixReference ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
+ _prefixReference ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
return _prefixReference;
}
@@ -2602,36 +3944,52 @@
@override
int get uriOffset {
- _uriOffset ??= const fb.Int32Reader().vTableGet(_bp, 6, 0);
+ _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 6, 0);
return _uriOffset;
}
@override
int get uriEnd {
- _uriEnd ??= const fb.Int32Reader().vTableGet(_bp, 7, 0);
+ _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 7, 0);
return _uriEnd;
}
@override
int get prefixOffset {
- _prefixOffset ??= const fb.Int32Reader().vTableGet(_bp, 8, 0);
+ _prefixOffset ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
return _prefixOffset;
}
}
-class UnlinkedParamBuilder {
+abstract class _UnlinkedImportMixin implements UnlinkedImport {
+ @override
+ Map<String, Object> toMap() => {
+ "uri": uri,
+ "offset": offset,
+ "prefixReference": prefixReference,
+ "combinators": combinators,
+ "isDeferred": isDeferred,
+ "isImplicit": isImplicit,
+ "uriOffset": uriOffset,
+ "uriEnd": uriEnd,
+ "prefixOffset": prefixOffset,
+ };
+}
+
+class UnlinkedParamBuilder extends Object with _UnlinkedParamMixin implements UnlinkedParam {
bool _finished = false;
String _name;
int _nameOffset;
- UnlinkedTypeRefBuilder _type;
+ EntityRefBuilder _type;
List<UnlinkedParamBuilder> _parameters;
UnlinkedParamKind _kind;
bool _isFunctionTyped;
bool _isInitializingFormal;
- bool _hasImplicitType;
+ int _inferredTypeSlot;
- UnlinkedParamBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the parameter.
@@ -2641,26 +3999,34 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the parameter name relative to the beginning of the file.
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ EntityRefBuilder get type => _type;
+
/**
* If [isFunctionTyped] is `true`, the declared return type. If
- * [isFunctionTyped] is `false`, the declared type. Absent if
- * [isFunctionTyped] is `true` and the declared return type is `void`. Note
- * that when strong mode is enabled, the actual type may be different due to
- * type inference.
+ * [isFunctionTyped] is `false`, the declared type. Absent if the type is
+ * implicit.
*/
- void set type(UnlinkedTypeRefBuilder _value) {
+ void set type(EntityRefBuilder _value) {
assert(!_finished);
_type = _value;
}
+ @override
+ List<UnlinkedParamBuilder> get parameters => _parameters ??= <UnlinkedParamBuilder>[];
+
/**
* If [isFunctionTyped] is `true`, the parameters of the function type.
*/
@@ -2669,6 +4035,9 @@
_parameters = _value;
}
+ @override
+ UnlinkedParamKind get kind => _kind ??= UnlinkedParamKind.required;
+
/**
* Kind of the parameter.
*/
@@ -2677,6 +4046,9 @@
_kind = _value;
}
+ @override
+ bool get isFunctionTyped => _isFunctionTyped ??= false;
+
/**
* Indicates whether this is a function-typed parameter.
*/
@@ -2685,6 +4057,9 @@
_isFunctionTyped = _value;
}
+ @override
+ bool get isInitializingFormal => _isInitializingFormal ??= false;
+
/**
* Indicates whether this is an initializing formal parameter (i.e. it is
* declared using `this.` syntax).
@@ -2694,15 +4069,36 @@
_isInitializingFormal = _value;
}
+ @override
+ int get inferredTypeSlot => _inferredTypeSlot ??= 0;
+
/**
- * Indicates whether this parameter lacks an explicit type declaration.
- * Always false for a function-typed parameter.
+ * If this parameter's type is inferrable, nonzero slot id identifying which
+ * entry in [LinkedLibrary.types] contains the inferred type. If there is no
+ * matching entry in [LinkedLibrary.types], then no type was inferred for
+ * this variable, so its static type is `dynamic`.
+ *
+ * Note that although strong mode considers initializing formals to be
+ * inferrable, they are not marked as such in the summary; if their type is
+ * not specified, they always inherit the static type of the corresponding
+ * field.
*/
- void set hasImplicitType(bool _value) {
+ void set inferredTypeSlot(int _value) {
assert(!_finished);
- _hasImplicitType = _value;
+ assert(_value == null || _value >= 0);
+ _inferredTypeSlot = _value;
}
+ UnlinkedParamBuilder({String name, int nameOffset, EntityRefBuilder type, List<UnlinkedParamBuilder> parameters, UnlinkedParamKind kind, bool isFunctionTyped, bool isInitializingFormal, int inferredTypeSlot})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _type = type,
+ _parameters = parameters,
+ _kind = kind,
+ _isFunctionTyped = isFunctionTyped,
+ _isInitializingFormal = isInitializingFormal,
+ _inferredTypeSlot = inferredTypeSlot;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -2723,7 +4119,7 @@
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_type != null) {
fbBuilder.addOffset(2, offset_type);
@@ -2732,7 +4128,7 @@
fbBuilder.addOffset(3, offset_parameters);
}
if (_kind != null && _kind != UnlinkedParamKind.required) {
- fbBuilder.addInt32(4, _kind.index);
+ fbBuilder.addUint32(4, _kind.index);
}
if (_isFunctionTyped == true) {
fbBuilder.addBool(5, true);
@@ -2740,26 +4136,13 @@
if (_isInitializingFormal == true) {
fbBuilder.addBool(6, true);
}
- if (_hasImplicitType == true) {
- fbBuilder.addBool(7, true);
+ if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
+ fbBuilder.addUint32(7, _inferredTypeSlot);
}
return fbBuilder.endTable();
}
}
-UnlinkedParamBuilder encodeUnlinkedParam({String name, int nameOffset, UnlinkedTypeRefBuilder type, List<UnlinkedParamBuilder> parameters, UnlinkedParamKind kind, bool isFunctionTyped, bool isInitializingFormal, bool hasImplicitType}) {
- UnlinkedParamBuilder builder = new UnlinkedParamBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.type = type;
- builder.parameters = parameters;
- builder.kind = kind;
- builder.isFunctionTyped = isFunctionTyped;
- builder.isInitializingFormal = isInitializingFormal;
- builder.hasImplicitType = hasImplicitType;
- return builder;
-}
-
/**
* Unlinked summary information about a function parameter.
*/
@@ -2777,12 +4160,10 @@
/**
* If [isFunctionTyped] is `true`, the declared return type. If
- * [isFunctionTyped] is `false`, the declared type. Absent if
- * [isFunctionTyped] is `true` and the declared return type is `void`. Note
- * that when strong mode is enabled, the actual type may be different due to
- * type inference.
+ * [isFunctionTyped] is `false`, the declared type. Absent if the type is
+ * implicit.
*/
- UnlinkedTypeRef get type;
+ EntityRef get type;
/**
* If [isFunctionTyped] is `true`, the parameters of the function type.
@@ -2806,10 +4187,17 @@
bool get isInitializingFormal;
/**
- * Indicates whether this parameter lacks an explicit type declaration.
- * Always false for a function-typed parameter.
+ * If this parameter's type is inferrable, nonzero slot id identifying which
+ * entry in [LinkedLibrary.types] contains the inferred type. If there is no
+ * matching entry in [LinkedLibrary.types], then no type was inferred for
+ * this variable, so its static type is `dynamic`.
+ *
+ * Note that although strong mode considers initializing formals to be
+ * inferrable, they are not marked as such in the summary; if their type is
+ * not specified, they always inherit the static type of the corresponding
+ * field.
*/
- bool get hasImplicitType;
+ int get inferredTypeSlot;
}
class _UnlinkedParamReader extends fb.TableReader<_UnlinkedParamImpl> {
@@ -2819,31 +4207,19 @@
_UnlinkedParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedParamImpl(bp);
}
-class _UnlinkedParamImpl implements UnlinkedParam {
+class _UnlinkedParamImpl extends Object with _UnlinkedParamMixin implements UnlinkedParam {
final fb.BufferPointer _bp;
_UnlinkedParamImpl(this._bp);
String _name;
int _nameOffset;
- UnlinkedTypeRef _type;
+ EntityRef _type;
List<UnlinkedParam> _parameters;
UnlinkedParamKind _kind;
bool _isFunctionTyped;
bool _isInitializingFormal;
- bool _hasImplicitType;
-
- @override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "type": type,
- "parameters": parameters,
- "kind": kind,
- "isFunctionTyped": isFunctionTyped,
- "isInitializingFormal": isInitializingFormal,
- "hasImplicitType": hasImplicitType,
- };
+ int _inferredTypeSlot;
@override
String get name {
@@ -2853,13 +4229,13 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@override
- UnlinkedTypeRef get type {
- _type ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 2, null);
+ EntityRef get type {
+ _type ??= const _EntityRefReader().vTableGet(_bp, 2, null);
return _type;
}
@@ -2871,7 +4247,7 @@
@override
UnlinkedParamKind get kind {
- _kind ??= UnlinkedParamKind.values[const fb.Int32Reader().vTableGet(_bp, 4, 0)];
+ _kind ??= const _UnlinkedParamKindReader().vTableGet(_bp, 4, UnlinkedParamKind.required);
return _kind;
}
@@ -2888,19 +4264,34 @@
}
@override
- bool get hasImplicitType {
- _hasImplicitType ??= const fb.BoolReader().vTableGet(_bp, 7, false);
- return _hasImplicitType;
+ int get inferredTypeSlot {
+ _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 7, 0);
+ return _inferredTypeSlot;
}
}
-class UnlinkedPartBuilder {
+abstract class _UnlinkedParamMixin implements UnlinkedParam {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "nameOffset": nameOffset,
+ "type": type,
+ "parameters": parameters,
+ "kind": kind,
+ "isFunctionTyped": isFunctionTyped,
+ "isInitializingFormal": isInitializingFormal,
+ "inferredTypeSlot": inferredTypeSlot,
+ };
+}
+
+class UnlinkedPartBuilder extends Object with _UnlinkedPartMixin implements UnlinkedPart {
bool _finished = false;
int _uriOffset;
int _uriEnd;
- UnlinkedPartBuilder();
+ @override
+ int get uriOffset => _uriOffset ??= 0;
/**
* Offset of the URI string (including quotes) relative to the beginning of
@@ -2908,39 +4299,41 @@
*/
void set uriOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_uriOffset = _value;
}
+ @override
+ int get uriEnd => _uriEnd ??= 0;
+
/**
* End of the URI string (including quotes) relative to the beginning of the
* file.
*/
void set uriEnd(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_uriEnd = _value;
}
+ UnlinkedPartBuilder({int uriOffset, int uriEnd})
+ : _uriOffset = uriOffset,
+ _uriEnd = uriEnd;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
fbBuilder.startTable();
if (_uriOffset != null && _uriOffset != 0) {
- fbBuilder.addInt32(0, _uriOffset);
+ fbBuilder.addUint32(0, _uriOffset);
}
if (_uriEnd != null && _uriEnd != 0) {
- fbBuilder.addInt32(1, _uriEnd);
+ fbBuilder.addUint32(1, _uriEnd);
}
return fbBuilder.endTable();
}
}
-UnlinkedPartBuilder encodeUnlinkedPart({int uriOffset, int uriEnd}) {
- UnlinkedPartBuilder builder = new UnlinkedPartBuilder();
- builder.uriOffset = uriOffset;
- builder.uriEnd = uriEnd;
- return builder;
-}
-
/**
* Unlinked summary information about a part declaration.
*/
@@ -2966,7 +4359,7 @@
_UnlinkedPartImpl createObject(fb.BufferPointer bp) => new _UnlinkedPartImpl(bp);
}
-class _UnlinkedPartImpl implements UnlinkedPart {
+class _UnlinkedPartImpl extends Object with _UnlinkedPartMixin implements UnlinkedPart {
final fb.BufferPointer _bp;
_UnlinkedPartImpl(this._bp);
@@ -2975,32 +4368,36 @@
int _uriEnd;
@override
- Map<String, Object> toMap() => {
- "uriOffset": uriOffset,
- "uriEnd": uriEnd,
- };
-
- @override
int get uriOffset {
- _uriOffset ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
+ _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
return _uriOffset;
}
@override
int get uriEnd {
- _uriEnd ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _uriEnd;
}
}
-class UnlinkedPublicNameBuilder {
+abstract class _UnlinkedPartMixin implements UnlinkedPart {
+ @override
+ Map<String, Object> toMap() => {
+ "uriOffset": uriOffset,
+ "uriEnd": uriEnd,
+ };
+}
+
+class UnlinkedPublicNameBuilder extends Object with _UnlinkedPublicNameMixin implements UnlinkedPublicName {
bool _finished = false;
String _name;
- PrelinkedReferenceKind _kind;
+ ReferenceKind _kind;
int _numTypeParameters;
+ List<UnlinkedPublicNameBuilder> _constMembers;
- UnlinkedPublicNameBuilder();
+ @override
+ String get name => _name ??= '';
/**
* The name itself.
@@ -3010,62 +4407,81 @@
_name = _value;
}
+ @override
+ ReferenceKind get kind => _kind ??= ReferenceKind.classOrEnum;
+
/**
* The kind of object referred to by the name.
*/
- void set kind(PrelinkedReferenceKind _value) {
+ void set kind(ReferenceKind _value) {
assert(!_finished);
_kind = _value;
}
+ @override
+ int get numTypeParameters => _numTypeParameters ??= 0;
+
/**
* If the entity being referred to is generic, the number of type parameters
* it accepts. Otherwise zero.
*/
void set numTypeParameters(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_numTypeParameters = _value;
}
+ @override
+ List<UnlinkedPublicNameBuilder> get constMembers => _constMembers ??= <UnlinkedPublicNameBuilder>[];
+
+ /**
+ * If this [UnlinkedPublicName] is a class, the list of members which can be
+ * referenced from constants - static constant fields, static methods, and
+ * constructors. Otherwise empty.
+ */
+ void set constMembers(List<UnlinkedPublicNameBuilder> _value) {
+ assert(!_finished);
+ _constMembers = _value;
+ }
+
+ UnlinkedPublicNameBuilder({String name, ReferenceKind kind, int numTypeParameters, List<UnlinkedPublicNameBuilder> constMembers})
+ : _name = name,
+ _kind = kind,
+ _numTypeParameters = numTypeParameters,
+ _constMembers = constMembers;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
fb.Offset offset_name;
+ fb.Offset offset_constMembers;
if (_name != null) {
offset_name = fbBuilder.writeString(_name);
}
+ if (!(_constMembers == null || _constMembers.isEmpty)) {
+ offset_constMembers = fbBuilder.writeList(_constMembers.map((b) => b.finish(fbBuilder)).toList());
+ }
fbBuilder.startTable();
if (offset_name != null) {
fbBuilder.addOffset(0, offset_name);
}
- if (_kind != null && _kind != PrelinkedReferenceKind.classOrEnum) {
- fbBuilder.addInt32(1, _kind.index);
+ if (_kind != null && _kind != ReferenceKind.classOrEnum) {
+ fbBuilder.addUint32(1, _kind.index);
}
if (_numTypeParameters != null && _numTypeParameters != 0) {
- fbBuilder.addInt32(2, _numTypeParameters);
+ fbBuilder.addUint32(2, _numTypeParameters);
+ }
+ if (offset_constMembers != null) {
+ fbBuilder.addOffset(3, offset_constMembers);
}
return fbBuilder.endTable();
}
}
-UnlinkedPublicNameBuilder encodeUnlinkedPublicName({String name, PrelinkedReferenceKind kind, int numTypeParameters}) {
- UnlinkedPublicNameBuilder builder = new UnlinkedPublicNameBuilder();
- builder.name = name;
- builder.kind = kind;
- builder.numTypeParameters = numTypeParameters;
- return builder;
-}
-
/**
* Unlinked summary information about a specific name contributed by a
* compilation unit to a library's public namespace.
*
- * TODO(paulberry): add a count of generic parameters, so that resynthesis
- * doesn't have to peek into the library to obtain this info.
- *
- * TODO(paulberry): for classes, add info about static members and
- * constructors, since this will be needed to prelink info about constants.
- *
* TODO(paulberry): some of this information is redundant with information
* elsewhere in the summary. Consider reducing the redundancy to reduce
* summary size.
@@ -3080,13 +4496,20 @@
/**
* The kind of object referred to by the name.
*/
- PrelinkedReferenceKind get kind;
+ ReferenceKind get kind;
/**
* If the entity being referred to is generic, the number of type parameters
* it accepts. Otherwise zero.
*/
int get numTypeParameters;
+
+ /**
+ * If this [UnlinkedPublicName] is a class, the list of members which can be
+ * referenced from constants - static constant fields, static methods, and
+ * constructors. Otherwise empty.
+ */
+ List<UnlinkedPublicName> get constMembers;
}
class _UnlinkedPublicNameReader extends fb.TableReader<_UnlinkedPublicNameImpl> {
@@ -3096,21 +4519,15 @@
_UnlinkedPublicNameImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNameImpl(bp);
}
-class _UnlinkedPublicNameImpl implements UnlinkedPublicName {
+class _UnlinkedPublicNameImpl extends Object with _UnlinkedPublicNameMixin implements UnlinkedPublicName {
final fb.BufferPointer _bp;
_UnlinkedPublicNameImpl(this._bp);
String _name;
- PrelinkedReferenceKind _kind;
+ ReferenceKind _kind;
int _numTypeParameters;
-
- @override
- Map<String, Object> toMap() => {
- "name": name,
- "kind": kind,
- "numTypeParameters": numTypeParameters,
- };
+ List<UnlinkedPublicName> _constMembers;
@override
String get name {
@@ -3119,26 +4536,43 @@
}
@override
- PrelinkedReferenceKind get kind {
- _kind ??= PrelinkedReferenceKind.values[const fb.Int32Reader().vTableGet(_bp, 1, 0)];
+ ReferenceKind get kind {
+ _kind ??= const _ReferenceKindReader().vTableGet(_bp, 1, ReferenceKind.classOrEnum);
return _kind;
}
@override
int get numTypeParameters {
- _numTypeParameters ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
+ _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
return _numTypeParameters;
}
+
+ @override
+ List<UnlinkedPublicName> get constMembers {
+ _constMembers ??= const fb.ListReader<UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 3, const <UnlinkedPublicName>[]);
+ return _constMembers;
+ }
}
-class UnlinkedPublicNamespaceBuilder {
+abstract class _UnlinkedPublicNameMixin implements UnlinkedPublicName {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "kind": kind,
+ "numTypeParameters": numTypeParameters,
+ "constMembers": constMembers,
+ };
+}
+
+class UnlinkedPublicNamespaceBuilder extends Object with _UnlinkedPublicNamespaceMixin implements UnlinkedPublicNamespace {
bool _finished = false;
List<UnlinkedPublicNameBuilder> _names;
List<UnlinkedExportPublicBuilder> _exports;
List<String> _parts;
- UnlinkedPublicNamespaceBuilder();
+ @override
+ List<UnlinkedPublicNameBuilder> get names => _names ??= <UnlinkedPublicNameBuilder>[];
/**
* Public names defined in the compilation unit.
@@ -3151,6 +4585,9 @@
_names = _value;
}
+ @override
+ List<UnlinkedExportPublicBuilder> get exports => _exports ??= <UnlinkedExportPublicBuilder>[];
+
/**
* Export declarations in the compilation unit.
*/
@@ -3159,6 +4596,9 @@
_exports = _value;
}
+ @override
+ List<String> get parts => _parts ??= <String>[];
+
/**
* URIs referenced by part declarations in the compilation unit.
*/
@@ -3167,6 +4607,11 @@
_parts = _value;
}
+ UnlinkedPublicNamespaceBuilder({List<UnlinkedPublicNameBuilder> names, List<UnlinkedExportPublicBuilder> exports, List<String> parts})
+ : _names = names,
+ _exports = exports,
+ _parts = parts;
+
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
return fbBuilder.finish(finish(fbBuilder));
@@ -3201,14 +4646,6 @@
}
}
-UnlinkedPublicNamespaceBuilder encodeUnlinkedPublicNamespace({List<UnlinkedPublicNameBuilder> names, List<UnlinkedExportPublicBuilder> exports, List<String> parts}) {
- UnlinkedPublicNamespaceBuilder builder = new UnlinkedPublicNamespaceBuilder();
- builder.names = names;
- builder.exports = exports;
- builder.parts = parts;
- return builder;
-}
-
/**
* Unlinked summary information about what a compilation unit contributes to a
* library's public namespace. This is the subset of [UnlinkedUnit] that is
@@ -3246,7 +4683,7 @@
_UnlinkedPublicNamespaceImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNamespaceImpl(bp);
}
-class _UnlinkedPublicNamespaceImpl implements UnlinkedPublicNamespace {
+class _UnlinkedPublicNamespaceImpl extends Object with _UnlinkedPublicNamespaceMixin implements UnlinkedPublicNamespace {
final fb.BufferPointer _bp;
_UnlinkedPublicNamespaceImpl(this._bp);
@@ -3256,13 +4693,6 @@
List<String> _parts;
@override
- Map<String, Object> toMap() => {
- "names": names,
- "exports": exports,
- "parts": parts,
- };
-
- @override
List<UnlinkedPublicName> get names {
_names ??= const fb.ListReader<UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 0, const <UnlinkedPublicName>[]);
return _names;
@@ -3281,23 +4711,36 @@
}
}
-class UnlinkedReferenceBuilder {
+abstract class _UnlinkedPublicNamespaceMixin implements UnlinkedPublicNamespace {
+ @override
+ Map<String, Object> toMap() => {
+ "names": names,
+ "exports": exports,
+ "parts": parts,
+ };
+}
+
+class UnlinkedReferenceBuilder extends Object with _UnlinkedReferenceMixin implements UnlinkedReference {
bool _finished = false;
String _name;
int _prefixReference;
- UnlinkedReferenceBuilder();
+ @override
+ String get name => _name ??= '';
/**
- * Name of the entity being referred to. The empty string refers to the
- * pseudo-type `dynamic`.
+ * Name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
*/
void set name(String _value) {
assert(!_finished);
_name = _value;
}
+ @override
+ int get prefixReference => _prefixReference ??= 0;
+
/**
* Prefix used to refer to the entity, or zero if no prefix is used. This is
* an index into [UnlinkedUnit.references].
@@ -3308,9 +4751,14 @@
*/
void set prefixReference(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_prefixReference = _value;
}
+ UnlinkedReferenceBuilder({String name, int prefixReference})
+ : _name = name,
+ _prefixReference = prefixReference;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -3323,19 +4771,12 @@
fbBuilder.addOffset(0, offset_name);
}
if (_prefixReference != null && _prefixReference != 0) {
- fbBuilder.addInt32(1, _prefixReference);
+ fbBuilder.addUint32(1, _prefixReference);
}
return fbBuilder.endTable();
}
}
-UnlinkedReferenceBuilder encodeUnlinkedReference({String name, int prefixReference}) {
- UnlinkedReferenceBuilder builder = new UnlinkedReferenceBuilder();
- builder.name = name;
- builder.prefixReference = prefixReference;
- return builder;
-}
-
/**
* Unlinked summary information about a name referred to in one library that
* might be defined in another.
@@ -3343,8 +4784,8 @@
abstract class UnlinkedReference extends base.SummaryClass {
/**
- * Name of the entity being referred to. The empty string refers to the
- * pseudo-type `dynamic`.
+ * Name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
*/
String get name;
@@ -3366,7 +4807,7 @@
_UnlinkedReferenceImpl createObject(fb.BufferPointer bp) => new _UnlinkedReferenceImpl(bp);
}
-class _UnlinkedReferenceImpl implements UnlinkedReference {
+class _UnlinkedReferenceImpl extends Object with _UnlinkedReferenceMixin implements UnlinkedReference {
final fb.BufferPointer _bp;
_UnlinkedReferenceImpl(this._bp);
@@ -3375,12 +4816,6 @@
int _prefixReference;
@override
- Map<String, Object> toMap() => {
- "name": name,
- "prefixReference": prefixReference,
- };
-
- @override
String get name {
_name ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _name;
@@ -3388,22 +4823,31 @@
@override
int get prefixReference {
- _prefixReference ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _prefixReference ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _prefixReference;
}
}
-class UnlinkedTypedefBuilder {
+abstract class _UnlinkedReferenceMixin implements UnlinkedReference {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "prefixReference": prefixReference,
+ };
+}
+
+class UnlinkedTypedefBuilder extends Object with _UnlinkedTypedefMixin implements UnlinkedTypedef {
bool _finished = false;
String _name;
int _nameOffset;
UnlinkedDocumentationCommentBuilder _documentationComment;
List<UnlinkedTypeParamBuilder> _typeParameters;
- UnlinkedTypeRefBuilder _returnType;
+ EntityRefBuilder _returnType;
List<UnlinkedParamBuilder> _parameters;
- UnlinkedTypedefBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the typedef.
@@ -3413,14 +4857,21 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the typedef name relative to the beginning of the file.
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
/**
* Documentation comment for the typedef, or `null` if there is no
* documentation comment.
@@ -3430,6 +4881,9 @@
_documentationComment = _value;
}
+ @override
+ List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+
/**
* Type parameters of the typedef, if any.
*/
@@ -3438,14 +4892,20 @@
_typeParameters = _value;
}
+ @override
+ EntityRefBuilder get returnType => _returnType;
+
/**
- * Return type of the typedef. Absent if the return type is `void`.
+ * Return type of the typedef.
*/
- void set returnType(UnlinkedTypeRefBuilder _value) {
+ void set returnType(EntityRefBuilder _value) {
assert(!_finished);
_returnType = _value;
}
+ @override
+ List<UnlinkedParamBuilder> get parameters => _parameters ??= <UnlinkedParamBuilder>[];
+
/**
* Parameters of the executable, if any.
*/
@@ -3454,6 +4914,14 @@
_parameters = _value;
}
+ UnlinkedTypedefBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, EntityRefBuilder returnType, List<UnlinkedParamBuilder> parameters})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _documentationComment = documentationComment,
+ _typeParameters = typeParameters,
+ _returnType = returnType,
+ _parameters = parameters;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -3482,7 +4950,7 @@
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_documentationComment != null) {
fbBuilder.addOffset(2, offset_documentationComment);
@@ -3500,17 +4968,6 @@
}
}
-UnlinkedTypedefBuilder encodeUnlinkedTypedef({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, UnlinkedTypeRefBuilder returnType, List<UnlinkedParamBuilder> parameters}) {
- UnlinkedTypedefBuilder builder = new UnlinkedTypedefBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.documentationComment = documentationComment;
- builder.typeParameters = typeParameters;
- builder.returnType = returnType;
- builder.parameters = parameters;
- return builder;
-}
-
/**
* Unlinked summary information about a typedef declaration.
*/
@@ -3538,9 +4995,9 @@
List<UnlinkedTypeParam> get typeParameters;
/**
- * Return type of the typedef. Absent if the return type is `void`.
+ * Return type of the typedef.
*/
- UnlinkedTypeRef get returnType;
+ EntityRef get returnType;
/**
* Parameters of the executable, if any.
@@ -3555,7 +5012,7 @@
_UnlinkedTypedefImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypedefImpl(bp);
}
-class _UnlinkedTypedefImpl implements UnlinkedTypedef {
+class _UnlinkedTypedefImpl extends Object with _UnlinkedTypedefMixin implements UnlinkedTypedef {
final fb.BufferPointer _bp;
_UnlinkedTypedefImpl(this._bp);
@@ -3564,20 +5021,10 @@
int _nameOffset;
UnlinkedDocumentationComment _documentationComment;
List<UnlinkedTypeParam> _typeParameters;
- UnlinkedTypeRef _returnType;
+ EntityRef _returnType;
List<UnlinkedParam> _parameters;
@override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "documentationComment": documentationComment,
- "typeParameters": typeParameters,
- "returnType": returnType,
- "parameters": parameters,
- };
-
- @override
String get name {
_name ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _name;
@@ -3585,7 +5032,7 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@@ -3602,8 +5049,8 @@
}
@override
- UnlinkedTypeRef get returnType {
- _returnType ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 4, null);
+ EntityRef get returnType {
+ _returnType ??= const _EntityRefReader().vTableGet(_bp, 4, null);
return _returnType;
}
@@ -3614,14 +5061,27 @@
}
}
-class UnlinkedTypeParamBuilder {
+abstract class _UnlinkedTypedefMixin implements UnlinkedTypedef {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "nameOffset": nameOffset,
+ "documentationComment": documentationComment,
+ "typeParameters": typeParameters,
+ "returnType": returnType,
+ "parameters": parameters,
+ };
+}
+
+class UnlinkedTypeParamBuilder extends Object with _UnlinkedTypeParamMixin implements UnlinkedTypeParam {
bool _finished = false;
String _name;
int _nameOffset;
- UnlinkedTypeRefBuilder _bound;
+ EntityRefBuilder _bound;
- UnlinkedTypeParamBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the type parameter.
@@ -3631,23 +5091,35 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the type parameter name relative to the beginning of the file.
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ EntityRefBuilder get bound => _bound;
+
/**
* Bound of the type parameter, if a bound is explicitly declared. Otherwise
* null.
*/
- void set bound(UnlinkedTypeRefBuilder _value) {
+ void set bound(EntityRefBuilder _value) {
assert(!_finished);
_bound = _value;
}
+ UnlinkedTypeParamBuilder({String name, int nameOffset, EntityRefBuilder bound})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _bound = bound;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
@@ -3664,7 +5136,7 @@
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_bound != null) {
fbBuilder.addOffset(2, offset_bound);
@@ -3673,14 +5145,6 @@
}
}
-UnlinkedTypeParamBuilder encodeUnlinkedTypeParam({String name, int nameOffset, UnlinkedTypeRefBuilder bound}) {
- UnlinkedTypeParamBuilder builder = new UnlinkedTypeParamBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.bound = bound;
- return builder;
-}
-
/**
* Unlinked summary information about a type parameter declaration.
*/
@@ -3700,7 +5164,7 @@
* Bound of the type parameter, if a bound is explicitly declared. Otherwise
* null.
*/
- UnlinkedTypeRef get bound;
+ EntityRef get bound;
}
class _UnlinkedTypeParamReader extends fb.TableReader<_UnlinkedTypeParamImpl> {
@@ -3710,21 +5174,14 @@
_UnlinkedTypeParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypeParamImpl(bp);
}
-class _UnlinkedTypeParamImpl implements UnlinkedTypeParam {
+class _UnlinkedTypeParamImpl extends Object with _UnlinkedTypeParamMixin implements UnlinkedTypeParam {
final fb.BufferPointer _bp;
_UnlinkedTypeParamImpl(this._bp);
String _name;
int _nameOffset;
- UnlinkedTypeRef _bound;
-
- @override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "bound": bound,
- };
+ EntityRef _bound;
@override
String get name {
@@ -3734,191 +5191,27 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@override
- UnlinkedTypeRef get bound {
- _bound ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 2, null);
+ EntityRef get bound {
+ _bound ??= const _EntityRefReader().vTableGet(_bp, 2, null);
return _bound;
}
}
-class UnlinkedTypeRefBuilder {
- bool _finished = false;
-
- int _reference;
- int _paramReference;
- List<UnlinkedTypeRefBuilder> _typeArguments;
-
- UnlinkedTypeRefBuilder();
-
- /**
- * Index into [UnlinkedUnit.references] for the type being referred to, or
- * zero if this is a reference to a type parameter.
- *
- * Note that since zero is also a valid index into
- * [UnlinkedUnit.references], we cannot distinguish between references to
- * type parameters and references to types by checking [reference] against
- * zero. To distinguish between references to type parameters and references
- * to types, check whether [paramReference] is zero.
- */
- void set reference(int _value) {
- assert(!_finished);
- _reference = _value;
- }
-
- /**
- * If this is a reference to a type parameter, one-based index into the list
- * of [UnlinkedTypeParam]s currently in effect. Indexing is done using De
- * Bruijn index conventions; that is, innermost parameters come first, and
- * if a class or method has multiple parameters, they are indexed from right
- * to left. So for instance, if the enclosing declaration is
- *
- * class C<T,U> {
- * m<V,W> {
- * ...
- * }
- * }
- *
- * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
- * respectively.
- *
- * If the type being referred to is not a type parameter, [paramReference] is
- * zero.
- */
- void set paramReference(int _value) {
- assert(!_finished);
- _paramReference = _value;
- }
-
- /**
- * If this is an instantiation of a generic type, the type arguments used to
- * instantiate it. Trailing type arguments of type `dynamic` are omitted.
- */
- void set typeArguments(List<UnlinkedTypeRefBuilder> _value) {
- assert(!_finished);
- _typeArguments = _value;
- }
-
- fb.Offset finish(fb.Builder fbBuilder) {
- assert(!_finished);
- _finished = true;
- fb.Offset offset_typeArguments;
- if (!(_typeArguments == null || _typeArguments.isEmpty)) {
- offset_typeArguments = fbBuilder.writeList(_typeArguments.map((b) => b.finish(fbBuilder)).toList());
- }
- fbBuilder.startTable();
- if (_reference != null && _reference != 0) {
- fbBuilder.addInt32(0, _reference);
- }
- if (_paramReference != null && _paramReference != 0) {
- fbBuilder.addInt32(1, _paramReference);
- }
- if (offset_typeArguments != null) {
- fbBuilder.addOffset(2, offset_typeArguments);
- }
- return fbBuilder.endTable();
- }
-}
-
-UnlinkedTypeRefBuilder encodeUnlinkedTypeRef({int reference, int paramReference, List<UnlinkedTypeRefBuilder> typeArguments}) {
- UnlinkedTypeRefBuilder builder = new UnlinkedTypeRefBuilder();
- builder.reference = reference;
- builder.paramReference = paramReference;
- builder.typeArguments = typeArguments;
- return builder;
-}
-
-/**
- * Unlinked summary information about a reference to a type.
- */
-abstract class UnlinkedTypeRef extends base.SummaryClass {
-
- /**
- * Index into [UnlinkedUnit.references] for the type being referred to, or
- * zero if this is a reference to a type parameter.
- *
- * Note that since zero is also a valid index into
- * [UnlinkedUnit.references], we cannot distinguish between references to
- * type parameters and references to types by checking [reference] against
- * zero. To distinguish between references to type parameters and references
- * to types, check whether [paramReference] is zero.
- */
- int get reference;
-
- /**
- * If this is a reference to a type parameter, one-based index into the list
- * of [UnlinkedTypeParam]s currently in effect. Indexing is done using De
- * Bruijn index conventions; that is, innermost parameters come first, and
- * if a class or method has multiple parameters, they are indexed from right
- * to left. So for instance, if the enclosing declaration is
- *
- * class C<T,U> {
- * m<V,W> {
- * ...
- * }
- * }
- *
- * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
- * respectively.
- *
- * If the type being referred to is not a type parameter, [paramReference] is
- * zero.
- */
- int get paramReference;
-
- /**
- * If this is an instantiation of a generic type, the type arguments used to
- * instantiate it. Trailing type arguments of type `dynamic` are omitted.
- */
- List<UnlinkedTypeRef> get typeArguments;
-}
-
-class _UnlinkedTypeRefReader extends fb.TableReader<_UnlinkedTypeRefImpl> {
- const _UnlinkedTypeRefReader();
-
- @override
- _UnlinkedTypeRefImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypeRefImpl(bp);
-}
-
-class _UnlinkedTypeRefImpl implements UnlinkedTypeRef {
- final fb.BufferPointer _bp;
-
- _UnlinkedTypeRefImpl(this._bp);
-
- int _reference;
- int _paramReference;
- List<UnlinkedTypeRef> _typeArguments;
-
+abstract class _UnlinkedTypeParamMixin implements UnlinkedTypeParam {
@override
Map<String, Object> toMap() => {
- "reference": reference,
- "paramReference": paramReference,
- "typeArguments": typeArguments,
+ "name": name,
+ "nameOffset": nameOffset,
+ "bound": bound,
};
-
- @override
- int get reference {
- _reference ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
- return _reference;
- }
-
- @override
- int get paramReference {
- _paramReference ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
- return _paramReference;
- }
-
- @override
- List<UnlinkedTypeRef> get typeArguments {
- _typeArguments ??= const fb.ListReader<UnlinkedTypeRef>(const _UnlinkedTypeRefReader()).vTableGet(_bp, 2, const <UnlinkedTypeRef>[]);
- return _typeArguments;
- }
}
-class UnlinkedUnitBuilder {
+class UnlinkedUnitBuilder extends Object with _UnlinkedUnitMixin implements UnlinkedUnit {
bool _finished = false;
String _libraryName;
@@ -3936,7 +5229,8 @@
List<UnlinkedTypedefBuilder> _typedefs;
List<UnlinkedVariableBuilder> _variables;
- UnlinkedUnitBuilder();
+ @override
+ String get libraryName => _libraryName ??= '';
/**
* Name of the library (from a "library" declaration, if present).
@@ -3946,24 +5240,35 @@
_libraryName = _value;
}
+ @override
+ int get libraryNameOffset => _libraryNameOffset ??= 0;
+
/**
* Offset of the library name relative to the beginning of the file (or 0 if
* the library has no name).
*/
void set libraryNameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_libraryNameOffset = _value;
}
+ @override
+ int get libraryNameLength => _libraryNameLength ??= 0;
+
/**
* Length of the library name as it appears in the source code (or 0 if the
* library has no name).
*/
void set libraryNameLength(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_libraryNameLength = _value;
}
+ @override
+ UnlinkedDocumentationCommentBuilder get libraryDocumentationComment => _libraryDocumentationComment;
+
/**
* Documentation comment for the library, or `null` if there is no
* documentation comment.
@@ -3973,6 +5278,9 @@
_libraryDocumentationComment = _value;
}
+ @override
+ UnlinkedPublicNamespaceBuilder get publicNamespace => _publicNamespace;
+
/**
* Unlinked public namespace of this compilation unit.
*/
@@ -3981,16 +5289,24 @@
_publicNamespace = _value;
}
+ @override
+ List<UnlinkedReferenceBuilder> get references => _references ??= <UnlinkedReferenceBuilder>[];
+
/**
* Top level and prefixed names referred to by this compilation unit. The
- * zeroth element of this array is always populated and always represents a
- * reference to the pseudo-type "dynamic".
+ * zeroth element of this array is always populated and is used to represent
+ * the absence of a reference in places where a reference is optional (for
+ * example [UnlinkedReference.prefixReference or
+ * UnlinkedImport.prefixReference]).
*/
void set references(List<UnlinkedReferenceBuilder> _value) {
assert(!_finished);
_references = _value;
}
+ @override
+ List<UnlinkedClassBuilder> get classes => _classes ??= <UnlinkedClassBuilder>[];
+
/**
* Classes declared in the compilation unit.
*/
@@ -3999,6 +5315,9 @@
_classes = _value;
}
+ @override
+ List<UnlinkedEnumBuilder> get enums => _enums ??= <UnlinkedEnumBuilder>[];
+
/**
* Enums declared in the compilation unit.
*/
@@ -4007,6 +5326,9 @@
_enums = _value;
}
+ @override
+ List<UnlinkedExecutableBuilder> get executables => _executables ??= <UnlinkedExecutableBuilder>[];
+
/**
* Top level executable objects (functions, getters, and setters) declared in
* the compilation unit.
@@ -4016,6 +5338,9 @@
_executables = _value;
}
+ @override
+ List<UnlinkedExportNonPublicBuilder> get exports => _exports ??= <UnlinkedExportNonPublicBuilder>[];
+
/**
* Export declarations in the compilation unit.
*/
@@ -4024,6 +5349,9 @@
_exports = _value;
}
+ @override
+ List<UnlinkedImportBuilder> get imports => _imports ??= <UnlinkedImportBuilder>[];
+
/**
* Import declarations in the compilation unit.
*/
@@ -4032,6 +5360,9 @@
_imports = _value;
}
+ @override
+ List<UnlinkedPartBuilder> get parts => _parts ??= <UnlinkedPartBuilder>[];
+
/**
* Part declarations in the compilation unit.
*/
@@ -4040,6 +5371,9 @@
_parts = _value;
}
+ @override
+ List<UnlinkedTypedefBuilder> get typedefs => _typedefs ??= <UnlinkedTypedefBuilder>[];
+
/**
* Typedefs declared in the compilation unit.
*/
@@ -4048,6 +5382,9 @@
_typedefs = _value;
}
+ @override
+ List<UnlinkedVariableBuilder> get variables => _variables ??= <UnlinkedVariableBuilder>[];
+
/**
* Top level variables declared in the compilation unit.
*/
@@ -4056,6 +5393,22 @@
_variables = _value;
}
+ UnlinkedUnitBuilder({String libraryName, int libraryNameOffset, int libraryNameLength, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedClassBuilder> classes, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, List<UnlinkedImportBuilder> imports, List<UnlinkedPartBuilder> parts, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables})
+ : _libraryName = libraryName,
+ _libraryNameOffset = libraryNameOffset,
+ _libraryNameLength = libraryNameLength,
+ _libraryDocumentationComment = libraryDocumentationComment,
+ _publicNamespace = publicNamespace,
+ _references = references,
+ _classes = classes,
+ _enums = enums,
+ _executables = executables,
+ _exports = exports,
+ _imports = imports,
+ _parts = parts,
+ _typedefs = typedefs,
+ _variables = variables;
+
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
return fbBuilder.finish(finish(fbBuilder));
@@ -4117,10 +5470,10 @@
fbBuilder.addOffset(0, offset_libraryName);
}
if (_libraryNameOffset != null && _libraryNameOffset != 0) {
- fbBuilder.addInt32(1, _libraryNameOffset);
+ fbBuilder.addUint32(1, _libraryNameOffset);
}
if (_libraryNameLength != null && _libraryNameLength != 0) {
- fbBuilder.addInt32(2, _libraryNameLength);
+ fbBuilder.addUint32(2, _libraryNameLength);
}
if (offset_libraryDocumentationComment != null) {
fbBuilder.addOffset(3, offset_libraryDocumentationComment);
@@ -4159,25 +5512,6 @@
}
}
-UnlinkedUnitBuilder encodeUnlinkedUnit({String libraryName, int libraryNameOffset, int libraryNameLength, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedClassBuilder> classes, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, List<UnlinkedImportBuilder> imports, List<UnlinkedPartBuilder> parts, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables}) {
- UnlinkedUnitBuilder builder = new UnlinkedUnitBuilder();
- builder.libraryName = libraryName;
- builder.libraryNameOffset = libraryNameOffset;
- builder.libraryNameLength = libraryNameLength;
- builder.libraryDocumentationComment = libraryDocumentationComment;
- builder.publicNamespace = publicNamespace;
- builder.references = references;
- builder.classes = classes;
- builder.enums = enums;
- builder.executables = executables;
- builder.exports = exports;
- builder.imports = imports;
- builder.parts = parts;
- builder.typedefs = typedefs;
- builder.variables = variables;
- return builder;
-}
-
/**
* Unlinked summary information about a compilation unit ("part file").
*/
@@ -4217,8 +5551,10 @@
/**
* Top level and prefixed names referred to by this compilation unit. The
- * zeroth element of this array is always populated and always represents a
- * reference to the pseudo-type "dynamic".
+ * zeroth element of this array is always populated and is used to represent
+ * the absence of a reference in places where a reference is optional (for
+ * example [UnlinkedReference.prefixReference or
+ * UnlinkedImport.prefixReference]).
*/
List<UnlinkedReference> get references;
@@ -4271,7 +5607,7 @@
_UnlinkedUnitImpl createObject(fb.BufferPointer bp) => new _UnlinkedUnitImpl(bp);
}
-class _UnlinkedUnitImpl implements UnlinkedUnit {
+class _UnlinkedUnitImpl extends Object with _UnlinkedUnitMixin implements UnlinkedUnit {
final fb.BufferPointer _bp;
_UnlinkedUnitImpl(this._bp);
@@ -4292,24 +5628,6 @@
List<UnlinkedVariable> _variables;
@override
- Map<String, Object> toMap() => {
- "libraryName": libraryName,
- "libraryNameOffset": libraryNameOffset,
- "libraryNameLength": libraryNameLength,
- "libraryDocumentationComment": libraryDocumentationComment,
- "publicNamespace": publicNamespace,
- "references": references,
- "classes": classes,
- "enums": enums,
- "executables": executables,
- "exports": exports,
- "imports": imports,
- "parts": parts,
- "typedefs": typedefs,
- "variables": variables,
- };
-
- @override
String get libraryName {
_libraryName ??= const fb.StringReader().vTableGet(_bp, 0, '');
return _libraryName;
@@ -4317,13 +5635,13 @@
@override
int get libraryNameOffset {
- _libraryNameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _libraryNameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _libraryNameOffset;
}
@override
int get libraryNameLength {
- _libraryNameLength ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
+ _libraryNameLength ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
return _libraryNameLength;
}
@@ -4394,19 +5712,42 @@
}
}
-class UnlinkedVariableBuilder {
+abstract class _UnlinkedUnitMixin implements UnlinkedUnit {
+ @override
+ Map<String, Object> toMap() => {
+ "libraryName": libraryName,
+ "libraryNameOffset": libraryNameOffset,
+ "libraryNameLength": libraryNameLength,
+ "libraryDocumentationComment": libraryDocumentationComment,
+ "publicNamespace": publicNamespace,
+ "references": references,
+ "classes": classes,
+ "enums": enums,
+ "executables": executables,
+ "exports": exports,
+ "imports": imports,
+ "parts": parts,
+ "typedefs": typedefs,
+ "variables": variables,
+ };
+}
+
+class UnlinkedVariableBuilder extends Object with _UnlinkedVariableMixin implements UnlinkedVariable {
bool _finished = false;
String _name;
int _nameOffset;
UnlinkedDocumentationCommentBuilder _documentationComment;
- UnlinkedTypeRefBuilder _type;
+ EntityRefBuilder _type;
+ UnlinkedConstBuilder _constExpr;
bool _isStatic;
bool _isFinal;
bool _isConst;
- bool _hasImplicitType;
+ int _propagatedTypeSlot;
+ int _inferredTypeSlot;
- UnlinkedVariableBuilder();
+ @override
+ String get name => _name ??= '';
/**
* Name of the variable.
@@ -4416,14 +5757,21 @@
_name = _value;
}
+ @override
+ int get nameOffset => _nameOffset ??= 0;
+
/**
* Offset of the variable name relative to the beginning of the file.
*/
void set nameOffset(int _value) {
assert(!_finished);
+ assert(_value == null || _value >= 0);
_nameOffset = _value;
}
+ @override
+ UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
/**
* Documentation comment for the variable, or `null` if there is no
* documentation comment.
@@ -4433,15 +5781,32 @@
_documentationComment = _value;
}
+ @override
+ EntityRefBuilder get type => _type;
+
/**
- * Declared type of the variable. Note that when strong mode is enabled, the
- * actual type of the variable may be different due to type inference.
+ * Declared type of the variable. Absent if the type is implicit.
*/
- void set type(UnlinkedTypeRefBuilder _value) {
+ void set type(EntityRefBuilder _value) {
assert(!_finished);
_type = _value;
}
+ @override
+ UnlinkedConstBuilder get constExpr => _constExpr;
+
+ /**
+ * If [isConst] is true, and the variable has an initializer, the constant
+ * expression in the initializer.
+ */
+ void set constExpr(UnlinkedConstBuilder _value) {
+ assert(!_finished);
+ _constExpr = _value;
+ }
+
+ @override
+ bool get isStatic => _isStatic ??= false;
+
/**
* Indicates whether the variable is declared using the `static` keyword.
*
@@ -4454,6 +5819,9 @@
_isStatic = _value;
}
+ @override
+ bool get isFinal => _isFinal ??= false;
+
/**
* Indicates whether the variable is declared using the `final` keyword.
*/
@@ -4462,6 +5830,9 @@
_isFinal = _value;
}
+ @override
+ bool get isConst => _isConst ??= false;
+
/**
* Indicates whether the variable is declared using the `const` keyword.
*/
@@ -4470,20 +5841,57 @@
_isConst = _value;
}
+ @override
+ int get propagatedTypeSlot => _propagatedTypeSlot ??= 0;
+
/**
- * Indicates whether this variable lacks an explicit type declaration.
+ * If this variable is propagable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the propagated type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then this variable's
+ * propagated type is the same as its declared type.
+ *
+ * Non-propagable variables have a [propagatedTypeSlot] of zero.
*/
- void set hasImplicitType(bool _value) {
+ void set propagatedTypeSlot(int _value) {
assert(!_finished);
- _hasImplicitType = _value;
+ assert(_value == null || _value >= 0);
+ _propagatedTypeSlot = _value;
}
+ @override
+ int get inferredTypeSlot => _inferredTypeSlot ??= 0;
+
+ /**
+ * If this variable is inferrable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the inferred type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then no type was
+ * inferred for this variable, so its static type is `dynamic`.
+ */
+ void set inferredTypeSlot(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _inferredTypeSlot = _value;
+ }
+
+ UnlinkedVariableBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, EntityRefBuilder type, UnlinkedConstBuilder constExpr, bool isStatic, bool isFinal, bool isConst, int propagatedTypeSlot, int inferredTypeSlot})
+ : _name = name,
+ _nameOffset = nameOffset,
+ _documentationComment = documentationComment,
+ _type = type,
+ _constExpr = constExpr,
+ _isStatic = isStatic,
+ _isFinal = isFinal,
+ _isConst = isConst,
+ _propagatedTypeSlot = propagatedTypeSlot,
+ _inferredTypeSlot = inferredTypeSlot;
+
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
fb.Offset offset_name;
fb.Offset offset_documentationComment;
fb.Offset offset_type;
+ fb.Offset offset_constExpr;
if (_name != null) {
offset_name = fbBuilder.writeString(_name);
}
@@ -4493,12 +5901,15 @@
if (_type != null) {
offset_type = _type.finish(fbBuilder);
}
+ if (_constExpr != null) {
+ offset_constExpr = _constExpr.finish(fbBuilder);
+ }
fbBuilder.startTable();
if (offset_name != null) {
fbBuilder.addOffset(0, offset_name);
}
if (_nameOffset != null && _nameOffset != 0) {
- fbBuilder.addInt32(1, _nameOffset);
+ fbBuilder.addUint32(1, _nameOffset);
}
if (offset_documentationComment != null) {
fbBuilder.addOffset(2, offset_documentationComment);
@@ -4506,35 +5917,28 @@
if (offset_type != null) {
fbBuilder.addOffset(3, offset_type);
}
- if (_isStatic == true) {
- fbBuilder.addBool(4, true);
+ if (offset_constExpr != null) {
+ fbBuilder.addOffset(4, offset_constExpr);
}
- if (_isFinal == true) {
+ if (_isStatic == true) {
fbBuilder.addBool(5, true);
}
- if (_isConst == true) {
+ if (_isFinal == true) {
fbBuilder.addBool(6, true);
}
- if (_hasImplicitType == true) {
+ if (_isConst == true) {
fbBuilder.addBool(7, true);
}
+ if (_propagatedTypeSlot != null && _propagatedTypeSlot != 0) {
+ fbBuilder.addUint32(8, _propagatedTypeSlot);
+ }
+ if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
+ fbBuilder.addUint32(9, _inferredTypeSlot);
+ }
return fbBuilder.endTable();
}
}
-UnlinkedVariableBuilder encodeUnlinkedVariable({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, UnlinkedTypeRefBuilder type, bool isStatic, bool isFinal, bool isConst, bool hasImplicitType}) {
- UnlinkedVariableBuilder builder = new UnlinkedVariableBuilder();
- builder.name = name;
- builder.nameOffset = nameOffset;
- builder.documentationComment = documentationComment;
- builder.type = type;
- builder.isStatic = isStatic;
- builder.isFinal = isFinal;
- builder.isConst = isConst;
- builder.hasImplicitType = hasImplicitType;
- return builder;
-}
-
/**
* Unlinked summary information about a top level variable, local variable, or
* a field.
@@ -4558,10 +5962,15 @@
UnlinkedDocumentationComment get documentationComment;
/**
- * Declared type of the variable. Note that when strong mode is enabled, the
- * actual type of the variable may be different due to type inference.
+ * Declared type of the variable. Absent if the type is implicit.
*/
- UnlinkedTypeRef get type;
+ EntityRef get type;
+
+ /**
+ * If [isConst] is true, and the variable has an initializer, the constant
+ * expression in the initializer.
+ */
+ UnlinkedConst get constExpr;
/**
* Indicates whether the variable is declared using the `static` keyword.
@@ -4583,9 +5992,22 @@
bool get isConst;
/**
- * Indicates whether this variable lacks an explicit type declaration.
+ * If this variable is propagable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the propagated type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then this variable's
+ * propagated type is the same as its declared type.
+ *
+ * Non-propagable variables have a [propagatedTypeSlot] of zero.
*/
- bool get hasImplicitType;
+ int get propagatedTypeSlot;
+
+ /**
+ * If this variable is inferrable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the inferred type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then no type was
+ * inferred for this variable, so its static type is `dynamic`.
+ */
+ int get inferredTypeSlot;
}
class _UnlinkedVariableReader extends fb.TableReader<_UnlinkedVariableImpl> {
@@ -4595,7 +6017,7 @@
_UnlinkedVariableImpl createObject(fb.BufferPointer bp) => new _UnlinkedVariableImpl(bp);
}
-class _UnlinkedVariableImpl implements UnlinkedVariable {
+class _UnlinkedVariableImpl extends Object with _UnlinkedVariableMixin implements UnlinkedVariable {
final fb.BufferPointer _bp;
_UnlinkedVariableImpl(this._bp);
@@ -4603,23 +6025,13 @@
String _name;
int _nameOffset;
UnlinkedDocumentationComment _documentationComment;
- UnlinkedTypeRef _type;
+ EntityRef _type;
+ UnlinkedConst _constExpr;
bool _isStatic;
bool _isFinal;
bool _isConst;
- bool _hasImplicitType;
-
- @override
- Map<String, Object> toMap() => {
- "name": name,
- "nameOffset": nameOffset,
- "documentationComment": documentationComment,
- "type": type,
- "isStatic": isStatic,
- "isFinal": isFinal,
- "isConst": isConst,
- "hasImplicitType": hasImplicitType,
- };
+ int _propagatedTypeSlot;
+ int _inferredTypeSlot;
@override
String get name {
@@ -4629,7 +6041,7 @@
@override
int get nameOffset {
- _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+ _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
return _nameOffset;
}
@@ -4640,33 +6052,61 @@
}
@override
- UnlinkedTypeRef get type {
- _type ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 3, null);
+ EntityRef get type {
+ _type ??= const _EntityRefReader().vTableGet(_bp, 3, null);
return _type;
}
@override
+ UnlinkedConst get constExpr {
+ _constExpr ??= const _UnlinkedConstReader().vTableGet(_bp, 4, null);
+ return _constExpr;
+ }
+
+ @override
bool get isStatic {
- _isStatic ??= const fb.BoolReader().vTableGet(_bp, 4, false);
+ _isStatic ??= const fb.BoolReader().vTableGet(_bp, 5, false);
return _isStatic;
}
@override
bool get isFinal {
- _isFinal ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+ _isFinal ??= const fb.BoolReader().vTableGet(_bp, 6, false);
return _isFinal;
}
@override
bool get isConst {
- _isConst ??= const fb.BoolReader().vTableGet(_bp, 6, false);
+ _isConst ??= const fb.BoolReader().vTableGet(_bp, 7, false);
return _isConst;
}
@override
- bool get hasImplicitType {
- _hasImplicitType ??= const fb.BoolReader().vTableGet(_bp, 7, false);
- return _hasImplicitType;
+ int get propagatedTypeSlot {
+ _propagatedTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
+ return _propagatedTypeSlot;
}
+
+ @override
+ int get inferredTypeSlot {
+ _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 9, 0);
+ return _inferredTypeSlot;
+ }
+}
+
+abstract class _UnlinkedVariableMixin implements UnlinkedVariable {
+ @override
+ Map<String, Object> toMap() => {
+ "name": name,
+ "nameOffset": nameOffset,
+ "documentationComment": documentationComment,
+ "type": type,
+ "constExpr": constExpr,
+ "isStatic": isStatic,
+ "isFinal": isFinal,
+ "isConst": isConst,
+ "propagatedTypeSlot": propagatedTypeSlot,
+ "inferredTypeSlot": inferredTypeSlot,
+ };
}
diff --git a/pkg/analyzer/lib/src/summary/prelink.dart b/pkg/analyzer/lib/src/summary/prelink.dart
index ad4834f..1e3caad 100644
--- a/pkg/analyzer/lib/src/summary/prelink.dart
+++ b/pkg/analyzer/lib/src/summary/prelink.dart
@@ -6,7 +6,7 @@
import 'package:analyzer/src/summary/name_filter.dart';
/**
- * Create a [PrelinkedLibraryBuilder] corresponding to the given
+ * Create a [LinkedLibraryBuilder] corresponding to the given
* [definingUnit], which should be the defining compilation unit for a library.
* Compilation units referenced by the defining compilation unit via `part`
* declarations will be retrieved using [getPart]. Public namespaces for
@@ -14,8 +14,8 @@
* declarations (and files reachable from them via `part` and `export`
* declarations) will be retrieved using [getImport].
*/
-PrelinkedLibraryBuilder prelink(UnlinkedUnit definingUnit,
- GetPartCallback getPart, GetImportCallback getImport) {
+LinkedLibraryBuilder prelink(UnlinkedUnit definingUnit, GetPartCallback getPart,
+ GetImportCallback getImport) {
return new _Prelinker(definingUnit, getPart, getImport).prelink();
}
@@ -32,7 +32,7 @@
/**
* Type of the callback used by the prelinker to obtain unlinked summaries of
- * part files of the library to be prelinked. [relaviteUri] should be
+ * part files of the library to be prelinked. [relativeUri] should be
* interpreted relative to the defining compilation unit of the library being
* prelinked.
*
@@ -41,6 +41,16 @@
typedef UnlinkedUnit GetPartCallback(String relativeUri);
/**
+ * A [_Meaning] representing a class.
+ */
+class _ClassMeaning extends _Meaning {
+ final Map<String, _Meaning> namespace;
+
+ _ClassMeaning(int unit, int dependency, int numTypeParameters, this.namespace)
+ : super(unit, ReferenceKind.classOrEnum, dependency, numTypeParameters);
+}
+
+/**
* A [_Meaning] stores all the information necessary to find the declaration
* referred to by a name in a namespace.
*/
@@ -53,7 +63,7 @@
/**
* The kind of entity being referred to.
*/
- final PrelinkedReferenceKind kind;
+ final ReferenceKind kind;
/**
* Which of the dependencies of the library being prelinked contains the
@@ -70,10 +80,18 @@
_Meaning(this.unit, this.kind, this.dependency, this.numTypeParameters);
/**
- * Encode this [_Meaning] as a [PrelinkedReference].
+ * Encode this [_Meaning] as a [LinkedExportName], using the given [name].
+ */
+ LinkedExportName encodeExportName(String name) {
+ return new LinkedExportNameBuilder(
+ name: name, dependency: dependency, unit: unit, kind: kind);
+ }
+
+/**
+ * Encode this [_Meaning] as a [LinkedReference].
*/
- PrelinkedReferenceBuilder encode() {
- return encodePrelinkedReference(
+ LinkedReferenceBuilder encodeReference() {
+ return new LinkedReferenceBuilder(
unit: unit,
kind: kind,
dependency: dependency,
@@ -87,7 +105,7 @@
class _PrefixMeaning extends _Meaning {
final Map<String, _Meaning> namespace = <String, _Meaning>{};
- _PrefixMeaning() : super(0, PrelinkedReferenceKind.prefix, 0, 0);
+ _PrefixMeaning() : super(0, ReferenceKind.prefix, 0, 0);
}
/**
@@ -117,15 +135,17 @@
* Names defined inside the library being prelinked.
*/
final Map<String, _Meaning> privateNamespace = <String, _Meaning>{
- '': new _Meaning(0, PrelinkedReferenceKind.classOrEnum, 0, 0)
+ 'dynamic': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0),
+ 'void': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0)
};
/**
* List of dependencies of the library being prelinked. This will be output
- * to [PrelinkedLibrary.dependencies].
+ * to [LinkedLibrary.dependencies].
*/
- final List<PrelinkedDependencyBuilder> dependencies =
- <PrelinkedDependencyBuilder>[encodePrelinkedDependency()];
+ final List<LinkedDependencyBuilder> dependencies = <LinkedDependencyBuilder>[
+ new LinkedDependencyBuilder()
+ ];
/**
* Map from the relative URI of a dependent library to the index of the
@@ -157,9 +177,9 @@
int dependency = dependencies.length;
uriToDependency[relativeUri] = dependency;
List<String> unitUris = getUnitUris(relativeUri);
- PrelinkedDependencyBuilder prelinkedDependency =
- encodePrelinkedDependency(uri: relativeUri, parts: unitUris.sublist(1));
- dependencies.add(prelinkedDependency);
+ LinkedDependencyBuilder linkedDependency = new LinkedDependencyBuilder(
+ uri: relativeUri, parts: unitUris.sublist(1));
+ dependencies.add(linkedDependency);
Map<String, _Meaning> aggregated = <String, _Meaning>{};
@@ -170,10 +190,19 @@
continue;
}
for (UnlinkedPublicName name in importedNamespace.names) {
- aggregated.putIfAbsent(
- name.name,
- () => new _Meaning(
- unitNum, name.kind, dependency, name.numTypeParameters));
+ aggregated.putIfAbsent(name.name, () {
+ if (name.kind == ReferenceKind.classOrEnum) {
+ Map<String, _Meaning> namespace = <String, _Meaning>{};
+ name.constMembers.forEach((executable) {
+ namespace[executable.name] = new _Meaning(unitNum,
+ executable.kind, dependency, executable.numTypeParameters);
+ });
+ return new _ClassMeaning(
+ unitNum, dependency, name.numTypeParameters, namespace);
+ }
+ return new _Meaning(
+ unitNum, name.kind, dependency, name.numTypeParameters);
+ });
}
}
@@ -185,10 +214,14 @@
* Compute the export namespace for the library whose URI is reachable from
* [definingUnit] via [relativeUri], by aggregating together public namespace
* information from the library and the transitive closure of its exports.
+ *
+ * If [relativeUri] is `null` (meaning the export namespace of [definingUnit]
+ * should be computed), then names defined in [definingUnit] are ignored.
*/
Map<String, _Meaning> computeExportNamespace(String relativeUri) {
- Map<String, _Meaning> exportNamespace =
- aggregatePublicNamespace(relativeUri);
+ Map<String, _Meaning> exportNamespace = relativeUri == null
+ ? <String, _Meaning>{}
+ : aggregatePublicNamespace(relativeUri);
void chaseExports(
NameFilter filter, String relativeUri, Set<String> seenUris) {
if (seenUris.add(relativeUri)) {
@@ -197,17 +230,16 @@
if (exportedNamespace != null) {
for (UnlinkedExportPublic export in exportedNamespace.exports) {
String exportUri = resolveUri(relativeUri, export.uri);
+ NameFilter newFilter = filter.merge(
+ new NameFilter.forUnlinkedCombinators(export.combinators));
aggregatePublicNamespace(exportUri)
.forEach((String name, _Meaning meaning) {
- if (filter.accepts(name) && !exportNamespace.containsKey(name)) {
+ if (newFilter.accepts(name) &&
+ !exportNamespace.containsKey(name)) {
exportNamespace[name] = meaning;
}
});
- chaseExports(
- filter.merge(
- new NameFilter.forUnlinkedCombinators(export.combinators)),
- exportUri,
- seenUris);
+ chaseExports(newFilter, exportUri, seenUris);
}
}
seenUris.remove(relativeUri);
@@ -224,32 +256,65 @@
*/
void extractPrivateNames(UnlinkedUnit unit, int unitNum) {
for (UnlinkedClass cls in unit.classes) {
- privateNamespace.putIfAbsent(
- cls.name,
- () => new _Meaning(unitNum, PrelinkedReferenceKind.classOrEnum, 0,
- cls.typeParameters.length));
+ privateNamespace.putIfAbsent(cls.name, () {
+ Map<String, _Meaning> namespace = <String, _Meaning>{};
+ cls.fields.forEach((field) {
+ if (field.isStatic && field.isConst) {
+ namespace[field.name] =
+ new _Meaning(unitNum, ReferenceKind.constField, 0, 0);
+ }
+ });
+ cls.executables.forEach((executable) {
+ ReferenceKind kind = null;
+ if (executable.kind == UnlinkedExecutableKind.constructor &&
+ executable.isConst) {
+ kind = ReferenceKind.constructor;
+ } else if (executable.kind ==
+ UnlinkedExecutableKind.functionOrMethod &&
+ executable.isStatic) {
+ kind = ReferenceKind.staticMethod;
+ }
+ if (kind != null) {
+ namespace[executable.name] = new _Meaning(
+ unitNum, kind, 0, executable.typeParameters.length);
+ }
+ });
+ return new _ClassMeaning(
+ unitNum, 0, cls.typeParameters.length, namespace);
+ });
}
for (UnlinkedEnum enm in unit.enums) {
- privateNamespace.putIfAbsent(
- enm.name,
- () =>
- new _Meaning(unitNum, PrelinkedReferenceKind.classOrEnum, 0, 0));
+ privateNamespace.putIfAbsent(enm.name,
+ () => new _Meaning(unitNum, ReferenceKind.classOrEnum, 0, 0));
}
for (UnlinkedExecutable executable in unit.executables) {
privateNamespace.putIfAbsent(
executable.name,
- () => new _Meaning(unitNum, PrelinkedReferenceKind.other, 0,
+ () => new _Meaning(
+ unitNum,
+ executable.kind == UnlinkedExecutableKind.functionOrMethod
+ ? ReferenceKind.topLevelFunction
+ : ReferenceKind.topLevelPropertyAccessor,
+ 0,
executable.typeParameters.length));
}
for (UnlinkedTypedef typedef in unit.typedefs) {
privateNamespace.putIfAbsent(
typedef.name,
- () => new _Meaning(unitNum, PrelinkedReferenceKind.typedef, 0,
+ () => new _Meaning(unitNum, ReferenceKind.typedef, 0,
typedef.typeParameters.length));
}
for (UnlinkedVariable variable in unit.variables) {
- privateNamespace.putIfAbsent(variable.name,
- () => new _Meaning(unitNum, PrelinkedReferenceKind.other, 0, 0));
+ privateNamespace.putIfAbsent(
+ variable.name,
+ () => new _Meaning(
+ unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
+ if (!(variable.isConst || variable.isFinal)) {
+ privateNamespace.putIfAbsent(
+ variable.name + '=',
+ () => new _Meaning(
+ unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
+ }
}
}
@@ -328,47 +393,60 @@
}
/**
- * Produce a [PrelinkedUnit] for the given [unit], by resolving every one of
+ * Produce a [LinkedUnit] for the given [unit], by resolving every one of
* its references.
*/
- PrelinkedUnitBuilder linkUnit(UnlinkedUnit unit) {
+ LinkedUnitBuilder linkUnit(UnlinkedUnit unit) {
if (unit == null) {
- return encodePrelinkedUnit();
+ return new LinkedUnitBuilder();
}
Map<int, Map<String, _Meaning>> prefixNamespaces =
<int, Map<String, _Meaning>>{};
- List<PrelinkedReferenceBuilder> references = <PrelinkedReferenceBuilder>[];
+ List<LinkedReferenceBuilder> references = <LinkedReferenceBuilder>[];
for (int i = 0; i < unit.references.length; i++) {
UnlinkedReference reference = unit.references[i];
Map<String, _Meaning> namespace;
- if (reference.prefixReference != 0) {
+ if (reference.prefixReference == 0) {
+ namespace = privateNamespace;
+ } else {
// Prefix references must always point backward.
assert(reference.prefixReference < i);
namespace = prefixNamespaces[reference.prefixReference];
+ // If in `a.length` the `a` prefix is a top-level variable or a field,
+ // then it must be the `String.length` property reference.
+ if (namespace == null && reference.name == 'length') {
+ ReferenceKind prefixKind = references[reference.prefixReference].kind;
+ if (prefixKind == ReferenceKind.topLevelPropertyAccessor ||
+ prefixKind == ReferenceKind.constField) {
+ references
+ .add(new LinkedReferenceBuilder(kind: ReferenceKind.length));
+ continue;
+ }
+ }
// Prefix references must always point to proper prefixes.
assert(namespace != null);
- } else {
- namespace = privateNamespace;
}
_Meaning meaning = namespace[reference.name];
if (meaning != null) {
if (meaning is _PrefixMeaning) {
prefixNamespaces[i] = meaning.namespace;
+ } else if (meaning is _ClassMeaning) {
+ prefixNamespaces[i] = meaning.namespace;
}
- references.add(meaning.encode());
+ references.add(meaning.encodeReference());
} else {
- references.add(
- encodePrelinkedReference(kind: PrelinkedReferenceKind.unresolved));
+ references
+ .add(new LinkedReferenceBuilder(kind: ReferenceKind.unresolved));
}
}
- return encodePrelinkedUnit(references: references);
+ return new LinkedUnitBuilder(references: references);
}
/**
- * Form the [PrelinkedLibrary] for the [definingUnit] that was passed to the
+ * Form the [LinkedLibrary] for the [definingUnit] that was passed to the
* constructor.
*/
- PrelinkedLibraryBuilder prelink() {
+ LinkedLibraryBuilder prelink() {
// Gather up the unlinked summaries for all the compilation units in the
// library.
List<UnlinkedUnit> units = getUnitUris(null).map(getPartCached).toList();
@@ -382,6 +460,16 @@
}
}
+ // Fill in exported names. This must be done before filling in prefixes
+ // defined in import declarations, because prefixes shouldn't shadow
+ // exports.
+ List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[];
+ computeExportNamespace(null).forEach((String name, _Meaning meaning) {
+ if (!privateNamespace.containsKey(name)) {
+ exportNames.add(meaning.encodeExportName(name));
+ }
+ });
+
// Fill in prefixes defined in import declarations.
for (UnlinkedImport import in units[0].imports) {
if (import.prefixReference != 0) {
@@ -396,12 +484,14 @@
definingUnit.imports.map(handleImport).toList();
// Link each compilation unit.
- List<PrelinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList();
+ List<LinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList();
- return encodePrelinkedLibrary(
+ return new LinkedLibraryBuilder(
units: linkedUnits,
dependencies: dependencies,
- importDependencies: importDependencies);
+ importDependencies: importDependencies,
+ exportNames: exportNames,
+ numPrelinkedDependencies: dependencies.length);
}
/**
diff --git a/pkg/analyzer/lib/src/summary/public_namespace_computer.dart b/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
index e8751b0..1f24248 100644
--- a/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
+++ b/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
@@ -14,7 +14,7 @@
UnlinkedPublicNamespaceBuilder computePublicNamespace(CompilationUnit unit) {
_PublicNamespaceVisitor visitor = new _PublicNamespaceVisitor();
unit.accept(visitor);
- return encodeUnlinkedPublicNamespace(
+ return new UnlinkedPublicNamespaceBuilder(
names: visitor.names, exports: visitor.exports, parts: visitor.parts);
}
@@ -26,12 +26,12 @@
@override
UnlinkedCombinatorBuilder visitHideCombinator(HideCombinator node) {
- return encodeUnlinkedCombinator(hides: encodeNames(node.hiddenNames));
+ return new UnlinkedCombinatorBuilder(hides: encodeNames(node.hiddenNames));
}
@override
UnlinkedCombinatorBuilder visitShowCombinator(ShowCombinator node) {
- return encodeUnlinkedCombinator(shows: encodeNames(node.shownNames));
+ return new UnlinkedCombinatorBuilder(shows: encodeNames(node.shownNames));
}
}
@@ -43,36 +43,81 @@
_PublicNamespaceVisitor();
- void addNameIfPublic(
- String name, PrelinkedReferenceKind kind, int numTypeParameters) {
+ UnlinkedPublicNameBuilder addNameIfPublic(
+ String name, ReferenceKind kind, int numTypeParameters) {
if (isPublic(name)) {
- names.add(encodeUnlinkedPublicName(
- name: name, kind: kind, numTypeParameters: numTypeParameters));
+ UnlinkedPublicNameBuilder b = new UnlinkedPublicNameBuilder(
+ name: name, kind: kind, numTypeParameters: numTypeParameters);
+ names.add(b);
+ return b;
}
+ return null;
}
bool isPublic(String name) => !name.startsWith('_');
@override
visitClassDeclaration(ClassDeclaration node) {
- addNameIfPublic(node.name.name, PrelinkedReferenceKind.classOrEnum,
+ UnlinkedPublicNameBuilder cls = addNameIfPublic(
+ node.name.name,
+ ReferenceKind.classOrEnum,
node.typeParameters?.typeParameters?.length ?? 0);
+ if (cls != null) {
+ for (ClassMember member in node.members) {
+ if (member is FieldDeclaration &&
+ member.isStatic &&
+ member.fields.isConst) {
+ for (VariableDeclaration field in member.fields.variables) {
+ String name = field.name.name;
+ if (isPublic(name)) {
+ cls.constMembers.add(new UnlinkedPublicNameBuilder(
+ name: name,
+ kind: ReferenceKind.constField,
+ numTypeParameters: 0));
+ }
+ }
+ }
+ if (member is MethodDeclaration &&
+ member.isStatic &&
+ !member.isGetter &&
+ !member.isSetter &&
+ !member.isOperator) {
+ String name = member.name.name;
+ if (isPublic(name)) {
+ cls.constMembers.add(new UnlinkedPublicNameBuilder(
+ name: name,
+ kind: ReferenceKind.staticMethod,
+ numTypeParameters:
+ member.typeParameters?.typeParameters?.length ?? 0));
+ }
+ }
+ if (member is ConstructorDeclaration && member.constKeyword != null) {
+ String name = member.name != null ? member.name.name : '';
+ if (isPublic(name)) {
+ cls.constMembers.add(new UnlinkedPublicNameBuilder(
+ name: name,
+ kind: ReferenceKind.constructor,
+ numTypeParameters: 0));
+ }
+ }
+ }
+ }
}
@override
visitClassTypeAlias(ClassTypeAlias node) {
- addNameIfPublic(node.name.name, PrelinkedReferenceKind.classOrEnum,
+ addNameIfPublic(node.name.name, ReferenceKind.classOrEnum,
node.typeParameters?.typeParameters?.length ?? 0);
}
@override
visitEnumDeclaration(EnumDeclaration node) {
- addNameIfPublic(node.name.name, PrelinkedReferenceKind.classOrEnum, 0);
+ addNameIfPublic(node.name.name, ReferenceKind.classOrEnum, 0);
}
@override
visitExportDirective(ExportDirective node) {
- exports.add(encodeUnlinkedExportPublic(
+ exports.add(new UnlinkedExportPublicBuilder(
uri: node.uri.stringValue,
combinators: node.combinators
.map((Combinator c) => c.accept(new _CombinatorEncoder()))
@@ -85,13 +130,17 @@
if (node.isSetter) {
name += '=';
}
- addNameIfPublic(name, PrelinkedReferenceKind.other,
+ addNameIfPublic(
+ name,
+ node.isGetter || node.isSetter
+ ? ReferenceKind.topLevelPropertyAccessor
+ : ReferenceKind.topLevelFunction,
node.functionExpression.typeParameters?.typeParameters?.length ?? 0);
}
@override
visitFunctionTypeAlias(FunctionTypeAlias node) {
- addNameIfPublic(node.name.name, PrelinkedReferenceKind.typedef,
+ addNameIfPublic(node.name.name, ReferenceKind.typedef,
node.typeParameters?.typeParameters?.length ?? 0);
}
@@ -103,9 +152,9 @@
@override
visitVariableDeclaration(VariableDeclaration node) {
String name = node.name.name;
- addNameIfPublic(name, PrelinkedReferenceKind.other, 0);
+ addNameIfPublic(name, ReferenceKind.topLevelPropertyAccessor, 0);
if (!node.isFinal && !node.isConst) {
- addNameIfPublic('$name=', PrelinkedReferenceKind.other, 0);
+ addNameIfPublic('$name=', ReferenceKind.topLevelPropertyAccessor, 0);
}
}
}
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 23b103c..d70d392 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -4,40 +4,30 @@
library summary_resynthesizer;
-import 'package:analyzer/analyzer.dart';
-import 'package:analyzer/src/generated/element.dart';
+import 'dart:collection';
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/element_handle.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/format.dart';
/**
- * Callback used by [SummaryResynthesizer] to obtain the prelinked summary for
- * a given URI.
- */
-typedef PrelinkedLibrary GetPrelinkedSummaryCallback(String uri);
-
-/**
- * Callback used by [SummaryResynthesizer] to obtain the unlinked summary for a
- * given URI.
- */
-typedef UnlinkedUnit GetUnlinkedSummaryCallback(String uri);
-
-/**
* Implementation of [ElementResynthesizer] used when resynthesizing an element
* model from summaries.
*/
-class SummaryResynthesizer extends ElementResynthesizer {
+abstract class SummaryResynthesizer extends ElementResynthesizer {
/**
- * Callback used to obtain the prelinked summary for a given URI.
+ * The parent [SummaryResynthesizer] which is asked to resynthesize elements
+ * and get summaries before this resynthesizer attempts to do this.
+ * Can be `null`.
*/
- final GetPrelinkedSummaryCallback getPrelinkedSummary;
-
- /**
- * Callback used to obtain the unlinked summary for a given URI.
- */
- final GetUnlinkedSummaryCallback getUnlinkedSummary;
+ final SummaryResynthesizer parent;
/**
* Source factory used to convert URIs to [Source] objects.
@@ -56,6 +46,12 @@
final TypeProvider typeProvider;
/**
+ * Indicates whether the summary should be resynthesized assuming strong mode
+ * semantics.
+ */
+ final bool strongMode;
+
+ /**
* Map of top level elements resynthesized from summaries. The three map
* keys are the first three elements of the element's location (the library
* URI, the compilation unit URI, and the name of the top level declaration).
@@ -70,8 +66,8 @@
final Map<String, LibraryElement> _resynthesizedLibraries =
<String, LibraryElement>{};
- SummaryResynthesizer(AnalysisContext context, this.typeProvider,
- this.getPrelinkedSummary, this.getUnlinkedSummary, this.sourceFactory)
+ SummaryResynthesizer(this.parent, AnalysisContext context, this.typeProvider,
+ this.sourceFactory, this.strongMode)
: super(context);
/**
@@ -79,28 +75,68 @@
*/
int get resynthesisCount => _resynthesizedLibraries.length;
+ /**
+ * Perform delayed finalization of the `dart:core` and `dart:async` libraries.
+ */
+ void finalizeCoreAsyncLibraries() {
+ (_resynthesizedLibraries['dart:core'] as LibraryElementImpl)
+ .createLoadLibraryFunction(typeProvider);
+ (_resynthesizedLibraries['dart:async'] as LibraryElementImpl)
+ .createLoadLibraryFunction(typeProvider);
+ }
+
@override
Element getElement(ElementLocation location) {
- if (location.components.length == 1) {
- return getLibraryElement(location.components[0]);
- } else if (location.components.length == 3) {
- String uri = location.components[0];
+ List<String> components = location.components;
+ String libraryUri = components[0];
+ // Ask the parent resynthesizer.
+ if (parent != null && parent._hasLibrarySummary(libraryUri)) {
+ return parent.getElement(location);
+ }
+ // Resynthesize locally.
+ if (components.length == 1) {
+ return getLibraryElement(libraryUri);
+ } else if (components.length == 3 || components.length == 4) {
Map<String, Map<String, Element>> libraryMap =
- _resynthesizedElements[uri];
+ _resynthesizedElements[libraryUri];
if (libraryMap == null) {
- getLibraryElement(uri);
- libraryMap = _resynthesizedElements[uri];
+ getLibraryElement(libraryUri);
+ libraryMap = _resynthesizedElements[libraryUri];
assert(libraryMap != null);
}
- Map<String, Element> compilationUnitElements =
- libraryMap[location.components[1]];
+ Map<String, Element> compilationUnitElements = libraryMap[components[1]];
+ Element element;
if (compilationUnitElements != null) {
- Element element = compilationUnitElements[location.components[2]];
- if (element != null) {
- return element;
+ element = compilationUnitElements[components[2]];
+ }
+ if (element != null && components.length == 4) {
+ String name = components[3];
+ Element parentElement = element;
+ if (parentElement is ClassElement) {
+ if (name.endsWith('?')) {
+ element =
+ parentElement.getGetter(name.substring(0, name.length - 1));
+ } else if (name.endsWith('=')) {
+ element =
+ parentElement.getSetter(name.substring(0, name.length - 1));
+ } else if (name.isEmpty) {
+ element = parentElement.unnamedConstructor;
+ } else {
+ element = parentElement.getField(name) ??
+ parentElement.getMethod(name) ??
+ parentElement.getNamedConstructor(name);
+ }
+ } else {
+ // The only elements that are currently retrieved using 4-component
+ // locations are class members.
+ throw new StateError(
+ '4-element locations not supported for ${element.runtimeType}');
}
}
- throw new Exception('Element not found in summary: $location');
+ if (element == null) {
+ throw new Exception('Element not found in summary: $location');
+ }
+ return element;
} else {
throw new UnimplementedError(location.toString());
}
@@ -111,16 +147,19 @@
* hasn't been resynthesized already.
*/
LibraryElement getLibraryElement(String uri) {
+ if (parent != null && parent._hasLibrarySummary(uri)) {
+ return parent.getLibraryElement(uri);
+ }
return _resynthesizedLibraries.putIfAbsent(uri, () {
- PrelinkedLibrary serializedLibrary = getPrelinkedSummary(uri);
+ LinkedLibrary serializedLibrary = _getLinkedSummaryOrThrow(uri);
List<UnlinkedUnit> serializedUnits = <UnlinkedUnit>[
- getUnlinkedSummary(uri)
+ _getUnlinkedSummaryOrThrow(uri)
];
Source librarySource = _getSource(uri);
for (String part in serializedUnits[0].publicNamespace.parts) {
Source partSource = sourceFactory.resolveUri(librarySource, part);
String partAbsUri = partSource.uri.toString();
- serializedUnits.add(getUnlinkedSummary(partAbsUri));
+ serializedUnits.add(_getUnlinkedSummaryOrThrow(partAbsUri));
}
_LibraryResynthesizer libraryResynthesizer = new _LibraryResynthesizer(
this, serializedLibrary, serializedUnits, librarySource);
@@ -131,11 +170,73 @@
}
/**
+ * Return the [LinkedLibrary] for the given [uri] or `null` if it could not
+ * be found. Caller has already checked that `parent.hasLibrarySummary(uri)`
+ * returns `false`.
+ */
+ LinkedLibrary getLinkedSummary(String uri);
+
+ /**
+ * Return the [UnlinkedUnit] for the given [uri] or `null` if it could not
+ * be found. Caller has already checked that `parent.hasLibrarySummary(uri)`
+ * returns `false`.
+ */
+ UnlinkedUnit getUnlinkedSummary(String uri);
+
+ /**
+ * Return `true` if this resynthesizer can provide summaries of the libraries
+ * with the given [uri]. Caller has already checked that
+ * `parent.hasLibrarySummary(uri)` returns `false`.
+ */
+ bool hasLibrarySummary(String uri);
+
+ /**
+ * Return the [LinkedLibrary] for the given [uri] or throw [StateError] if it
+ * could not be found.
+ */
+ LinkedLibrary _getLinkedSummaryOrThrow(String uri) {
+ if (parent != null && parent._hasLibrarySummary(uri)) {
+ return parent._getLinkedSummaryOrThrow(uri);
+ }
+ LinkedLibrary summary = getLinkedSummary(uri);
+ if (summary != null) {
+ return summary;
+ }
+ throw new StateError('Unable to find linked summary: $uri');
+ }
+
+ /**
* Get the [Source] object for the given [uri].
*/
Source _getSource(String uri) {
return _sources.putIfAbsent(uri, () => sourceFactory.forUri(uri));
}
+
+ /**
+ * Return the [UnlinkedUnit] for the given [uri] or throw [StateError] if it
+ * could not be found.
+ */
+ UnlinkedUnit _getUnlinkedSummaryOrThrow(String uri) {
+ if (parent != null && parent._hasLibrarySummary(uri)) {
+ return parent._getUnlinkedSummaryOrThrow(uri);
+ }
+ UnlinkedUnit summary = getUnlinkedSummary(uri);
+ if (summary != null) {
+ return summary;
+ }
+ throw new StateError('Unable to find unlinked summary: $uri');
+ }
+
+ /**
+ * Return `true` if this resynthesizer can provide summaries of the libraries
+ * with the given [uri].
+ */
+ bool _hasLibrarySummary(String uri) {
+ if (parent != null && parent._hasLibrarySummary(uri)) {
+ return true;
+ }
+ return hasLibrarySummary(uri);
+ }
}
/**
@@ -149,9 +250,9 @@
final SummaryResynthesizer summaryResynthesizer;
/**
- * Prelinked summary of the library to be resynthesized.
+ * Linked summary of the library to be resynthesized.
*/
- final PrelinkedLibrary prelinkedLibrary;
+ final LinkedLibrary linkedLibrary;
/**
* Unlinked compilation units constituting the library to be resynthesized.
@@ -182,9 +283,9 @@
ElementHolder unitHolder;
/**
- * The [PrelinkedUnit] from which elements are currently being resynthesized.
+ * The [LinkedUnit] from which elements are currently being resynthesized.
*/
- PrelinkedUnit prelinkedUnit;
+ LinkedUnit linkedUnit;
/**
* The [UnlinkedUnit] from which elements are currently being resynthesized.
@@ -192,6 +293,12 @@
UnlinkedUnit unlinkedUnit;
/**
+ * Map from slot id to the corresponding [EntityRef] object for linked types
+ * (i.e. propagated and inferred types).
+ */
+ Map<int, EntityRef> linkedTypeMap;
+
+ /**
* Map of top level elements that have been resynthesized so far. The first
* key is the URI of the compilation unit; the second is the name of the top
* level element.
@@ -210,7 +317,14 @@
*/
List<TypeParameterElement> currentTypeParameters = <TypeParameterElement>[];
- _LibraryResynthesizer(this.summaryResynthesizer, this.prelinkedLibrary,
+ /**
+ * If a class is currently being resynthesized, map from field name to the
+ * corresponding field element. This is used when resynthesizing
+ * initializing formal parameters.
+ */
+ Map<String, FieldElementImpl> fields;
+
+ _LibraryResynthesizer(this.summaryResynthesizer, this.linkedLibrary,
this.unlinkedUnits, this.librarySource) {
isCoreLibrary = librarySource.uri.toString() == 'dart:core';
}
@@ -235,6 +349,7 @@
}
ClassElementImpl classElement = new ClassElementImpl(
serializedClass.name, serializedClass.nameOffset);
+ classElement.abstract = serializedClass.isAbstract;
classElement.mixinApplication = serializedClass.isMixinApplication;
InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
if (serializedClass.supertype != null) {
@@ -251,6 +366,10 @@
classElement.mixins = serializedClass.mixins.map(buildType).toList();
classElement.typeParameters = currentTypeParameters;
ElementHolder memberHolder = new ElementHolder();
+ fields = <String, FieldElementImpl>{};
+ for (UnlinkedVariable serializedVariable in serializedClass.fields) {
+ buildVariable(serializedVariable, memberHolder);
+ }
bool constructorFound = false;
for (UnlinkedExecutable serializedExecutable
in serializedClass.executables) {
@@ -267,9 +386,6 @@
break;
}
}
- for (UnlinkedVariable serializedVariable in serializedClass.fields) {
- buildVariable(serializedVariable, memberHolder);
- }
if (!serializedClass.isMixinApplication) {
if (!constructorFound) {
// Synthesize implicit constructors.
@@ -292,6 +408,7 @@
unitHolder.addType(classElement);
} finally {
currentTypeParameters = <TypeParameterElement>[];
+ fields = null;
}
}
@@ -350,7 +467,6 @@
*/
void buildEnum(UnlinkedEnum serializedEnum) {
assert(!isCoreLibrary);
- // TODO(paulberry): add offset support (for this element type and others)
ClassElementImpl classElement =
new ClassElementImpl(serializedEnum.name, serializedEnum.nameOffset);
classElement.enum2 = true;
@@ -413,6 +529,7 @@
} else {
MethodElementImpl executableElement =
new MethodElementImpl(name, serializedExecutable.nameOffset);
+ executableElement.abstract = serializedExecutable.isAbstract;
buildExecutableCommonParts(executableElement, serializedExecutable);
executableElement.static = serializedExecutable.isStatic;
holder.addMethod(executableElement);
@@ -427,6 +544,7 @@
executableElement.static = true;
} else {
executableElement.static = serializedExecutable.isStatic;
+ executableElement.abstract = serializedExecutable.isAbstract;
}
buildExecutableCommonParts(executableElement, serializedExecutable);
DartType type;
@@ -455,8 +573,6 @@
} else {
implicitVariable.setter = executableElement;
}
- // TODO(paulberry): do the right thing when getter and setter are in
- // different units.
break;
default:
// The only other executable type is a constructor, and that is handled
@@ -481,18 +597,21 @@
}
executableElement.parameters =
serializedExecutable.parameters.map(buildParameter).toList();
- if (serializedExecutable.returnType != null) {
- executableElement.returnType = buildType(serializedExecutable.returnType);
- } else if (serializedExecutable.kind ==
- UnlinkedExecutableKind.constructor) {
- // Return type was set by the caller.
+ if (serializedExecutable.kind == UnlinkedExecutableKind.constructor) {
+ // Caller handles setting the return type.
+ assert(serializedExecutable.returnType == null);
} else {
- executableElement.returnType = VoidTypeImpl.instance;
+ bool isSetter =
+ serializedExecutable.kind == UnlinkedExecutableKind.setter;
+ executableElement.returnType =
+ buildLinkedType(serializedExecutable.inferredReturnTypeSlot) ??
+ buildType(serializedExecutable.returnType,
+ defaultVoid: isSetter && summaryResynthesizer.strongMode);
+ executableElement.hasImplicitReturnType =
+ serializedExecutable.returnType == null;
}
executableElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
executableElement, null, oldTypeArguments, false);
- executableElement.hasImplicitReturnType =
- serializedExecutable.hasImplicitReturnType;
executableElement.external = serializedExecutable.isExternal;
currentTypeParameters.removeRange(
oldTypeParametersLength, currentTypeParameters.length);
@@ -523,6 +642,62 @@
}
/**
+ * Build an [ElementHandle] referring to the entity referred to by the given
+ * [exportName].
+ */
+ ElementHandle buildExportName(LinkedExportName exportName) {
+ String name = exportName.name;
+ if (exportName.kind == ReferenceKind.topLevelPropertyAccessor &&
+ !name.endsWith('=')) {
+ name += '?';
+ }
+ ElementLocationImpl location = getReferencedLocation(
+ linkedLibrary.dependencies[exportName.dependency],
+ exportName.unit,
+ name);
+ switch (exportName.kind) {
+ case ReferenceKind.classOrEnum:
+ return new ClassElementHandle(summaryResynthesizer, location);
+ case ReferenceKind.typedef:
+ return new FunctionTypeAliasElementHandle(
+ summaryResynthesizer, location);
+ case ReferenceKind.topLevelFunction:
+ return new FunctionElementHandle(summaryResynthesizer, location);
+ case ReferenceKind.topLevelPropertyAccessor:
+ return new PropertyAccessorElementHandle(
+ summaryResynthesizer, location);
+ case ReferenceKind.constructor:
+ case ReferenceKind.constField:
+ case ReferenceKind.staticMethod:
+ case ReferenceKind.length:
+ case ReferenceKind.prefix:
+ case ReferenceKind.unresolved:
+ // Should never happen. Exported names never refer to import prefixes,
+ // and they always refer to defined top-level entities.
+ throw new StateError('Unexpected export name kind: ${exportName.kind}');
+ }
+ }
+
+ /**
+ * Build the export namespace for the library by aggregating together its
+ * [publicNamespace] and [exportNames].
+ */
+ Namespace buildExportNamespace(
+ Namespace publicNamespace, List<LinkedExportName> exportNames) {
+ HashMap<String, Element> definedNames = new HashMap<String, Element>();
+ // Start by populating all the public names from [publicNamespace].
+ publicNamespace.definedNames.forEach((String name, Element element) {
+ definedNames[name] = element;
+ });
+ // Add all the names from [exportNames].
+ for (LinkedExportName exportName in exportNames) {
+ definedNames.putIfAbsent(
+ exportName.name, () => buildExportName(exportName));
+ }
+ return new Namespace(definedNames);
+ }
+
+ /**
* Resynthesize a [FieldElement].
*/
FieldElement buildField(UnlinkedVariable serializedField) {
@@ -618,13 +793,10 @@
*/
ImportElement buildImport(UnlinkedImport serializedImport, int dependency) {
bool isSynthetic = serializedImport.isImplicit;
- // TODO(paulberry): it seems problematic for the offset to be 0 for
- // non-synthetic imports, since it is used to disambiguate location.
ImportElementImpl importElement =
new ImportElementImpl(isSynthetic ? -1 : serializedImport.offset);
String absoluteUri = summaryResynthesizer.sourceFactory
- .resolveUri(
- librarySource, prelinkedLibrary.dependencies[dependency].uri)
+ .resolveUri(librarySource, linkedLibrary.dependencies[dependency].uri)
.uri
.toString();
importElement.importedLibrary = new LibraryElementHandle(
@@ -636,7 +808,9 @@
importElement.uri = serializedImport.uri;
importElement.uriOffset = serializedImport.uriOffset;
importElement.uriEnd = serializedImport.uriEnd;
+ importElement.deferred = serializedImport.isDeferred;
}
+ importElement.prefixOffset = serializedImport.prefixOffset;
if (serializedImport.prefixReference != 0) {
UnlinkedReference serializedPrefix =
unlinkedUnits[0].references[serializedImport.prefixReference];
@@ -653,36 +827,35 @@
*/
LibraryElement buildLibrary() {
bool hasName = unlinkedUnits[0].libraryName.isNotEmpty;
- LibraryElementImpl libraryElement = new LibraryElementImpl(
+ LibraryElementImpl library = new LibraryElementImpl(
summaryResynthesizer.context,
unlinkedUnits[0].libraryName,
hasName ? unlinkedUnits[0].libraryNameOffset : -1,
unlinkedUnits[0].libraryNameLength);
- buildDocumentation(
- libraryElement, unlinkedUnits[0].libraryDocumentationComment);
+ buildDocumentation(library, unlinkedUnits[0].libraryDocumentationComment);
CompilationUnitElementImpl definingCompilationUnit =
new CompilationUnitElementImpl(librarySource.shortName);
- libraryElement.definingCompilationUnit = definingCompilationUnit;
+ library.definingCompilationUnit = definingCompilationUnit;
definingCompilationUnit.source = librarySource;
definingCompilationUnit.librarySource = librarySource;
List<CompilationUnitElement> parts = <CompilationUnitElement>[];
UnlinkedUnit unlinkedDefiningUnit = unlinkedUnits[0];
assert(unlinkedDefiningUnit.publicNamespace.parts.length + 1 ==
- prelinkedLibrary.units.length);
- for (int i = 1; i < prelinkedLibrary.units.length; i++) {
+ linkedLibrary.units.length);
+ for (int i = 1; i < linkedLibrary.units.length; i++) {
CompilationUnitElementImpl part = buildPart(
unlinkedDefiningUnit.publicNamespace.parts[i - 1],
unlinkedDefiningUnit.parts[i - 1],
unlinkedUnits[i]);
parts.add(part);
}
- libraryElement.parts = parts;
+ library.parts = parts;
List<ImportElement> imports = <ImportElement>[];
for (int i = 0; i < unlinkedDefiningUnit.imports.length; i++) {
imports.add(buildImport(unlinkedDefiningUnit.imports[i],
- prelinkedLibrary.importDependencies[i]));
+ linkedLibrary.importDependencies[i]));
}
- libraryElement.imports = imports;
+ library.imports = imports;
List<ExportElement> exports = <ExportElement>[];
assert(unlinkedDefiningUnit.exports.length ==
unlinkedDefiningUnit.publicNamespace.exports.length);
@@ -690,40 +863,75 @@
exports.add(buildExport(unlinkedDefiningUnit.publicNamespace.exports[i],
unlinkedDefiningUnit.exports[i]));
}
- libraryElement.exports = exports;
+ library.exports = exports;
populateUnit(definingCompilationUnit, 0);
for (int i = 0; i < parts.length; i++) {
populateUnit(parts[i], i + 1);
}
+ BuildLibraryElementUtils.patchTopLevelAccessors(library);
+ // Update delayed Object class references.
if (isCoreLibrary) {
- ClassElement objectElement = libraryElement.getType('Object');
+ ClassElement objectElement = library.getType('Object');
assert(objectElement != null);
for (ClassElementImpl classElement in delayedObjectSubclasses) {
classElement.supertype = objectElement.type;
}
}
// Compute namespaces.
- libraryElement.publicNamespace =
- new NamespaceBuilder().createPublicNamespaceForLibrary(libraryElement);
- // TODO(paulberry): compute the export namespace from prelinked data, so
- // that exported libraries won't be unnecessarily resynthesized.
- libraryElement.exportNamespace =
- new NamespaceBuilder().createExportNamespaceForLibrary(libraryElement);
- // Find the entry point.
- libraryElement.entryPoint =
- libraryElement.exportNamespace.definedNames.values.firstWhere(
- (element) => element is FunctionElement && element.isEntryPoint,
- orElse: () => null);
+ library.publicNamespace =
+ new NamespaceBuilder().createPublicNamespaceForLibrary(library);
+ library.exportNamespace = buildExportNamespace(
+ library.publicNamespace, linkedLibrary.exportNames);
+ // Find the entry point. Note: we can't use element.isEntryPoint because
+ // that will trigger resynthesis of exported libraries.
+ Element entryPoint =
+ library.exportNamespace.get(FunctionElement.MAIN_FUNCTION_NAME);
+ if (entryPoint is FunctionElement) {
+ library.entryPoint = entryPoint;
+ }
+ // Create the synthetic element for `loadLibrary`.
+ // Until the client received dart:core and dart:async, we cannot do this,
+ // because the TypeProvider is not fully initialized. So, it is up to the
+ // Dart SDK client to initialize TypeProvider and finish the dart:core and
+ // dart:async libraries creation.
+ if (library.name != 'dart.core' && library.name != 'dart.async') {
+ library.createLoadLibraryFunction(summaryResynthesizer.typeProvider);
+ }
// Done.
- return libraryElement;
+ return library;
+ }
+
+ /**
+ * Build the appropriate [DartType] object corresponding to a slot id in the
+ * [LinkedUnit.types] table.
+ */
+ DartType buildLinkedType(int slot) {
+ if (slot == 0) {
+ // A slot id of 0 means there is no [DartType] object to build.
+ return null;
+ }
+ EntityRef type = linkedTypeMap[slot];
+ if (type == null) {
+ // A missing entry in [LinkedUnit.types] means there is no [DartType]
+ // stored in this slot.
+ return null;
+ }
+ return buildType(type);
}
/**
* Resynthesize a [ParameterElement].
*/
ParameterElement buildParameter(UnlinkedParam serializedParameter) {
- ParameterElementImpl parameterElement = new ParameterElementImpl(
- serializedParameter.name, serializedParameter.nameOffset);
+ ParameterElementImpl parameterElement;
+ if (serializedParameter.isInitializingFormal) {
+ parameterElement = new FieldFormalParameterElementImpl.forNameAndOffset(
+ serializedParameter.name, serializedParameter.nameOffset)
+ ..field = fields[serializedParameter.name];
+ } else {
+ parameterElement = new ParameterElementImpl(
+ serializedParameter.name, serializedParameter.nameOffset);
+ }
if (serializedParameter.isFunctionTyped) {
FunctionElementImpl parameterTypeElement =
new FunctionElementImpl('', -1);
@@ -732,16 +940,21 @@
serializedParameter.parameters.map(buildParameter).toList();
parameterTypeElement.enclosingElement = parameterElement;
parameterTypeElement.shareParameters(parameterElement.parameters);
- if (serializedParameter.type != null) {
- parameterTypeElement.returnType = buildType(serializedParameter.type);
- } else {
- parameterTypeElement.returnType = VoidTypeImpl.instance;
- }
+ parameterTypeElement.returnType = buildType(serializedParameter.type);
parameterElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
parameterTypeElement, null, currentTypeArguments, false);
} else {
- parameterElement.type = buildType(serializedParameter.type);
- parameterElement.hasImplicitType = serializedParameter.hasImplicitType;
+ if (serializedParameter.isInitializingFormal &&
+ serializedParameter.type == null) {
+ // The type is inherited from the matching field.
+ parameterElement.type = fields[serializedParameter.name]?.type ??
+ summaryResynthesizer.typeProvider.dynamicType;
+ } else {
+ parameterElement.type =
+ buildLinkedType(serializedParameter.inferredTypeSlot) ??
+ buildType(serializedParameter.type);
+ }
+ parameterElement.hasImplicitType = serializedParameter.type == null;
}
switch (serializedParameter.kind) {
case UnlinkedParamKind.named:
@@ -776,55 +989,47 @@
}
/**
- * Build a [DartType] object based on an [UnlinkedTypeRef]. This [DartType]
+ * Build a [DartType] object based on a [EntityRef]. This [DartType]
* may refer to elements in other libraries than the library being
* deserialized, so handles are used to avoid having to deserialize other
* libraries in the process.
*/
- DartType buildType(UnlinkedTypeRef type) {
+ DartType buildType(EntityRef type, {bool defaultVoid: false}) {
+ if (type == null) {
+ if (defaultVoid) {
+ return VoidTypeImpl.instance;
+ } else {
+ return summaryResynthesizer.typeProvider.dynamicType;
+ }
+ }
if (type.paramReference != 0) {
// TODO(paulberry): make this work for generic methods.
return currentTypeParameters[
- currentTypeParameters.length - type.paramReference]
- .type;
+ currentTypeParameters.length - type.paramReference].type;
} else {
- // TODO(paulberry): handle references to things other than classes (note:
- // this should only occur in the case of erroneous code).
- // TODO(paulberry): test reference to something inside a part.
- // TODO(paulberry): test reference to something inside a part of the
- // current lib.
- UnlinkedReference reference = unlinkedUnit.references[type.reference];
- PrelinkedReference referenceResolution =
- prelinkedUnit.references[type.reference];
- String referencedLibraryUri;
- String partUri;
- if (referenceResolution.dependency != 0) {
- PrelinkedDependency dependency =
- prelinkedLibrary.dependencies[referenceResolution.dependency];
- Source referencedLibrarySource = summaryResynthesizer.sourceFactory
- .resolveUri(librarySource, dependency.uri);
- referencedLibraryUri = referencedLibrarySource.uri.toString();
- // TODO(paulberry): consider changing Location format so that this is
- // not necessary (2nd string in location should just be the unit
- // number).
- if (referenceResolution.unit != 0) {
- UnlinkedUnit referencedLibraryDefiningUnit =
- summaryResynthesizer.getUnlinkedSummary(referencedLibraryUri);
- String uri = referencedLibraryDefiningUnit.publicNamespace.parts[
- referenceResolution.unit - 1];
- Source partSource = summaryResynthesizer.sourceFactory
- .resolveUri(referencedLibrarySource, uri);
- partUri = partSource.uri.toString();
- } else {
- partUri = referencedLibraryUri;
- }
- } else if (referenceResolution.kind ==
- PrelinkedReferenceKind.unresolved) {
- return summaryResynthesizer.typeProvider.undefinedType;
- } else if (reference.name.isEmpty) {
- return summaryResynthesizer.typeProvider.dynamicType;
+ LinkedReference referenceResolution =
+ linkedUnit.references[type.reference];
+ String name;
+ if (type.reference < unlinkedUnit.references.length) {
+ name = unlinkedUnit.references[type.reference].name;
} else {
- referencedLibraryUri = librarySource.uri.toString();
+ name = referenceResolution.name;
+ }
+ ElementLocationImpl location;
+ if (referenceResolution.dependency != 0) {
+ location = getReferencedLocation(
+ linkedLibrary.dependencies[referenceResolution.dependency],
+ referenceResolution.unit,
+ name);
+ } else if (referenceResolution.kind == ReferenceKind.unresolved) {
+ return summaryResynthesizer.typeProvider.undefinedType;
+ } else if (name == 'dynamic') {
+ return summaryResynthesizer.typeProvider.dynamicType;
+ } else if (name == 'void') {
+ return VoidTypeImpl.instance;
+ } else {
+ String referencedLibraryUri = librarySource.uri.toString();
+ String partUri;
if (referenceResolution.unit != 0) {
String uri = unlinkedUnits[0].publicNamespace.parts[
referenceResolution.unit - 1];
@@ -834,9 +1039,9 @@
} else {
partUri = referencedLibraryUri;
}
+ location = new ElementLocationImpl.con3(
+ <String>[referencedLibraryUri, partUri, name]);
}
- ElementLocationImpl location = new ElementLocationImpl.con3(
- <String>[referencedLibraryUri, partUri, reference.name]);
List<DartType> typeArguments = const <DartType>[];
if (referenceResolution.numTypeParameters != 0) {
typeArguments = <DartType>[];
@@ -849,16 +1054,16 @@
}
}
switch (referenceResolution.kind) {
- case PrelinkedReferenceKind.classOrEnum:
+ case ReferenceKind.classOrEnum:
return new InterfaceTypeImpl.elementWithNameAndArgs(
new ClassElementHandle(summaryResynthesizer, location),
- reference.name,
+ name,
typeArguments);
- case PrelinkedReferenceKind.typedef:
+ case ReferenceKind.typedef:
return new FunctionTypeImpl.elementWithNameAndArgs(
new FunctionTypeAliasElementHandle(
summaryResynthesizer, location),
- reference.name,
+ name,
typeArguments,
typeArguments.isNotEmpty);
default:
@@ -886,12 +1091,8 @@
serializedTypedef.name, serializedTypedef.nameOffset);
functionTypeAliasElement.parameters =
serializedTypedef.parameters.map(buildParameter).toList();
- if (serializedTypedef.returnType != null) {
- functionTypeAliasElement.returnType =
- buildType(serializedTypedef.returnType);
- } else {
- functionTypeAliasElement.returnType = VoidTypeImpl.instance;
- }
+ functionTypeAliasElement.returnType =
+ buildType(serializedTypedef.returnType);
functionTypeAliasElement.type =
new FunctionTypeImpl.forTypedef(functionTypeAliasElement);
functionTypeAliasElement.typeParameters = currentTypeParameters;
@@ -938,6 +1139,7 @@
element.static = serializedVariable.isStatic;
holder.addField(element);
buildImplicitAccessors(element, holder);
+ fields[element.name] = element;
}
}
@@ -946,9 +1148,13 @@
*/
void buildVariableCommonParts(PropertyInducingElementImpl element,
UnlinkedVariable serializedVariable) {
- element.type = buildType(serializedVariable.type);
+ element.type = buildLinkedType(serializedVariable.inferredTypeSlot) ??
+ buildType(serializedVariable.type);
element.const3 = serializedVariable.isConst;
- element.hasImplicitType = serializedVariable.hasImplicitType;
+ element.final2 = serializedVariable.isFinal;
+ element.hasImplicitType = serializedVariable.type == null;
+ element.propagatedType =
+ buildLinkedType(serializedVariable.propagatedTypeSlot);
buildDocumentation(element, serializedVariable.documentationComment);
}
@@ -963,12 +1169,44 @@
}
/**
+ * Build an [ElementLocationImpl] for the entity in the given [unit] of the
+ * given [dependency], having the given [name].
+ */
+ ElementLocationImpl getReferencedLocation(
+ LinkedDependency dependency, int unit, String name) {
+ Source referencedLibrarySource = summaryResynthesizer.sourceFactory
+ .resolveUri(librarySource, dependency.uri);
+ String referencedLibraryUri = referencedLibrarySource.uri.toString();
+ // TODO(paulberry): consider changing Location format so that this is
+ // not necessary (2nd string in location should just be the unit
+ // number).
+ String partUri;
+ if (unit != 0) {
+ UnlinkedUnit referencedLibraryDefiningUnit =
+ summaryResynthesizer._getUnlinkedSummaryOrThrow(referencedLibraryUri);
+ String uri =
+ referencedLibraryDefiningUnit.publicNamespace.parts[unit - 1];
+ Source partSource = summaryResynthesizer.sourceFactory
+ .resolveUri(referencedLibrarySource, uri);
+ partUri = partSource.uri.toString();
+ } else {
+ partUri = referencedLibraryUri;
+ }
+ return new ElementLocationImpl.con3(
+ <String>[referencedLibraryUri, partUri, name]);
+ }
+
+ /**
* Populate a [CompilationUnitElement] by deserializing all the elements
* contained in it.
*/
void populateUnit(CompilationUnitElementImpl unit, int unitNum) {
- prelinkedUnit = prelinkedLibrary.units[unitNum];
+ linkedUnit = linkedLibrary.units[unitNum];
unlinkedUnit = unlinkedUnits[unitNum];
+ linkedTypeMap = <int, EntityRef>{};
+ for (EntityRef t in linkedUnit.types) {
+ linkedTypeMap[t.slot] = t;
+ }
unitHolder = new ElementHolder();
unlinkedUnit.classes.forEach(buildClass);
unlinkedUnit.enums.forEach(buildEnum);
@@ -998,9 +1236,16 @@
for (FunctionTypeAliasElement typeAlias in unit.functionTypeAliases) {
elementMap[typeAlias.name] = typeAlias;
}
+ for (FunctionElement function in unit.functions) {
+ elementMap[function.name] = function;
+ }
+ for (PropertyAccessorElementImpl accessor in unit.accessors) {
+ elementMap[accessor.identifier] = accessor;
+ }
resummarizedElements[absoluteUri] = elementMap;
unitHolder = null;
- prelinkedUnit = null;
+ linkedUnit = null;
unlinkedUnit = null;
+ linkedTypeMap = null;
}
}
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
new file mode 100644
index 0000000..c43a9b9
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -0,0 +1,884 @@
+// Copyright (c) 2016, 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 serialization.summarize_ast;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/public_namespace_computer.dart';
+import 'package:analyzer/src/summary/summarize_const_expr.dart';
+
+/**
+ * Serialize all the declarations in [compilationUnit] to an unlinked summary.
+ */
+UnlinkedUnitBuilder serializeAstUnlinked(CompilationUnit compilationUnit) {
+ return new _SummarizeAstVisitor().serializeCompilationUnit(compilationUnit);
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single constant [Expression].
+ */
+class _ConstExprSerializer extends AbstractConstExprSerializer {
+ final _SummarizeAstVisitor visitor;
+
+ _ConstExprSerializer(this.visitor);
+
+ @override
+ EntityRefBuilder serializeConstructorName(ConstructorName constructor) {
+ EntityRefBuilder typeBuilder = serializeType(constructor.type);
+ if (constructor.name == null) {
+ return typeBuilder;
+ } else {
+ String name = constructor.name.name;
+ int nameRef = visitor.serializeReference(typeBuilder.reference, name);
+ return new EntityRefBuilder(reference: nameRef);
+ }
+ }
+
+ EntityRefBuilder serializeIdentifier(Identifier identifier) {
+ EntityRefBuilder b = new EntityRefBuilder();
+ if (identifier is SimpleIdentifier) {
+ b.reference = visitor.serializeReference(null, identifier.name);
+ } else if (identifier is PrefixedIdentifier) {
+ int prefix = visitor.serializeReference(null, identifier.prefix.name);
+ b.reference =
+ visitor.serializeReference(prefix, identifier.identifier.name);
+ } else {
+ throw new StateError(
+ 'Unexpected identifier type: ${identifier.runtimeType}');
+ }
+ return b;
+ }
+
+ @override
+ EntityRefBuilder serializePropertyAccess(PropertyAccess access) {
+ Expression target = access.target;
+ if (target is Identifier) {
+ EntityRefBuilder targetRef = serializeIdentifier(target);
+ return new EntityRefBuilder(
+ reference: visitor.serializeReference(
+ targetRef.reference, access.propertyName.name));
+ } else {
+ // TODO(scheglov) should we handle other targets in malformed constants?
+ throw new StateError('Unexpected target type: ${target.runtimeType}');
+ }
+ }
+
+ @override
+ EntityRefBuilder serializeType(TypeName node) {
+ return visitor.serializeTypeName(node);
+ }
+}
+
+/**
+ * An [_OtherScopedEntity] is a [_ScopedEntity] that does not refer to a type
+ * parameter. Since we don't need to track any special information about these
+ * types of scoped entities, it is a singleton class.
+ */
+class _OtherScopedEntity extends _ScopedEntity {
+ static final _OtherScopedEntity _instance = new _OtherScopedEntity._();
+
+ factory _OtherScopedEntity() => _instance;
+
+ _OtherScopedEntity._();
+}
+
+/**
+ * A [_Scope] represents a set of name/value pairs defined locally within a
+ * limited span of a compilation unit. (Note that the spec also uses the term
+ * "scope" to refer to the set of names defined at top level within a
+ * compilation unit, but we do not use [_Scope] for that purpose).
+ */
+class _Scope {
+ /**
+ * Names defined in this scope, and their meanings.
+ */
+ Map<String, _ScopedEntity> _definedNames = <String, _ScopedEntity>{};
+
+ /**
+ * Look up the meaning associated with the given [name], and return it. If
+ * [name] is not defined in this scope, return `null`.
+ */
+ _ScopedEntity operator [](String name) => _definedNames[name];
+
+ /**
+ * Let the given [name] refer to [entity] within this scope.
+ */
+ void operator []=(String name, _ScopedEntity entity) {
+ _definedNames[name] = entity;
+ }
+}
+
+/**
+ * Base class for entities that can live inside a scope.
+ */
+abstract class _ScopedEntity {}
+
+/**
+ * A [_ScopedTypeParameter] is a [_ScopedEntity] that refers to a type
+ * parameter of a class, typedef, or executable.
+ */
+class _ScopedTypeParameter extends _ScopedEntity {
+ /**
+ * Index of the type parameter within this scope. Since summaries use De
+ * Bruijn indices to refer to type parameters, which count upwards from the
+ * innermost bound name, the last type parameter in the scope has an index of
+ * 1, and each preceding type parameter has the next higher index.
+ */
+ final int index;
+
+ _ScopedTypeParameter(this.index);
+}
+
+/**
+ * Visitor used to create a summary from an AST.
+ */
+class _SummarizeAstVisitor extends SimpleAstVisitor {
+ /**
+ * List of objects which should be written to [UnlinkedUnit.classes].
+ */
+ final List<UnlinkedClassBuilder> classes = <UnlinkedClassBuilder>[];
+
+ /**
+ * List of objects which should be written to [UnlinkedUnit.enums].
+ */
+ final List<UnlinkedEnumBuilder> enums = <UnlinkedEnumBuilder>[];
+
+ /**
+ * List of objects which should be written to [UnlinkedUnit.executables]
+ * or [UnlinkedClass.executables].
+ */
+ List<UnlinkedExecutableBuilder> executables = <UnlinkedExecutableBuilder>[];
+
+ /**
+ * List of objects which should be written to [UnlinkedUnit.exports].
+ */
+ final List<UnlinkedExportNonPublicBuilder> exports =
+ <UnlinkedExportNonPublicBuilder>[];
+
+ /**
+ * List of objects which should be written to [UnlinkedUnit.parts].
+ */
+ final List<UnlinkedPartBuilder> parts = <UnlinkedPartBuilder>[];
+
+ /**
+ * List of objects which should be written to [UnlinkedUnit.typedefs].
+ */
+ final List<UnlinkedTypedefBuilder> typedefs = <UnlinkedTypedefBuilder>[];
+
+ /**
+ * List of objects which should be written to [UnlinkedUnit.variables] or
+ * [UnlinkedClass.fields].
+ */
+ List<UnlinkedVariableBuilder> variables = <UnlinkedVariableBuilder>[];
+
+ /**
+ * The unlinked portion of the "imports table". This is the list of objects
+ * which should be written to [UnlinkedUnit.imports].
+ */
+ final List<UnlinkedImportBuilder> unlinkedImports = <UnlinkedImportBuilder>[];
+
+ /**
+ * The unlinked portion of the "references table". This is the list of
+ * objects which should be written to [UnlinkedUnit.references].
+ */
+ final List<UnlinkedReferenceBuilder> unlinkedReferences =
+ <UnlinkedReferenceBuilder>[new UnlinkedReferenceBuilder()];
+
+ /**
+ * Map associating names used as prefixes in this compilation unit with their
+ * associated indices into [UnlinkedUnit.references].
+ */
+ final Map<String, int> prefixIndices = <String, int>{};
+
+ /**
+ * List of [_Scope]s currently in effect. This is used to resolve type names
+ * to type parameters within classes, typedefs, and executables.
+ */
+ final List<_Scope> scopes = <_Scope>[];
+
+ /**
+ * True if 'dart:core' has been explicitly imported.
+ */
+ bool hasCoreBeenImported = false;
+
+ /**
+ * Names referenced by this compilation unit. Structured as a map from
+ * prefix index to (map from name to reference table index), where "prefix
+ * index" means the index into [UnlinkedUnit.references] of the prefix (or
+ * `null` if there is no prefix), and "reference table index" means the index
+ * into [UnlinkedUnit.references] for the name itself.
+ */
+ final Map<int, Map<String, int>> nameToReference = <int, Map<String, int>>{};
+
+ /**
+ * If the library has a library directive, the library name derived from it.
+ * Otherwise `null`.
+ */
+ String libraryName;
+
+ /**
+ * If the library has a library directive, the offset of the library name.
+ * Otherwise `null`.
+ */
+ int libraryNameOffset;
+
+ /**
+ * If the library has a library directive, the length of the library name, as
+ * it appears in the source file. Otherwise `null`.
+ */
+ int libraryNameLength;
+
+ /**
+ * If the library has a library directive, the documentation comment for it
+ * (if any). Otherwise `null`.
+ */
+ UnlinkedDocumentationCommentBuilder libraryDocumentationComment;
+
+ /**
+ * The number of slot ids which have been assigned to this compilation unit.
+ */
+ int numSlots = 0;
+
+ /**
+ * Create a slot id for storing a propagated or inferred type.
+ */
+ int assignTypeSlot() => ++numSlots;
+
+ /**
+ * Build a [_Scope] object containing the names defined within the body of a
+ * class declaration.
+ */
+ _Scope buildClassMemberScope(NodeList<ClassMember> members) {
+ _Scope scope = new _Scope();
+ for (ClassMember member in members) {
+ // TODO(paulbery): consider replacing these if-tests with dynamic method
+ // dispatch.
+ if (member is MethodDeclaration) {
+ if (member.isSetter || member.isOperator) {
+ // We don't have to handle setters or operators because the only
+ // thing we look up is type names.
+ } else {
+ scope[member.name.name] = new _OtherScopedEntity();
+ }
+ } else if (member is FieldDeclaration) {
+ for (VariableDeclaration field in member.fields.variables) {
+ // A field declaration introduces two names, one with a trailing `=`.
+ // We don't have to worry about the one with a trailing `=` because
+ // the only thing we look up is type names.
+ scope[field.name.name] = new _OtherScopedEntity();
+ }
+ }
+ }
+ return scope;
+ }
+
+ /**
+ * Serialize a [ClassDeclaration] or [ClassTypeAlias] into an [UnlinkedClass]
+ * and store the result in [classes].
+ */
+ void serializeClass(
+ Token abstractKeyword,
+ String name,
+ int nameOffset,
+ TypeParameterList typeParameters,
+ TypeName superclass,
+ WithClause withClause,
+ ImplementsClause implementsClause,
+ NodeList<ClassMember> members,
+ bool isMixinApplication,
+ Comment documentationComment) {
+ int oldScopesLength = scopes.length;
+ List<UnlinkedExecutableBuilder> oldExecutables = executables;
+ executables = <UnlinkedExecutableBuilder>[];
+ List<UnlinkedVariableBuilder> oldVariables = variables;
+ variables = <UnlinkedVariableBuilder>[];
+ _TypeParameterScope typeParameterScope = new _TypeParameterScope();
+ scopes.add(typeParameterScope);
+ UnlinkedClassBuilder b = new UnlinkedClassBuilder();
+ b.name = name;
+ b.nameOffset = nameOffset;
+ b.isMixinApplication = isMixinApplication;
+ b.typeParameters =
+ serializeTypeParameters(typeParameters, typeParameterScope);
+ if (superclass != null) {
+ b.supertype = serializeTypeName(superclass);
+ }
+ if (withClause != null) {
+ b.mixins = withClause.mixinTypes.map(serializeTypeName).toList();
+ }
+ if (implementsClause != null) {
+ b.interfaces =
+ implementsClause.interfaces.map(serializeTypeName).toList();
+ }
+ if (members != null) {
+ scopes.add(buildClassMemberScope(members));
+ for (ClassMember member in members) {
+ member.accept(this);
+ }
+ scopes.removeLast();
+ }
+ b.executables = executables;
+ b.fields = variables;
+ b.isAbstract = abstractKeyword != null;
+ b.documentationComment = serializeDocumentation(documentationComment);
+ classes.add(b);
+ scopes.removeLast();
+ assert(scopes.length == oldScopesLength);
+ executables = oldExecutables;
+ variables = oldVariables;
+ }
+
+ /**
+ * Serialize a [Combinator] into an [UnlinkedCombinator].
+ */
+ UnlinkedCombinatorBuilder serializeCombinator(Combinator combinator) {
+ UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder();
+ if (combinator is ShowCombinator) {
+ b.shows =
+ combinator.shownNames.map((SimpleIdentifier id) => id.name).toList();
+ } else if (combinator is HideCombinator) {
+ b.hides =
+ combinator.hiddenNames.map((SimpleIdentifier id) => id.name).toList();
+ } else {
+ throw new StateError(
+ 'Unexpected combinator type: ${combinator.runtimeType}');
+ }
+ return b;
+ }
+
+ /**
+ * Main entry point for serializing an AST.
+ */
+ UnlinkedUnitBuilder serializeCompilationUnit(
+ CompilationUnit compilationUnit) {
+ compilationUnit.directives.accept(this);
+ if (!hasCoreBeenImported) {
+ unlinkedImports.add(new UnlinkedImportBuilder(isImplicit: true));
+ }
+ compilationUnit.declarations.accept(this);
+ UnlinkedUnitBuilder b = new UnlinkedUnitBuilder();
+ b.libraryName = libraryName;
+ b.libraryNameOffset = libraryNameOffset;
+ b.libraryNameLength = libraryNameLength;
+ b.libraryDocumentationComment = libraryDocumentationComment;
+ b.classes = classes;
+ b.enums = enums;
+ b.executables = executables;
+ b.exports = exports;
+ b.imports = unlinkedImports;
+ b.parts = parts;
+ b.references = unlinkedReferences;
+ b.typedefs = typedefs;
+ b.variables = variables;
+ b.publicNamespace = computePublicNamespace(compilationUnit);
+ return b;
+ }
+
+ /**
+ * Serialize the given [expression], creating an [UnlinkedConstBuilder].
+ */
+ UnlinkedConstBuilder serializeConstExpr(Expression expression) {
+ _ConstExprSerializer serializer = new _ConstExprSerializer(this);
+ serializer.serialize(expression);
+ return serializer.toBuilder();
+ }
+
+ /**
+ * Serialize a [Comment] node into an [UnlinkedDocumentationComment] object.
+ */
+ UnlinkedDocumentationCommentBuilder serializeDocumentation(
+ Comment documentationComment) {
+ if (documentationComment == null) {
+ return null;
+ }
+ String text = documentationComment.tokens
+ .map((Token t) => t.toString())
+ .join()
+ .replaceAll('\r\n', '\n');
+ return new UnlinkedDocumentationCommentBuilder(
+ text: text,
+ offset: documentationComment.offset,
+ length: documentationComment.length);
+ }
+
+ /**
+ * Serialize a [FunctionDeclaration] or [MethodDeclaration] into an
+ * [UnlinkedExecutable].
+ */
+ UnlinkedExecutableBuilder serializeExecutable(
+ SimpleIdentifier name,
+ bool isGetter,
+ bool isSetter,
+ TypeName returnType,
+ FormalParameterList formalParameters,
+ FunctionBody body,
+ bool isTopLevel,
+ bool isDeclaredStatic,
+ Comment documentationComment,
+ TypeParameterList typeParameters,
+ bool isExternal) {
+ int oldScopesLength = scopes.length;
+ _TypeParameterScope typeParameterScope = new _TypeParameterScope();
+ scopes.add(typeParameterScope);
+ UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder();
+ String nameString = name.name;
+ if (isGetter) {
+ b.kind = UnlinkedExecutableKind.getter;
+ } else if (isSetter) {
+ b.kind = UnlinkedExecutableKind.setter;
+ nameString = '$nameString=';
+ } else {
+ b.kind = UnlinkedExecutableKind.functionOrMethod;
+ }
+ b.isAbstract = body is EmptyFunctionBody;
+ b.name = nameString;
+ b.nameOffset = name.offset;
+ b.typeParameters =
+ serializeTypeParameters(typeParameters, typeParameterScope);
+ if (!isTopLevel) {
+ b.isStatic = isDeclaredStatic;
+ }
+ b.returnType = serializeTypeName(returnType);
+ b.isExternal = isExternal;
+ bool isSemanticallyStatic = isTopLevel || isDeclaredStatic;
+ if (formalParameters != null) {
+ b.parameters = formalParameters.parameters
+ .map((FormalParameter p) => p.accept(this))
+ .toList();
+ if (!isSemanticallyStatic) {
+ for (int i = 0; i < formalParameters.parameters.length; i++) {
+ if (!b.parameters[i].isFunctionTyped &&
+ b.parameters[i].type == null) {
+ b.parameters[i].inferredTypeSlot = assignTypeSlot();
+ }
+ }
+ }
+ }
+ b.documentationComment = serializeDocumentation(documentationComment);
+ if (returnType == null && !isSemanticallyStatic) {
+ b.inferredReturnTypeSlot = assignTypeSlot();
+ }
+ scopes.removeLast();
+ assert(scopes.length == oldScopesLength);
+ return b;
+ }
+
+ /**
+ * Serialize the return type and parameters of a function-typed formal
+ * parameter and store them in [b].
+ */
+ void serializeFunctionTypedParameterDetails(UnlinkedParamBuilder b,
+ TypeName returnType, FormalParameterList parameters) {
+ EntityRefBuilder serializedReturnType = serializeTypeName(returnType);
+ if (serializedReturnType != null) {
+ b.type = serializedReturnType;
+ }
+ b.parameters = parameters.parameters
+ .map((FormalParameter p) => p.accept(this))
+ .toList();
+ }
+
+ /**
+ * Serialize a [FieldFormalParameter], [FunctionTypedFormalParameter], or
+ * [SimpleFormalParameter] into an [UnlinkedParam].
+ */
+ UnlinkedParamBuilder serializeParameter(NormalFormalParameter node) {
+ UnlinkedParamBuilder b = new UnlinkedParamBuilder();
+ b.name = node.identifier.name;
+ b.nameOffset = node.identifier.offset;
+ switch (node.kind) {
+ case ParameterKind.REQUIRED:
+ b.kind = UnlinkedParamKind.required;
+ break;
+ case ParameterKind.POSITIONAL:
+ b.kind = UnlinkedParamKind.positional;
+ break;
+ case ParameterKind.NAMED:
+ b.kind = UnlinkedParamKind.named;
+ break;
+ default:
+ throw new StateError('Unexpected parameter kind: ${node.kind}');
+ }
+ return b;
+ }
+
+ /**
+ * Serialize a reference to a top level name declared elsewhere, by adding an
+ * entry to the references table if necessary. If [prefixIndex] is not null,
+ * the reference is associated with the prefix having the given index in the
+ * references table.
+ */
+ int serializeReference(int prefixIndex, String name) => nameToReference
+ .putIfAbsent(prefixIndex, () => <String, int>{})
+ .putIfAbsent(name, () {
+ int index = unlinkedReferences.length;
+ unlinkedReferences.add(new UnlinkedReferenceBuilder(
+ prefixReference: prefixIndex, name: name));
+ return index;
+ });
+
+ /**
+ * Serialize a type name (which might be defined in a nested scope, at top
+ * level within this library, or at top level within an imported library) to
+ * a [EntityRef]. Note that this method does the right thing if the
+ * name doesn't refer to an entity other than a type (e.g. a class member).
+ */
+ EntityRefBuilder serializeTypeName(TypeName node) {
+ if (node == null) {
+ return null;
+ } else {
+ EntityRefBuilder b = new EntityRefBuilder();
+ Identifier identifier = node.name;
+ if (identifier is SimpleIdentifier) {
+ String name = identifier.name;
+ int indexOffset = 0;
+ for (int i = scopes.length - 1; i >= 0; i--) {
+ _Scope scope = scopes[i];
+ _ScopedEntity entity = scope[name];
+ if (entity != null) {
+ if (entity is _ScopedTypeParameter) {
+ b.paramReference = indexOffset + entity.index;
+ return b;
+ } else {
+ // None of the other things that can be declared in local scopes
+ // are types, so this is an error and should be treated as a
+ // reference to `dynamic`.
+ b.reference = serializeReference(null, 'dynamic');
+ return b;
+ }
+ }
+ if (scope is _TypeParameterScope) {
+ indexOffset += scope.length;
+ }
+ }
+ b.reference = serializeReference(null, name);
+ } else if (identifier is PrefixedIdentifier) {
+ int prefixIndex = prefixIndices.putIfAbsent(identifier.prefix.name,
+ () => serializeReference(null, identifier.prefix.name));
+ b.reference =
+ serializeReference(prefixIndex, identifier.identifier.name);
+ } else {
+ throw new StateError(
+ 'Unexpected identifier type: ${identifier.runtimeType}');
+ }
+ if (node.typeArguments != null) {
+ // Trailing type arguments of type 'dynamic' should be omitted.
+ NodeList<TypeName> args = node.typeArguments.arguments;
+ int numArgsToSerialize = args.length;
+ while (
+ numArgsToSerialize > 0 && isDynamic(args[numArgsToSerialize - 1])) {
+ --numArgsToSerialize;
+ }
+ if (numArgsToSerialize > 0) {
+ List<EntityRefBuilder> serializedArguments = <EntityRefBuilder>[];
+ for (int i = 0; i < numArgsToSerialize; i++) {
+ serializedArguments.add(serializeTypeName(args[i]));
+ }
+ b.typeArguments = serializedArguments;
+ }
+ }
+ return b;
+ }
+ }
+
+ /**
+ * Serialize the given [typeParameters] into a list of [UnlinkedTypeParam]s,
+ * and also store them in [typeParameterScope].
+ */
+ List<UnlinkedTypeParamBuilder> serializeTypeParameters(
+ TypeParameterList typeParameters,
+ _TypeParameterScope typeParameterScope) {
+ if (typeParameters != null) {
+ for (int i = 0; i < typeParameters.typeParameters.length; i++) {
+ TypeParameter typeParameter = typeParameters.typeParameters[i];
+ typeParameterScope[typeParameter.name.name] =
+ new _ScopedTypeParameter(typeParameters.typeParameters.length - i);
+ }
+ return typeParameters.typeParameters.map(visitTypeParameter).toList();
+ }
+ return const <UnlinkedTypeParamBuilder>[];
+ }
+
+ /**
+ * Serialize the given [variables] into [UnlinkedVariable]s, and store them
+ * in [this.variables].
+ */
+ void serializeVariables(VariableDeclarationList variables,
+ bool isDeclaredStatic, Comment documentationComment, bool isField) {
+ for (VariableDeclaration variable in variables.variables) {
+ UnlinkedVariableBuilder b = new UnlinkedVariableBuilder();
+ b.isFinal = variables.isFinal;
+ b.isConst = variables.isConst;
+ b.isStatic = isDeclaredStatic;
+ b.name = variable.name.name;
+ b.nameOffset = variable.name.offset;
+ b.type = serializeTypeName(variables.type);
+ b.documentationComment = serializeDocumentation(documentationComment);
+ if (variable.isConst) {
+ Expression initializer = variable.initializer;
+ if (initializer != null) {
+ b.constExpr = serializeConstExpr(initializer);
+ }
+ }
+ if (variable.initializer != null &&
+ (variables.isFinal || variables.isConst)) {
+ b.propagatedTypeSlot = assignTypeSlot();
+ }
+ bool isSemanticallyStatic = !isField || isDeclaredStatic;
+ if (variables.type == null &&
+ (variable.initializer != null || !isSemanticallyStatic)) {
+ b.inferredTypeSlot = assignTypeSlot();
+ }
+ this.variables.add(b);
+ }
+ }
+
+ @override
+ void visitClassDeclaration(ClassDeclaration node) {
+ TypeName superclass =
+ node.extendsClause == null ? null : node.extendsClause.superclass;
+ serializeClass(
+ node.abstractKeyword,
+ node.name.name,
+ node.name.offset,
+ node.typeParameters,
+ superclass,
+ node.withClause,
+ node.implementsClause,
+ node.members,
+ false,
+ node.documentationComment);
+ }
+
+ @override
+ void visitClassTypeAlias(ClassTypeAlias node) {
+ serializeClass(
+ node.abstractKeyword,
+ node.name.name,
+ node.name.offset,
+ node.typeParameters,
+ node.superclass,
+ node.withClause,
+ node.implementsClause,
+ null,
+ true,
+ node.documentationComment);
+ }
+
+ @override
+ void visitConstructorDeclaration(ConstructorDeclaration node) {
+ UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder();
+ if (node.name != null) {
+ b.name = node.name.name;
+ b.nameOffset = node.name.offset;
+ } else {
+ b.nameOffset = node.returnType.offset;
+ }
+ b.parameters = node.parameters.parameters
+ .map((FormalParameter p) => p.accept(this))
+ .toList();
+ b.kind = UnlinkedExecutableKind.constructor;
+ b.isFactory = node.factoryKeyword != null;
+ b.isConst = node.constKeyword != null;
+ b.isExternal = node.externalKeyword != null;
+ b.documentationComment = serializeDocumentation(node.documentationComment);
+ executables.add(b);
+ }
+
+ @override
+ UnlinkedParamBuilder visitDefaultFormalParameter(
+ DefaultFormalParameter node) {
+ return node.parameter.accept(this);
+ }
+
+ @override
+ void visitEnumDeclaration(EnumDeclaration node) {
+ UnlinkedEnumBuilder b = new UnlinkedEnumBuilder();
+ b.name = node.name.name;
+ b.nameOffset = node.name.offset;
+ b.values = node.constants
+ .map((EnumConstantDeclaration value) => new UnlinkedEnumValueBuilder(
+ name: value.name.name, nameOffset: value.name.offset))
+ .toList();
+ b.documentationComment = serializeDocumentation(node.documentationComment);
+ enums.add(b);
+ }
+
+ @override
+ void visitExportDirective(ExportDirective node) {
+ UnlinkedExportNonPublicBuilder b = new UnlinkedExportNonPublicBuilder(
+ uriOffset: node.uri.offset, uriEnd: node.uri.end, offset: node.offset);
+ exports.add(b);
+ }
+
+ @override
+ void visitFieldDeclaration(FieldDeclaration node) {
+ serializeVariables(node.fields, node.staticKeyword != null,
+ node.documentationComment, true);
+ }
+
+ @override
+ UnlinkedParamBuilder visitFieldFormalParameter(FieldFormalParameter node) {
+ UnlinkedParamBuilder b = serializeParameter(node);
+ b.isInitializingFormal = true;
+ if (node.type != null || node.parameters != null) {
+ b.isFunctionTyped = node.parameters != null;
+ if (node.parameters != null) {
+ serializeFunctionTypedParameterDetails(b, node.type, node.parameters);
+ } else {
+ b.type = serializeTypeName(node.type);
+ }
+ }
+ return b;
+ }
+
+ @override
+ void visitFunctionDeclaration(FunctionDeclaration node) {
+ executables.add(serializeExecutable(
+ node.name,
+ node.isGetter,
+ node.isSetter,
+ node.returnType,
+ node.functionExpression.parameters,
+ node.functionExpression.body,
+ true,
+ false,
+ node.documentationComment,
+ node.functionExpression.typeParameters,
+ node.externalKeyword != null));
+ }
+
+ @override
+ void visitFunctionTypeAlias(FunctionTypeAlias node) {
+ int oldScopesLength = scopes.length;
+ _TypeParameterScope typeParameterScope = new _TypeParameterScope();
+ scopes.add(typeParameterScope);
+ UnlinkedTypedefBuilder b = new UnlinkedTypedefBuilder();
+ b.name = node.name.name;
+ b.nameOffset = node.name.offset;
+ b.typeParameters =
+ serializeTypeParameters(node.typeParameters, typeParameterScope);
+ EntityRefBuilder serializedReturnType = serializeTypeName(node.returnType);
+ if (serializedReturnType != null) {
+ b.returnType = serializedReturnType;
+ }
+ b.parameters = node.parameters.parameters
+ .map((FormalParameter p) => p.accept(this))
+ .toList();
+ b.documentationComment = serializeDocumentation(node.documentationComment);
+ typedefs.add(b);
+ scopes.removeLast();
+ assert(scopes.length == oldScopesLength);
+ }
+
+ @override
+ UnlinkedParamBuilder visitFunctionTypedFormalParameter(
+ FunctionTypedFormalParameter node) {
+ UnlinkedParamBuilder b = serializeParameter(node);
+ b.isFunctionTyped = true;
+ serializeFunctionTypedParameterDetails(b, node.returnType, node.parameters);
+ return b;
+ }
+
+ @override
+ void visitImportDirective(ImportDirective node) {
+ UnlinkedImportBuilder b = new UnlinkedImportBuilder();
+ if (node.uri.stringValue == 'dart:core') {
+ hasCoreBeenImported = true;
+ }
+ b.offset = node.offset;
+ b.combinators = node.combinators.map(serializeCombinator).toList();
+ if (node.prefix != null) {
+ b.prefixReference = serializeReference(null, node.prefix.name);
+ b.prefixOffset = node.prefix.offset;
+ }
+ b.isDeferred = node.deferredKeyword != null;
+ b.uri = node.uri.stringValue;
+ b.uriOffset = node.uri.offset;
+ b.uriEnd = node.uri.end;
+ unlinkedImports.add(b);
+ }
+
+ @override
+ void visitLibraryDirective(LibraryDirective node) {
+ libraryName =
+ node.name.components.map((SimpleIdentifier id) => id.name).join('.');
+ libraryNameOffset = node.name.offset;
+ libraryNameLength = node.name.length;
+ libraryDocumentationComment =
+ serializeDocumentation(node.documentationComment);
+ }
+
+ @override
+ void visitMethodDeclaration(MethodDeclaration node) {
+ executables.add(serializeExecutable(
+ node.name,
+ node.isGetter,
+ node.isSetter,
+ node.returnType,
+ node.parameters,
+ node.body,
+ false,
+ node.isStatic,
+ node.documentationComment,
+ node.typeParameters,
+ node.externalKeyword != null));
+ }
+
+ @override
+ void visitPartDirective(PartDirective node) {
+ parts.add(new UnlinkedPartBuilder(
+ uriOffset: node.uri.offset, uriEnd: node.uri.end));
+ }
+
+ @override
+ void visitPartOfDirective(PartOfDirective node) {}
+
+ @override
+ UnlinkedParamBuilder visitSimpleFormalParameter(SimpleFormalParameter node) {
+ UnlinkedParamBuilder b = serializeParameter(node);
+ b.type = serializeTypeName(node.type);
+ return b;
+ }
+
+ @override
+ void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+ serializeVariables(node.variables, false, node.documentationComment, false);
+ }
+
+ @override
+ UnlinkedTypeParamBuilder visitTypeParameter(TypeParameter node) {
+ UnlinkedTypeParamBuilder b = new UnlinkedTypeParamBuilder();
+ b.name = node.name.name;
+ b.nameOffset = node.name.offset;
+ if (node.bound != null) {
+ b.bound = serializeTypeName(node.bound);
+ }
+ return b;
+ }
+
+ /**
+ * Helper method to determine if a given [typeName] refers to `dynamic`.
+ */
+ static bool isDynamic(TypeName typeName) {
+ Identifier name = typeName.name;
+ return name is SimpleIdentifier && name.name == 'dynamic';
+ }
+}
+
+/**
+ * A [_TypeParameterScope] is a [_Scope] which defines [_ScopedTypeParameter]s.
+ */
+class _TypeParameterScope extends _Scope {
+ /**
+ * Get the number of [_ScopedTypeParameter]s defined in this
+ * [_TypeParameterScope].
+ */
+ int get length => _definedNames.length;
+}
diff --git a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
new file mode 100644
index 0000000..f6dea26
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
@@ -0,0 +1,308 @@
+// Copyright (c) 2016, 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 serialization.summarize_const_expr;
+
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/summary/format.dart';
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single constant [Expression].
+ */
+abstract class AbstractConstExprSerializer {
+ /**
+ * See [UnlinkedConstBuilder.operations].
+ */
+ final List<UnlinkedConstOperation> operations = <UnlinkedConstOperation>[];
+
+ /**
+ * See [UnlinkedConstBuilder.ints].
+ */
+ final List<int> ints = <int>[];
+
+ /**
+ * See [UnlinkedConstBuilder.doubles].
+ */
+ final List<double> doubles = <double>[];
+
+ /**
+ * See [UnlinkedConstBuilder.strings].
+ */
+ final List<String> strings = <String>[];
+
+ /**
+ * See [UnlinkedConstBuilder.references].
+ */
+ final List<EntityRefBuilder> references = <EntityRefBuilder>[];
+
+ /**
+ * Serialize the given [expr] expression into this serializer state.
+ */
+ void serialize(Expression expr) {
+ if (expr is IntegerLiteral) {
+ _pushInt(expr.value);
+ } else if (expr is DoubleLiteral) {
+ operations.add(UnlinkedConstOperation.pushDouble);
+ doubles.add(expr.value);
+ } else if (expr is BooleanLiteral) {
+ if (expr.value) {
+ operations.add(UnlinkedConstOperation.pushTrue);
+ } else {
+ operations.add(UnlinkedConstOperation.pushFalse);
+ }
+ } else if (expr is StringLiteral) {
+ _serializeString(expr);
+ } else if (expr is SymbolLiteral) {
+ strings.add(expr.components.map((token) => token.lexeme).join('.'));
+ operations.add(UnlinkedConstOperation.pushString);
+ operations.add(UnlinkedConstOperation.makeSymbol);
+ } else if (expr is NullLiteral) {
+ operations.add(UnlinkedConstOperation.pushNull);
+ } else if (expr is Identifier) {
+ references.add(serializeIdentifier(expr));
+ operations.add(UnlinkedConstOperation.pushReference);
+ } else if (expr is InstanceCreationExpression) {
+ _serializeInstanceCreation(expr);
+ } else if (expr is ListLiteral) {
+ _serializeListLiteral(expr);
+ } else if (expr is MapLiteral) {
+ _serializeMapLiteral(expr);
+ } else if (expr is MethodInvocation) {
+ String name = expr.methodName.name;
+ if (name != 'identical') {
+ throw new _ConstExprSerializationError(
+ 'Only "identity" function invocation is allowed.');
+ }
+ if (expr.argumentList == null ||
+ expr.argumentList.arguments.length != 2) {
+ throw new _ConstExprSerializationError(
+ 'The function "identity" requires exactly 2 arguments.');
+ }
+ expr.argumentList.arguments.forEach(serialize);
+ operations.add(UnlinkedConstOperation.identical);
+ } else if (expr is BinaryExpression) {
+ _serializeBinaryExpression(expr);
+ } else if (expr is ConditionalExpression) {
+ serialize(expr.condition);
+ serialize(expr.thenExpression);
+ serialize(expr.elseExpression);
+ operations.add(UnlinkedConstOperation.conditional);
+ } else if (expr is PrefixExpression) {
+ _serializePrefixExpression(expr);
+ } else if (expr is PropertyAccess) {
+ if (expr.target is! PrefixedIdentifier &&
+ expr.propertyName.name == 'length') {
+ serialize(expr.target);
+ operations.add(UnlinkedConstOperation.length);
+ } else {
+ references.add(serializePropertyAccess(expr));
+ operations.add(UnlinkedConstOperation.pushReference);
+ }
+ } else if (expr is ParenthesizedExpression) {
+ serialize(expr.expression);
+ } else {
+ throw new _ConstExprSerializationError('Unknown expression type: $expr');
+ }
+ }
+
+ /**
+ * Return [EntityRefBuilder] that corresponds to the given [constructor].
+ */
+ EntityRefBuilder serializeConstructorName(ConstructorName constructor);
+
+ /**
+ * Return [EntityRefBuilder] that corresponds to the given [identifier].
+ */
+ EntityRefBuilder serializeIdentifier(Identifier identifier);
+
+ /**
+ * Return [EntityRefBuilder] that corresponds to the given [access].
+ */
+ EntityRefBuilder serializePropertyAccess(PropertyAccess access);
+
+ /**
+ * Return [EntityRefBuilder] that corresponds to the given [type].
+ */
+ EntityRefBuilder serializeType(TypeName type);
+
+ /**
+ * Return the [UnlinkedConstBuilder] that corresponds to the state of this
+ * serializer.
+ */
+ UnlinkedConstBuilder toBuilder() {
+ return new UnlinkedConstBuilder(
+ operations: operations,
+ ints: ints,
+ doubles: doubles,
+ strings: strings,
+ references: references);
+ }
+
+ void _pushInt(int value) {
+ assert(value >= 0);
+ if (value >= (1 << 32)) {
+ _pushInt(value >> 32);
+ operations.add(UnlinkedConstOperation.shiftOr);
+ ints.add(value & 0xFFFFFFFF);
+ } else {
+ operations.add(UnlinkedConstOperation.pushInt);
+ ints.add(value);
+ }
+ }
+
+ void _serializeBinaryExpression(BinaryExpression expr) {
+ serialize(expr.leftOperand);
+ serialize(expr.rightOperand);
+ TokenType operator = expr.operator.type;
+ if (operator == TokenType.EQ_EQ) {
+ operations.add(UnlinkedConstOperation.equal);
+ } else if (operator == TokenType.BANG_EQ) {
+ operations.add(UnlinkedConstOperation.equal);
+ operations.add(UnlinkedConstOperation.not);
+ } else if (operator == TokenType.AMPERSAND_AMPERSAND) {
+ operations.add(UnlinkedConstOperation.and);
+ } else if (operator == TokenType.BAR_BAR) {
+ operations.add(UnlinkedConstOperation.or);
+ } else if (operator == TokenType.CARET) {
+ operations.add(UnlinkedConstOperation.bitXor);
+ } else if (operator == TokenType.AMPERSAND) {
+ operations.add(UnlinkedConstOperation.bitAnd);
+ } else if (operator == TokenType.BAR) {
+ operations.add(UnlinkedConstOperation.bitOr);
+ } else if (operator == TokenType.GT_GT) {
+ operations.add(UnlinkedConstOperation.bitShiftRight);
+ } else if (operator == TokenType.LT_LT) {
+ operations.add(UnlinkedConstOperation.bitShiftLeft);
+ } else if (operator == TokenType.PLUS) {
+ operations.add(UnlinkedConstOperation.add);
+ } else if (operator == TokenType.MINUS) {
+ operations.add(UnlinkedConstOperation.subtract);
+ } else if (operator == TokenType.STAR) {
+ operations.add(UnlinkedConstOperation.multiply);
+ } else if (operator == TokenType.SLASH) {
+ operations.add(UnlinkedConstOperation.divide);
+ } else if (operator == TokenType.TILDE_SLASH) {
+ operations.add(UnlinkedConstOperation.floorDivide);
+ } else if (operator == TokenType.GT) {
+ operations.add(UnlinkedConstOperation.greater);
+ } else if (operator == TokenType.LT) {
+ operations.add(UnlinkedConstOperation.less);
+ } else if (operator == TokenType.GT_EQ) {
+ operations.add(UnlinkedConstOperation.greaterEqual);
+ } else if (operator == TokenType.LT_EQ) {
+ operations.add(UnlinkedConstOperation.lessEqual);
+ } else if (operator == TokenType.PERCENT) {
+ operations.add(UnlinkedConstOperation.modulo);
+ } else {
+ throw new _ConstExprSerializationError('Unknown operator: $operator');
+ }
+ }
+
+ void _serializeInstanceCreation(InstanceCreationExpression expr) {
+ ConstructorName constructor = expr.constructorName;
+ List<Expression> arguments = expr.argumentList.arguments;
+ // Serialize the arguments.
+ List<String> argumentNames = <String>[];
+ arguments.forEach((arg) {
+ if (arg is NamedExpression) {
+ argumentNames.add(arg.name.label.name);
+ serialize(arg.expression);
+ } else {
+ serialize(arg);
+ }
+ });
+ // Add the op-code and numbers of named and positional arguments.
+ operations.add(UnlinkedConstOperation.invokeConstructor);
+ ints.add(argumentNames.length);
+ strings.addAll(argumentNames);
+ ints.add(arguments.length - argumentNames.length);
+ // Serialize the reference.
+ references.add(serializeConstructorName(constructor));
+ }
+
+ void _serializeListLiteral(ListLiteral expr) {
+ List<Expression> elements = expr.elements;
+ elements.forEach(serialize);
+ ints.add(elements.length);
+ if (expr.typeArguments != null &&
+ expr.typeArguments.arguments.length == 1) {
+ references.add(serializeType(expr.typeArguments.arguments[0]));
+ operations.add(UnlinkedConstOperation.makeTypedList);
+ } else {
+ operations.add(UnlinkedConstOperation.makeUntypedList);
+ }
+ }
+
+ void _serializeMapLiteral(MapLiteral expr) {
+ for (MapLiteralEntry entry in expr.entries) {
+ serialize(entry.key);
+ serialize(entry.value);
+ }
+ ints.add(expr.entries.length);
+ if (expr.typeArguments != null &&
+ expr.typeArguments.arguments.length == 2) {
+ references.add(serializeType(expr.typeArguments.arguments[0]));
+ references.add(serializeType(expr.typeArguments.arguments[1]));
+ operations.add(UnlinkedConstOperation.makeTypedMap);
+ } else {
+ operations.add(UnlinkedConstOperation.makeUntypedMap);
+ }
+ }
+
+ void _serializePrefixExpression(PrefixExpression expr) {
+ serialize(expr.operand);
+ TokenType operator = expr.operator.type;
+ if (operator == TokenType.BANG) {
+ operations.add(UnlinkedConstOperation.not);
+ } else if (operator == TokenType.MINUS) {
+ operations.add(UnlinkedConstOperation.negate);
+ } else if (operator == TokenType.TILDE) {
+ operations.add(UnlinkedConstOperation.complement);
+ } else {
+ throw new _ConstExprSerializationError('Unknown operator: $operator');
+ }
+ }
+
+ void _serializeString(StringLiteral expr) {
+ if (expr is AdjacentStrings) {
+ if (expr.strings.every((string) => string is SimpleStringLiteral)) {
+ operations.add(UnlinkedConstOperation.pushString);
+ strings.add(expr.stringValue);
+ } else {
+ expr.strings.forEach(_serializeString);
+ operations.add(UnlinkedConstOperation.concatenate);
+ ints.add(expr.strings.length);
+ }
+ } else if (expr is SimpleStringLiteral) {
+ operations.add(UnlinkedConstOperation.pushString);
+ strings.add(expr.value);
+ } else {
+ StringInterpolation interpolation = expr as StringInterpolation;
+ for (InterpolationElement element in interpolation.elements) {
+ if (element is InterpolationString) {
+ operations.add(UnlinkedConstOperation.pushString);
+ strings.add(element.value);
+ } else {
+ serialize((element as InterpolationExpression).expression);
+ }
+ }
+ operations.add(UnlinkedConstOperation.concatenate);
+ ints.add(interpolation.elements.length);
+ }
+ }
+}
+
+/**
+ * Error that describes a problem during a constant expression serialization.
+ */
+class _ConstExprSerializationError {
+ final String message;
+
+ _ConstExprSerializationError(this.message);
+
+ @override
+ String toString() => message;
+}
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index 0eac910..66f31ecc 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -6,32 +6,65 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/name_filter.dart';
+import 'package:analyzer/src/summary/summarize_const_expr.dart';
/**
* Serialize all the elements in [lib] to a summary using [ctx] as the context
* for building the summary, and using [typeProvider] to find built-in types.
*/
LibrarySerializationResult serializeLibrary(
- LibraryElement lib, TypeProvider typeProvider) {
- var serializer = new _LibrarySerializer(lib, typeProvider);
- PrelinkedLibraryBuilder prelinked = serializer.serializeLibrary();
+ LibraryElement lib, TypeProvider typeProvider, bool strongMode) {
+ var serializer = new _LibrarySerializer(lib, typeProvider, strongMode);
+ LinkedLibraryBuilder linked = serializer.serializeLibrary();
return new LibrarySerializationResult(
- prelinked, serializer.unlinkedUnits, serializer.unitUris);
+ linked, serializer.unlinkedUnits, serializer.unitUris);
}
+ReferenceKind _getReferenceKind(Element element) {
+ if (element == null ||
+ element is ClassElement ||
+ element is DynamicElementImpl) {
+ return ReferenceKind.classOrEnum;
+ } else if (element is ConstructorElement) {
+ return ReferenceKind.constructor;
+ } else if (element is FunctionElement) {
+ return ReferenceKind.topLevelFunction;
+ } else if (element is FunctionTypeAliasElement) {
+ return ReferenceKind.typedef;
+ } else if (element is PropertyAccessorElement) {
+ if (element.enclosingElement is ClassElement) {
+ return ReferenceKind.constField;
+ }
+ return ReferenceKind.topLevelPropertyAccessor;
+ } else if (element is MethodElement) {
+ return ReferenceKind.staticMethod;
+ } else {
+ throw new Exception('Unexpected element kind: ${element.runtimeType}');
+ }
+}
+
+/**
+ * Type of closures used by [_LibrarySerializer] to defer generation of
+ * [EntityRefBuilder] objects until the end of serialization of a
+ * compilation unit.
+ */
+typedef EntityRefBuilder _SerializeTypeRef();
+
/**
* Data structure holding the result of serializing a [LibraryElement].
*/
class LibrarySerializationResult {
/**
- * Pre-linked information the given library.
+ * Linked information the given library.
*/
- final PrelinkedLibraryBuilder prelinked;
+ final LinkedLibraryBuilder linked;
/**
* Unlinked information for the compilation units constituting the library.
@@ -46,58 +79,45 @@
*/
final List<String> unitUris;
- LibrarySerializationResult(this.prelinked, this.unlinkedUnits, this.unitUris);
+ LibrarySerializationResult(this.linked, this.unlinkedUnits, this.unitUris);
}
/**
* Instances of this class keep track of intermediate state during
- * serialization of a single library.`
+ * serialization of a single compilation unit.
*/
-class _LibrarySerializer {
+class _CompilationUnitSerializer {
/**
- * The library to be serialized.
+ * The [_LibrarySerializer] which is serializing the library of which
+ * [compilationUnit] is a part.
*/
- final LibraryElement libraryElement;
+ final _LibrarySerializer librarySerializer;
/**
- * The type provider. This is used to locate the library for `dart:core`.
+ * The [CompilationUnitElement] being serialized.
*/
- final TypeProvider typeProvider;
+ final CompilationUnitElement compilationUnit;
/**
- * List of objects which should be written to [PrelinkedLibrary.units].
+ * The ordinal index of [compilationUnit] within the library, where 0
+ * represents the defining compilation unit.
*/
- final List<PrelinkedUnitBuilder> prelinkedUnits = <PrelinkedUnitBuilder>[];
+ final int unitNum;
/**
- * List of unlinked units corresponding to the pre-linked units in
- * [prelinkedUnits],
+ * The final linked summary of the compilation unit.
*/
- final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
+ final LinkedUnitBuilder linkedUnit = new LinkedUnitBuilder();
/**
- * List of absolute URIs of the compilation units in the library.
+ * The final unlinked summary of the compilation unit.
*/
- final List<String> unitUris = <String>[];
+ final UnlinkedUnitBuilder unlinkedUnit = new UnlinkedUnitBuilder();
- /**
- * Map from [LibraryElement] to the index of the entry in the "dependency
- * table" that refers to it.
- */
- final Map<LibraryElement, int> dependencyMap = <LibraryElement, int>{};
-
- /**
- * The "dependency table". This is the list of objects which should be
- * written to [PrelinkedLibrary.dependencies].
- */
- final List<PrelinkedDependencyBuilder> dependencies =
- <PrelinkedDependencyBuilder>[];
-
- /**
- * The prelinked portion of the "imports table". This is the list of ints
- * which should be written to [PrelinkedLibrary.imports].
- */
- final List<int> prelinkedImports = <int>[];
+/**
+ * Absolute URI of the compilation unit.
+ */
+ String unitUri;
/**
* Map from [Element] to the index of the entry in the "references table"
@@ -112,12 +132,21 @@
List<UnlinkedReferenceBuilder> unlinkedReferences;
/**
- * The prelinked portion of the "references table". This is the list of
- * objects which should be written to [PrelinkedUnit.references].
+ * The linked portion of the "references table". This is the list of
+ * objects which should be written to [LinkedUnit.references].
*/
- List<PrelinkedReferenceBuilder> prelinkedReferences;
+ List<LinkedReferenceBuilder> linkedReferences;
- //final Map<String, int> prefixIndices = <String, int>{};
+ /**
+ * The number of slot ids which have been assigned to this compilation unit.
+ */
+ int numSlots = 0;
+
+ /**
+ * List of closures which should be invoked at the end of serialization of a
+ * compilation unit, to produce [LinkedUnit.types].
+ */
+ final List<_SerializeTypeRef> deferredLinkedTypes = <_SerializeTypeRef>[];
/**
* Index into the "references table" representing an unresolved reference, if
@@ -126,99 +155,86 @@
*/
int unresolvedReferenceIndex = null;
- /**
- * Set of libraries which have been seen so far while visiting the transitive
- * closure of exports.
- */
- final Set<LibraryElement> librariesAddedToTransitiveExportClosure =
- new Set<LibraryElement>();
-
- /**
- * Map from imported element to the prefix which may be used to refer to that
- * element; elements for which no prefix is needed are absent from this map.
- */
- final Map<Element, PrefixElement> prefixMap = <Element, PrefixElement>{};
-
- _LibrarySerializer(this.libraryElement, this.typeProvider) {
- dependencies.add(encodePrelinkedDependency());
- dependencyMap[libraryElement] = 0;
- }
-
- /**
- * Retrieve the library element for `dart:core`.
- */
- LibraryElement get coreLibrary => typeProvider.objectType.element.library;
+ _CompilationUnitSerializer(
+ this.librarySerializer, this.compilationUnit, this.unitNum);
/**
* Add all classes, enums, typedefs, executables, and top level variables
- * from the given compilation unit [element] to the library summary.
+ * from the given compilation unit [element] to the compilation unit summary.
* [unitNum] indicates the ordinal position of this compilation unit in the
* library.
*/
- void addCompilationUnitElements(CompilationUnitElement element, int unitNum) {
- UnlinkedUnitBuilder b = new UnlinkedUnitBuilder();
- referenceMap.clear();
- unlinkedReferences = <UnlinkedReferenceBuilder>[encodeUnlinkedReference()];
- prelinkedReferences = <PrelinkedReferenceBuilder>[
- encodePrelinkedReference(kind: PrelinkedReferenceKind.classOrEnum)
+ void addCompilationUnitElements() {
+ unlinkedReferences = <UnlinkedReferenceBuilder>[
+ new UnlinkedReferenceBuilder()
+ ];
+ linkedReferences = <LinkedReferenceBuilder>[
+ new LinkedReferenceBuilder(kind: ReferenceKind.classOrEnum)
];
List<UnlinkedPublicNameBuilder> names = <UnlinkedPublicNameBuilder>[];
- for (PropertyAccessorElement accessor in element.accessors) {
+ for (PropertyAccessorElement accessor in compilationUnit.accessors) {
if (accessor.isPublic) {
- names.add(encodeUnlinkedPublicName(
- kind: PrelinkedReferenceKind.other,
+ names.add(new UnlinkedPublicNameBuilder(
+ kind: ReferenceKind.topLevelPropertyAccessor,
name: accessor.name,
numTypeParameters: accessor.typeParameters.length));
}
}
- for (ClassElement cls in element.types) {
+ for (ClassElement cls in compilationUnit.types) {
if (cls.isPublic) {
- names.add(encodeUnlinkedPublicName(
- kind: PrelinkedReferenceKind.classOrEnum,
+ names.add(new UnlinkedPublicNameBuilder(
+ kind: ReferenceKind.classOrEnum,
name: cls.name,
- numTypeParameters: cls.typeParameters.length));
+ numTypeParameters: cls.typeParameters.length,
+ constMembers: serializeClassConstMembers(cls)));
}
}
- for (ClassElement enm in element.enums) {
+ for (ClassElement enm in compilationUnit.enums) {
if (enm.isPublic) {
- names.add(encodeUnlinkedPublicName(
- kind: PrelinkedReferenceKind.classOrEnum, name: enm.name));
+ names.add(new UnlinkedPublicNameBuilder(
+ kind: ReferenceKind.classOrEnum, name: enm.name));
}
}
- for (FunctionElement function in element.functions) {
+ for (FunctionElement function in compilationUnit.functions) {
if (function.isPublic) {
- names.add(encodeUnlinkedPublicName(
- kind: PrelinkedReferenceKind.other,
+ names.add(new UnlinkedPublicNameBuilder(
+ kind: ReferenceKind.topLevelFunction,
name: function.name,
numTypeParameters: function.typeParameters.length));
}
}
- for (FunctionTypeAliasElement typedef in element.functionTypeAliases) {
+ for (FunctionTypeAliasElement typedef
+ in compilationUnit.functionTypeAliases) {
if (typedef.isPublic) {
- names.add(encodeUnlinkedPublicName(
- kind: PrelinkedReferenceKind.typedef,
+ names.add(new UnlinkedPublicNameBuilder(
+ kind: ReferenceKind.typedef,
name: typedef.name,
numTypeParameters: typedef.typeParameters.length));
}
}
if (unitNum == 0) {
+ LibraryElement libraryElement = librarySerializer.libraryElement;
if (libraryElement.name.isNotEmpty) {
- b.libraryName = libraryElement.name;
- b.libraryNameOffset = libraryElement.nameOffset;
- b.libraryNameLength = libraryElement.nameLength;
- b.libraryDocumentationComment = serializeDocumentation(libraryElement);
+ LibraryElement libraryElement = librarySerializer.libraryElement;
+ unlinkedUnit.libraryName = libraryElement.name;
+ unlinkedUnit.libraryNameOffset = libraryElement.nameOffset;
+ unlinkedUnit.libraryNameLength = libraryElement.nameLength;
+ unlinkedUnit.libraryDocumentationComment =
+ serializeDocumentation(libraryElement);
}
- b.publicNamespace = encodeUnlinkedPublicNamespace(
+ unlinkedUnit.publicNamespace = new UnlinkedPublicNamespaceBuilder(
exports: libraryElement.exports.map(serializeExportPublic).toList(),
parts: libraryElement.parts
.map((CompilationUnitElement e) => e.uri)
.toList(),
names: names);
- b.exports = libraryElement.exports.map(serializeExportNonPublic).toList();
- b.imports = libraryElement.imports.map(serializeImport).toList();
- b.parts = libraryElement.parts
+ unlinkedUnit.exports =
+ libraryElement.exports.map(serializeExportNonPublic).toList();
+ unlinkedUnit.imports =
+ libraryElement.imports.map(serializeImport).toList();
+ unlinkedUnit.parts = libraryElement.parts
.map((CompilationUnitElement e) =>
- encodeUnlinkedPart(uriOffset: e.uriOffset, uriEnd: e.uriEnd))
+ new UnlinkedPartBuilder(uriOffset: e.uriOffset, uriEnd: e.uriEnd))
.toList();
} else {
// TODO(paulberry): we need to figure out a way to record library, part,
@@ -227,21 +243,23 @@
// language), so that if the user makes code changes that cause a
// non-defining compilation unit to become a defining compilation unit,
// we can create a correct summary by simply re-linking.
- b.publicNamespace = encodeUnlinkedPublicNamespace(names: names);
+ unlinkedUnit.publicNamespace =
+ new UnlinkedPublicNamespaceBuilder(names: names);
}
- b.classes = element.types.map(serializeClass).toList();
- b.enums = element.enums.map(serializeEnum).toList();
- b.typedefs = element.functionTypeAliases.map(serializeTypedef).toList();
+ unlinkedUnit.classes = compilationUnit.types.map(serializeClass).toList();
+ unlinkedUnit.enums = compilationUnit.enums.map(serializeEnum).toList();
+ unlinkedUnit.typedefs =
+ compilationUnit.functionTypeAliases.map(serializeTypedef).toList();
List<UnlinkedExecutableBuilder> executables =
- element.functions.map(serializeExecutable).toList();
- for (PropertyAccessorElement accessor in element.accessors) {
+ compilationUnit.functions.map(serializeExecutable).toList();
+ for (PropertyAccessorElement accessor in compilationUnit.accessors) {
if (!accessor.isSynthetic) {
executables.add(serializeExecutable(accessor));
}
}
- b.executables = executables;
+ unlinkedUnit.executables = executables;
List<UnlinkedVariableBuilder> variables = <UnlinkedVariableBuilder>[];
- for (PropertyAccessorElement accessor in element.accessors) {
+ for (PropertyAccessorElement accessor in compilationUnit.accessors) {
if (accessor.isSynthetic && accessor.isGetter) {
PropertyInducingElement variable = accessor.variable;
if (variable != null) {
@@ -250,45 +268,20 @@
}
}
}
- b.variables = variables;
- b.references = unlinkedReferences;
- unlinkedUnits.add(b);
- prelinkedUnits.add(encodePrelinkedUnit(references: prelinkedReferences));
- unitUris.add(element.source.uri.toString());
- unlinkedReferences = null;
- prelinkedReferences = null;
+ unlinkedUnit.variables = variables;
+ unlinkedUnit.references = unlinkedReferences;
+ linkedUnit.references = linkedReferences;
+ unitUri = compilationUnit.source.uri.toString();
}
/**
- * Add [exportedLibrary] (and the transitive closure of all libraries it
- * exports) to the dependency table ([PrelinkedLibrary.dependencies]).
+ * Create the [LinkedUnit.types] table based on deferred types that were
+ * found during [addCompilationUnitElements].
*/
- void addTransitiveExportClosure(LibraryElement exportedLibrary) {
- if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) {
- serializeDependency(exportedLibrary);
- for (LibraryElement transitiveExport
- in exportedLibrary.exportedLibraries) {
- addTransitiveExportClosure(transitiveExport);
- }
- }
- }
-
- /**
- * Fill in [prefixMap] using information from [libraryElement.imports].
- */
- void computePrefixMap() {
- for (ImportElement import in libraryElement.imports) {
- if (import.prefix == null) {
- continue;
- }
- import.importedLibrary.exportNamespace.definedNames
- .forEach((String name, Element e) {
- if (new NameFilter.forNamespaceCombinators(import.combinators)
- .accepts(name)) {
- prefixMap[e] = import.prefix;
- }
- });
- }
+ void createLinkedTypes() {
+ linkedUnit.types = deferredLinkedTypes
+ .map((_SerializeTypeRef closure) => closure())
+ .toList();
}
/**
@@ -321,6 +314,23 @@
}
/**
+ * Get the type arguments for the given [type], or `null` if the type has no
+ * type arguments.
+ *
+ * TODO(paulberry): consider adding an abstract getter to [DartType] to do
+ * this.
+ */
+ List<DartType> getTypeArguments(DartType type) {
+ if (type is InterfaceType) {
+ return type.typeArguments;
+ } else if (type is FunctionType) {
+ return type.typeArguments;
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Serialize the given [classElement], creating an [UnlinkedClass].
*/
UnlinkedClassBuilder serializeClass(ClassElement classElement) {
@@ -369,6 +379,43 @@
}
/**
+ * If [cls] is a class, return the list of its members available for
+ * constants - static constant fields, static methods and constructors.
+ * Otherwise return `null`.
+ */
+ List<UnlinkedPublicNameBuilder> serializeClassConstMembers(ClassElement cls) {
+ if (cls.kind == ElementKind.CLASS) {
+ List<UnlinkedPublicNameBuilder> bs = <UnlinkedPublicNameBuilder>[];
+ for (FieldElement field in cls.fields) {
+ if (field.isStatic && field.isConst && field.isPublic) {
+ bs.add(new UnlinkedPublicNameBuilder(
+ name: field.name,
+ kind: ReferenceKind.constField,
+ numTypeParameters: 0));
+ }
+ }
+ for (MethodElement method in cls.methods) {
+ if (method.isStatic && method.isPublic) {
+ bs.add(new UnlinkedPublicNameBuilder(
+ name: method.name,
+ kind: ReferenceKind.staticMethod,
+ numTypeParameters: method.typeParameters.length));
+ }
+ }
+ for (ConstructorElement constructor in cls.constructors) {
+ if (constructor.isConst && constructor.isPublic) {
+ bs.add(new UnlinkedPublicNameBuilder(
+ name: constructor.name,
+ kind: ReferenceKind.constructor,
+ numTypeParameters: 0));
+ }
+ }
+ return bs;
+ }
+ return null;
+ }
+
+ /**
* Serialize the given [combinator] into an [UnlinkedCombinator].
*/
UnlinkedCombinatorBuilder serializeCombinator(
@@ -383,20 +430,12 @@
}
/**
- * Return the index of the entry in the dependency table
- * ([PrelinkedLibrary.dependencies]) for the given [dependentLibrary]. A new
- * entry is added to the table if necessary to satisfy the request.
+ * Serialize the given [expression], creating an [UnlinkedConstBuilder].
*/
- int serializeDependency(LibraryElement dependentLibrary) {
- return dependencyMap.putIfAbsent(dependentLibrary, () {
- int index = dependencies.length;
- List<String> parts = dependentLibrary.parts
- .map((CompilationUnitElement e) => e.source.uri.toString())
- .toList();
- dependencies.add(encodePrelinkedDependency(
- uri: dependentLibrary.source.uri.toString(), parts: parts));
- return index;
- });
+ UnlinkedConstBuilder serializeConstExpr(Expression expression) {
+ _ConstExprSerializer serializer = new _ConstExprSerializer(this);
+ serializer.serialize(expression);
+ return serializer.toBuilder();
}
/**
@@ -409,20 +448,13 @@
if (element.documentationComment == null) {
return null;
}
- return encodeUnlinkedDocumentationComment(
+ return new UnlinkedDocumentationCommentBuilder(
text: element.documentationComment,
offset: element.docRange.offset,
length: element.docRange.length);
}
/**
- * Return the index of the entry in the references table
- * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references])
- * representing the pseudo-type `dynamic`.
- */
- int serializeDynamicReference() => 0;
-
- /**
* Serialize the given [enumElement], creating an [UnlinkedEnum].
*/
UnlinkedEnumBuilder serializeEnum(ClassElement enumElement) {
@@ -432,7 +464,7 @@
List<UnlinkedEnumValueBuilder> values = <UnlinkedEnumValueBuilder>[];
for (FieldElement field in enumElement.fields) {
if (field.isConst && field.type.element == enumElement) {
- values.add(encodeUnlinkedEnumValue(
+ values.add(new UnlinkedEnumValueBuilder(
name: field.name,
nameOffset: field.nameOffset,
documentationComment: serializeDocumentation(field)));
@@ -451,10 +483,14 @@
UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder();
b.name = executableElement.name;
b.nameOffset = executableElement.nameOffset;
- if (executableElement is! ConstructorElement &&
- !executableElement.type.returnType.isVoid) {
- b.returnType = serializeTypeRef(
- executableElement.type.returnType, executableElement);
+ if (executableElement is! ConstructorElement) {
+ if (!executableElement.hasImplicitReturnType) {
+ b.returnType = serializeTypeRef(
+ executableElement.type.returnType, executableElement);
+ } else if (!executableElement.isStatic) {
+ b.inferredReturnTypeSlot =
+ storeInferredType(executableElement.returnType, executableElement);
+ }
}
b.typeParameters =
executableElement.typeParameters.map(serializeTypeParam).toList();
@@ -476,7 +512,6 @@
b.isAbstract = executableElement.isAbstract;
b.isStatic = executableElement.isStatic &&
executableElement.enclosingElement is ClassElement;
- b.hasImplicitReturnType = executableElement.hasImplicitReturnType;
b.isExternal = executableElement.isExternal;
b.documentationComment = serializeDocumentation(executableElement);
return b;
@@ -507,12 +542,11 @@
/**
* Serialize the given [importElement] yielding an [UnlinkedImportBuilder].
- * Also, add pre-linked information about it to the [prelinkedImports] list.
+ * Also, add linked information about it to the [linkedImports] list.
*/
UnlinkedImportBuilder serializeImport(ImportElement importElement) {
UnlinkedImportBuilder b = new UnlinkedImportBuilder();
b.isDeferred = importElement.isDeferred;
- b.offset = importElement.nameOffset;
b.combinators = importElement.combinators.map(serializeCombinator).toList();
if (importElement.prefix != null) {
b.prefixReference = serializePrefix(importElement.prefix);
@@ -521,36 +555,15 @@
if (importElement.isSynthetic) {
b.isImplicit = true;
} else {
+ b.offset = importElement.nameOffset;
b.uri = importElement.uri;
b.uriOffset = importElement.uriOffset;
b.uriEnd = importElement.uriEnd;
}
- addTransitiveExportClosure(importElement.importedLibrary);
- prelinkedImports.add(serializeDependency(importElement.importedLibrary));
return b;
}
/**
- * Serialize the whole library element into a [PrelinkedLibrary]. Should be
- * called exactly once for each instance of [_LibrarySerializer].
- *
- * The unlinked compilation units are stored in [unlinkedUnits], and their
- * absolute URIs are stored in [unitUris].
- */
- PrelinkedLibraryBuilder serializeLibrary() {
- computePrefixMap();
- PrelinkedLibraryBuilder pb = new PrelinkedLibraryBuilder();
- addCompilationUnitElements(libraryElement.definingCompilationUnit, 0);
- for (int i = 0; i < libraryElement.parts.length; i++) {
- addCompilationUnitElements(libraryElement.parts[i], i + 1);
- }
- pb.units = prelinkedUnits;
- pb.dependencies = dependencies;
- pb.importDependencies = prelinkedImports;
- return pb;
- }
-
- /**
* Serialize the given [parameter] into an [UnlinkedParam].
*/
UnlinkedParamBuilder serializeParam(ParameterElement parameter,
@@ -572,17 +585,24 @@
}
b.isInitializingFormal = parameter.isInitializingFormal;
DartType type = parameter.type;
- if (type is FunctionType) {
- b.isFunctionTyped = true;
- if (!type.returnType.isVoid) {
- b.type = serializeTypeRef(type.returnType, parameter);
+ if (parameter.hasImplicitType) {
+ Element contextParent = context.enclosingElement;
+ if (!parameter.isInitializingFormal &&
+ contextParent is ExecutableElement &&
+ !contextParent.isStatic &&
+ contextParent is! ConstructorElement) {
+ b.inferredTypeSlot = storeInferredType(type, context);
}
- b.parameters = type.parameters
- .map((parameter) => serializeParam(parameter, context))
- .toList();
} else {
- b.type = serializeTypeRef(type, context);
- b.hasImplicitType = parameter.hasImplicitType;
+ if (type is FunctionType) {
+ b.isFunctionTyped = true;
+ b.type = serializeTypeRef(type.returnType, parameter);
+ b.parameters = type.parameters
+ .map((parameter) => serializeParam(parameter, context))
+ .toList();
+ } else {
+ b.type = serializeTypeRef(type, context);
+ }
}
return b;
}
@@ -592,16 +612,36 @@
*/
int serializePrefix(PrefixElement element) {
return referenceMap.putIfAbsent(element, () {
- assert(unlinkedReferences.length == prelinkedReferences.length);
+ assert(unlinkedReferences.length == linkedReferences.length);
int index = unlinkedReferences.length;
- unlinkedReferences.add(encodeUnlinkedReference(name: element.name));
- prelinkedReferences
- .add(encodePrelinkedReference(kind: PrelinkedReferenceKind.prefix));
+ unlinkedReferences.add(new UnlinkedReferenceBuilder(name: element.name));
+ linkedReferences
+ .add(new LinkedReferenceBuilder(kind: ReferenceKind.prefix));
return index;
});
}
/**
+ * Compute the reference index which should be stored in a [EntityRef].
+ *
+ * If [linked] is true, and a new reference has to be created, the reference
+ * will only be stored in [linkedReferences].
+ */
+ int serializeReferenceForType(DartType type, bool linked) {
+ Element element = type.element;
+ LibraryElement dependentLibrary = element?.library;
+ if (dependentLibrary == null) {
+ assert(type.isDynamic || type.isVoid);
+ if (type is UndefinedTypeImpl) {
+ return serializeUnresolvedReference();
+ }
+ // Note: for a type which is truly `dynamic` or `void`, fall through to
+ // use [_getElementReferenceId].
+ }
+ return _getElementReferenceId(element, linked: linked);
+ }
+
+ /**
* Serialize the given [typedefElement], creating an [UnlinkedTypedef].
*/
UnlinkedTypedefBuilder serializeTypedef(
@@ -611,10 +651,7 @@
b.nameOffset = typedefElement.nameOffset;
b.typeParameters =
typedefElement.typeParameters.map(serializeTypeParam).toList();
- if (!typedefElement.returnType.isVoid) {
- b.returnType =
- serializeTypeRef(typedefElement.returnType, typedefElement);
- }
+ b.returnType = serializeTypeRef(typedefElement.returnType, typedefElement);
b.parameters = typedefElement.parameters.map(serializeParam).toList();
b.documentationComment = serializeDocumentation(typedefElement);
return b;
@@ -635,67 +672,37 @@
}
/**
- * Serialize the given [type] into an [UnlinkedTypeRef].
+ * Serialize the given [type] into a [EntityRef]. If [slot] is provided,
+ * it should be included in the [EntityRef]. If [linked] is true, any
+ * references that are created will be populated into [linkedReferences] but
+ * [not [unlinkedReferences].
+ *
+ * [context] is the element within which the [EntityRef] will be
+ * interpreted; this is used to serialize type parameters.
*/
- UnlinkedTypeRefBuilder serializeTypeRef(DartType type, Element context) {
- UnlinkedTypeRefBuilder b = new UnlinkedTypeRefBuilder();
+ EntityRefBuilder serializeTypeRef(DartType type, Element context,
+ {bool linked: false, int slot}) {
+ EntityRefBuilder b = new EntityRefBuilder(slot: slot);
if (type is TypeParameterType) {
b.paramReference = findTypeParameterIndex(type, context);
} else {
- Element element = type.element;
- LibraryElement dependentLibrary = element.library;
- if (dependentLibrary == null) {
- assert(type.isDynamic);
- if (type is UndefinedTypeImpl) {
- b.reference = serializeUnresolvedReference();
- } else {
- b.reference = serializeDynamicReference();
+ b.reference = serializeReferenceForType(type, linked);
+ List<DartType> typeArguments = getTypeArguments(type);
+ if (typeArguments != null) {
+ // Trailing type arguments of type 'dynamic' should be omitted.
+ int numArgsToSerialize = typeArguments.length;
+ while (numArgsToSerialize > 0 &&
+ typeArguments[numArgsToSerialize - 1].isDynamic) {
+ --numArgsToSerialize;
}
- } else {
- b.reference = referenceMap.putIfAbsent(element, () {
- assert(unlinkedReferences.length == prelinkedReferences.length);
- CompilationUnitElement unitElement =
- element.getAncestor((Element e) => e is CompilationUnitElement);
- int unit = dependentLibrary.units.indexOf(unitElement);
- assert(unit != -1);
- int numTypeParameters = 0;
- if (element is TypeParameterizedElement) {
- numTypeParameters = element.typeParameters.length;
+ if (numArgsToSerialize > 0) {
+ List<EntityRefBuilder> serializedArguments = <EntityRefBuilder>[];
+ for (int i = 0; i < numArgsToSerialize; i++) {
+ serializedArguments.add(
+ serializeTypeRef(typeArguments[i], context, linked: linked));
}
- // Figure out a prefix that may be used to refer to the given type.
- // TODO(paulberry): to avoid subtle relinking inconsistencies we
- // should use the actual prefix from the AST (a given type may be
- // reachable via multiple prefixes), but sadly, this information is
- // not recorded in the element model.
- int prefixReference = 0;
- PrefixElement prefix = prefixMap[element];
- if (prefix != null) {
- prefixReference = serializePrefix(prefix);
- }
- int index = unlinkedReferences.length;
- unlinkedReferences.add(encodeUnlinkedReference(
- name: element.name, prefixReference: prefixReference));
- prelinkedReferences.add(encodePrelinkedReference(
- dependency: serializeDependency(dependentLibrary),
- kind: element is FunctionTypeAliasElement
- ? PrelinkedReferenceKind.typedef
- : PrelinkedReferenceKind.classOrEnum,
- unit: unit,
- numTypeParameters: numTypeParameters));
- return index;
- });
- }
- List<DartType> typeArguments;
- if (type is InterfaceType) {
- typeArguments = type.typeArguments;
- } else if (type is FunctionType) {
- typeArguments = type.typeArguments;
- }
- if (typeArguments != null &&
- typeArguments.any((DartType argument) => !argument.isDynamic)) {
- b.typeArguments = typeArguments
- .map((DartType t) => serializeTypeRef(t, context))
- .toList();
+ b.typeArguments = serializedArguments;
+ }
}
}
return b;
@@ -703,7 +710,7 @@
/**
* Return the index of the entry in the references table
- * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references]) used for
+ * ([UnlinkedLibrary.references] and [LinkedLibrary.references]) used for
* unresolved references. A new entry is added to the table if necessary to
* satisfy the request.
*/
@@ -713,11 +720,12 @@
// the element model. For the moment we use a name that can't possibly
// ever exist.
if (unresolvedReferenceIndex == null) {
- assert(unlinkedReferences.length == prelinkedReferences.length);
+ assert(unlinkedReferences.length == linkedReferences.length);
unresolvedReferenceIndex = unlinkedReferences.length;
- unlinkedReferences.add(encodeUnlinkedReference(name: '*unresolved*'));
- prelinkedReferences.add(
- encodePrelinkedReference(kind: PrelinkedReferenceKind.unresolved));
+ unlinkedReferences
+ .add(new UnlinkedReferenceBuilder(name: '*unresolved*'));
+ linkedReferences
+ .add(new LinkedReferenceBuilder(kind: ReferenceKind.unresolved));
}
return unresolvedReferenceIndex;
}
@@ -729,12 +737,390 @@
UnlinkedVariableBuilder b = new UnlinkedVariableBuilder();
b.name = variable.name;
b.nameOffset = variable.nameOffset;
- b.type = serializeTypeRef(variable.type, variable);
+ if (!variable.hasImplicitType) {
+ b.type = serializeTypeRef(variable.type, variable);
+ }
b.isStatic = variable.isStatic && variable.enclosingElement is ClassElement;
b.isFinal = variable.isFinal;
b.isConst = variable.isConst;
- b.hasImplicitType = variable.hasImplicitType;
b.documentationComment = serializeDocumentation(variable);
+ if (variable.isConst && variable is ConstVariableElement) {
+ ConstVariableElement constVariable = variable as ConstVariableElement;
+ Expression initializer = constVariable.constantInitializer;
+ if (initializer != null) {
+ b.constExpr = serializeConstExpr(initializer);
+ }
+ }
+ if (b.isFinal || b.isConst) {
+ b.propagatedTypeSlot = storeLinkedType(variable.propagatedType, variable);
+ } else {
+ // Variable is not propagable.
+ assert(variable.propagatedType == null);
+ }
+ if (variable.hasImplicitType &&
+ (variable.initializer != null || !variable.isStatic)) {
+ b.inferredTypeSlot = storeInferredType(variable.type, variable);
+ }
return b;
}
+
+ /**
+ * Create a slot id for the given [type] (which is an inferred type). If
+ * strong mode is enabled and [type] is not `dynamic`, it is stored in
+ * [linkedTypes] so that once the compilation unit has been fully visited, it
+ * will be serialized into [LinkedUnit.types].
+ *
+ * [context] is the element within which the slot id will appear; this is
+ * used to serialize type parameters.
+ */
+ int storeInferredType(DartType type, Element context) {
+ return storeLinkedType(
+ librarySerializer.strongMode && !type.isDynamic ? type : null, context);
+ }
+
+ /**
+ * Create a slot id for the given [type] (which may be either a propagated
+ * type or an inferred type). If [type] is not `null`, it is stored in
+ * [linkedTypes] so that once the compilation unit has been fully visited,
+ * it will be serialized to [LinkedUnit.types].
+ *
+ * [context] is the element within which the slot id will appear; this is
+ * used to serialize type parameters.
+ */
+ int storeLinkedType(DartType type, Element context) {
+ int slot = ++numSlots;
+ if (type != null) {
+ deferredLinkedTypes
+ .add(() => serializeTypeRef(type, context, linked: true, slot: slot));
+ }
+ return slot;
+ }
+
+ int _getElementReferenceId(Element element, {bool linked: false}) {
+ return referenceMap.putIfAbsent(element, () {
+ if (element is ConstructorElement && element.displayName.isEmpty) {
+ return _getElementReferenceId(element.enclosingElement, linked: linked);
+ }
+ if (element is MethodElement && !element.isStatic) {
+ throw new StateError('Only static methods can be serialized.');
+ }
+ if (element is PropertyAccessorElement) {
+ Element enclosing = element.enclosingElement;
+ if (!(enclosing is CompilationUnitElement || element.isStatic)) {
+ throw new StateError(
+ 'Only top-level or static property accessors can be serialized.');
+ }
+ }
+ LibraryElement dependentLibrary = element?.library;
+ int unit;
+ if (dependentLibrary == null) {
+ assert(element == librarySerializer.typeProvider.dynamicType.element ||
+ element == null);
+ unit = 0;
+ dependentLibrary = librarySerializer.libraryElement;
+ } else {
+ CompilationUnitElement unitElement =
+ element.getAncestor((Element e) => e is CompilationUnitElement);
+ unit = dependentLibrary.units.indexOf(unitElement);
+ assert(unit != -1);
+ }
+ int numTypeParameters = 0;
+ if (element is TypeParameterizedElement) {
+ numTypeParameters = element.typeParameters.length;
+ }
+ LinkedReferenceBuilder linkedReference = new LinkedReferenceBuilder(
+ dependency: librarySerializer.serializeDependency(dependentLibrary),
+ kind: _getReferenceKind(element),
+ unit: unit,
+ numTypeParameters: numTypeParameters);
+ String name = element == null ? 'void' : element.name;
+ if (linked) {
+ linkedReference.name = name;
+ } else {
+ assert(unlinkedReferences.length == linkedReferences.length);
+ int prefixReference = 0;
+ Element enclosing = element?.enclosingElement;
+ if (enclosing == null || enclosing is CompilationUnitElement) {
+ // Figure out a prefix that may be used to refer to the given element.
+ // TODO(paulberry): to avoid subtle relinking inconsistencies we
+ // should use the actual prefix from the AST (a given type may be
+ // reachable via multiple prefixes), but sadly, this information is
+ // not recorded in the element model.
+ PrefixElement prefix = librarySerializer.prefixMap[element];
+ if (prefix != null) {
+ prefixReference = serializePrefix(prefix);
+ }
+ } else {
+ prefixReference = _getElementReferenceId(enclosing, linked: linked);
+ }
+ unlinkedReferences.add(new UnlinkedReferenceBuilder(
+ name: name, prefixReference: prefixReference));
+ }
+ int index = linkedReferences.length;
+ linkedReferences.add(linkedReference);
+ return index;
+ });
+ }
+
+ int _getLengthPropertyReference(int prefix) {
+ assert(unlinkedReferences.length == linkedReferences.length);
+ int index = linkedReferences.length;
+ unlinkedReferences.add(
+ new UnlinkedReferenceBuilder(name: 'length', prefixReference: prefix));
+ LinkedReferenceBuilder linkedReference =
+ new LinkedReferenceBuilder(kind: ReferenceKind.length);
+ linkedReferences.add(linkedReference);
+ return index;
+ }
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single constant [Expression].
+ */
+class _ConstExprSerializer extends AbstractConstExprSerializer {
+ final _CompilationUnitSerializer serializer;
+
+ _ConstExprSerializer(this.serializer);
+
+ @override
+ EntityRefBuilder serializeConstructorName(ConstructorName constructor) {
+ ConstructorElement element = constructor.staticElement;
+ assert(element != null);
+ int referenceId = serializer._getElementReferenceId(element);
+ return new EntityRefBuilder(reference: referenceId);
+ }
+
+ EntityRefBuilder serializeIdentifier(Identifier identifier) {
+ Element element = identifier.staticElement;
+ assert(element != null);
+ // The only supported instance property accessor - `length`.
+ if (identifier is PrefixedIdentifier &&
+ element is PropertyAccessorElement &&
+ !element.isStatic) {
+ assert(element.name == 'length');
+ Element prefixElement = identifier.prefix.staticElement;
+ int prefixRef = serializer._getElementReferenceId(prefixElement);
+ int lengthRef = serializer._getLengthPropertyReference(prefixRef);
+ return new EntityRefBuilder(reference: lengthRef);
+ }
+ return new EntityRefBuilder(
+ reference: serializer._getElementReferenceId(element));
+ }
+
+ @override
+ EntityRefBuilder serializePropertyAccess(PropertyAccess access) {
+ Element element = access.propertyName.staticElement;
+ assert(element != null);
+ // The only supported instance property accessor - `length`.
+ Expression target = access.target;
+ if (target is Identifier &&
+ element is PropertyAccessorElement &&
+ !element.isStatic) {
+ assert(element.name == 'length');
+ Element prefixElement = target.staticElement;
+ int prefixRef = serializer._getElementReferenceId(prefixElement);
+ int lengthRef = serializer._getLengthPropertyReference(prefixRef);
+ return new EntityRefBuilder(reference: lengthRef);
+ }
+ return new EntityRefBuilder(
+ reference: serializer._getElementReferenceId(element));
+ }
+
+ @override
+ EntityRefBuilder serializeType(TypeName typeName) {
+ DartType type = typeName != null ? typeName.type : DynamicTypeImpl.instance;
+ return serializer.serializeTypeRef(type, null);
+ }
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single library.
+ */
+class _LibrarySerializer {
+ /**
+ * The library to be serialized.
+ */
+ final LibraryElement libraryElement;
+
+ /**
+ * The type provider. This is used to locate the library for `dart:core`.
+ */
+ final TypeProvider typeProvider;
+
+ /**
+ * Indicates whether the element model being serialized was analyzed using
+ * strong mode.
+ */
+ final bool strongMode;
+
+ /**
+ * Map from [LibraryElement] to the index of the entry in the "dependency
+ * table" that refers to it.
+ */
+ final Map<LibraryElement, int> dependencyMap = <LibraryElement, int>{};
+
+ /**
+ * The "dependency table". This is the list of objects which should be
+ * written to [LinkedLibrary.dependencies].
+ */
+ final List<LinkedDependencyBuilder> dependencies =
+ <LinkedDependencyBuilder>[];
+
+ /**
+ * The linked portion of the "imports table". This is the list of ints
+ * which should be written to [LinkedLibrary.imports].
+ */
+ final List<int> linkedImports = <int>[];
+
+ /**
+ * Set of libraries which have been seen so far while visiting the transitive
+ * closure of exports.
+ */
+ final Set<LibraryElement> librariesAddedToTransitiveExportClosure =
+ new Set<LibraryElement>();
+
+ /**
+ * Map from imported element to the prefix which may be used to refer to that
+ * element; elements for which no prefix is needed are absent from this map.
+ */
+ final Map<Element, PrefixElement> prefixMap = <Element, PrefixElement>{};
+
+ /**
+ * List of serializers for the compilation units constituting this library.
+ */
+ final List<_CompilationUnitSerializer> compilationUnitSerializers =
+ <_CompilationUnitSerializer>[];
+
+ _LibrarySerializer(this.libraryElement, this.typeProvider, this.strongMode) {
+ dependencies.add(new LinkedDependencyBuilder());
+ dependencyMap[libraryElement] = 0;
+ }
+
+ /**
+ * Retrieve a list of the URIs for the compilation units in the library.
+ */
+ List<String> get unitUris => compilationUnitSerializers
+ .map((_CompilationUnitSerializer s) => s.unitUri)
+ .toList();
+
+ /**
+ * Retrieve a list of the [UnlinkedUnitBuilder]s for the compilation units in
+ * the library.
+ */
+ List<UnlinkedUnitBuilder> get unlinkedUnits => compilationUnitSerializers
+ .map((_CompilationUnitSerializer s) => s.unlinkedUnit)
+ .toList();
+
+ /**
+ * Add [exportedLibrary] (and the transitive closure of all libraries it
+ * exports) to the dependency table ([LinkedLibrary.dependencies]).
+ */
+ void addTransitiveExportClosure(LibraryElement exportedLibrary) {
+ if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) {
+ serializeDependency(exportedLibrary);
+ for (LibraryElement transitiveExport
+ in exportedLibrary.exportedLibraries) {
+ addTransitiveExportClosure(transitiveExport);
+ }
+ }
+ }
+
+ /**
+ * Fill in [prefixMap] using information from [libraryElement.imports].
+ */
+ void computePrefixMap() {
+ for (ImportElement import in libraryElement.imports) {
+ if (import.prefix == null) {
+ continue;
+ }
+ import.importedLibrary.exportNamespace.definedNames
+ .forEach((String name, Element e) {
+ if (new NameFilter.forNamespaceCombinators(import.combinators)
+ .accepts(name)) {
+ prefixMap[e] = import.prefix;
+ }
+ });
+ }
+ }
+
+ /**
+ * Return the index of the entry in the dependency table
+ * ([LinkedLibrary.dependencies]) for the given [dependentLibrary]. A new
+ * entry is added to the table if necessary to satisfy the request.
+ */
+ int serializeDependency(LibraryElement dependentLibrary) {
+ return dependencyMap.putIfAbsent(dependentLibrary, () {
+ int index = dependencies.length;
+ List<String> parts = dependentLibrary.parts
+ .map((CompilationUnitElement e) => e.source.uri.toString())
+ .toList();
+ dependencies.add(new LinkedDependencyBuilder(
+ uri: dependentLibrary.source.uri.toString(), parts: parts));
+ return index;
+ });
+ }
+
+ /**
+ * Serialize the whole library element into a [LinkedLibrary]. Should be
+ * called exactly once for each instance of [_LibrarySerializer].
+ *
+ * The unlinked compilation units are stored in [unlinkedUnits], and their
+ * absolute URIs are stored in [unitUris].
+ */
+ LinkedLibraryBuilder serializeLibrary() {
+ computePrefixMap();
+ LinkedLibraryBuilder pb = new LinkedLibraryBuilder();
+ for (ExportElement exportElement in libraryElement.exports) {
+ addTransitiveExportClosure(exportElement.exportedLibrary);
+ }
+ for (ImportElement importElement in libraryElement.imports) {
+ addTransitiveExportClosure(importElement.importedLibrary);
+ linkedImports.add(serializeDependency(importElement.importedLibrary));
+ }
+ compilationUnitSerializers.add(new _CompilationUnitSerializer(
+ this, libraryElement.definingCompilationUnit, 0));
+ for (int i = 0; i < libraryElement.parts.length; i++) {
+ compilationUnitSerializers.add(
+ new _CompilationUnitSerializer(this, libraryElement.parts[i], i + 1));
+ }
+ for (_CompilationUnitSerializer compilationUnitSerializer
+ in compilationUnitSerializers) {
+ compilationUnitSerializer.addCompilationUnitElements();
+ }
+ pb.units = compilationUnitSerializers
+ .map((_CompilationUnitSerializer s) => s.linkedUnit)
+ .toList();
+ pb.dependencies = dependencies;
+ pb.numPrelinkedDependencies = dependencies.length;
+ for (_CompilationUnitSerializer compilationUnitSerializer
+ in compilationUnitSerializers) {
+ compilationUnitSerializer.createLinkedTypes();
+ }
+ pb.importDependencies = linkedImports;
+ List<String> exportedNames =
+ libraryElement.exportNamespace.definedNames.keys.toList();
+ exportedNames.sort();
+ List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[];
+ for (String name in exportedNames) {
+ if (libraryElement.publicNamespace.definedNames.containsKey(name)) {
+ continue;
+ }
+ Element element = libraryElement.exportNamespace.get(name);
+ LibraryElement dependentLibrary = element.library;
+ CompilationUnitElement unitElement =
+ element.getAncestor((Element e) => e is CompilationUnitElement);
+ int unit = dependentLibrary.units.indexOf(unitElement);
+ assert(unit != -1);
+ ReferenceKind kind = _getReferenceKind(element);
+ exportNames.add(new LinkedExportNameBuilder(
+ name: name,
+ dependency: serializeDependency(dependentLibrary),
+ unit: unit,
+ kind: kind));
+ }
+ pb.exportNames = exportNames;
+ return pb;
+ }
}
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 4d9b9fe..95c33f4 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -10,12 +10,15 @@
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart' show Source, SourceKind;
+import 'package:analyzer/src/generated/source.dart'
+ show DartUriResolver, Source, SourceFactory, SourceKind;
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
import 'package:analyzer/src/task/dart.dart'
show
+ CONSTANT_VALUE,
LIBRARY_ELEMENT1,
LIBRARY_ELEMENT2,
LIBRARY_ELEMENT3,
@@ -32,32 +35,40 @@
import 'package:analyzer/task/model.dart'
show AnalysisTarget, ResultDescriptor, TargetedResult;
-/**
- * An [SdkAnalysisContext] for Dart SDK with a summary [SdkBundle].
- */
-class SummarySdkAnalysisContext extends SdkAnalysisContext {
+class SdkSummaryResultProvider implements SummaryResultProvider {
+ final InternalAnalysisContext context;
final SdkBundle bundle;
final SummaryTypeProvider typeProvider = new SummaryTypeProvider();
+ @override
SummaryResynthesizer resynthesizer;
- SummarySdkAnalysisContext(this.bundle);
+ SdkSummaryResultProvider(this.context, this.bundle) {
+ resynthesizer = new SdkSummaryResynthesizer(
+ context, typeProvider, context.sourceFactory, bundle);
+ _buildCoreLibrary();
+ _buildAsyncLibrary();
+ resynthesizer.finalizeCoreAsyncLibraries();
+ context.typeProvider = typeProvider;
+ }
@override
- bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result) {
- if (resynthesizer == null) {
- resynthesizer = new SummaryResynthesizer(this, typeProvider,
- _getPrelinkedSummary, _getUnlinkedSummary, sourceFactory);
- _buildCoreLibrary();
- _buildAsyncLibrary();
- }
+ bool compute(CacheEntry entry, ResultDescriptor result) {
if (result == TYPE_PROVIDER) {
+// print('SummarySdkAnalysisContext: $result');
entry.setValue(result, typeProvider, TargetedResult.EMPTY_LIST);
return true;
}
AnalysisTarget target = entry.target;
-// print('SummarySdkAnalysisContext: $result of $target');
+ // TODO(scheglov) we don't actually update "evaluationResult" yet
+ if (result == CONSTANT_VALUE) {
+ if (target.source != null && target.source.isInSystemLibrary) {
+ entry.setValue(result, target, TargetedResult.EMPTY_LIST);
+ return true;
+ }
+ }
if (target is Source && target.isInSystemLibrary) {
+// print('SummarySdkAnalysisContext: $result of $target');
if (result == LIBRARY_ELEMENT1 ||
result == LIBRARY_ELEMENT2 ||
result == LIBRARY_ELEMENT3 ||
@@ -80,12 +91,9 @@
return true;
} else if (result == SOURCE_KIND) {
String uri = target.uri.toString();
- if (bundle.prelinkedLibraryUris.contains(uri)) {
- entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
- return true;
- }
- if (bundle.unlinkedUnitUris.contains(uri)) {
- entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST);
+ SourceKind kind = _getSourceKind(uri);
+ if (kind != null) {
+ entry.setValue(result, kind, TargetedResult.EMPTY_LIST);
return true;
}
return false;
@@ -106,23 +114,65 @@
typeProvider.initializeCore(library);
}
- PrelinkedLibrary _getPrelinkedSummary(String uri) {
- for (int i = 0; i < bundle.prelinkedLibraryUris.length; i++) {
- if (bundle.prelinkedLibraryUris[i] == uri) {
- return bundle.prelinkedLibraries[i];
- }
+ /**
+ * Return the [SourceKind] of the given [uri] or `null` if it is unknown.
+ */
+ SourceKind _getSourceKind(String uri) {
+ if (bundle.linkedLibraryUris.contains(uri)) {
+ return SourceKind.LIBRARY;
}
- throw new StateError('Unable to find prelinked summary for $uri');
+ if (bundle.unlinkedUnitUris.contains(uri)) {
+ return SourceKind.PART;
+ }
+ return null;
+ }
+}
+
+/**
+ * The implementation of [SummaryResynthesizer] for Dart SDK.
+ */
+class SdkSummaryResynthesizer extends SummaryResynthesizer {
+ final SdkBundle bundle;
+ final Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{};
+ final Map<String, LinkedLibrary> linkedSummaries = <String, LinkedLibrary>{};
+
+ SdkSummaryResynthesizer(AnalysisContext context, TypeProvider typeProvider,
+ SourceFactory sourceFactory, this.bundle)
+ : super(null, context, typeProvider, sourceFactory, false) {
+ // TODO(paulberry): we always resynthesize the summary in weak mode. Is
+ // this ok?
+ for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
+ unlinkedSummaries[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
+ }
+ for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
+ linkedSummaries[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
+ }
}
- UnlinkedUnit _getUnlinkedSummary(String uri) {
- for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
- if (bundle.unlinkedUnitUris[i] == uri) {
- return bundle.unlinkedUnits[i];
- }
- }
- throw new StateError('Unable to find unlinked summary for $uri');
+ @override
+ LinkedLibrary getLinkedSummary(String uri) {
+ return linkedSummaries[uri];
}
+
+ @override
+ UnlinkedUnit getUnlinkedSummary(String uri) {
+ return unlinkedSummaries[uri];
+ }
+
+ @override
+ bool hasLibrarySummary(String uri) {
+ return uri.startsWith('dart:');
+ }
+}
+
+/**
+ * Provider for analysis results.
+ */
+abstract class SummaryResultProvider extends ResultProvider {
+ /**
+ * The [SummaryResynthesizer] of this context, maybe `null`.
+ */
+ SummaryResynthesizer get resynthesizer;
}
/**
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index df4e7ac..2c99cd2 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -6,11 +6,14 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -1226,10 +1229,24 @@
TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
//
+ // Build the enum members if they have not already been created.
+ //
+ EnumDeclaration findFirstEnum() {
+ for (CompilationUnitMember member in unit.declarations) {
+ if (member is EnumDeclaration) {
+ return member;
+ }
+ }
+ return null;
+ }
+ EnumDeclaration firstEnum = findFirstEnum();
+ if (firstEnum != null && firstEnum.element.accessors.isEmpty) {
+ EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider);
+ unit.accept(builder);
+ }
+ //
// Record outputs.
//
- EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider);
- unit.accept(builder);
outputs[CREATED_RESOLVED_UNIT2] = true;
outputs[RESOLVED_UNIT2] = unit;
}
@@ -1395,7 +1412,6 @@
//
// Update "part" directives.
//
- LibraryDirective libraryDirective = null;
LibraryIdentifier libraryNameNode = null;
String partsLibraryName = _UNKNOWN_LIBRARY_NAME;
bool hasPartDirective = false;
@@ -1406,11 +1422,8 @@
<CompilationUnitElementImpl>[];
for (Directive directive in definingCompilationUnit.directives) {
if (directive is LibraryDirective) {
- if (libraryDirective == null) {
- libraryDirective = directive;
- libraryNameNode = directive.name;
- directivesToResolve.add(directive);
- }
+ libraryNameNode = directive.name;
+ directivesToResolve.add(directive);
} else if (directive is PartDirective) {
PartDirective partDirective = directive;
StringLiteral partUri = partDirective.uri;
@@ -1488,12 +1501,13 @@
for (Directive directive in directivesToResolve) {
directive.element = libraryElement;
}
- if (sourcedCompilationUnits.isNotEmpty) {
- _patchTopLevelAccessors(libraryElement);
+ BuildLibraryElementUtils.patchTopLevelAccessors(libraryElement);
+ // set the library documentation to the docs associated with the first
+ // directive in the compilation unit.
+ if (definingCompilationUnit.directives.isNotEmpty) {
+ _setDoc(libraryElement, definingCompilationUnit.directives.first);
}
- if (libraryDirective != null) {
- _setDoc(libraryElement, libraryDirective);
- }
+
//
// Record outputs.
//
@@ -1503,25 +1517,6 @@
}
/**
- * Add all of the non-synthetic [getters] and [setters] defined in the given
- * [unit] that have no corresponding accessor to one of the given collections.
- */
- void _collectAccessors(Map<String, PropertyAccessorElement> getters,
- List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
- for (PropertyAccessorElement accessor in unit.accessors) {
- if (accessor.isGetter) {
- if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
- getters[accessor.displayName] = accessor;
- }
- } else {
- if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
- setters.add(accessor);
- }
- }
- }
- }
-
- /**
* Return the top-level [FunctionElement] entry point, or `null` if the given
* [element] does not define an entry point.
*/
@@ -1553,33 +1548,6 @@
}
/**
- * Look through all of the compilation units defined for the given [library],
- * looking for getters and setters that are defined in different compilation
- * units but that have the same names. If any are found, make sure that they
- * have the same variable element.
- */
- void _patchTopLevelAccessors(LibraryElementImpl library) {
- HashMap<String, PropertyAccessorElement> getters =
- new HashMap<String, PropertyAccessorElement>();
- List<PropertyAccessorElement> setters = <PropertyAccessorElement>[];
- _collectAccessors(getters, setters, library.definingCompilationUnit);
- for (CompilationUnitElement unit in library.parts) {
- _collectAccessors(getters, setters, unit);
- }
- for (PropertyAccessorElement setter in setters) {
- PropertyAccessorElement getter = getters[setter.displayName];
- if (getter != null) {
- TopLevelVariableElementImpl variable = getter.variable;
- TopLevelVariableElementImpl setterVariable = setter.variable;
- CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement;
- setterUnit.replaceTopLevelVariable(setterVariable, variable);
- variable.setter = setter;
- (setter as PropertyAccessorElementImpl).variable = variable;
- }
- }
- }
-
- /**
* If the given [node] has a documentation comment, remember its content
* and range into the given [element].
*/
@@ -1765,6 +1733,11 @@
//
// Record outputs.
//
+ if (!context.analysisOptions.enableAsync) {
+ AnalysisContextImpl contextImpl = context;
+ asyncLibrary = contextImpl.createMockAsyncLib(coreLibrary);
+ asyncNamespace = asyncLibrary.publicNamespace;
+ }
TypeProvider typeProvider =
new TypeProviderImpl.forNamespaces(coreNamespace, asyncNamespace);
(context as InternalAnalysisContext).typeProvider = typeProvider;
@@ -3257,14 +3230,7 @@
if (newType == null || newType.isBottom) {
newType = typeProvider.dynamicType;
}
- variable.type = newType;
- (variable.initializer as ExecutableElementImpl).returnType = newType;
- if (variable is PropertyInducingElementImpl) {
- setReturnType(variable.getter, newType);
- if (!variable.isFinal && !variable.isConst) {
- setParameterType(variable.setter, newType);
- }
- }
+ setFieldType(variable, newType);
} else {
// TODO(brianwilkerson) For now we simply don't infer any type for
// variables or fields involved in a cycle. We could try to be smarter
@@ -3591,6 +3557,16 @@
HashSet<Source> importedSourceSet =
new HashSet.from(explicitlyImportedSourceSet);
Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE);
+ if (coreLibrarySource == null) {
+ String message;
+ DartSdk sdk = context.sourceFactory.dartSdk;
+ if (sdk == null) {
+ message = 'Could not resolve "dart:core": SDK not defined';
+ } else {
+ message = 'Could not resolve "dart:core": SDK incorrectly configured';
+ }
+ throw new AnalysisException(message);
+ }
importedSourceSet.add(coreLibrarySource);
//
// Compute kind.
@@ -5087,7 +5063,8 @@
'ScanDartTask',
createTask,
buildInputs,
- <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM]);
+ <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM],
+ suitabilityFor: suitabilityFor);
/**
* Initialize a newly created task to access the content of the source
@@ -5183,6 +5160,21 @@
AnalysisContext context, AnalysisTarget target) {
return new ScanDartTask(context, target);
}
+
+ /**
+ * Return an indication of how suitable this task is for the given [target].
+ */
+ static TaskSuitability suitabilityFor(AnalysisTarget target) {
+ if (target is Source) {
+ if (target.shortName.endsWith(AnalysisEngine.SUFFIX_DART)) {
+ return TaskSuitability.HIGHEST;
+ }
+ return TaskSuitability.LOWEST;
+ } else if (target is DartScript) {
+ return TaskSuitability.HIGHEST;
+ }
+ return TaskSuitability.NONE;
+ }
}
/**
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index db9cd1d..0f3b523 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -154,7 +154,7 @@
/**
* Create a work order that will produce the given [result] for the given
* [target]. Return the work order that was created, or `null` if the result
- * has already been computed.
+ * has either already been computed or cannot be computed.
*/
WorkOrder createWorkOrderForResult(
AnalysisTarget target, ResultDescriptor result) {
@@ -166,6 +166,9 @@
return null;
}
TaskDescriptor taskDescriptor = taskManager.findTask(target, result);
+ if (taskDescriptor == null) {
+ return null;
+ }
try {
WorkItem workItem =
new WorkItem(context, target, taskDescriptor, result, 0, null);
@@ -709,11 +712,22 @@
try {
TaskDescriptor descriptor =
taskManager.findTask(inputTarget, inputResult);
+ if (descriptor == null) {
+ throw new AnalysisException(
+ 'Cannot find task to build $inputResult for $inputTarget');
+ }
return new WorkItem(context, inputTarget, descriptor, inputResult,
level + 1, workOrder);
} on AnalysisException catch (exception, stackTrace) {
this.exception = new CaughtException(exception, stackTrace);
return null;
+ } catch (exception, stackTrace) {
+ this.exception = new CaughtException(
+ throw new AnalysisException(
+ 'Cannot create work order to build $inputResult for $inputTarget',
+ exception),
+ stackTrace);
+ return null;
}
}
} else {
diff --git a/pkg/analyzer/lib/src/task/html.dart b/pkg/analyzer/lib/src/task/html.dart
index b6a771a..01cdd5a 100644
--- a/pkg/analyzer/lib/src/task/html.dart
+++ b/pkg/analyzer/lib/src/task/html.dart
@@ -279,7 +279,8 @@
'ParseHtmlTask',
createTask,
buildInputs,
- <ResultDescriptor>[HTML_DOCUMENT, HTML_DOCUMENT_ERRORS, LINE_INFO]);
+ <ResultDescriptor>[HTML_DOCUMENT, HTML_DOCUMENT_ERRORS, LINE_INFO],
+ suitabilityFor: suitabilityFor);
/**
* Initialize a newly created task to access the content of the source
@@ -358,6 +359,20 @@
}
/**
+ * Return an indication of how suitable this task is for the given [target].
+ */
+ static TaskSuitability suitabilityFor(AnalysisTarget target) {
+ if (target is Source) {
+ String name = target.shortName;
+ if (name.endsWith(AnalysisEngine.SUFFIX_HTML) ||
+ name.endsWith(AnalysisEngine.SUFFIX_HTM)) {
+ return TaskSuitability.HIGHEST;
+ }
+ }
+ return TaskSuitability.NONE;
+ }
+
+ /**
* Compute [LineInfo] for the given [content].
*/
static LineInfo _computeLineInfo(String content) {
diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
index 07550c5..05029d3 100644
--- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
+++ b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
@@ -6,10 +6,11 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/lib/src/task/manager.dart b/pkg/analyzer/lib/src/task/manager.dart
index eebc084..c8252fa 100644
--- a/pkg/analyzer/lib/src/task/manager.dart
+++ b/pkg/analyzer/lib/src/task/manager.dart
@@ -83,7 +83,7 @@
throw new AnalysisException(
'No tasks registered to compute $result for $target');
}
- return _findBestTask(descriptors);
+ return _findBestTask(descriptors, target);
}
/**
@@ -104,11 +104,20 @@
/**
* Given a list of task [descriptors] that can be used to compute some
- * unspecified result, return the descriptor that will compute the result with
- * the least amount of work.
+ * unspecified result for the given [target], return the descriptor that
+ * should be used to compute the result.
*/
- TaskDescriptor _findBestTask(List<TaskDescriptor> descriptors) {
- // TODO(brianwilkerson) Improve this implementation.
- return descriptors[0];
+ TaskDescriptor _findBestTask(
+ List<TaskDescriptor> descriptors, AnalysisTarget target) {
+ TaskDescriptor best = null;
+ for (TaskDescriptor descriptor in descriptors) {
+ TaskSuitability suitability = descriptor.suitabilityFor(target);
+ if (suitability == TaskSuitability.HIGHEST) {
+ return descriptor;
+ } else if (best == null && suitability == TaskSuitability.LOWEST) {
+ best = descriptor;
+ }
+ }
+ return best;
}
}
diff --git a/pkg/analyzer/lib/src/task/model.dart b/pkg/analyzer/lib/src/task/model.dart
index 8eaa838..56e2827 100644
--- a/pkg/analyzer/lib/src/task/model.dart
+++ b/pkg/analyzer/lib/src/task/model.dart
@@ -126,13 +126,23 @@
final List<ResultDescriptor> results;
/**
+ * The function used to determine whether the described task is suitable for
+ * a given target.
+ */
+ final SuitabilityFor _suitabilityFor;
+
+ /**
* Initialize a newly created task descriptor to have the given [name] and to
- * describe a task that takes the inputs built using the given [createTaskInputs],
- * and produces the given [results]. The [buildTask] will be used to create
- * the instance of [AnalysisTask] thusly described.
+ * describe a task that takes the inputs built using the given [inputBuilder],
+ * and produces the given [results]. The [buildTask] function will be used to
+ * create the instance of [AnalysisTask] being described. If provided, the
+ * [isAppropriateFor] function will be used to determine whether the task can
+ * be used on a specific target.
*/
TaskDescriptorImpl(
- this.name, this.buildTask, this.createTaskInputs, this.results);
+ this.name, this.buildTask, this.createTaskInputs, this.results,
+ {SuitabilityFor suitabilityFor})
+ : _suitabilityFor = suitabilityFor ?? _defaultSuitability;
@override
AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
@@ -143,5 +153,16 @@
}
@override
+ TaskSuitability suitabilityFor(AnalysisTarget target) =>
+ _suitabilityFor(target);
+
+ @override
String toString() => name;
+
+ /**
+ * The function that will be used to determine the suitability of a task if no
+ * other function is provided.
+ */
+ static TaskSuitability _defaultSuitability(AnalysisTarget target) =>
+ TaskSuitability.LOWEST;
}
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 6775408..4a6483c 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -202,7 +202,8 @@
'GenerateOptionsErrorsTask',
createTask,
buildInputs,
- <ResultDescriptor>[ANALYSIS_OPTIONS_ERRORS, LINE_INFO]);
+ <ResultDescriptor>[ANALYSIS_OPTIONS_ERRORS, LINE_INFO],
+ suitabilityFor: suitabilityFor);
final AnalysisOptionsProvider optionsProvider = new AnalysisOptionsProvider();
@@ -257,6 +258,17 @@
static GenerateOptionsErrorsTask createTask(
AnalysisContext context, AnalysisTarget target) =>
new GenerateOptionsErrorsTask(context, target);
+
+ /**
+ * Return an indication of how suitable this task is for the given [target].
+ */
+ static TaskSuitability suitabilityFor(AnalysisTarget target) {
+ if (target is Source &&
+ target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_FILE) {
+ return TaskSuitability.HIGHEST;
+ }
+ return TaskSuitability.NONE;
+ }
}
/// Validates `analyzer` language configuration options.
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 29857b0..a67251e7 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -7,10 +7,11 @@
library analyzer.src.task.strong.checker;
import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
import 'package:analyzer/src/generated/type_system.dart';
@@ -129,14 +130,9 @@
Expression arg = list[i];
ParameterElement element = arg.staticParameterElement;
if (element == null) {
- if (type.parameters.length < len) {
- // We found an argument mismatch, the analyzer will report this too,
- // so no need to insert an error for this here.
- continue;
- }
- element = type.parameters[i];
- // TODO(vsm): When can this happen?
- assert(element != null);
+ // We found an argument mismatch, the analyzer will report this too,
+ // so no need to insert an error for this here.
+ continue;
}
DartType expectedType = _elementType(element);
if (expectedType == null) expectedType = DynamicTypeImpl.instance;
diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
index cf4f822..4f39f6b 100644
--- a/pkg/analyzer/lib/src/task/strong/info.dart
+++ b/pkg/analyzer/lib/src/task/strong/info.dart
@@ -8,10 +8,10 @@
// refactored to fit into analyzer.
library analyzer.src.task.strong.info;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/type_system.dart';
@@ -95,13 +95,15 @@
baseType.isAssignableTo(_cast.toType)));
}
- @override List<Object> get arguments => [node, baseType, convertedType];
+ @override
+ List<Object> get arguments => [baseType, convertedType];
Cast get cast => _cast;
DartType get convertedType => _cast.toType;
- @override String get message => '{0} ({1}) will need runtime check '
- 'to cast to type {2}';
+
+ @override
+ String get message => 'Unsound implicit cast from {0} to {1}';
// Factory to create correct DownCast variant.
static StaticInfo create(
@@ -122,20 +124,18 @@
}
// Inference "casts":
- if (expression is Literal) {
+ if (expression is Literal || expression is FunctionExpression) {
// fromT should be an exact type - this will almost certainly fail at
// runtime.
return new StaticTypeError(rules, expression, toT, reason: reason);
}
- if (expression is FunctionExpression) {
- // fromT should be an exact type - this will almost certainly fail at
- // runtime.
- return new UninferredClosure(rules, expression, cast);
- }
if (expression is InstanceCreationExpression) {
- // fromT should be an exact type - this will almost certainly fail at
- // runtime.
- return new StaticTypeError(rules, expression, toT, reason: reason);
+ ConstructorElement e = expression.staticElement;
+ if (e == null || !e.isFactory) {
+ // fromT should be an exact type - this will almost certainly fail at
+ // runtime.
+ return new StaticTypeError(rules, expression, toT, reason: reason);
+ }
}
// TODO(vsm): Change this to an assert when we have generic methods and
@@ -292,9 +292,11 @@
TypeSystem rules, Expression expression, this._type)
: super(rules, expression);
- @override List get arguments => [node, type];
+ @override
+ List get arguments => [node, type];
DartType get convertedType => type;
- @override String get message => '{0} has inferred type {1}';
+ @override
+ String get message => '{0} has inferred type {1}';
DartType get type => _type;
toErrorCode() => new HintCode(name, message);
@@ -370,7 +372,8 @@
fromMixin = node.parent is WithClause,
super(node);
- @override List<Object> get arguments =>
+ @override
+ List<Object> get arguments =>
[parent.name, element.name, subType, base, baseType];
ClassElement get parent => element.enclosingElement;
@@ -392,8 +395,10 @@
TypeSystem rules, FormalParameter declaration, this.expectedType)
: super(declaration);
- @override List<Object> get arguments => [node, expectedType];
- @override String get message => 'Type check failed: {0} is not of type {1}';
+ @override
+ List<Object> get arguments => [node, expectedType];
+ @override
+ String get message => 'Type check failed: {0} is not of type {1}';
@override
String get name => 'STRONG_MODE_INVALID_PARAMETER_DECLARATION';
}
@@ -424,14 +429,15 @@
/// could be if initializers have side effects.
///
/// Better to have `super` at the end, as required by the Dart style guide:
-/// <http://goo.gl/q1T4BB>
+/// <https://goo.gl/EY6hDP>
///
/// For now this is the only pattern we support.
class InvalidSuperInvocation extends StaticError {
InvalidSuperInvocation(SuperConstructorInvocation node) : super(node);
- @override String get message => "super call must be last in an initializer "
- "list (see http://goo.gl/q1T4BB): {0}";
+ @override
+ String get message => "super call must be last in an initializer "
+ "list (see https://goo.gl/EY6hDP): {0}";
@override
String get name => 'STRONG_MODE_INVALID_SUPER_INVOCATION';
@@ -444,8 +450,10 @@
TypeSystem rules, AstNode declaration, this.expectedType)
: super(declaration);
- @override List<Object> get arguments => [expectedType];
- @override String get message => 'Type check failed: null is not of type {0}';
+ @override
+ List<Object> get arguments => [expectedType];
+ @override
+ String get message => 'Type check failed: null is not of type {0}';
@override
String get name => 'STRONG_MODE_INVALID_VARIABLE_DECLARATION';
@@ -459,7 +467,8 @@
assert(node is IsExpression || node is AsExpression);
}
- @override List<Object> get arguments => [type];
+ @override
+ List<Object> get arguments => [type];
String get message =>
"Runtime check on non-ground type {0} may throw StrongModeError";
@@ -541,31 +550,13 @@
: baseType = expression.staticType ?? DynamicTypeImpl.instance,
super(expression);
- @override List<Object> get arguments => [node, baseType, expectedType];
- @override String get message =>
+ @override
+ List<Object> get arguments => [node, baseType, expectedType];
+ @override
+ String get message =>
'Type check failed: {0} ({1}) is not of type {2}' +
((reason == null) ? '' : ' because $reason');
@override
String get name => 'STRONG_MODE_STATIC_TYPE_ERROR';
}
-
-//
-// Temporary "casts" of allocation sites - literals, constructor invocations,
-// and closures. These should be handled by contextual inference. In most
-// cases, inference will be sufficient, though in some it may unmask an actual
-// error: e.g.,
-// List<int> l = [1, 2, 3]; // Inference succeeds
-// List<String> l = [1, 2, 3]; // Inference reveals static type error
-// We're marking all as warnings for now.
-//
-// TODO(vsm,leafp): Remove this.
-class UninferredClosure extends DownCast {
- UninferredClosure(TypeSystem rules, FunctionExpression expression, Cast cast)
- : super._internal(rules, expression, cast);
-
- @override
- String get name => 'STRONG_MODE_UNINFERRED_CLOSURE';
-
- toErrorCode() => new StaticTypeWarningCode(name, message);
-}
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 46b84e0..05b5f1a 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -6,67 +6,31 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/resolver.dart'
show TypeProvider, InheritanceManager;
import 'package:analyzer/src/generated/type_system.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
/**
- * Set the type of the sole parameter of the given [element] to the given [type].
+ * Sets the type of the field. This is stored in the field itself, and the
+ * synthetic getter/setter types.
*/
-void setParameterType(PropertyAccessorElement element, DartType type) {
- if (element is PropertyAccessorElementImpl) {
- ParameterElement parameter = _getParameter(element);
- if (parameter is ParameterElementImpl) {
- //
- // Update the type of the parameter.
- //
- parameter.type = type;
- //
- // Update the type of the setter to reflect the new parameter type.
- //
- // TODO(jmesserly): why is this necessary? The function type should always
- // delegate to the orginal element.
- FunctionType functionType = element.type;
- if (functionType is FunctionTypeImpl) {
- element.type = new FunctionTypeImpl(element);
- } else {
- assert(false);
- }
- } else {
- assert(false);
- }
- } else {
- throw new StateError('element is an instance of ${element.runtimeType}');
- assert(false);
+void setFieldType(VariableElement field, DartType newType) {
+ (field as VariableElementImpl).type = newType;
+ if (field.initializer != null) {
+ (field.initializer as ExecutableElementImpl).returnType = newType;
}
-}
-
-/**
- * Set the return type of the given [element] to the given [type].
- */
-void setReturnType(ExecutableElement element, DartType type) {
- if (element is ExecutableElementImpl) {
- //
- // Update the return type of the element, which is stored in two places:
- // directly in the element and indirectly in the type of the element.
- //
- // TODO(jmesserly): why is this necessary? The function type should always
- // delegate to the orginal element.
- element.returnType = type;
- FunctionType functionType = element.type;
- if (functionType is FunctionTypeImpl) {
- element.type = new FunctionTypeImpl(element);
- } else {
- assert(false);
+ if (field is PropertyInducingElementImpl) {
+ (field.getter as ExecutableElementImpl).returnType = newType;
+ if (!field.isFinal && !field.isConst) {
+ (field.setter.parameters[0] as ParameterElementImpl).type =
+ newType;
}
- } else {
- assert(false);
}
}
@@ -317,7 +281,8 @@
!_allSameElementKind(element, overriddenMethods)) {
return;
}
- setReturnType(element, _computeReturnType(overriddenMethods));
+ (element as ExecutableElementImpl).returnType =
+ _computeReturnType(overriddenMethods);
if (element is PropertyAccessorElement) {
_updateSyntheticVariableType(element);
}
@@ -387,11 +352,7 @@
if (newType == null || newType.isBottom) {
newType = typeProvider.dynamicType;
}
- (fieldElement as FieldElementImpl).type = newType;
- setReturnType(fieldElement.getter, newType);
- if (!fieldElement.isFinal && !fieldElement.isConst) {
- setParameterType(fieldElement.setter, newType);
- }
+ setFieldType(fieldElement, newType);
}
}
diff --git a/pkg/analyzer/lib/src/task/yaml.dart b/pkg/analyzer/lib/src/task/yaml.dart
new file mode 100644
index 0000000..8ce7ec1
--- /dev/null
+++ b/pkg/analyzer/lib/src/task/yaml.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2016, 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 analyzer.src.task.yaml;
+
+import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/general.dart';
+import 'package:analyzer/task/general.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:analyzer/task/yaml.dart';
+import 'package:source_span/source_span.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * A task that scans the content of a YAML file, producing a YAML document.
+ */
+class ParseYamlTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the input whose value is the content of the file.
+ */
+ static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ParseYamlTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[YAML_DOCUMENT, YAML_ERRORS, LINE_INFO],
+ suitabilityFor: suitabilityFor);
+
+ /**
+ * Initialize a newly created task to access the content of the source
+ * associated with the given [target] in the given [context].
+ */
+ ParseYamlTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ Source source = target.source;
+ String uri = source.uri.toString();
+ String content = getRequiredInput(CONTENT_INPUT_NAME);
+
+ if (context.getModificationStamp(source) < 0) {
+ String message = 'Content could not be read';
+ if (context is InternalAnalysisContext) {
+ CacheEntry entry =
+ (context as InternalAnalysisContext).getCacheEntry(target);
+ CaughtException exception = entry.exception;
+ if (exception != null) {
+ message = exception.toString();
+ }
+ }
+ //
+ // Record outputs.
+ //
+ outputs[YAML_DOCUMENT] = loadYamlDocument('', sourceUrl: uri);
+ outputs[YAML_ERRORS] = <AnalysisError>[
+ new AnalysisError(
+ source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])
+ ];
+ outputs[LINE_INFO] = new LineInfo(<int>[0]);
+ } else {
+ YamlDocument document;
+ List<AnalysisError> errors = <AnalysisError>[];
+ try {
+ document = loadYamlDocument(content, sourceUrl: uri);
+ } on YamlException catch (exception) {
+ SourceSpan span = exception.span;
+ int offset = span.start.offset;
+ int length = span.end.offset - offset;
+ errors.add(new AnalysisError(source, offset, length,
+ YamlErrorCode.PARSE_ERROR, [exception.message]));
+ } catch (exception, stackTrace) {
+ throw new AnalysisException('Error while parsing ${source.fullName}',
+ new CaughtException(exception, stackTrace));
+ }
+ //
+ // Record outputs.
+ //
+ outputs[YAML_DOCUMENT] = document;
+ outputs[YAML_ERRORS] = errors;
+ outputs[LINE_INFO] = new LineInfo.fromContent(content);
+ }
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the given
+ * [source].
+ */
+ static Map<String, TaskInput> buildInputs(Source source) {
+ return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)};
+ }
+
+ /**
+ * Create a [ParseYamlTask] based on the given [target] in the given [context].
+ */
+ static ParseYamlTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ParseYamlTask(context, target);
+ }
+
+ /**
+ * Return an indication of how suitable this task is for the given [target].
+ */
+ static TaskSuitability suitabilityFor(AnalysisTarget target) {
+ if (target is Source && target.shortName.endsWith('.yaml')) {
+ return TaskSuitability.HIGHEST;
+ }
+ return TaskSuitability.NONE;
+ }
+}
+
+/**
+ * The error codes used for errors in YAML files.
+ */
+class YamlErrorCode extends ErrorCode {
+ // TODO(brianwilkerson) Move this class to error.dart.
+
+ /**
+ * An error code indicating that there is a syntactic error in the file.
+ *
+ * Parameters:
+ * 0: the error message from the parse error
+ */
+ static const YamlErrorCode PARSE_ERROR =
+ const YamlErrorCode('PARSE_ERROR', '{0}');
+
+ /**
+ * Initialize a newly created error code to have the given [name]. The message
+ * associated with the error will be created from the given [message]
+ * template. The correction associated with the error will be created from the
+ * given [correction] template.
+ */
+ const YamlErrorCode(String name, String message, [String correction])
+ : super(name, message, correction);
+
+ @override
+ ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
+
+ @override
+ ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
+}
diff --git a/pkg/analyzer/lib/task/dart.dart b/pkg/analyzer/lib/task/dart.dart
index 27258c3..ea132e3 100644
--- a/pkg/analyzer/lib/task/dart.dart
+++ b/pkg/analyzer/lib/task/dart.dart
@@ -4,8 +4,8 @@
library analyzer.task.dart;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index c320659..58e095b 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -36,6 +36,14 @@
typedef Map<String, TaskInput> CreateTaskInputs(AnalysisTarget target);
/**
+ * A function that takes the target for which a task will produce results and
+ * returns an indication of how suitable the task is for the target. Such
+ * functions are passed to a [TaskDescriptor] to be used to determine their
+ * suitability for computing results.
+ */
+typedef TaskSuitability SuitabilityFor(AnalysisTarget target);
+
+/**
* A function that converts an object of the type [B] into a [TaskInput].
* This is used, for example, by a [ListTaskInput] to create task inputs
* for each value in a list of values.
@@ -355,37 +363,36 @@
* Return a task input that can be used to compute a flatten list whose
* elements are combined [subListResult]'s associated with those elements.
*/
- ListTaskInput /*<V>*/ toFlattenListOf /*<V>*/ (
- ListResultDescriptor /*<V>*/ subListResult);
+ ListTaskInput/*<V>*/ toFlattenListOf/*<V>*/(
+ ListResultDescriptor/*<V>*/ subListResult);
/**
* Return a task input that can be used to compute a list whose elements are
* the result of passing the elements of this input to the [mapper] function.
*/
- ListTaskInput /*<V>*/ toList /*<V>*/ (
- UnaryFunction<E, dynamic /*<=V>*/ > mapper);
+ ListTaskInput/*<V>*/ toList/*<V>*/(UnaryFunction<E, dynamic/*<=V>*/ > mapper);
/**
* Return a task input that can be used to compute a list whose elements are
* [valueResult]'s associated with those elements.
*/
- ListTaskInput /*<V>*/ toListOf /*<V>*/ (ResultDescriptor /*<V>*/ valueResult);
+ ListTaskInput/*<V>*/ toListOf/*<V>*/(ResultDescriptor/*<V>*/ valueResult);
/**
* Return a task input that can be used to compute a map whose keys are the
* elements of this input and whose values are the result of passing the
* corresponding key to the [mapper] function.
*/
- MapTaskInput<E, dynamic /*=V*/ > toMap /*<V>*/ (
- UnaryFunction<E, dynamic /*=V*/ > mapper);
+ MapTaskInput<E, dynamic/*=V*/ > toMap/*<V>*/(
+ UnaryFunction<E, dynamic/*=V*/ > mapper);
/**
* Return a task input that can be used to compute a map whose keys are the
* elements of this input and whose values are the [valueResult]'s associated
* with those elements.
*/
- MapTaskInput<AnalysisTarget, dynamic /*=V*/ > toMapOf /*<V>*/ (
- ResultDescriptor /*<V>*/ valueResult);
+ MapTaskInput<AnalysisTarget, dynamic/*=V*/ > toMapOf/*<V>*/(
+ ResultDescriptor/*<V>*/ valueResult);
}
/**
@@ -400,8 +407,8 @@
* the result of passing keys [K] and the corresponding elements of [V] to
* the [mapper] function.
*/
- TaskInput<List /*<E>*/ > toFlattenList /*<E>*/ (
- BinaryFunction<K, dynamic /*element of V*/, dynamic /*=E*/ > mapper);
+ TaskInput<List/*<E>*/ > toFlattenList/*<E>*/(
+ BinaryFunction<K, dynamic /*element of V*/, dynamic/*=E*/ > mapper);
}
/**
@@ -523,14 +530,14 @@
/**
* Initialize a newly created task descriptor to have the given [name] and to
* describe a task that takes the inputs built using the given [inputBuilder],
- * and produces the given [results]. The [buildTask] will be used to create
- * the instance of [AnalysisTask] thusly described.
+ * and produces the given [results]. The [buildTask] function will be used to
+ * create the instance of [AnalysisTask] being described. If provided, the
+ * [isAppropriateFor] function will be used to determine whether the task can
+ * be used on a specific target.
*/
- factory TaskDescriptor(
- String name,
- BuildTask buildTask,
- CreateTaskInputs inputBuilder,
- List<ResultDescriptor> results) = TaskDescriptorImpl;
+ factory TaskDescriptor(String name, BuildTask buildTask,
+ CreateTaskInputs inputBuilder, List<ResultDescriptor> results,
+ {SuitabilityFor suitabilityFor}) = TaskDescriptorImpl;
/**
* Return the builder used to build the inputs to the task.
@@ -553,6 +560,11 @@
*/
AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
Map<String, dynamic> inputs);
+
+ /**
+ * Return an indication of how suitable this task is for the given [target].
+ */
+ TaskSuitability suitabilityFor(AnalysisTarget target);
}
/**
@@ -571,7 +583,7 @@
* Return a task input that can be used to compute a list whose elements are
* the result of passing the result of this input to the [mapper] function.
*/
- ListTaskInput /*<E>*/ mappedToList /*<E>*/ (List /*<E>*/ mapper(V value));
+ ListTaskInput/*<E>*/ mappedToList/*<E>*/(List/*<E>*/ mapper(V value));
}
/**
@@ -651,6 +663,11 @@
}
/**
+ * An indication of how suitable a task is for a given target.
+ */
+enum TaskSuitability { NONE, LOWEST, HIGHEST }
+
+/**
* [WorkManager]s are used to drive analysis.
*
* They know specific of the targets and results they care about,
diff --git a/pkg/analyzer/lib/task/yaml.dart b/pkg/analyzer/lib/task/yaml.dart
new file mode 100644
index 0000000..1795d8f
--- /dev/null
+++ b/pkg/analyzer/lib/task/yaml.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, 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 analyzer.task.yaml;
+
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * The result of parsing a YAML file.
+ */
+final ResultDescriptor<YamlDocument> YAML_DOCUMENT =
+ new ResultDescriptor<YamlDocument>('YAML_DOCUMENT', null);
+
+/**
+ * The analysis errors associated with a [Source] representing a YAML file.
+ */
+final ListResultDescriptor<AnalysisError> YAML_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'YAML_ERRORS', AnalysisError.NO_ERRORS);
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 607b92c..01abc35 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.27.1+2
+version: 0.27.2-alpha.0
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
new file mode 100644
index 0000000..f8d51f1
--- /dev/null
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -0,0 +1,1308 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.dart.ast.ast_test;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
+import 'package:analyzer/src/generated/testing/token_factory.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../generated/parser_test.dart' show ParserTestCase;
+import '../../generated/test_support.dart';
+import '../../reflective_tests.dart';
+import '../../utils.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(ClassDeclarationTest);
+ runReflectiveTests(ClassTypeAliasTest);
+ runReflectiveTests(ConstructorDeclarationTest);
+ runReflectiveTests(FieldFormalParameterTest);
+ runReflectiveTests(IndexExpressionTest);
+ runReflectiveTests(NodeListTest);
+ runReflectiveTests(SimpleIdentifierTest);
+ runReflectiveTests(SimpleStringLiteralTest);
+ runReflectiveTests(StringInterpolationTest);
+ runReflectiveTests(VariableDeclarationTest);
+}
+
+@reflectiveTest
+class ClassDeclarationTest extends ParserTestCase {
+ void test_getConstructor() {
+ List<ConstructorInitializer> initializers =
+ new List<ConstructorInitializer>();
+ ConstructorDeclaration defaultConstructor =
+ AstFactory.constructorDeclaration(AstFactory.identifier3("Test"), null,
+ AstFactory.formalParameterList(), initializers);
+ ConstructorDeclaration aConstructor = AstFactory.constructorDeclaration(
+ AstFactory.identifier3("Test"),
+ "a",
+ AstFactory.formalParameterList(),
+ initializers);
+ ConstructorDeclaration bConstructor = AstFactory.constructorDeclaration(
+ AstFactory.identifier3("Test"),
+ "b",
+ AstFactory.formalParameterList(),
+ initializers);
+ ClassDeclaration clazz = AstFactory.classDeclaration(null, "Test", null,
+ null, null, null, [defaultConstructor, aConstructor, bConstructor]);
+ expect(clazz.getConstructor(null), same(defaultConstructor));
+ expect(clazz.getConstructor("a"), same(aConstructor));
+ expect(clazz.getConstructor("b"), same(bConstructor));
+ expect(clazz.getConstructor("noSuchConstructor"), same(null));
+ }
+
+ void test_getField() {
+ VariableDeclaration aVar = AstFactory.variableDeclaration("a");
+ VariableDeclaration bVar = AstFactory.variableDeclaration("b");
+ VariableDeclaration cVar = AstFactory.variableDeclaration("c");
+ ClassDeclaration clazz =
+ AstFactory.classDeclaration(null, "Test", null, null, null, null, [
+ AstFactory.fieldDeclaration2(false, null, [aVar]),
+ AstFactory.fieldDeclaration2(false, null, [bVar, cVar])
+ ]);
+ expect(clazz.getField("a"), same(aVar));
+ expect(clazz.getField("b"), same(bVar));
+ expect(clazz.getField("c"), same(cVar));
+ expect(clazz.getField("noSuchField"), same(null));
+ }
+
+ void test_getMethod() {
+ MethodDeclaration aMethod = AstFactory.methodDeclaration(null, null, null,
+ null, AstFactory.identifier3("a"), AstFactory.formalParameterList());
+ MethodDeclaration bMethod = AstFactory.methodDeclaration(null, null, null,
+ null, AstFactory.identifier3("b"), AstFactory.formalParameterList());
+ ClassDeclaration clazz = AstFactory.classDeclaration(
+ null, "Test", null, null, null, null, [aMethod, bMethod]);
+ expect(clazz.getMethod("a"), same(aMethod));
+ expect(clazz.getMethod("b"), same(bMethod));
+ expect(clazz.getMethod("noSuchMethod"), same(null));
+ }
+
+ void test_isAbstract() {
+ expect(
+ AstFactory
+ .classDeclaration(null, "A", null, null, null, null)
+ .isAbstract,
+ isFalse);
+ expect(
+ AstFactory
+ .classDeclaration(Keyword.ABSTRACT, "B", null, null, null, null)
+ .isAbstract,
+ isTrue);
+ }
+}
+
+@reflectiveTest
+class ClassTypeAliasTest extends ParserTestCase {
+ void test_isAbstract() {
+ expect(
+ AstFactory.classTypeAlias("A", null, null, null, null, null).isAbstract,
+ isFalse);
+ expect(
+ AstFactory
+ .classTypeAlias("B", null, Keyword.ABSTRACT, null, null, null)
+ .isAbstract,
+ isTrue);
+ }
+}
+
+@reflectiveTest
+class ConstructorDeclarationTest extends EngineTestCase {
+ void test_firstTokenAfterCommentAndMetadata_all_inverted() {
+ Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
+ externalKeyword.offset = 14;
+ ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+ Keyword.CONST,
+ Keyword.FACTORY,
+ AstFactory.identifier3('int'),
+ null,
+ null,
+ null,
+ null);
+ declaration.externalKeyword = externalKeyword;
+ declaration.constKeyword.offset = 8;
+ Token factoryKeyword = declaration.factoryKeyword;
+ factoryKeyword.offset = 0;
+ expect(declaration.firstTokenAfterCommentAndMetadata, factoryKeyword);
+ }
+
+ void test_firstTokenAfterCommentAndMetadata_all_normal() {
+ Token token = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
+ token.offset = 0;
+ ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+ Keyword.CONST,
+ Keyword.FACTORY,
+ AstFactory.identifier3('int'),
+ null,
+ null,
+ null,
+ null);
+ declaration.externalKeyword = token;
+ declaration.constKeyword.offset = 9;
+ declaration.factoryKeyword.offset = 15;
+ expect(declaration.firstTokenAfterCommentAndMetadata, token);
+ }
+
+ void test_firstTokenAfterCommentAndMetadata_constOnly() {
+ ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+ Keyword.CONST,
+ null,
+ AstFactory.identifier3('int'),
+ null,
+ null,
+ null,
+ null);
+ expect(declaration.firstTokenAfterCommentAndMetadata,
+ declaration.constKeyword);
+ }
+
+ void test_firstTokenAfterCommentAndMetadata_externalOnly() {
+ Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
+ ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+ null, null, AstFactory.identifier3('int'), null, null, null, null);
+ declaration.externalKeyword = externalKeyword;
+ expect(declaration.firstTokenAfterCommentAndMetadata, externalKeyword);
+ }
+
+ void test_firstTokenAfterCommentAndMetadata_factoryOnly() {
+ ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+ null,
+ Keyword.FACTORY,
+ AstFactory.identifier3('int'),
+ null,
+ null,
+ null,
+ null);
+ expect(declaration.firstTokenAfterCommentAndMetadata,
+ declaration.factoryKeyword);
+ }
+}
+
+@reflectiveTest
+class FieldFormalParameterTest extends EngineTestCase {
+ void test_endToken_noParameters() {
+ FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('field');
+ expect(parameter.endToken, parameter.identifier.endToken);
+ }
+
+ void test_endToken_parameters() {
+ FieldFormalParameter parameter = AstFactory.fieldFormalParameter(
+ null, null, 'field', AstFactory.formalParameterList([]));
+ expect(parameter.endToken, parameter.parameters.endToken);
+ }
+}
+
+@reflectiveTest
+class IndexExpressionTest extends EngineTestCase {
+ void test_inGetterContext_assignment_compound_left() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // a[b] += c
+ AstFactory.assignmentExpression(
+ expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
+ expect(expression.inGetterContext(), isTrue);
+ }
+
+ void test_inGetterContext_assignment_simple_left() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // a[b] = c
+ AstFactory.assignmentExpression(
+ expression, TokenType.EQ, AstFactory.identifier3("c"));
+ expect(expression.inGetterContext(), isFalse);
+ }
+
+ void test_inGetterContext_nonAssignment() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // a[b] + c
+ AstFactory.binaryExpression(
+ expression, TokenType.PLUS, AstFactory.identifier3("c"));
+ expect(expression.inGetterContext(), isTrue);
+ }
+
+ void test_inSetterContext_assignment_compound_left() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // a[b] += c
+ AstFactory.assignmentExpression(
+ expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
+ expect(expression.inSetterContext(), isTrue);
+ }
+
+ void test_inSetterContext_assignment_compound_right() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // c += a[b]
+ AstFactory.assignmentExpression(
+ AstFactory.identifier3("c"), TokenType.PLUS_EQ, expression);
+ expect(expression.inSetterContext(), isFalse);
+ }
+
+ void test_inSetterContext_assignment_simple_left() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // a[b] = c
+ AstFactory.assignmentExpression(
+ expression, TokenType.EQ, AstFactory.identifier3("c"));
+ expect(expression.inSetterContext(), isTrue);
+ }
+
+ void test_inSetterContext_assignment_simple_right() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // c = a[b]
+ AstFactory.assignmentExpression(
+ AstFactory.identifier3("c"), TokenType.EQ, expression);
+ expect(expression.inSetterContext(), isFalse);
+ }
+
+ void test_inSetterContext_nonAssignment() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ AstFactory.binaryExpression(
+ expression, TokenType.PLUS, AstFactory.identifier3("c"));
+ // a[b] + cc
+ expect(expression.inSetterContext(), isFalse);
+ }
+
+ void test_inSetterContext_postfix() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
+ // a[b]++
+ expect(expression.inSetterContext(), isTrue);
+ }
+
+ void test_inSetterContext_prefix_bang() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // !a[b]
+ AstFactory.prefixExpression(TokenType.BANG, expression);
+ expect(expression.inSetterContext(), isFalse);
+ }
+
+ void test_inSetterContext_prefix_minusMinus() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // --a[b]
+ AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
+ expect(expression.inSetterContext(), isTrue);
+ }
+
+ void test_inSetterContext_prefix_plusPlus() {
+ IndexExpression expression = AstFactory.indexExpression(
+ AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+ // ++a[b]
+ AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
+ expect(expression.inSetterContext(), isTrue);
+ }
+}
+
+@reflectiveTest
+class NodeListTest extends EngineTestCase {
+ void test_add() {
+ AstNode parent = AstFactory.argumentList();
+ AstNode firstNode = AstFactory.booleanLiteral(true);
+ AstNode secondNode = AstFactory.booleanLiteral(false);
+ NodeList<AstNode> list = new NodeList<AstNode>(parent);
+ list.insert(0, secondNode);
+ list.insert(0, firstNode);
+ expect(list, hasLength(2));
+ expect(list[0], same(firstNode));
+ expect(list[1], same(secondNode));
+ expect(firstNode.parent, same(parent));
+ expect(secondNode.parent, same(parent));
+ AstNode thirdNode = AstFactory.booleanLiteral(false);
+ list.insert(1, thirdNode);
+ expect(list, hasLength(3));
+ expect(list[0], same(firstNode));
+ expect(list[1], same(thirdNode));
+ expect(list[2], same(secondNode));
+ expect(firstNode.parent, same(parent));
+ expect(secondNode.parent, same(parent));
+ expect(thirdNode.parent, same(parent));
+ }
+
+ void test_add_negative() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ list.insert(-1, AstFactory.booleanLiteral(true));
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+
+ void test_add_tooBig() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ list.insert(1, AstFactory.booleanLiteral(true));
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+
+ void test_addAll() {
+ AstNode parent = AstFactory.argumentList();
+ List<AstNode> firstNodes = new List<AstNode>();
+ AstNode firstNode = AstFactory.booleanLiteral(true);
+ AstNode secondNode = AstFactory.booleanLiteral(false);
+ firstNodes.add(firstNode);
+ firstNodes.add(secondNode);
+ NodeList<AstNode> list = new NodeList<AstNode>(parent);
+ list.addAll(firstNodes);
+ expect(list, hasLength(2));
+ expect(list[0], same(firstNode));
+ expect(list[1], same(secondNode));
+ expect(firstNode.parent, same(parent));
+ expect(secondNode.parent, same(parent));
+ List<AstNode> secondNodes = new List<AstNode>();
+ AstNode thirdNode = AstFactory.booleanLiteral(true);
+ AstNode fourthNode = AstFactory.booleanLiteral(false);
+ secondNodes.add(thirdNode);
+ secondNodes.add(fourthNode);
+ list.addAll(secondNodes);
+ expect(list, hasLength(4));
+ expect(list[0], same(firstNode));
+ expect(list[1], same(secondNode));
+ expect(list[2], same(thirdNode));
+ expect(list[3], same(fourthNode));
+ expect(firstNode.parent, same(parent));
+ expect(secondNode.parent, same(parent));
+ expect(thirdNode.parent, same(parent));
+ expect(fourthNode.parent, same(parent));
+ }
+
+ void test_creation() {
+ AstNode owner = AstFactory.argumentList();
+ NodeList<AstNode> list = new NodeList<AstNode>(owner);
+ expect(list, isNotNull);
+ expect(list, hasLength(0));
+ expect(list.owner, same(owner));
+ }
+
+ void test_get_negative() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ list[-1];
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+
+ void test_get_tooBig() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ list[1];
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+
+ void test_getBeginToken_empty() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ expect(list.beginToken, isNull);
+ }
+
+ void test_getBeginToken_nonEmpty() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ AstNode node =
+ AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
+ list.add(node);
+ expect(list.beginToken, same(node.beginToken));
+ }
+
+ void test_getEndToken_empty() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ expect(list.endToken, isNull);
+ }
+
+ void test_getEndToken_nonEmpty() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ AstNode node =
+ AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
+ list.add(node);
+ expect(list.endToken, same(node.endToken));
+ }
+
+ void test_indexOf() {
+ List<AstNode> nodes = new List<AstNode>();
+ AstNode firstNode = AstFactory.booleanLiteral(true);
+ AstNode secondNode = AstFactory.booleanLiteral(false);
+ AstNode thirdNode = AstFactory.booleanLiteral(true);
+ AstNode fourthNode = AstFactory.booleanLiteral(false);
+ nodes.add(firstNode);
+ nodes.add(secondNode);
+ nodes.add(thirdNode);
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ list.addAll(nodes);
+ expect(list, hasLength(3));
+ expect(list.indexOf(firstNode), 0);
+ expect(list.indexOf(secondNode), 1);
+ expect(list.indexOf(thirdNode), 2);
+ expect(list.indexOf(fourthNode), -1);
+ expect(list.indexOf(null), -1);
+ }
+
+ void test_remove() {
+ List<AstNode> nodes = new List<AstNode>();
+ AstNode firstNode = AstFactory.booleanLiteral(true);
+ AstNode secondNode = AstFactory.booleanLiteral(false);
+ AstNode thirdNode = AstFactory.booleanLiteral(true);
+ nodes.add(firstNode);
+ nodes.add(secondNode);
+ nodes.add(thirdNode);
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ list.addAll(nodes);
+ expect(list, hasLength(3));
+ expect(list.removeAt(1), same(secondNode));
+ expect(list, hasLength(2));
+ expect(list[0], same(firstNode));
+ expect(list[1], same(thirdNode));
+ }
+
+ void test_remove_negative() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ list.removeAt(-1);
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+
+ void test_remove_tooBig() {
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ list.removeAt(1);
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+
+ void test_set() {
+ List<AstNode> nodes = new List<AstNode>();
+ AstNode firstNode = AstFactory.booleanLiteral(true);
+ AstNode secondNode = AstFactory.booleanLiteral(false);
+ AstNode thirdNode = AstFactory.booleanLiteral(true);
+ nodes.add(firstNode);
+ nodes.add(secondNode);
+ nodes.add(thirdNode);
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ list.addAll(nodes);
+ expect(list, hasLength(3));
+ AstNode fourthNode = AstFactory.integer(0);
+ expect(javaListSet(list, 1, fourthNode), same(secondNode));
+ expect(list, hasLength(3));
+ expect(list[0], same(firstNode));
+ expect(list[1], same(fourthNode));
+ expect(list[2], same(thirdNode));
+ }
+
+ void test_set_negative() {
+ AstNode node = AstFactory.booleanLiteral(true);
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ javaListSet(list, -1, node);
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+
+ void test_set_tooBig() {
+ AstNode node = AstFactory.booleanLiteral(true);
+ NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+ try {
+ javaListSet(list, 1, node);
+ fail("Expected IndexOutOfBoundsException");
+ } on RangeError {
+ // Expected
+ }
+ }
+}
+
+@reflectiveTest
+class SimpleIdentifierTest extends ParserTestCase {
+ void test_inDeclarationContext_catch_exception() {
+ SimpleIdentifier identifier =
+ AstFactory.catchClause("e").exceptionParameter;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_catch_stack() {
+ SimpleIdentifier identifier =
+ AstFactory.catchClause2("e", "s").stackTraceParameter;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_classDeclaration() {
+ SimpleIdentifier identifier =
+ AstFactory.classDeclaration(null, "C", null, null, null, null).name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_classTypeAlias() {
+ SimpleIdentifier identifier =
+ AstFactory.classTypeAlias("C", null, null, null, null, null).name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_constructorDeclaration() {
+ SimpleIdentifier identifier = AstFactory
+ .constructorDeclaration(AstFactory.identifier3("C"), "c", null, null)
+ .name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_declaredIdentifier() {
+ DeclaredIdentifier declaredIdentifier = AstFactory.declaredIdentifier3("v");
+ SimpleIdentifier identifier = declaredIdentifier.identifier;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_enumConstantDeclaration() {
+ EnumDeclaration enumDeclaration =
+ AstFactory.enumDeclaration2('MyEnum', ['CONST']);
+ SimpleIdentifier identifier = enumDeclaration.constants[0].name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_enumDeclaration() {
+ EnumDeclaration enumDeclaration =
+ AstFactory.enumDeclaration2('MyEnum', ['A', 'B', 'C']);
+ SimpleIdentifier identifier = enumDeclaration.name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_fieldFormalParameter() {
+ SimpleIdentifier identifier =
+ AstFactory.fieldFormalParameter2("p").identifier;
+ expect(identifier.inDeclarationContext(), isFalse);
+ }
+
+ void test_inDeclarationContext_functionDeclaration() {
+ SimpleIdentifier identifier =
+ AstFactory.functionDeclaration(null, null, "f", null).name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_functionTypeAlias() {
+ SimpleIdentifier identifier =
+ AstFactory.typeAlias(null, "F", null, null).name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_label_false() {
+ SimpleIdentifier identifier =
+ AstFactory.namedExpression2("l", AstFactory.integer(0)).name.label;
+ expect(identifier.inDeclarationContext(), isFalse);
+ }
+
+ void test_inDeclarationContext_label_true() {
+ Label label = AstFactory.label2("l");
+ SimpleIdentifier identifier = label.label;
+ AstFactory.labeledStatement([label], AstFactory.emptyStatement());
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_methodDeclaration() {
+ SimpleIdentifier identifier = AstFactory.identifier3("m");
+ AstFactory.methodDeclaration2(
+ null, null, null, null, identifier, null, null);
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_prefix() {
+ SimpleIdentifier identifier =
+ AstFactory.importDirective3("uri", "pref").prefix;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_simpleFormalParameter() {
+ SimpleIdentifier identifier =
+ AstFactory.simpleFormalParameter3("p").identifier;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_typeParameter_bound() {
+ TypeName bound = AstFactory.typeName4("A");
+ SimpleIdentifier identifier = bound.name as SimpleIdentifier;
+ AstFactory.typeParameter2("E", bound);
+ expect(identifier.inDeclarationContext(), isFalse);
+ }
+
+ void test_inDeclarationContext_typeParameter_name() {
+ SimpleIdentifier identifier = AstFactory.typeParameter("E").name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inDeclarationContext_variableDeclaration() {
+ SimpleIdentifier identifier = AstFactory.variableDeclaration("v").name;
+ expect(identifier.inDeclarationContext(), isTrue);
+ }
+
+ void test_inGetterContext() {
+ for (_WrapperKind wrapper in _WrapperKind.values) {
+ for (_AssignmentKind assignment in _AssignmentKind.values) {
+ SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
+ if (assignment == _AssignmentKind.SIMPLE_LEFT &&
+ wrapper != _WrapperKind.PREFIXED_LEFT &&
+ wrapper != _WrapperKind.PROPERTY_LEFT) {
+ if (identifier.inGetterContext()) {
+ fail("Expected ${_topMostNode(identifier).toSource()} to be false");
+ }
+ } else {
+ if (!identifier.inGetterContext()) {
+ fail("Expected ${_topMostNode(identifier).toSource()} to be true");
+ }
+ }
+ }
+ }
+ }
+
+ void test_inGetterContext_forEachLoop() {
+ SimpleIdentifier identifier = AstFactory.identifier3("a");
+ Expression iterator = AstFactory.listLiteral();
+ Statement body = AstFactory.block();
+ AstFactory.forEachStatement2(identifier, iterator, body);
+ expect(identifier.inGetterContext(), isFalse);
+ }
+
+ void test_inReferenceContext() {
+ SimpleIdentifier identifier = AstFactory.identifier3("id");
+ AstFactory.namedExpression(
+ AstFactory.label(identifier), AstFactory.identifier3("_"));
+ expect(identifier.inGetterContext(), isFalse);
+ expect(identifier.inSetterContext(), isFalse);
+ }
+
+ void test_inSetterContext() {
+ for (_WrapperKind wrapper in _WrapperKind.values) {
+ for (_AssignmentKind assignment in _AssignmentKind.values) {
+ SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
+ if (wrapper == _WrapperKind.PREFIXED_LEFT ||
+ wrapper == _WrapperKind.PROPERTY_LEFT ||
+ assignment == _AssignmentKind.BINARY ||
+ assignment == _AssignmentKind.COMPOUND_RIGHT ||
+ assignment == _AssignmentKind.PREFIX_NOT ||
+ assignment == _AssignmentKind.SIMPLE_RIGHT ||
+ assignment == _AssignmentKind.NONE) {
+ if (identifier.inSetterContext()) {
+ fail("Expected ${_topMostNode(identifier).toSource()} to be false");
+ }
+ } else {
+ if (!identifier.inSetterContext()) {
+ fail("Expected ${_topMostNode(identifier).toSource()} to be true");
+ }
+ }
+ }
+ }
+ }
+
+ void test_inSetterContext_forEachLoop() {
+ SimpleIdentifier identifier = AstFactory.identifier3("a");
+ Expression iterator = AstFactory.listLiteral();
+ Statement body = AstFactory.block();
+ AstFactory.forEachStatement2(identifier, iterator, body);
+ expect(identifier.inSetterContext(), isTrue);
+ }
+
+ void test_isQualified_inMethodInvocation_noTarget() {
+ MethodInvocation invocation =
+ AstFactory.methodInvocation2("test", [AstFactory.identifier3("arg0")]);
+ SimpleIdentifier identifier = invocation.methodName;
+ expect(identifier.isQualified, isFalse);
+ }
+
+ void test_isQualified_inMethodInvocation_withTarget() {
+ MethodInvocation invocation = AstFactory.methodInvocation(
+ AstFactory.identifier3("target"),
+ "test",
+ [AstFactory.identifier3("arg0")]);
+ SimpleIdentifier identifier = invocation.methodName;
+ expect(identifier.isQualified, isTrue);
+ }
+
+ void test_isQualified_inPrefixedIdentifier_name() {
+ SimpleIdentifier identifier = AstFactory.identifier3("test");
+ AstFactory.identifier4("prefix", identifier);
+ expect(identifier.isQualified, isTrue);
+ }
+
+ void test_isQualified_inPrefixedIdentifier_prefix() {
+ SimpleIdentifier identifier = AstFactory.identifier3("test");
+ AstFactory.identifier(identifier, AstFactory.identifier3("name"));
+ expect(identifier.isQualified, isFalse);
+ }
+
+ void test_isQualified_inPropertyAccess_name() {
+ SimpleIdentifier identifier = AstFactory.identifier3("test");
+ AstFactory.propertyAccess(AstFactory.identifier3("target"), identifier);
+ expect(identifier.isQualified, isTrue);
+ }
+
+ void test_isQualified_inPropertyAccess_target() {
+ SimpleIdentifier identifier = AstFactory.identifier3("test");
+ AstFactory.propertyAccess(identifier, AstFactory.identifier3("name"));
+ expect(identifier.isQualified, isFalse);
+ }
+
+ void test_isQualified_inReturnStatement() {
+ SimpleIdentifier identifier = AstFactory.identifier3("test");
+ AstFactory.returnStatement2(identifier);
+ expect(identifier.isQualified, isFalse);
+ }
+
+ SimpleIdentifier _createIdentifier(
+ _WrapperKind wrapper, _AssignmentKind assignment) {
+ SimpleIdentifier identifier = AstFactory.identifier3("a");
+ Expression expression = identifier;
+ while (true) {
+ if (wrapper == _WrapperKind.PREFIXED_LEFT) {
+ expression =
+ AstFactory.identifier(identifier, AstFactory.identifier3("_"));
+ } else if (wrapper == _WrapperKind.PREFIXED_RIGHT) {
+ expression =
+ AstFactory.identifier(AstFactory.identifier3("_"), identifier);
+ } else if (wrapper == _WrapperKind.PROPERTY_LEFT) {
+ expression = AstFactory.propertyAccess2(expression, "_");
+ } else if (wrapper == _WrapperKind.PROPERTY_RIGHT) {
+ expression =
+ AstFactory.propertyAccess(AstFactory.identifier3("_"), identifier);
+ } else if (wrapper == _WrapperKind.NONE) {}
+ break;
+ }
+ while (true) {
+ if (assignment == _AssignmentKind.BINARY) {
+ AstFactory.binaryExpression(
+ expression, TokenType.PLUS, AstFactory.identifier3("_"));
+ } else if (assignment == _AssignmentKind.COMPOUND_LEFT) {
+ AstFactory.assignmentExpression(
+ expression, TokenType.PLUS_EQ, AstFactory.identifier3("_"));
+ } else if (assignment == _AssignmentKind.COMPOUND_RIGHT) {
+ AstFactory.assignmentExpression(
+ AstFactory.identifier3("_"), TokenType.PLUS_EQ, expression);
+ } else if (assignment == _AssignmentKind.POSTFIX_INC) {
+ AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
+ } else if (assignment == _AssignmentKind.PREFIX_DEC) {
+ AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
+ } else if (assignment == _AssignmentKind.PREFIX_INC) {
+ AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
+ } else if (assignment == _AssignmentKind.PREFIX_NOT) {
+ AstFactory.prefixExpression(TokenType.BANG, expression);
+ } else if (assignment == _AssignmentKind.SIMPLE_LEFT) {
+ AstFactory.assignmentExpression(
+ expression, TokenType.EQ, AstFactory.identifier3("_"));
+ } else if (assignment == _AssignmentKind.SIMPLE_RIGHT) {
+ AstFactory.assignmentExpression(
+ AstFactory.identifier3("_"), TokenType.EQ, expression);
+ } else if (assignment == _AssignmentKind.NONE) {}
+ break;
+ }
+ return identifier;
+ }
+
+ /**
+ * Return the top-most node in the AST structure containing the given identifier.
+ *
+ * @param identifier the identifier in the AST structure being traversed
+ * @return the root of the AST structure containing the identifier
+ */
+ AstNode _topMostNode(SimpleIdentifier identifier) {
+ AstNode child = identifier;
+ AstNode parent = identifier.parent;
+ while (parent != null) {
+ child = parent;
+ parent = parent.parent;
+ }
+ return child;
+ }
+}
+
+@reflectiveTest
+class SimpleStringLiteralTest extends ParserTestCase {
+ void test_contentsEnd() {
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
+ .contentsEnd,
+ 2);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString('"X"'), "X")
+ .contentsEnd,
+ 2);
+
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString('"""X"""'), "X")
+ .contentsEnd,
+ 4);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+ .contentsEnd,
+ 4);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("''' \nX'''"), "X")
+ .contentsEnd,
+ 7);
+
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+ .contentsEnd,
+ 3);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString('r"X"'), "X")
+ .contentsEnd,
+ 3);
+
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString('r"""X"""'), "X")
+ .contentsEnd,
+ 5);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+ .contentsEnd,
+ 5);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("r''' \nX'''"), "X")
+ .contentsEnd,
+ 8);
+ }
+
+ void test_contentsOffset() {
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
+ .contentsOffset,
+ 1);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
+ .contentsOffset,
+ 1);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X")
+ .contentsOffset,
+ 3);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+ .contentsOffset,
+ 3);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+ .contentsOffset,
+ 2);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
+ .contentsOffset,
+ 2);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X")
+ .contentsOffset,
+ 4);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+ .contentsOffset,
+ 4);
+ // leading whitespace
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("''' \ \nX''"), "X")
+ .contentsOffset,
+ 6);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString('r""" \ \nX"""'), "X")
+ .contentsOffset,
+ 7);
+ }
+
+ void test_isMultiline() {
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
+ .isMultiline,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+ .isMultiline,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
+ .isMultiline,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
+ .isMultiline,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+ .isMultiline,
+ isTrue);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+ .isMultiline,
+ isTrue);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X")
+ .isMultiline,
+ isTrue);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X")
+ .isMultiline,
+ isTrue);
+ }
+
+ void test_isRaw() {
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X").isRaw,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
+ .isRaw,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X")
+ .isRaw,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+ .isRaw,
+ isFalse);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+ .isRaw,
+ isTrue);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
+ .isRaw,
+ isTrue);
+ expect(
+ new SimpleStringLiteral(
+ TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X")
+ .isRaw,
+ isTrue);
+ expect(
+ new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+ .isRaw,
+ isTrue);
+ }
+
+ void test_isSingleQuoted() {
+ // '
+ {
+ var token = TokenFactory.tokenFromString("'X'");
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isTrue);
+ }
+ // '''
+ {
+ var token = TokenFactory.tokenFromString("'''X'''");
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isTrue);
+ }
+ // "
+ {
+ var token = TokenFactory.tokenFromString('"X"');
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isFalse);
+ }
+ // """
+ {
+ var token = TokenFactory.tokenFromString('"""X"""');
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isFalse);
+ }
+ }
+
+ void test_isSingleQuoted_raw() {
+ // r'
+ {
+ var token = TokenFactory.tokenFromString("r'X'");
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isTrue);
+ }
+ // r'''
+ {
+ var token = TokenFactory.tokenFromString("r'''X'''");
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isTrue);
+ }
+ // r"
+ {
+ var token = TokenFactory.tokenFromString('r"X"');
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isFalse);
+ }
+ // r"""
+ {
+ var token = TokenFactory.tokenFromString('r"""X"""');
+ var node = new SimpleStringLiteral(token, null);
+ expect(node.isSingleQuoted, isFalse);
+ }
+ }
+
+ void test_simple() {
+ Token token = TokenFactory.tokenFromString("'value'");
+ SimpleStringLiteral stringLiteral = new SimpleStringLiteral(token, "value");
+ expect(stringLiteral.literal, same(token));
+ expect(stringLiteral.beginToken, same(token));
+ expect(stringLiteral.endToken, same(token));
+ expect(stringLiteral.value, "value");
+ }
+}
+
+@reflectiveTest
+class StringInterpolationTest extends ParserTestCase {
+ void test_contentsOffsetEnd() {
+ AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
+ // 'a${bb}ccc'
+ {
+ var ae = AstFactory.interpolationString("'a", "a");
+ var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
+ var cElement = new InterpolationString(cToken, 'ccc');
+ StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+ expect(node.contentsOffset, 1);
+ expect(node.contentsEnd, 10 + 4 - 1);
+ }
+ // '''a${bb}ccc'''
+ {
+ var ae = AstFactory.interpolationString("'''a", "a");
+ var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
+ var cElement = new InterpolationString(cToken, 'ccc');
+ StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+ expect(node.contentsOffset, 3);
+ expect(node.contentsEnd, 10 + 4 - 1);
+ }
+ // """a${bb}ccc"""
+ {
+ var ae = AstFactory.interpolationString('"""a', "a");
+ var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
+ var cElement = new InterpolationString(cToken, 'ccc');
+ StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+ expect(node.contentsOffset, 3);
+ expect(node.contentsEnd, 10 + 4 - 1);
+ }
+ // r'a${bb}ccc'
+ {
+ var ae = AstFactory.interpolationString("r'a", "a");
+ var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
+ var cElement = new InterpolationString(cToken, 'ccc');
+ StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+ expect(node.contentsOffset, 2);
+ expect(node.contentsEnd, 10 + 4 - 1);
+ }
+ // r'''a${bb}ccc'''
+ {
+ var ae = AstFactory.interpolationString("r'''a", "a");
+ var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
+ var cElement = new InterpolationString(cToken, 'ccc');
+ StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+ expect(node.contentsOffset, 4);
+ expect(node.contentsEnd, 10 + 4 - 1);
+ }
+ // r"""a${bb}ccc"""
+ {
+ var ae = AstFactory.interpolationString('r"""a', "a");
+ var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
+ var cElement = new InterpolationString(cToken, 'ccc');
+ StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+ expect(node.contentsOffset, 4);
+ expect(node.contentsEnd, 10 + 4 - 1);
+ }
+ }
+
+ void test_isMultiline() {
+ var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
+ // '
+ {
+ var a = AstFactory.interpolationString("'a", "a");
+ var c = AstFactory.interpolationString("ccc'", "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isMultiline, isFalse);
+ }
+ // '''
+ {
+ var a = AstFactory.interpolationString("'''a", "a");
+ var c = AstFactory.interpolationString("ccc'''", "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isMultiline, isTrue);
+ }
+ // "
+ {
+ var a = AstFactory.interpolationString('"a', "a");
+ var c = AstFactory.interpolationString('ccc"', "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isMultiline, isFalse);
+ }
+ // """
+ {
+ var a = AstFactory.interpolationString('"""a', "a");
+ var c = AstFactory.interpolationString('ccc"""', "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isMultiline, isTrue);
+ }
+ }
+
+ void test_isRaw() {
+ StringInterpolation node = AstFactory.string();
+ expect(node.isRaw, isFalse);
+ }
+
+ void test_isSingleQuoted() {
+ var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
+ // "
+ {
+ var a = AstFactory.interpolationString('"a', "a");
+ var c = AstFactory.interpolationString('ccc"', "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isSingleQuoted, isFalse);
+ }
+ // """
+ {
+ var a = AstFactory.interpolationString('"""a', "a");
+ var c = AstFactory.interpolationString('ccc"""', "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isSingleQuoted, isFalse);
+ }
+ // '
+ {
+ var a = AstFactory.interpolationString("'a", "a");
+ var c = AstFactory.interpolationString("ccc'", "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isSingleQuoted, isTrue);
+ }
+ // '''
+ {
+ var a = AstFactory.interpolationString("'''a", "a");
+ var c = AstFactory.interpolationString("ccc'''", "ccc");
+ StringInterpolation node = AstFactory.string([a, b, c]);
+ expect(node.isSingleQuoted, isTrue);
+ }
+ }
+}
+
+@reflectiveTest
+class VariableDeclarationTest extends ParserTestCase {
+ void test_getDocumentationComment_onGrandParent() {
+ VariableDeclaration varDecl = AstFactory.variableDeclaration("a");
+ TopLevelVariableDeclaration decl =
+ AstFactory.topLevelVariableDeclaration2(Keyword.VAR, [varDecl]);
+ Comment comment = Comment.createDocumentationComment(new List<Token>(0));
+ expect(varDecl.documentationComment, isNull);
+ decl.documentationComment = comment;
+ expect(varDecl.documentationComment, isNotNull);
+ expect(decl.documentationComment, isNotNull);
+ }
+
+ void test_getDocumentationComment_onNode() {
+ VariableDeclaration decl = AstFactory.variableDeclaration("a");
+ Comment comment = Comment.createDocumentationComment(new List<Token>(0));
+ decl.documentationComment = comment;
+ expect(decl.documentationComment, isNotNull);
+ }
+}
+
+class _AssignmentKind {
+ static const _AssignmentKind BINARY = const _AssignmentKind('BINARY', 0);
+
+ static const _AssignmentKind COMPOUND_LEFT =
+ const _AssignmentKind('COMPOUND_LEFT', 1);
+
+ static const _AssignmentKind COMPOUND_RIGHT =
+ const _AssignmentKind('COMPOUND_RIGHT', 2);
+
+ static const _AssignmentKind POSTFIX_INC =
+ const _AssignmentKind('POSTFIX_INC', 3);
+
+ static const _AssignmentKind PREFIX_DEC =
+ const _AssignmentKind('PREFIX_DEC', 4);
+
+ static const _AssignmentKind PREFIX_INC =
+ const _AssignmentKind('PREFIX_INC', 5);
+
+ static const _AssignmentKind PREFIX_NOT =
+ const _AssignmentKind('PREFIX_NOT', 6);
+
+ static const _AssignmentKind SIMPLE_LEFT =
+ const _AssignmentKind('SIMPLE_LEFT', 7);
+
+ static const _AssignmentKind SIMPLE_RIGHT =
+ const _AssignmentKind('SIMPLE_RIGHT', 8);
+
+ static const _AssignmentKind NONE = const _AssignmentKind('NONE', 9);
+
+ static const List<_AssignmentKind> values = const [
+ BINARY,
+ COMPOUND_LEFT,
+ COMPOUND_RIGHT,
+ POSTFIX_INC,
+ PREFIX_DEC,
+ PREFIX_INC,
+ PREFIX_NOT,
+ SIMPLE_LEFT,
+ SIMPLE_RIGHT,
+ NONE
+ ];
+
+ final String name;
+
+ final int ordinal;
+
+ const _AssignmentKind(this.name, this.ordinal);
+
+ int get hashCode => ordinal;
+
+ int compareTo(_AssignmentKind other) => ordinal - other.ordinal;
+
+ String toString() => name;
+}
+
+class _WrapperKind {
+ static const _WrapperKind PREFIXED_LEFT =
+ const _WrapperKind('PREFIXED_LEFT', 0);
+
+ static const _WrapperKind PREFIXED_RIGHT =
+ const _WrapperKind('PREFIXED_RIGHT', 1);
+
+ static const _WrapperKind PROPERTY_LEFT =
+ const _WrapperKind('PROPERTY_LEFT', 2);
+
+ static const _WrapperKind PROPERTY_RIGHT =
+ const _WrapperKind('PROPERTY_RIGHT', 3);
+
+ static const _WrapperKind NONE = const _WrapperKind('NONE', 4);
+
+ static const List<_WrapperKind> values = const [
+ PREFIXED_LEFT,
+ PREFIXED_RIGHT,
+ PROPERTY_LEFT,
+ PROPERTY_RIGHT,
+ NONE
+ ];
+
+ final String name;
+
+ final int ordinal;
+
+ const _WrapperKind(this.name, this.ordinal);
+
+ int get hashCode => ordinal;
+
+ int compareTo(_WrapperKind other) => ordinal - other.ordinal;
+
+ String toString() => name;
+}
diff --git a/pkg/analyzer/test/dart/ast/test_all.dart b/pkg/analyzer/test/dart/ast/test_all.dart
new file mode 100644
index 0000000..64f8170
--- /dev/null
+++ b/pkg/analyzer/test/dart/ast/test_all.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.dart.ast.test_all;
+
+import 'package:unittest/unittest.dart';
+
+import '../../utils.dart';
+import 'ast_test.dart' as ast;
+import 'visitor_test.dart' as visitor;
+
+/// Utility for manually running all tests.
+main() {
+ initializeTestEnvironment();
+ group('ast tests', () {
+ ast.main();
+ visitor.main();
+ });
+}
diff --git a/pkg/analyzer/test/dart/ast/visitor_test.dart b/pkg/analyzer/test/dart/ast/visitor_test.dart
new file mode 100644
index 0000000..1645daa
--- /dev/null
+++ b/pkg/analyzer/test/dart/ast/visitor_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.dart.ast.visitor_test;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../generated/parser_test.dart' show ParserTestCase;
+import '../../generated/test_support.dart';
+import '../../reflective_tests.dart';
+import '../../utils.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(BreadthFirstVisitorTest);
+}
+
+@reflectiveTest
+class BreadthFirstVisitorTest extends ParserTestCase {
+ void test_it() {
+ String source = r'''
+class A {
+ bool get g => true;
+}
+class B {
+ int f() {
+ num q() {
+ return 3;
+ }
+ return q() + 4;
+ }
+}
+A f(var p) {
+ if ((p as A).g) {
+ return p;
+ } else {
+ return null;
+ }
+}''';
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(source);
+ List<AstNode> nodes = new List<AstNode>();
+ BreadthFirstVisitor<Object> visitor =
+ new _BreadthFirstVisitorTestHelper(nodes);
+ visitor.visitAllNodes(unit);
+ expect(nodes, hasLength(59));
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is CompilationUnit, CompilationUnit, nodes[0]);
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is ClassDeclaration, ClassDeclaration, nodes[2]);
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is FunctionDeclaration, FunctionDeclaration, nodes[3]);
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is FunctionDeclarationStatement,
+ FunctionDeclarationStatement,
+ nodes[27]);
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is IntegerLiteral, IntegerLiteral, nodes[58]);
+ //3
+ }
+}
+
+/**
+ * A helper class used to collect the nodes that were visited and to preserve
+ * the order in which they were visited.
+ */
+class _BreadthFirstVisitorTestHelper extends BreadthFirstVisitor<Object> {
+ List<AstNode> nodes;
+
+ _BreadthFirstVisitorTestHelper(this.nodes) : super();
+
+ @override
+ Object visitNode(AstNode node) {
+ nodes.add(node);
+ return super.visitNode(node);
+ }
+}
diff --git a/pkg/analyzer/test/dart/element/test_all.dart b/pkg/analyzer/test/dart/element/test_all.dart
index 392c06a..5dac037 100644
--- a/pkg/analyzer/test/dart/element/test_all.dart
+++ b/pkg/analyzer/test/dart/element/test_all.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.
-library analyzer.test.generated.test_all;
+library analyzer.test.dart.element.test_all;
import 'package:unittest/unittest.dart';
@@ -12,7 +12,7 @@
/// Utility for manually running all tests.
main() {
initializeTestEnvironment();
- group('generated tests', () {
+ group('element tests', () {
element.main();
});
}
diff --git a/pkg/analyzer/test/dart/test_all.dart b/pkg/analyzer/test/dart/test_all.dart
index 669b706..df7ff55 100644
--- a/pkg/analyzer/test/dart/test_all.dart
+++ b/pkg/analyzer/test/dart/test_all.dart
@@ -7,12 +7,14 @@
import 'package:unittest/unittest.dart';
import '../utils.dart';
+import 'ast/test_all.dart' as ast;
import 'element/test_all.dart' as element;
/// Utility for manually running all tests.
main() {
initializeTestEnvironment();
group('dart tests', () {
+ ast.main();
element.main();
});
}
diff --git a/pkg/analyzer/test/enum_test.dart b/pkg/analyzer/test/enum_test.dart
index 625cf40..a61765d 100644
--- a/pkg/analyzer/test/enum_test.dart
+++ b/pkg/analyzer/test/enum_test.dart
@@ -7,6 +7,7 @@
import 'dart:mirrors';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -15,7 +16,6 @@
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:unittest/unittest.dart';
-import 'generated/ast_test.dart';
import 'reflective_tests.dart';
import 'utils.dart';
@@ -32,12 +32,6 @@
..check_explicit_values();
}
- void test_AssignmentKind() {
- new EnumTester<AssignmentKind>()
- ..check_getters()
- ..check_explicit_values();
- }
-
void test_CacheState() {
new EnumTester<CacheState>()
..check_getters()
@@ -103,12 +97,6 @@
..check_getters()
..check_explicit_values();
}
-
- void test_WrapperKind() {
- new EnumTester<WrapperKind>()
- ..check_getters()
- ..check_explicit_values();
- }
}
/**
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index f8ca1dc..34b9797 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -4,11 +4,12 @@
library analyzer.test.generated.all_the_rest_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart' hide ConstantEvaluator;
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -25,26 +26,19 @@
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
-import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/task/dart.dart';
import 'package:path/path.dart';
import 'package:source_span/source_span.dart';
import 'package:unittest/unittest.dart';
import '../reflective_tests.dart';
import '../utils.dart';
-import 'engine_test.dart';
import 'parser_test.dart';
import 'resolver_test.dart';
import 'test_support.dart';
main() {
initializeTestEnvironment();
- runReflectiveTests(ConstantEvaluatorTest);
- runReflectiveTests(ConstantFinderTest);
- runReflectiveTests(ConstantValueComputerTest);
- runReflectiveTests(ConstantVisitorTest);
runReflectiveTests(ContentCacheTest);
runReflectiveTests(CustomUriResolverTest);
runReflectiveTests(DartObjectImplTest);
@@ -61,2120 +55,10 @@
runReflectiveTests(ExitDetectorTest2);
runReflectiveTests(FileBasedSourceTest);
runReflectiveTests(FileUriResolverTest);
- runReflectiveTests(ReferenceFinderTest);
runReflectiveTests(SDKLibrariesReaderTest);
runReflectiveTests(UriKindTest);
}
-/**
- * Implementation of [ConstantEvaluationValidator] used during unit tests;
- * verifies that any nodes referenced during constant evaluation are present in
- * the dependency graph.
- */
-class ConstantEvaluationValidator_ForTest
- implements ConstantEvaluationValidator {
- ConstantValueComputer computer;
-
- ConstantEvaluationTarget _nodeBeingEvaluated;
-
- @override
- void beforeComputeValue(ConstantEvaluationTarget constant) {
- _nodeBeingEvaluated = constant;
- }
-
- @override
- void beforeGetConstantInitializers(ConstructorElement constructor) {
- // Make sure we properly recorded the dependency.
- expect(
- computer.referenceGraph.containsPath(_nodeBeingEvaluated, constructor),
- isTrue);
- }
-
- @override
- void beforeGetEvaluationResult(ConstantEvaluationTarget constant) {
- // Make sure we properly recorded the dependency.
- expect(computer.referenceGraph.containsPath(_nodeBeingEvaluated, constant),
- isTrue);
- }
-
- @override
- void beforeGetFieldEvaluationResult(FieldElementImpl field) {
- // Make sure we properly recorded the dependency.
- expect(computer.referenceGraph.containsPath(_nodeBeingEvaluated, field),
- isTrue);
- }
-
- @override
- void beforeGetParameterDefault(ParameterElement parameter) {
- // Make sure we properly recorded the dependency.
- expect(computer.referenceGraph.containsPath(_nodeBeingEvaluated, parameter),
- isTrue);
- }
-}
-
-@reflectiveTest
-class ConstantEvaluatorTest extends ResolverTestCase {
- void fail_constructor() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_identifier_class() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_identifier_function() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_identifier_static() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_identifier_staticMethod() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_identifier_topLevel() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_identifier_typeParameter() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_prefixedIdentifier_invalid() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_prefixedIdentifier_valid() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_propertyAccess_invalid() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_propertyAccess_valid() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_simpleIdentifier_invalid() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void fail_simpleIdentifier_valid() {
- EvaluationResult result = _getExpressionValue("?");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value, null);
- }
-
- void test_bitAnd_int_int() {
- _assertValue3(74 & 42, "74 & 42");
- }
-
- void test_bitNot() {
- _assertValue3(~42, "~42");
- }
-
- void test_bitOr_int_int() {
- _assertValue3(74 | 42, "74 | 42");
- }
-
- void test_bitXor_int_int() {
- _assertValue3(74 ^ 42, "74 ^ 42");
- }
-
- void test_divide_double_double() {
- _assertValue2(3.2 / 2.3, "3.2 / 2.3");
- }
-
- void test_divide_double_double_byZero() {
- EvaluationResult result = _getExpressionValue("3.2 / 0.0");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value.type.name, "double");
- expect(value.toDoubleValue().isInfinite, isTrue);
- }
-
- void test_divide_int_int() {
- _assertValue2(1.5, "3 / 2");
- }
-
- void test_divide_int_int_byZero() {
- EvaluationResult result = _getExpressionValue("3 / 0");
- expect(result.isValid, isTrue);
- }
-
- void test_equal_boolean_boolean() {
- _assertValue(false, "true == false");
- }
-
- void test_equal_int_int() {
- _assertValue(false, "2 == 3");
- }
-
- void test_equal_invalidLeft() {
- EvaluationResult result = _getExpressionValue("a == 3");
- expect(result.isValid, isFalse);
- }
-
- void test_equal_invalidRight() {
- EvaluationResult result = _getExpressionValue("2 == a");
- expect(result.isValid, isFalse);
- }
-
- void test_equal_string_string() {
- _assertValue(false, "'a' == 'b'");
- }
-
- void test_greaterThan_int_int() {
- _assertValue(false, "2 > 3");
- }
-
- void test_greaterThanOrEqual_int_int() {
- _assertValue(false, "2 >= 3");
- }
-
- void test_leftShift_int_int() {
- _assertValue3(64, "16 << 2");
- }
-
- void test_lessThan_int_int() {
- _assertValue(true, "2 < 3");
- }
-
- void test_lessThanOrEqual_int_int() {
- _assertValue(true, "2 <= 3");
- }
-
- void test_literal_boolean_false() {
- _assertValue(false, "false");
- }
-
- void test_literal_boolean_true() {
- _assertValue(true, "true");
- }
-
- void test_literal_list() {
- EvaluationResult result = _getExpressionValue("const ['a', 'b', 'c']");
- expect(result.isValid, isTrue);
- }
-
- void test_literal_map() {
- EvaluationResult result =
- _getExpressionValue("const {'a' : 'm', 'b' : 'n', 'c' : 'o'}");
- expect(result.isValid, isTrue);
- }
-
- void test_literal_null() {
- EvaluationResult result = _getExpressionValue("null");
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value.isNull, isTrue);
- }
-
- void test_literal_number_double() {
- _assertValue2(3.45, "3.45");
- }
-
- void test_literal_number_integer() {
- _assertValue3(42, "42");
- }
-
- void test_literal_string_adjacent() {
- _assertValue4("abcdef", "'abc' 'def'");
- }
-
- void test_literal_string_interpolation_invalid() {
- EvaluationResult result = _getExpressionValue("'a\${f()}c'");
- expect(result.isValid, isFalse);
- }
-
- void test_literal_string_interpolation_valid() {
- _assertValue4("a3c", "'a\${3}c'");
- }
-
- void test_literal_string_simple() {
- _assertValue4("abc", "'abc'");
- }
-
- void test_logicalAnd() {
- _assertValue(false, "true && false");
- }
-
- void test_logicalNot() {
- _assertValue(false, "!true");
- }
-
- void test_logicalOr() {
- _assertValue(true, "true || false");
- }
-
- void test_minus_double_double() {
- _assertValue2(3.2 - 2.3, "3.2 - 2.3");
- }
-
- void test_minus_int_int() {
- _assertValue3(1, "3 - 2");
- }
-
- void test_negated_boolean() {
- EvaluationResult result = _getExpressionValue("-true");
- expect(result.isValid, isFalse);
- }
-
- void test_negated_double() {
- _assertValue2(-42.3, "-42.3");
- }
-
- void test_negated_integer() {
- _assertValue3(-42, "-42");
- }
-
- void test_notEqual_boolean_boolean() {
- _assertValue(true, "true != false");
- }
-
- void test_notEqual_int_int() {
- _assertValue(true, "2 != 3");
- }
-
- void test_notEqual_invalidLeft() {
- EvaluationResult result = _getExpressionValue("a != 3");
- expect(result.isValid, isFalse);
- }
-
- void test_notEqual_invalidRight() {
- EvaluationResult result = _getExpressionValue("2 != a");
- expect(result.isValid, isFalse);
- }
-
- void test_notEqual_string_string() {
- _assertValue(true, "'a' != 'b'");
- }
-
- void test_parenthesizedExpression() {
- _assertValue4("a", "('a')");
- }
-
- void test_plus_double_double() {
- _assertValue2(2.3 + 3.2, "2.3 + 3.2");
- }
-
- void test_plus_int_int() {
- _assertValue3(5, "2 + 3");
- }
-
- void test_plus_string_string() {
- _assertValue4("ab", "'a' + 'b'");
- }
-
- void test_remainder_double_double() {
- _assertValue2(3.2 % 2.3, "3.2 % 2.3");
- }
-
- void test_remainder_int_int() {
- _assertValue3(2, "8 % 3");
- }
-
- void test_rightShift() {
- _assertValue3(16, "64 >> 2");
- }
-
- void test_stringLength_complex() {
- _assertValue3(6, "('qwe' + 'rty').length");
- }
-
- void test_stringLength_simple() {
- _assertValue3(6, "'Dvorak'.length");
- }
-
- void test_times_double_double() {
- _assertValue2(2.3 * 3.2, "2.3 * 3.2");
- }
-
- void test_times_int_int() {
- _assertValue3(6, "2 * 3");
- }
-
- void test_truncatingDivide_double_double() {
- _assertValue3(1, "3.2 ~/ 2.3");
- }
-
- void test_truncatingDivide_int_int() {
- _assertValue3(3, "10 ~/ 3");
- }
-
- void _assertValue(bool expectedValue, String contents) {
- EvaluationResult result = _getExpressionValue(contents);
- DartObject value = result.value;
- expect(value.type.name, "bool");
- expect(value.toBoolValue(), expectedValue);
- }
-
- void _assertValue2(double expectedValue, String contents) {
- EvaluationResult result = _getExpressionValue(contents);
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value.type.name, "double");
- expect(value.toDoubleValue(), expectedValue);
- }
-
- void _assertValue3(int expectedValue, String contents) {
- EvaluationResult result = _getExpressionValue(contents);
- expect(result.isValid, isTrue);
- DartObject value = result.value;
- expect(value.type.name, "int");
- expect(value.toIntValue(), expectedValue);
- }
-
- void _assertValue4(String expectedValue, String contents) {
- EvaluationResult result = _getExpressionValue(contents);
- DartObject value = result.value;
- expect(value, isNotNull);
- ParameterizedType type = value.type;
- expect(type, isNotNull);
- expect(type.name, "String");
- expect(value.toStringValue(), expectedValue);
- }
-
- EvaluationResult _getExpressionValue(String contents) {
- Source source = addSource("var x = $contents;");
- LibraryElement library = resolve2(source);
- CompilationUnit unit =
- analysisContext.resolveCompilationUnit(source, library);
- expect(unit, isNotNull);
- NodeList<CompilationUnitMember> declarations = unit.declarations;
- expect(declarations, hasLength(1));
- CompilationUnitMember declaration = declarations[0];
- EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableDeclaration,
- TopLevelVariableDeclaration, declaration);
- NodeList<VariableDeclaration> variables =
- (declaration as TopLevelVariableDeclaration).variables.variables;
- expect(variables, hasLength(1));
- ConstantEvaluator evaluator = new ConstantEvaluator(
- source, analysisContext.typeProvider,
- typeSystem: analysisContext.typeSystem);
- return evaluator.evaluate(variables[0].initializer);
- }
-}
-
-@reflectiveTest
-class ConstantFinderTest {
- AstNode _node;
- TypeProvider _typeProvider;
- AnalysisContext _context;
- Source _source;
-
- void setUp() {
- _typeProvider = new TestTypeProvider();
- _context = new TestAnalysisContext_ConstantFinderTest();
- _source = new TestSource();
- }
-
- /**
- * Test an annotation that consists solely of an identifier (and hence
- * represents a reference to a compile-time constant variable).
- */
- void test_visitAnnotation_constantVariable() {
- _node = AstFactory.annotation(AstFactory.identifier3('x'));
- expect(_findAnnotations(), contains(_node));
- }
-
- /**
- * Test an annotation that represents the invocation of a constant
- * constructor.
- */
- void test_visitAnnotation_invocation() {
- _node = AstFactory.annotation2(
- AstFactory.identifier3('A'), null, AstFactory.argumentList());
- expect(_findAnnotations(), contains(_node));
- }
-
- void test_visitConstructorDeclaration_const() {
- ConstructorElement element = _setupConstructorDeclaration("A", true);
- expect(_findConstants(), contains(element));
- }
-
- void test_visitConstructorDeclaration_nonConst() {
- _setupConstructorDeclaration("A", false);
- expect(_findConstants(), isEmpty);
- }
-
- void test_visitVariableDeclaration_const() {
- VariableElement element = _setupVariableDeclaration("v", true, true);
- expect(_findConstants(), contains(element));
- }
-
- void test_visitVariableDeclaration_final_inClass() {
- _setupFieldDeclaration('C', 'f', Keyword.FINAL);
- expect(_findConstants(), isEmpty);
- }
-
- void test_visitVariableDeclaration_final_inClassWithConstConstructor() {
- VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
- hasConstConstructor: true);
- expect(_findConstants(), contains(field.element));
- }
-
- void test_visitVariableDeclaration_final_outsideClass() {
- _setupVariableDeclaration('v', false, true, isFinal: true);
- expect(_findConstants(), isEmpty);
- }
-
- void test_visitVariableDeclaration_noInitializer() {
- _setupVariableDeclaration("v", true, false);
- expect(_findConstants(), isEmpty);
- }
-
- void test_visitVariableDeclaration_nonConst() {
- _setupVariableDeclaration("v", false, true);
- expect(_findConstants(), isEmpty);
- }
-
- void test_visitVariableDeclaration_static_const_inClass() {
- VariableDeclaration field =
- _setupFieldDeclaration('C', 'f', Keyword.CONST, isStatic: true);
- expect(_findConstants(), contains(field.element));
- }
-
- void test_visitVariableDeclaration_static_const_inClassWithConstConstructor() {
- VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.CONST,
- isStatic: true, hasConstConstructor: true);
- expect(_findConstants(), contains(field.element));
- }
-
- void test_visitVariableDeclaration_static_final_inClassWithConstConstructor() {
- VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
- isStatic: true, hasConstConstructor: true);
- expect(_findConstants(), isNot(contains(field.element)));
- }
-
- void test_visitVariableDeclaration_uninitialized_final_inClassWithConstConstructor() {
- VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
- isInitialized: false, hasConstConstructor: true);
- expect(_findConstants(), isNot(contains(field.element)));
- }
-
- void test_visitVariableDeclaration_uninitialized_static_const_inClass() {
- _setupFieldDeclaration('C', 'f', Keyword.CONST,
- isStatic: true, isInitialized: false);
- expect(_findConstants(), isEmpty);
- }
-
- List<Annotation> _findAnnotations() {
- Set<Annotation> annotations = new Set<Annotation>();
- for (ConstantEvaluationTarget target in _findConstants()) {
- if (target is ConstantEvaluationTarget_Annotation) {
- expect(target.context, same(_context));
- expect(target.source, same(_source));
- annotations.add(target.annotation);
- }
- }
- return new List<Annotation>.from(annotations);
- }
-
- Set<ConstantEvaluationTarget> _findConstants() {
- ConstantFinder finder = new ConstantFinder(_context, _source, _source);
- _node.accept(finder);
- Set<ConstantEvaluationTarget> constants = finder.constantsToCompute;
- expect(constants, isNotNull);
- return constants;
- }
-
- ConstructorElement _setupConstructorDeclaration(String name, bool isConst) {
- Keyword constKeyword = isConst ? Keyword.CONST : null;
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration2(
- constKeyword,
- null,
- null,
- name,
- AstFactory.formalParameterList(),
- null,
- AstFactory.blockFunctionBody2());
- ClassElement classElement = ElementFactory.classElement2(name);
- ConstructorElement element =
- ElementFactory.constructorElement(classElement, name, isConst);
- constructorDeclaration.element = element;
- _node = constructorDeclaration;
- return element;
- }
-
- VariableDeclaration _setupFieldDeclaration(
- String className, String fieldName, Keyword keyword,
- {bool isInitialized: true,
- bool isStatic: false,
- bool hasConstConstructor: false}) {
- VariableDeclaration variableDeclaration = isInitialized
- ? AstFactory.variableDeclaration2(fieldName, AstFactory.integer(0))
- : AstFactory.variableDeclaration(fieldName);
- VariableElement fieldElement = ElementFactory.fieldElement(
- fieldName,
- isStatic,
- keyword == Keyword.FINAL,
- keyword == Keyword.CONST,
- _typeProvider.intType);
- variableDeclaration.name.staticElement = fieldElement;
- FieldDeclaration fieldDeclaration = AstFactory.fieldDeclaration2(
- isStatic, keyword, <VariableDeclaration>[variableDeclaration]);
- ClassDeclaration classDeclaration =
- AstFactory.classDeclaration(null, className, null, null, null, null);
- classDeclaration.members.add(fieldDeclaration);
- _node = classDeclaration;
- ClassElementImpl classElement = ElementFactory.classElement2(className);
- classElement.fields = <FieldElement>[fieldElement];
- classDeclaration.name.staticElement = classElement;
- if (hasConstConstructor) {
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration2(
- Keyword.CONST,
- null,
- AstFactory.identifier3(className),
- null,
- AstFactory.formalParameterList(),
- null,
- AstFactory.blockFunctionBody2());
- classDeclaration.members.add(constructorDeclaration);
- ConstructorElement constructorElement =
- ElementFactory.constructorElement(classElement, '', true);
- constructorDeclaration.element = constructorElement;
- classElement.constructors = <ConstructorElement>[constructorElement];
- } else {
- classElement.constructors = ConstructorElement.EMPTY_LIST;
- }
- return variableDeclaration;
- }
-
- VariableElement _setupVariableDeclaration(
- String name, bool isConst, bool isInitialized,
- {isFinal: false}) {
- VariableDeclaration variableDeclaration = isInitialized
- ? AstFactory.variableDeclaration2(name, AstFactory.integer(0))
- : AstFactory.variableDeclaration(name);
- SimpleIdentifier identifier = variableDeclaration.name;
- VariableElement element = ElementFactory.localVariableElement(identifier);
- identifier.staticElement = element;
- Keyword keyword = isConst ? Keyword.CONST : isFinal ? Keyword.FINAL : null;
- AstFactory.variableDeclarationList2(keyword, [variableDeclaration]);
- _node = variableDeclaration;
- return element;
- }
-}
-
-@reflectiveTest
-class ConstantValueComputerTest extends ResolverTestCase {
- void test_annotation_constConstructor() {
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- final int i;
- const A(this.i);
-}
-
-class C {
- @A(5)
- f() {}
-}
-''');
- EvaluationResultImpl result =
- _evaluateAnnotation(compilationUnit, "C", "f");
- Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
- _assertIntField(annotationFields, 'i', 5);
- }
-
- void test_annotation_constConstructor_named() {
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- final int i;
- const A.named(this.i);
-}
-
-class C {
- @A.named(5)
- f() {}
-}
-''');
- EvaluationResultImpl result =
- _evaluateAnnotation(compilationUnit, "C", "f");
- Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
- _assertIntField(annotationFields, 'i', 5);
- }
-
- void test_annotation_constConstructor_noArgs() {
- // Failing to pass arguments to an annotation which is a constant
- // constructor is illegal, but shouldn't crash analysis.
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- final int i;
- const A(this.i);
-}
-
-class C {
- @A
- f() {}
-}
-''');
- _evaluateAnnotation(compilationUnit, "C", "f");
- }
-
- void test_annotation_constConstructor_noArgs_named() {
- // Failing to pass arguments to an annotation which is a constant
- // constructor is illegal, but shouldn't crash analysis.
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- final int i;
- const A.named(this.i);
-}
-
-class C {
- @A.named
- f() {}
-}
-''');
- _evaluateAnnotation(compilationUnit, "C", "f");
- }
-
- void test_annotation_nonConstConstructor() {
- // Calling a non-const constructor from an annotation that is illegal, but
- // shouldn't crash analysis.
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- final int i;
- A(this.i);
-}
-
-class C {
- @A(5)
- f() {}
-}
-''');
- _evaluateAnnotation(compilationUnit, "C", "f");
- }
-
- void test_annotation_staticConst() {
- CompilationUnit compilationUnit = resolveSource(r'''
-class C {
- static const int i = 5;
-
- @i
- f() {}
-}
-''');
- EvaluationResultImpl result =
- _evaluateAnnotation(compilationUnit, "C", "f");
- expect(_assertValidInt(result), 5);
- }
-
- void test_annotation_staticConst_args() {
- // Applying arguments to an annotation that is a static const is
- // illegal, but shouldn't crash analysis.
- CompilationUnit compilationUnit = resolveSource(r'''
-class C {
- static const int i = 5;
-
- @i(1)
- f() {}
-}
-''');
- _evaluateAnnotation(compilationUnit, "C", "f");
- }
-
- void test_annotation_staticConst_otherClass() {
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- static const int i = 5;
-}
-
-class C {
- @A.i
- f() {}
-}
-''');
- EvaluationResultImpl result =
- _evaluateAnnotation(compilationUnit, "C", "f");
- expect(_assertValidInt(result), 5);
- }
-
- void test_annotation_staticConst_otherClass_args() {
- // Applying arguments to an annotation that is a static const is
- // illegal, but shouldn't crash analysis.
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- static const int i = 5;
-}
-
-class C {
- @A.i(1)
- f() {}
-}
-''');
- _evaluateAnnotation(compilationUnit, "C", "f");
- }
-
- void test_annotation_toplevelVariable() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const int i = 5;
-class C {
- @i
- f() {}
-}
-''');
- EvaluationResultImpl result =
- _evaluateAnnotation(compilationUnit, "C", "f");
- expect(_assertValidInt(result), 5);
- }
-
- void test_annotation_toplevelVariable_args() {
- // Applying arguments to an annotation that is a toplevel variable is
- // illegal, but shouldn't crash analysis.
- CompilationUnit compilationUnit = resolveSource(r'''
-const int i = 5;
-class C {
- @i(1)
- f() {}
-}
-''');
- _evaluateAnnotation(compilationUnit, "C", "f");
- }
-
- void test_computeValues_cycle() {
- TestLogger logger = new TestLogger();
- AnalysisEngine.instance.logger = logger;
- try {
- Source librarySource = addSource(r'''
- const int a = c;
- const int b = a;
- const int c = b;''');
- LibraryElement libraryElement = resolve2(librarySource);
- CompilationUnit unit =
- analysisContext.resolveCompilationUnit(librarySource, libraryElement);
- analysisContext.computeErrors(librarySource);
- expect(unit, isNotNull);
- ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, librarySource, librarySource);
- computer.computeValues();
- NodeList<CompilationUnitMember> members = unit.declarations;
- expect(members, hasLength(3));
- _validate(false, (members[0] as TopLevelVariableDeclaration).variables);
- _validate(false, (members[1] as TopLevelVariableDeclaration).variables);
- _validate(false, (members[2] as TopLevelVariableDeclaration).variables);
- } finally {
- AnalysisEngine.instance.logger = Logger.NULL;
- }
- }
-
- void test_computeValues_dependentVariables() {
- Source librarySource = addSource(r'''
-const int b = a;
-const int a = 0;''');
- LibraryElement libraryElement = resolve2(librarySource);
- CompilationUnit unit =
- analysisContext.resolveCompilationUnit(librarySource, libraryElement);
- expect(unit, isNotNull);
- ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, librarySource, librarySource);
- computer.computeValues();
- NodeList<CompilationUnitMember> members = unit.declarations;
- expect(members, hasLength(2));
- _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
- _validate(true, (members[1] as TopLevelVariableDeclaration).variables);
- }
-
- void test_computeValues_empty() {
- ConstantValueComputer computer = _makeConstantValueComputer();
- computer.computeValues();
- }
-
- void test_computeValues_multipleSources() {
- Source librarySource = addNamedSource(
- "/lib.dart",
- r'''
-library lib;
-part 'part.dart';
-const int c = b;
-const int a = 0;''');
- Source partSource = addNamedSource(
- "/part.dart",
- r'''
-part of lib;
-const int b = a;
-const int d = c;''');
- LibraryElement libraryElement = resolve2(librarySource);
- CompilationUnit libraryUnit =
- analysisContext.resolveCompilationUnit(librarySource, libraryElement);
- expect(libraryUnit, isNotNull);
- CompilationUnit partUnit =
- analysisContext.resolveCompilationUnit(partSource, libraryElement);
- expect(partUnit, isNotNull);
- ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(libraryUnit, librarySource, librarySource);
- computer.add(partUnit, partSource, librarySource);
- computer.computeValues();
- NodeList<CompilationUnitMember> libraryMembers = libraryUnit.declarations;
- expect(libraryMembers, hasLength(2));
- _validate(
- true, (libraryMembers[0] as TopLevelVariableDeclaration).variables);
- _validate(
- true, (libraryMembers[1] as TopLevelVariableDeclaration).variables);
- NodeList<CompilationUnitMember> partMembers = libraryUnit.declarations;
- expect(partMembers, hasLength(2));
- _validate(true, (partMembers[0] as TopLevelVariableDeclaration).variables);
- _validate(true, (partMembers[1] as TopLevelVariableDeclaration).variables);
- }
-
- void test_computeValues_singleVariable() {
- Source librarySource = addSource("const int a = 0;");
- LibraryElement libraryElement = resolve2(librarySource);
- CompilationUnit unit =
- analysisContext.resolveCompilationUnit(librarySource, libraryElement);
- expect(unit, isNotNull);
- ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, librarySource, librarySource);
- computer.computeValues();
- NodeList<CompilationUnitMember> members = unit.declarations;
- expect(members, hasLength(1));
- _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
- }
-
- void test_computeValues_value_depends_on_enum() {
- Source librarySource = addSource('''
-enum E { id0, id1 }
-const E e = E.id0;
-''');
- LibraryElement libraryElement = resolve2(librarySource);
- CompilationUnit unit =
- analysisContext.resolveCompilationUnit(librarySource, libraryElement);
- expect(unit, isNotNull);
- ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, librarySource, librarySource);
- computer.computeValues();
- TopLevelVariableDeclaration declaration = unit.declarations
- .firstWhere((member) => member is TopLevelVariableDeclaration);
- _validate(true, declaration.variables);
- }
-
- void test_dependencyOnConstructor() {
- // x depends on "const A()"
- _assertProperDependencies(r'''
-class A {
- const A();
-}
-const x = const A();''');
- }
-
- void test_dependencyOnConstructorArgument() {
- // "const A(x)" depends on x
- _assertProperDependencies(r'''
-class A {
- const A(this.next);
- final A next;
-}
-const A x = const A(null);
-const A y = const A(x);''');
- }
-
- void test_dependencyOnConstructorArgument_unresolvedConstructor() {
- // "const A.a(x)" depends on x even if the constructor A.a can't be found.
- _assertProperDependencies(
- r'''
-class A {
-}
-const int x = 1;
-const A y = const A.a(x);''',
- [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR]);
- }
-
- void test_dependencyOnConstructorInitializer() {
- // "const A()" depends on x
- _assertProperDependencies(r'''
-const int x = 1;
-class A {
- const A() : v = x;
- final int v;
-}''');
- }
-
- void test_dependencyOnExplicitSuperConstructor() {
- // b depends on B() depends on A()
- _assertProperDependencies(r'''
-class A {
- const A(this.x);
- final int x;
-}
-class B extends A {
- const B() : super(5);
-}
-const B b = const B();''');
- }
-
- void test_dependencyOnExplicitSuperConstructorParameters() {
- // b depends on B() depends on i
- _assertProperDependencies(r'''
-class A {
- const A(this.x);
- final int x;
-}
-class B extends A {
- const B() : super(i);
-}
-const B b = const B();
-const int i = 5;''');
- }
-
- void test_dependencyOnFactoryRedirect() {
- // a depends on A.foo() depends on A.bar()
- _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
- factory const A.foo() = A.bar;
- const A.bar();
-}''');
- }
-
- void test_dependencyOnFactoryRedirectWithTypeParams() {
- _assertProperDependencies(r'''
-class A {
- const factory A(var a) = B<int>;
-}
-
-class B<T> implements A {
- final T x;
- const B(this.x);
-}
-
-const A a = const A(10);''');
- }
-
- void test_dependencyOnImplicitSuperConstructor() {
- // b depends on B() depends on A()
- _assertProperDependencies(r'''
-class A {
- const A() : x = 5;
- final int x;
-}
-class B extends A {
- const B();
-}
-const B b = const B();''');
- }
-
- void test_dependencyOnInitializedFinal() {
- // a depends on A() depends on A.x
- _assertProperDependencies('''
-class A {
- const A();
- final int x = 1;
-}
-const A a = const A();
-''');
- }
-
- void test_dependencyOnInitializedNonStaticConst() {
- // Even though non-static consts are not allowed by the language, we need
- // to handle them for error recovery purposes.
- // a depends on A() depends on A.x
- _assertProperDependencies(
- '''
-class A {
- const A();
- const int x = 1;
-}
-const A a = const A();
-''',
- [CompileTimeErrorCode.CONST_INSTANCE_FIELD]);
- }
-
- void test_dependencyOnNonFactoryRedirect() {
- // a depends on A.foo() depends on A.bar()
- _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
- const A.foo() : this.bar();
- const A.bar();
-}''');
- }
-
- void test_dependencyOnNonFactoryRedirect_arg() {
- // a depends on A.foo() depends on b
- _assertProperDependencies(r'''
-const A a = const A.foo();
-const int b = 1;
-class A {
- const A.foo() : this.bar(b);
- const A.bar(x) : y = x;
- final int y;
-}''');
- }
-
- void test_dependencyOnNonFactoryRedirect_defaultValue() {
- // a depends on A.foo() depends on A.bar() depends on b
- _assertProperDependencies(r'''
-const A a = const A.foo();
-const int b = 1;
-class A {
- const A.foo() : this.bar();
- const A.bar([x = b]) : y = x;
- final int y;
-}''');
- }
-
- void test_dependencyOnNonFactoryRedirect_toMissing() {
- // a depends on A.foo() which depends on nothing, since A.bar() is
- // missing.
- _assertProperDependencies(
- r'''
-const A a = const A.foo();
-class A {
- const A.foo() : this.bar();
-}''',
- [CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR]);
- }
-
- void test_dependencyOnNonFactoryRedirect_toNonConst() {
- // a depends on A.foo() which depends on nothing, since A.bar() is
- // non-const.
- _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
- const A.foo() : this.bar();
- A.bar();
-}''');
- }
-
- void test_dependencyOnNonFactoryRedirect_unnamed() {
- // a depends on A.foo() depends on A()
- _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
- const A.foo() : this();
- const A();
-}''');
- }
-
- void test_dependencyOnOptionalParameterDefault() {
- // a depends on A() depends on B()
- _assertProperDependencies(r'''
-class A {
- const A([x = const B()]) : b = x;
- final B b;
-}
-class B {
- const B();
-}
-const A a = const A();''');
- }
-
- void test_dependencyOnVariable() {
- // x depends on y
- _assertProperDependencies(r'''
-const x = y + 1;
-const y = 2;''');
- }
-
- void test_final_initialized_at_declaration() {
- CompilationUnit compilationUnit = resolveSource('''
-class A {
- final int i = 123;
- const A();
-}
-
-const A a = const A();
-''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, 'a');
- Map<String, DartObjectImpl> fields = _assertType(result, "A");
- expect(fields, hasLength(1));
- _assertIntField(fields, "i", 123);
- }
-
- void test_fromEnvironment_bool_default_false() {
- expect(_assertValidBool(_check_fromEnvironment_bool(null, "false")), false);
- }
-
- void test_fromEnvironment_bool_default_overridden() {
- expect(
- _assertValidBool(_check_fromEnvironment_bool("false", "true")), false);
- }
-
- void test_fromEnvironment_bool_default_parseError() {
- expect(_assertValidBool(_check_fromEnvironment_bool("parseError", "true")),
- true);
- }
-
- void test_fromEnvironment_bool_default_true() {
- expect(_assertValidBool(_check_fromEnvironment_bool(null, "true")), true);
- }
-
- void test_fromEnvironment_bool_false() {
- expect(_assertValidBool(_check_fromEnvironment_bool("false", null)), false);
- }
-
- void test_fromEnvironment_bool_parseError() {
- expect(_assertValidBool(_check_fromEnvironment_bool("parseError", null)),
- false);
- }
-
- void test_fromEnvironment_bool_true() {
- expect(_assertValidBool(_check_fromEnvironment_bool("true", null)), true);
- }
-
- void test_fromEnvironment_bool_undeclared() {
- _assertValidUnknown(_check_fromEnvironment_bool(null, null));
- }
-
- void test_fromEnvironment_int_default_overridden() {
- expect(_assertValidInt(_check_fromEnvironment_int("234", "123")), 234);
- }
-
- void test_fromEnvironment_int_default_parseError() {
- expect(
- _assertValidInt(_check_fromEnvironment_int("parseError", "123")), 123);
- }
-
- void test_fromEnvironment_int_default_undeclared() {
- expect(_assertValidInt(_check_fromEnvironment_int(null, "123")), 123);
- }
-
- void test_fromEnvironment_int_ok() {
- expect(_assertValidInt(_check_fromEnvironment_int("234", null)), 234);
- }
-
- void test_fromEnvironment_int_parseError() {
- _assertValidNull(_check_fromEnvironment_int("parseError", null));
- }
-
- void test_fromEnvironment_int_parseError_nullDefault() {
- _assertValidNull(_check_fromEnvironment_int("parseError", "null"));
- }
-
- void test_fromEnvironment_int_undeclared() {
- _assertValidUnknown(_check_fromEnvironment_int(null, null));
- }
-
- void test_fromEnvironment_int_undeclared_nullDefault() {
- _assertValidNull(_check_fromEnvironment_int(null, "null"));
- }
-
- void test_fromEnvironment_string_default_overridden() {
- expect(_assertValidString(_check_fromEnvironment_string("abc", "'def'")),
- "abc");
- }
-
- void test_fromEnvironment_string_default_undeclared() {
- expect(_assertValidString(_check_fromEnvironment_string(null, "'def'")),
- "def");
- }
-
- void test_fromEnvironment_string_empty() {
- expect(_assertValidString(_check_fromEnvironment_string("", null)), "");
- }
-
- void test_fromEnvironment_string_ok() {
- expect(
- _assertValidString(_check_fromEnvironment_string("abc", null)), "abc");
- }
-
- void test_fromEnvironment_string_undeclared() {
- _assertValidUnknown(_check_fromEnvironment_string(null, null));
- }
-
- void test_fromEnvironment_string_undeclared_nullDefault() {
- _assertValidNull(_check_fromEnvironment_string(null, "null"));
- }
-
- void test_instanceCreationExpression_computedField() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(4, 5);
-class A {
- const A(int i, int j) : k = 2 * i + j;
- final int k;
-}''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- Map<String, DartObjectImpl> fields = _assertType(result, "A");
- expect(fields, hasLength(1));
- _assertIntField(fields, "k", 13);
- }
-
- void test_instanceCreationExpression_computedField_namedOptionalWithDefault() {
- _checkInstanceCreationOptionalParams(false, true, true);
- }
-
- void test_instanceCreationExpression_computedField_namedOptionalWithoutDefault() {
- _checkInstanceCreationOptionalParams(false, true, false);
- }
-
- void test_instanceCreationExpression_computedField_unnamedOptionalWithDefault() {
- _checkInstanceCreationOptionalParams(false, false, true);
- }
-
- void test_instanceCreationExpression_computedField_unnamedOptionalWithoutDefault() {
- _checkInstanceCreationOptionalParams(false, false, false);
- }
-
- void test_instanceCreationExpression_computedField_usesConstConstructor() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(3);
-class A {
- const A(int i) : b = const B(4);
- final int b;
-}
-class B {
- const B(this.k);
- final int k;
-}''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- Map<String, DartObjectImpl> fieldsOfA = _assertType(result, "A");
- expect(fieldsOfA, hasLength(1));
- Map<String, DartObjectImpl> fieldsOfB =
- _assertFieldType(fieldsOfA, "b", "B");
- expect(fieldsOfB, hasLength(1));
- _assertIntField(fieldsOfB, "k", 4);
- }
-
- void test_instanceCreationExpression_computedField_usesStaticConst() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(3);
-class A {
- const A(int i) : k = i + B.bar;
- final int k;
-}
-class B {
- static const bar = 4;
-}''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- Map<String, DartObjectImpl> fields = _assertType(result, "A");
- expect(fields, hasLength(1));
- _assertIntField(fields, "k", 7);
- }
-
- void test_instanceCreationExpression_computedField_usesToplevelConst() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(3);
-const bar = 4;
-class A {
- const A(int i) : k = i + bar;
- final int k;
-}''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- Map<String, DartObjectImpl> fields = _assertType(result, "A");
- expect(fields, hasLength(1));
- _assertIntField(fields, "k", 7);
- }
-
- void test_instanceCreationExpression_explicitSuper() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const B(4, 5);
-class A {
- const A(this.x);
- final int x;
-}
-class B extends A {
- const B(int x, this.y) : super(x * 2);
- final int y;
-}''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- Map<String, DartObjectImpl> fields = _assertType(result, "B");
- expect(fields, hasLength(2));
- _assertIntField(fields, "y", 5);
- Map<String, DartObjectImpl> superclassFields =
- _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
- expect(superclassFields, hasLength(1));
- _assertIntField(superclassFields, "x", 8);
- }
-
- void test_instanceCreationExpression_fieldFormalParameter() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(42);
-class A {
- int x;
- const A(this.x)
-}''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- Map<String, DartObjectImpl> fields = _assertType(result, "A");
- expect(fields, hasLength(1));
- _assertIntField(fields, "x", 42);
- }
-
- void test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithDefault() {
- _checkInstanceCreationOptionalParams(true, true, true);
- }
-
- void test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithoutDefault() {
- _checkInstanceCreationOptionalParams(true, true, false);
- }
-
- void test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithDefault() {
- _checkInstanceCreationOptionalParams(true, false, true);
- }
-
- void test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithoutDefault() {
- _checkInstanceCreationOptionalParams(true, false, false);
- }
-
- void test_instanceCreationExpression_implicitSuper() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const B(4);
-class A {
- const A() : x = 3;
- final int x;
-}
-class B extends A {
- const B(this.y);
- final int y;
-}''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- Map<String, DartObjectImpl> fields = _assertType(result, "B");
- expect(fields, hasLength(2));
- _assertIntField(fields, "y", 4);
- Map<String, DartObjectImpl> superclassFields =
- _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
- expect(superclassFields, hasLength(1));
- _assertIntField(superclassFields, "x", 3);
- }
-
- void test_instanceCreationExpression_nonFactoryRedirect() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
- const A.a1() : this.a2();
- const A.a2() : x = 5;
- final int x;
-}''');
- Map<String, DartObjectImpl> aFields =
- _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
- _assertIntField(aFields, 'x', 5);
- }
-
- void test_instanceCreationExpression_nonFactoryRedirect_arg() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1(1);
-class A {
- const A.a1(x) : this.a2(x + 100);
- const A.a2(x) : y = x + 10;
- final int y;
-}''');
- Map<String, DartObjectImpl> aFields =
- _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
- _assertIntField(aFields, 'y', 111);
- }
-
- void test_instanceCreationExpression_nonFactoryRedirect_cycle() {
- // It is an error to have a cycle in non-factory redirects; however, we
- // need to make sure that even if the error occurs, attempting to evaluate
- // the constant will terminate.
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
- const A() : this.b();
- const A.b() : this();
-}''');
- _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
- }
-
- void test_instanceCreationExpression_nonFactoryRedirect_defaultArg() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
- const A.a1() : this.a2();
- const A.a2([x = 100]) : y = x + 10;
- final int y;
-}''');
- Map<String, DartObjectImpl> aFields =
- _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
- _assertIntField(aFields, 'y', 110);
- }
-
- void test_instanceCreationExpression_nonFactoryRedirect_toMissing() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
- const A.a1() : this.a2();
-}''');
- // We don't care what value foo evaluates to (since there is a compile
- // error), but we shouldn't crash, and we should figure
- // out that it evaluates to an instance of class A.
- _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
- }
-
- void test_instanceCreationExpression_nonFactoryRedirect_toNonConst() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
- const A.a1() : this.a2();
- A.a2();
-}''');
- // We don't care what value foo evaluates to (since there is a compile
- // error), but we shouldn't crash, and we should figure
- // out that it evaluates to an instance of class A.
- _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
- }
-
- void test_instanceCreationExpression_nonFactoryRedirect_unnamed() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
- const A.a1() : this();
- const A() : x = 5;
- final int x;
-}''');
- Map<String, DartObjectImpl> aFields =
- _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
- _assertIntField(aFields, 'x', 5);
- }
-
- void test_instanceCreationExpression_redirect() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
- const factory A() = B;
-}
-class B implements A {
- const B();
-}''');
- _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "B");
- }
-
- void test_instanceCreationExpression_redirect_cycle() {
- // It is an error to have a cycle in factory redirects; however, we need
- // to make sure that even if the error occurs, attempting to evaluate the
- // constant will terminate.
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
- const factory A() = A.b;
- const factory A.b() = A;
-}''');
- _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
- }
-
- void test_instanceCreationExpression_redirect_extern() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
- external const factory A();
-}''');
- _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
- }
-
- void test_instanceCreationExpression_redirect_nonConst() {
- // It is an error for a const factory constructor redirect to a non-const
- // constructor; however, we need to make sure that even if the error
- // attempting to evaluate the constant won't cause a crash.
- CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
- const factory A() = A.b;
- A.b();
-}''');
- _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
- }
-
- void test_instanceCreationExpression_redirectWithTypeParams() {
- CompilationUnit compilationUnit = resolveSource(r'''
-class A {
- const factory A(var a) = B<int>;
-}
-
-class B<T> implements A {
- final T x;
- const B(this.x);
-}
-
-const A a = const A(10);''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "a");
- Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
- expect(fields, hasLength(1));
- _assertIntField(fields, "x", 10);
- }
-
- void test_instanceCreationExpression_redirectWithTypeSubstitution() {
- // To evaluate the redirection of A<int>,
- // A's template argument (T=int) must be substituted
- // into B's template argument (B<U> where U=T) to get B<int>.
- CompilationUnit compilationUnit = resolveSource(r'''
-class A<T> {
- const factory A(var a) = B<T>;
-}
-
-class B<U> implements A {
- final U x;
- const B(this.x);
-}
-
-const A<int> a = const A<int>(10);''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, "a");
- Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
- expect(fields, hasLength(1));
- _assertIntField(fields, "x", 10);
- }
-
- void test_instanceCreationExpression_symbol() {
- CompilationUnit compilationUnit =
- resolveSource("const foo = const Symbol('a');");
- EvaluationResultImpl evaluationResult =
- _evaluateTopLevelVariable(compilationUnit, "foo");
- expect(evaluationResult.value, isNotNull);
- DartObjectImpl value = evaluationResult.value;
- expect(value.type, typeProvider.symbolType);
- expect(value.toSymbolValue(), "a");
- }
-
- void test_instanceCreationExpression_withSupertypeParams_explicit() {
- _checkInstanceCreation_withSupertypeParams(true);
- }
-
- void test_instanceCreationExpression_withSupertypeParams_implicit() {
- _checkInstanceCreation_withSupertypeParams(false);
- }
-
- void test_instanceCreationExpression_withTypeParams() {
- CompilationUnit compilationUnit = resolveSource(r'''
-class C<E> {
- const C();
-}
-const c_int = const C<int>();
-const c_num = const C<num>();''');
- EvaluationResultImpl c_int =
- _evaluateTopLevelVariable(compilationUnit, "c_int");
- _assertType(c_int, "C<int>");
- DartObjectImpl c_int_value = c_int.value;
- EvaluationResultImpl c_num =
- _evaluateTopLevelVariable(compilationUnit, "c_num");
- _assertType(c_num, "C<num>");
- DartObjectImpl c_num_value = c_num.value;
- expect(c_int_value == c_num_value, isFalse);
- }
-
- void test_isValidSymbol() {
- expect(ConstantEvaluationEngine.isValidPublicSymbol(""), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$bar"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("iff"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("gif"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("if\$"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("\$if"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo="), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar="), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.+"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("void"), isTrue);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo.bar"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo._bar"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("if"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("if.foo"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.if"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo=.bar"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo."), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("+.foo"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("void.foo"), isFalse);
- expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.void"), isFalse);
- }
-
- void test_length_of_improperly_typed_string_expression() {
- // Since type annotations are ignored in unchecked mode, the improper
- // types on s1 and s2 shouldn't prevent us from evaluating i to
- // 'alpha'.length.
- CompilationUnit compilationUnit = resolveSource('''
-const int s1 = 'alpha';
-const int s2 = 'beta';
-const int i = (true ? s1 : s2).length;
-''');
- ConstTopLevelVariableElementImpl element =
- findTopLevelDeclaration(compilationUnit, 'i').element;
- EvaluationResultImpl result = element.evaluationResult;
- expect(_assertValidInt(result), 5);
- }
-
- void test_length_of_improperly_typed_string_identifier() {
- // Since type annotations are ignored in unchecked mode, the improper type
- // on s shouldn't prevent us from evaluating i to 'alpha'.length.
- CompilationUnit compilationUnit = resolveSource('''
-const int s = 'alpha';
-const int i = s.length;
-''');
- ConstTopLevelVariableElementImpl element =
- findTopLevelDeclaration(compilationUnit, 'i').element;
- EvaluationResultImpl result = element.evaluationResult;
- expect(_assertValidInt(result), 5);
- }
-
- void test_non_static_const_initialized_at_declaration() {
- // Even though non-static consts are not allowed by the language, we need
- // to handle them for error recovery purposes.
- CompilationUnit compilationUnit = resolveSource('''
-class A {
- const int i = 123;
- const A();
-}
-
-const A a = const A();
-''');
- EvaluationResultImpl result =
- _evaluateTopLevelVariable(compilationUnit, 'a');
- Map<String, DartObjectImpl> fields = _assertType(result, "A");
- expect(fields, hasLength(1));
- _assertIntField(fields, "i", 123);
- }
-
- void test_symbolLiteral_void() {
- CompilationUnit compilationUnit =
- resolveSource("const voidSymbol = #void;");
- VariableDeclaration voidSymbol =
- findTopLevelDeclaration(compilationUnit, "voidSymbol");
- EvaluationResultImpl voidSymbolResult =
- (voidSymbol.element as VariableElementImpl).evaluationResult;
- DartObjectImpl value = voidSymbolResult.value;
- expect(value.type, typeProvider.symbolType);
- expect(value.toSymbolValue(), "void");
- }
-
- Map<String, DartObjectImpl> _assertFieldType(
- Map<String, DartObjectImpl> fields,
- String fieldName,
- String expectedType) {
- DartObjectImpl field = fields[fieldName];
- expect(field.type.displayName, expectedType);
- return field.fields;
- }
-
- void _assertIntField(
- Map<String, DartObjectImpl> fields, String fieldName, int expectedValue) {
- DartObjectImpl field = fields[fieldName];
- expect(field.type.name, "int");
- expect(field.toIntValue(), expectedValue);
- }
-
- void _assertNullField(Map<String, DartObjectImpl> fields, String fieldName) {
- DartObjectImpl field = fields[fieldName];
- expect(field.isNull, isTrue);
- }
-
- void _assertProperDependencies(String sourceText,
- [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
- Source source = addSource(sourceText);
- LibraryElement element = resolve2(source);
- CompilationUnit unit =
- analysisContext.resolveCompilationUnit(source, element);
- expect(unit, isNotNull);
- ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, source, source);
- computer.computeValues();
- assertErrors(source, expectedErrorCodes);
- }
-
- Map<String, DartObjectImpl> _assertType(
- EvaluationResultImpl result, String typeName) {
- expect(result.value, isNotNull);
- DartObjectImpl value = result.value;
- expect(value.type.displayName, typeName);
- return value.fields;
- }
-
- bool _assertValidBool(EvaluationResultImpl result) {
- expect(result.value, isNotNull);
- DartObjectImpl value = result.value;
- expect(value.type, typeProvider.boolType);
- bool boolValue = value.toBoolValue();
- expect(boolValue, isNotNull);
- return boolValue;
- }
-
- int _assertValidInt(EvaluationResultImpl result) {
- expect(result.value, isNotNull);
- DartObjectImpl value = result.value;
- expect(value.type, typeProvider.intType);
- return value.toIntValue();
- }
-
- void _assertValidNull(EvaluationResultImpl result) {
- expect(result.value, isNotNull);
- DartObjectImpl value = result.value;
- expect(value.type, typeProvider.nullType);
- }
-
- String _assertValidString(EvaluationResultImpl result) {
- expect(result.value, isNotNull);
- DartObjectImpl value = result.value;
- expect(value.type, typeProvider.stringType);
- return value.toStringValue();
- }
-
- void _assertValidUnknown(EvaluationResultImpl result) {
- expect(result.value, isNotNull);
- DartObjectImpl value = result.value;
- expect(value.isUnknown, isTrue);
- }
-
- EvaluationResultImpl _check_fromEnvironment_bool(
- String valueInEnvironment, String defaultExpr) {
- String envVarName = "x";
- String varName = "foo";
- if (valueInEnvironment != null) {
- analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
- }
- String defaultArg =
- defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
- CompilationUnit compilationUnit = resolveSource(
- "const $varName = const bool.fromEnvironment('$envVarName'$defaultArg);");
- return _evaluateTopLevelVariable(compilationUnit, varName);
- }
-
- EvaluationResultImpl _check_fromEnvironment_int(
- String valueInEnvironment, String defaultExpr) {
- String envVarName = "x";
- String varName = "foo";
- if (valueInEnvironment != null) {
- analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
- }
- String defaultArg =
- defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
- CompilationUnit compilationUnit = resolveSource(
- "const $varName = const int.fromEnvironment('$envVarName'$defaultArg);");
- return _evaluateTopLevelVariable(compilationUnit, varName);
- }
-
- EvaluationResultImpl _check_fromEnvironment_string(
- String valueInEnvironment, String defaultExpr) {
- String envVarName = "x";
- String varName = "foo";
- if (valueInEnvironment != null) {
- analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
- }
- String defaultArg =
- defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
- CompilationUnit compilationUnit = resolveSource(
- "const $varName = const String.fromEnvironment('$envVarName'$defaultArg);");
- return _evaluateTopLevelVariable(compilationUnit, varName);
- }
-
- void _checkInstanceCreation_withSupertypeParams(bool isExplicit) {
- String superCall = isExplicit ? " : super()" : "";
- CompilationUnit compilationUnit = resolveSource("""
-class A<T> {
- const A();
-}
-class B<T, U> extends A<T> {
- const B()$superCall;
-}
-class C<T, U> extends A<U> {
- const C()$superCall;
-}
-const b_int_num = const B<int, num>();
-const c_int_num = const C<int, num>();""");
- EvaluationResultImpl b_int_num =
- _evaluateTopLevelVariable(compilationUnit, "b_int_num");
- Map<String, DartObjectImpl> b_int_num_fields =
- _assertType(b_int_num, "B<int, num>");
- _assertFieldType(b_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<int>");
- EvaluationResultImpl c_int_num =
- _evaluateTopLevelVariable(compilationUnit, "c_int_num");
- Map<String, DartObjectImpl> c_int_num_fields =
- _assertType(c_int_num, "C<int, num>");
- _assertFieldType(c_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<num>");
- }
-
- void _checkInstanceCreationOptionalParams(
- bool isFieldFormal, bool isNamed, bool hasDefault) {
- String fieldName = "j";
- String paramName = isFieldFormal ? fieldName : "i";
- String formalParam =
- "${isFieldFormal ? "this." : "int "}$paramName${hasDefault ? " = 3" : ""}";
- CompilationUnit compilationUnit = resolveSource("""
-const x = const A();
-const y = const A(${isNamed ? '$paramName: ' : ''}10);
-class A {
- const A(${isNamed ? "{$formalParam}" : "[$formalParam]"})${isFieldFormal ? "" : " : $fieldName = $paramName"};
- final int $fieldName;
-}""");
- EvaluationResultImpl x = _evaluateTopLevelVariable(compilationUnit, "x");
- Map<String, DartObjectImpl> fieldsOfX = _assertType(x, "A");
- expect(fieldsOfX, hasLength(1));
- if (hasDefault) {
- _assertIntField(fieldsOfX, fieldName, 3);
- } else {
- _assertNullField(fieldsOfX, fieldName);
- }
- EvaluationResultImpl y = _evaluateTopLevelVariable(compilationUnit, "y");
- Map<String, DartObjectImpl> fieldsOfY = _assertType(y, "A");
- expect(fieldsOfY, hasLength(1));
- _assertIntField(fieldsOfY, fieldName, 10);
- }
-
- /**
- * Search [compilationUnit] for a class named [className], containing a
- * method [methodName], with exactly one annotation. Return the constant
- * value of the annotation.
- */
- EvaluationResultImpl _evaluateAnnotation(
- CompilationUnit compilationUnit, String className, String memberName) {
- for (CompilationUnitMember member in compilationUnit.declarations) {
- if (member is ClassDeclaration && member.name.name == className) {
- for (ClassMember classMember in member.members) {
- if (classMember is MethodDeclaration &&
- classMember.name.name == memberName) {
- expect(classMember.metadata, hasLength(1));
- ElementAnnotationImpl elementAnnotation =
- classMember.metadata[0].elementAnnotation;
- return elementAnnotation.evaluationResult;
- }
- }
- }
- }
- fail('Class member not found');
- return null;
- }
-
- EvaluationResultImpl _evaluateTopLevelVariable(
- CompilationUnit compilationUnit, String name) {
- VariableDeclaration varDecl =
- findTopLevelDeclaration(compilationUnit, name);
- ConstTopLevelVariableElementImpl varElement = varDecl.element;
- return varElement.evaluationResult;
- }
-
- ConstantValueComputer _makeConstantValueComputer() {
- ConstantEvaluationValidator_ForTest validator =
- new ConstantEvaluationValidator_ForTest();
- validator.computer = new ConstantValueComputer(
- analysisContext2,
- analysisContext2.typeProvider,
- analysisContext2.declaredVariables,
- validator,
- analysisContext2.typeSystem);
- return validator.computer;
- }
-
- void _validate(bool shouldBeValid, VariableDeclarationList declarationList) {
- for (VariableDeclaration declaration in declarationList.variables) {
- VariableElementImpl element = declaration.element as VariableElementImpl;
- expect(element, isNotNull);
- EvaluationResultImpl result = element.evaluationResult;
- if (shouldBeValid) {
- expect(result.value, isNotNull);
- } else {
- expect(result.value, isNull);
- }
- }
- }
-}
-
-@reflectiveTest
-class ConstantVisitorTest extends ResolverTestCase {
- void test_visitConditionalExpression_false() {
- Expression thenExpression = AstFactory.integer(1);
- Expression elseExpression = AstFactory.integer(0);
- ConditionalExpression expression = AstFactory.conditionalExpression(
- AstFactory.booleanLiteral(false), thenExpression, elseExpression);
- GatheringErrorListener errorListener = new GatheringErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, _dummySource());
- _assertValue(
- 0,
- expression.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(
- new TestTypeProvider(), new DeclaredVariables(),
- typeSystem: new TypeSystemImpl()),
- errorReporter)));
- errorListener.assertNoErrors();
- }
-
- void test_visitConditionalExpression_nonBooleanCondition() {
- Expression thenExpression = AstFactory.integer(1);
- Expression elseExpression = AstFactory.integer(0);
- NullLiteral conditionExpression = AstFactory.nullLiteral();
- ConditionalExpression expression = AstFactory.conditionalExpression(
- conditionExpression, thenExpression, elseExpression);
- GatheringErrorListener errorListener = new GatheringErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, _dummySource());
- DartObjectImpl result = expression.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(
- new TestTypeProvider(), new DeclaredVariables(),
- typeSystem: new TypeSystemImpl()),
- errorReporter));
- expect(result, isNull);
- errorListener
- .assertErrorsWithCodes([CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL]);
- }
-
- void test_visitConditionalExpression_nonConstantElse() {
- Expression thenExpression = AstFactory.integer(1);
- Expression elseExpression = AstFactory.identifier3("x");
- ConditionalExpression expression = AstFactory.conditionalExpression(
- AstFactory.booleanLiteral(true), thenExpression, elseExpression);
- GatheringErrorListener errorListener = new GatheringErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, _dummySource());
- DartObjectImpl result = expression.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(
- new TestTypeProvider(), new DeclaredVariables(),
- typeSystem: new TypeSystemImpl()),
- errorReporter));
- expect(result, isNull);
- errorListener
- .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
- }
-
- void test_visitConditionalExpression_nonConstantThen() {
- Expression thenExpression = AstFactory.identifier3("x");
- Expression elseExpression = AstFactory.integer(0);
- ConditionalExpression expression = AstFactory.conditionalExpression(
- AstFactory.booleanLiteral(true), thenExpression, elseExpression);
- GatheringErrorListener errorListener = new GatheringErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, _dummySource());
- DartObjectImpl result = expression.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(
- new TestTypeProvider(), new DeclaredVariables(),
- typeSystem: new TypeSystemImpl()),
- errorReporter));
- expect(result, isNull);
- errorListener
- .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
- }
-
- void test_visitConditionalExpression_true() {
- Expression thenExpression = AstFactory.integer(1);
- Expression elseExpression = AstFactory.integer(0);
- ConditionalExpression expression = AstFactory.conditionalExpression(
- AstFactory.booleanLiteral(true), thenExpression, elseExpression);
- GatheringErrorListener errorListener = new GatheringErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, _dummySource());
- _assertValue(
- 1,
- expression.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(
- new TestTypeProvider(), new DeclaredVariables(),
- typeSystem: new TypeSystemImpl()),
- errorReporter)));
- errorListener.assertNoErrors();
- }
-
- void test_visitSimpleIdentifier_className() {
- CompilationUnit compilationUnit = resolveSource('''
-const a = C;
-class C {}
-''');
- DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
- expect(result.type, typeProvider.typeType);
- expect(result.toTypeValue().name, 'C');
- }
-
- void test_visitSimpleIdentifier_dynamic() {
- CompilationUnit compilationUnit = resolveSource('''
-const a = dynamic;
-''');
- DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
- expect(result.type, typeProvider.typeType);
- expect(result.toTypeValue(), typeProvider.dynamicType);
- }
-
- void test_visitSimpleIdentifier_inEnvironment() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const a = b;
-const b = 3;''');
- Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
- DartObjectImpl six =
- new DartObjectImpl(typeProvider.intType, new IntState(6));
- environment["b"] = six;
- _assertValue(6, _evaluateConstant(compilationUnit, "a", environment));
- }
-
- void test_visitSimpleIdentifier_notInEnvironment() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const a = b;
-const b = 3;''');
- Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
- DartObjectImpl six =
- new DartObjectImpl(typeProvider.intType, new IntState(6));
- environment["c"] = six;
- _assertValue(3, _evaluateConstant(compilationUnit, "a", environment));
- }
-
- void test_visitSimpleIdentifier_withoutEnvironment() {
- CompilationUnit compilationUnit = resolveSource(r'''
-const a = b;
-const b = 3;''');
- _assertValue(3, _evaluateConstant(compilationUnit, "a", null));
- }
-
- void _assertValue(int expectedValue, DartObjectImpl result) {
- expect(result, isNotNull);
- expect(result.type.name, "int");
- expect(result.toIntValue(), expectedValue);
- }
-
- NonExistingSource _dummySource() {
- String path = '/test.dart';
- return new NonExistingSource(path, toUri(path), UriKind.FILE_URI);
- }
-
- DartObjectImpl _evaluateConstant(CompilationUnit compilationUnit, String name,
- Map<String, DartObjectImpl> lexicalEnvironment) {
- Source source = compilationUnit.element.source;
- Expression expression =
- findTopLevelConstantExpression(compilationUnit, name);
- GatheringErrorListener errorListener = new GatheringErrorListener();
- ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
- DartObjectImpl result = expression.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(typeProvider, new DeclaredVariables(),
- typeSystem: typeSystem),
- errorReporter,
- lexicalEnvironment: lexicalEnvironment));
- errorListener.assertNoErrors();
- return result;
- }
-}
-
@reflectiveTest
class ContentCacheTest {
void test_setContents() {
@@ -4603,7 +2487,25 @@
}
@reflectiveTest
-class ElementBuilderTest extends EngineTestCase {
+class ElementBuilderTest extends ParserTestCase {
+ void fail_visitMethodDeclaration_setter_duplicate() {
+ // https://github.com/dart-lang/sdk/issues/25601
+ String code = r'''
+class C {
+ set zzz(x) {}
+ set zzz(y) {}
+}
+''';
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
+ ElementHolder holder = new ElementHolder();
+ ElementBuilder builder = new ElementBuilder(holder);
+ unit.accept(builder);
+ ClassElement classElement = holder.types[0];
+ for (PropertyAccessorElement accessor in classElement.accessors) {
+ expect(accessor.variable.setter, same(accessor));
+ }
+ }
+
void test_visitCatchClause() {
// } catch (e, s) {
ElementHolder holder = new ElementHolder();
@@ -4857,8 +2759,8 @@
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
String className = "A";
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration2(
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration2(
null,
null,
AstFactory.identifier3(className),
@@ -4886,8 +2788,8 @@
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
String className = "A";
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration2(
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration2(
null,
Keyword.FACTORY,
AstFactory.identifier3(className),
@@ -4913,8 +2815,8 @@
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
String className = "A";
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration2(
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration2(
null,
null,
AstFactory.identifier3(className),
@@ -4946,8 +2848,8 @@
ElementBuilder builder = new ElementBuilder(holder);
String className = "A";
String constructorName = "c";
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration2(
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration2(
null,
null,
AstFactory.identifier3(className),
@@ -4975,8 +2877,8 @@
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
String className = "A";
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration2(
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration2(
null,
null,
AstFactory.identifier3(className),
@@ -5056,8 +2958,8 @@
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
String parameterName = 'p';
- DefaultFormalParameter formalParameter = AstFactory
- .positionalFormalParameter(
+ DefaultFormalParameter formalParameter =
+ AstFactory.positionalFormalParameter(
AstFactory.simpleFormalParameter3(parameterName),
AstFactory.integer(0));
formalParameter.accept(builder);
@@ -6462,7 +4364,8 @@
(obj) => obj is FunctionElement, FunctionElement, element);
}
- void test_locate_Identifier_annotationClass_namedConstructor_forSimpleFormalParameter() {
+ void
+ test_locate_Identifier_annotationClass_namedConstructor_forSimpleFormalParameter() {
AstNode id = _findNodeIndexedIn(
"Class",
2,
@@ -6477,7 +4380,8 @@
(obj) => obj is ClassElement, ClassElement, element);
}
- void test_locate_Identifier_annotationClass_unnamedConstructor_forSimpleFormalParameter() {
+ void
+ test_locate_Identifier_annotationClass_unnamedConstructor_forSimpleFormalParameter() {
AstNode id = _findNodeIndexedIn(
"Class",
2,
@@ -6584,8 +4488,8 @@
SimpleIdentifier identifier = AstFactory.identifier3("A");
PrefixedIdentifier prefixedIdentifier =
AstFactory.identifier4("pref", identifier);
- InstanceCreationExpression creation = AstFactory
- .instanceCreationExpression2(
+ InstanceCreationExpression creation =
+ AstFactory.instanceCreationExpression2(
Keyword.NEW, AstFactory.typeName3(prefixedIdentifier));
// set ClassElement
ClassElement classElement = ElementFactory.classElement2("A");
@@ -6602,8 +4506,8 @@
void test_locate_InstanceCreationExpression_type_simpleIdentifier() {
// prepare: new A()
SimpleIdentifier identifier = AstFactory.identifier3("A");
- InstanceCreationExpression creation = AstFactory
- .instanceCreationExpression2(
+ InstanceCreationExpression creation =
+ AstFactory.instanceCreationExpression2(
Keyword.NEW, AstFactory.typeName3(identifier));
// set ClassElement
ClassElement classElement = ElementFactory.classElement2("A");
@@ -8052,98 +5956,6 @@
}
@reflectiveTest
-class ReferenceFinderTest {
- DirectedGraph<ConstantEvaluationTarget> _referenceGraph;
- VariableElement _head;
- Element _tail;
-
- void setUp() {
- _referenceGraph = new DirectedGraph<ConstantEvaluationTarget>();
- _head = ElementFactory.topLevelVariableElement2("v1");
- }
-
- void test_visitSimpleIdentifier_const() {
- _visitNode(_makeTailVariable("v2", true));
- _assertOneArc(_tail);
- }
-
- void test_visitSimpleIdentifier_nonConst() {
- _visitNode(_makeTailVariable("v2", false));
- _assertOneArc(_tail);
- }
-
- void test_visitSuperConstructorInvocation_const() {
- _visitNode(_makeTailSuperConstructorInvocation("A", true));
- _assertOneArc(_tail);
- }
-
- void test_visitSuperConstructorInvocation_nonConst() {
- _visitNode(_makeTailSuperConstructorInvocation("A", false));
- _assertOneArc(_tail);
- }
-
- void test_visitSuperConstructorInvocation_unresolved() {
- SuperConstructorInvocation superConstructorInvocation =
- AstFactory.superConstructorInvocation();
- _visitNode(superConstructorInvocation);
- _assertNoArcs();
- }
-
- void _assertNoArcs() {
- Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
- expect(tails, hasLength(0));
- }
-
- void _assertOneArc(Element tail) {
- Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
- expect(tails, hasLength(1));
- expect(tails.first, same(tail));
- }
-
- ReferenceFinder _createReferenceFinder(ConstantEvaluationTarget source) =>
- new ReferenceFinder((ConstantEvaluationTarget dependency) {
- _referenceGraph.addEdge(source, dependency);
- });
- SuperConstructorInvocation _makeTailSuperConstructorInvocation(
- String name, bool isConst) {
- List<ConstructorInitializer> initializers =
- new List<ConstructorInitializer>();
- ConstructorDeclaration constructorDeclaration = AstFactory
- .constructorDeclaration(AstFactory.identifier3(name), null,
- AstFactory.formalParameterList(), initializers);
- if (isConst) {
- constructorDeclaration.constKeyword = new KeywordToken(Keyword.CONST, 0);
- }
- ClassElementImpl classElement = ElementFactory.classElement2(name);
- SuperConstructorInvocation superConstructorInvocation =
- AstFactory.superConstructorInvocation();
- ConstructorElementImpl constructorElement =
- ElementFactory.constructorElement(classElement, name, isConst);
- _tail = constructorElement;
- superConstructorInvocation.staticElement = constructorElement;
- return superConstructorInvocation;
- }
-
- SimpleIdentifier _makeTailVariable(String name, bool isConst) {
- VariableDeclaration variableDeclaration =
- AstFactory.variableDeclaration(name);
- ConstLocalVariableElementImpl variableElement =
- ElementFactory.constLocalVariableElement(name);
- _tail = variableElement;
- variableElement.const3 = isConst;
- AstFactory.variableDeclarationList2(
- isConst ? Keyword.CONST : Keyword.VAR, [variableDeclaration]);
- SimpleIdentifier identifier = AstFactory.identifier3(name);
- identifier.staticElement = variableElement;
- return identifier;
- }
-
- void _visitNode(AstNode node) {
- node.accept(_createReferenceFinder(_head));
- }
-}
-
-@reflectiveTest
class SDKLibrariesReaderTest extends EngineTestCase {
void test_readFrom_dart2js() {
LibraryMap libraryMap = new SdkLibrariesReader(true).readFromFile(
@@ -8218,16 +6030,6 @@
}
}
-class TestAnalysisContext_ConstantFinderTest extends TestAnalysisContext {
- bool invoked = false;
- TestAnalysisContext_ConstantFinderTest();
-
- @override
- InternalAnalysisContext getContextFor(Source source) {
- return this;
- }
-}
-
@reflectiveTest
class UriKindTest {
void test_fromEncoding() {
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 5f2abf5..15ef8ad 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -897,7 +897,8 @@
// TODO(paulberry): the error CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE is
// redundant and ought to be suppressed.
assertErrors(source, [
- CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
+ CompileTimeErrorCode
+ .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
]);
verify([source]);
@@ -1265,6 +1266,20 @@
verify([source]);
}
+ void test_constInitializedWithNonConstValue_finalField() {
+ // Regression test for bug #25526 which previously
+ // caused two errors to be reported.
+ Source source = addSource(r'''
+class Foo {
+ final field = [];
+ foo([int x = field]) {}
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE]);
+ verify([source]);
+ }
+
void test_constInitializedWithNonConstValue_missingConstInListLiteral() {
Source source = addSource("const List L = [0];");
computeLibrarySourceErrors(source);
@@ -1291,7 +1306,8 @@
import 'lib1.dart' deferred as a;
const B = a.V;'''
], <ErrorCode>[
- CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
+ CompileTimeErrorCode
+ .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
]);
}
@@ -1305,7 +1321,8 @@
import 'lib1.dart' deferred as a;
const B = a.V + 1;'''
], <ErrorCode>[
- CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
+ CompileTimeErrorCode
+ .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
]);
}
@@ -1827,7 +1844,8 @@
verify([source]);
}
- void test_duplicateDefinitionInheritance_instanceGetterAbstract_staticGetter() {
+ void
+ test_duplicateDefinitionInheritance_instanceGetterAbstract_staticGetter() {
Source source = addSource(r'''
abstract class A {
int get x;
@@ -1855,7 +1873,8 @@
verify([source]);
}
- void test_duplicateDefinitionInheritance_instanceMethodAbstract_staticMethod() {
+ void
+ test_duplicateDefinitionInheritance_instanceMethodAbstract_staticMethod() {
Source source = addSource(r'''
abstract class A {
x();
@@ -1883,7 +1902,8 @@
verify([source]);
}
- void test_duplicateDefinitionInheritance_instanceSetterAbstract_staticSetter() {
+ void
+ test_duplicateDefinitionInheritance_instanceSetterAbstract_staticSetter() {
Source source = addSource(r'''
abstract class A {
set x(value);
@@ -1967,9 +1987,7 @@
void test_extendsDisallowedClass_class_double() {
Source source = addSource("class A extends double {}");
computeLibrarySourceErrors(source);
- assertErrors(source, [
- CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS
- ]);
+ assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
verify([source]);
}
@@ -1996,9 +2014,7 @@
void test_extendsDisallowedClass_class_num() {
Source source = addSource("class A extends num {}");
computeLibrarySourceErrors(source);
- assertErrors(source, [
- CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS
- ]);
+ assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
verify([source]);
}
@@ -2638,7 +2654,8 @@
verify([source]);
}
- void test_implicitThisReferenceInInitializer_redirectingConstructorInvocation() {
+ void
+ test_implicitThisReferenceInInitializer_redirectingConstructorInvocation() {
Source source = addSource(r'''
class A {
A(p) {}
@@ -3004,7 +3021,8 @@
verify([source]);
}
- void test_invalidAnnotation_importWithPrefix_notVariableOrConstructorInvocation() {
+ void
+ test_invalidAnnotation_importWithPrefix_notVariableOrConstructorInvocation() {
addNamedSource(
"/lib.dart",
r'''
@@ -4653,7 +4671,8 @@
const A() : x = a.c;
}'''
], <ErrorCode>[
- CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+ CompileTimeErrorCode
+ .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
]);
}
@@ -4670,7 +4689,8 @@
const A() : x = a.c + 1;
}'''
], <ErrorCode>[
- CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+ CompileTimeErrorCode
+ .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
]);
}
@@ -4687,7 +4707,8 @@
const A() : this.named(a.c);
}'''
], <ErrorCode>[
- CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+ CompileTimeErrorCode
+ .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
]);
}
@@ -4706,7 +4727,8 @@
const B() : super(a.c);
}'''
], <ErrorCode>[
- CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+ CompileTimeErrorCode
+ .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
]);
}
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
new file mode 100644
index 0000000..04592ff
--- /dev/null
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -0,0 +1,2290 @@
+// Copyright (c) 2016, 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 analyzer.test.constant_test;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
+import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:analyzer/src/generated/testing/test_type_provider.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:path/path.dart';
+import 'package:unittest/unittest.dart';
+
+import '../reflective_tests.dart';
+import '../utils.dart';
+import 'engine_test.dart';
+import 'resolver_test.dart';
+import 'test_support.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(ConstantEvaluatorTest);
+ runReflectiveTests(ConstantFinderTest);
+ runReflectiveTests(ConstantValueComputerTest);
+ runReflectiveTests(ConstantVisitorTest);
+ runReflectiveTests(ReferenceFinderTest);
+}
+
+/**
+ * Implementation of [ConstantEvaluationValidator] used during unit tests;
+ * verifies that any nodes referenced during constant evaluation are present in
+ * the dependency graph.
+ */
+class ConstantEvaluationValidator_ForTest
+ implements ConstantEvaluationValidator {
+ final InternalAnalysisContext context;
+ ConstantValueComputer computer;
+ ConstantEvaluationTarget _nodeBeingEvaluated;
+
+ ConstantEvaluationValidator_ForTest(this.context);
+
+ @override
+ void beforeComputeValue(ConstantEvaluationTarget constant) {
+ _nodeBeingEvaluated = constant;
+ }
+
+ @override
+ void beforeGetConstantInitializers(ConstructorElement constructor) =>
+ _checkPathTo(constructor);
+
+ @override
+ void beforeGetEvaluationResult(ConstantEvaluationTarget constant) =>
+ _checkPathTo(constant);
+
+ @override
+ void beforeGetFieldEvaluationResult(FieldElementImpl field) =>
+ _checkPathTo(field);
+
+ @override
+ void beforeGetParameterDefault(ParameterElement parameter) =>
+ _checkPathTo(parameter);
+
+ void _checkPathTo(ConstantEvaluationTarget target) {
+ if (computer.referenceGraph.containsPath(_nodeBeingEvaluated, target)) {
+ return; // pass
+ }
+ // print a nice error message on failure
+ StringBuffer out = new StringBuffer();
+ out.writeln("missing path in constant dependency graph");
+ out.writeln("from $_nodeBeingEvaluated to $target");
+ for (var s in context.analysisCache.sources) {
+ String text = context.getContents(s).data;
+ if (text != "") {
+ out.writeln('''
+=== ${s.shortName}
+$text''');
+ }
+ }
+ fail(out.toString());
+ }
+}
+
+@reflectiveTest
+class ConstantEvaluatorTest extends ResolverTestCase {
+ void fail_constructor() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_identifier_class() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_identifier_function() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_identifier_static() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_identifier_staticMethod() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_identifier_topLevel() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_identifier_typeParameter() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_prefixedIdentifier_invalid() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_prefixedIdentifier_valid() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_propertyAccess_invalid() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_propertyAccess_valid() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_simpleIdentifier_invalid() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void fail_simpleIdentifier_valid() {
+ EvaluationResult result = _getExpressionValue("?");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value, null);
+ }
+
+ void test_bitAnd_int_int() {
+ _assertValue3(74 & 42, "74 & 42");
+ }
+
+ void test_bitNot() {
+ _assertValue3(~42, "~42");
+ }
+
+ void test_bitOr_int_int() {
+ _assertValue3(74 | 42, "74 | 42");
+ }
+
+ void test_bitXor_int_int() {
+ _assertValue3(74 ^ 42, "74 ^ 42");
+ }
+
+ void test_divide_double_double() {
+ _assertValue2(3.2 / 2.3, "3.2 / 2.3");
+ }
+
+ void test_divide_double_double_byZero() {
+ EvaluationResult result = _getExpressionValue("3.2 / 0.0");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value.type.name, "double");
+ expect(value.toDoubleValue().isInfinite, isTrue);
+ }
+
+ void test_divide_int_int() {
+ _assertValue2(1.5, "3 / 2");
+ }
+
+ void test_divide_int_int_byZero() {
+ EvaluationResult result = _getExpressionValue("3 / 0");
+ expect(result.isValid, isTrue);
+ }
+
+ void test_equal_boolean_boolean() {
+ _assertValue(false, "true == false");
+ }
+
+ void test_equal_int_int() {
+ _assertValue(false, "2 == 3");
+ }
+
+ void test_equal_invalidLeft() {
+ EvaluationResult result = _getExpressionValue("a == 3");
+ expect(result.isValid, isFalse);
+ }
+
+ void test_equal_invalidRight() {
+ EvaluationResult result = _getExpressionValue("2 == a");
+ expect(result.isValid, isFalse);
+ }
+
+ void test_equal_string_string() {
+ _assertValue(false, "'a' == 'b'");
+ }
+
+ void test_greaterThan_int_int() {
+ _assertValue(false, "2 > 3");
+ }
+
+ void test_greaterThanOrEqual_int_int() {
+ _assertValue(false, "2 >= 3");
+ }
+
+ void test_leftShift_int_int() {
+ _assertValue3(64, "16 << 2");
+ }
+
+ void test_lessThan_int_int() {
+ _assertValue(true, "2 < 3");
+ }
+
+ void test_lessThanOrEqual_int_int() {
+ _assertValue(true, "2 <= 3");
+ }
+
+ void test_literal_boolean_false() {
+ _assertValue(false, "false");
+ }
+
+ void test_literal_boolean_true() {
+ _assertValue(true, "true");
+ }
+
+ void test_literal_list() {
+ EvaluationResult result = _getExpressionValue("const ['a', 'b', 'c']");
+ expect(result.isValid, isTrue);
+ }
+
+ void test_literal_map() {
+ EvaluationResult result =
+ _getExpressionValue("const {'a' : 'm', 'b' : 'n', 'c' : 'o'}");
+ expect(result.isValid, isTrue);
+ }
+
+ void test_literal_null() {
+ EvaluationResult result = _getExpressionValue("null");
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value.isNull, isTrue);
+ }
+
+ void test_literal_number_double() {
+ _assertValue2(3.45, "3.45");
+ }
+
+ void test_literal_number_integer() {
+ _assertValue3(42, "42");
+ }
+
+ void test_literal_string_adjacent() {
+ _assertValue4("abcdef", "'abc' 'def'");
+ }
+
+ void test_literal_string_interpolation_invalid() {
+ EvaluationResult result = _getExpressionValue("'a\${f()}c'");
+ expect(result.isValid, isFalse);
+ }
+
+ void test_literal_string_interpolation_valid() {
+ _assertValue4("a3c", "'a\${3}c'");
+ }
+
+ void test_literal_string_simple() {
+ _assertValue4("abc", "'abc'");
+ }
+
+ void test_logicalAnd() {
+ _assertValue(false, "true && false");
+ }
+
+ void test_logicalNot() {
+ _assertValue(false, "!true");
+ }
+
+ void test_logicalOr() {
+ _assertValue(true, "true || false");
+ }
+
+ void test_minus_double_double() {
+ _assertValue2(3.2 - 2.3, "3.2 - 2.3");
+ }
+
+ void test_minus_int_int() {
+ _assertValue3(1, "3 - 2");
+ }
+
+ void test_negated_boolean() {
+ EvaluationResult result = _getExpressionValue("-true");
+ expect(result.isValid, isFalse);
+ }
+
+ void test_negated_double() {
+ _assertValue2(-42.3, "-42.3");
+ }
+
+ void test_negated_integer() {
+ _assertValue3(-42, "-42");
+ }
+
+ void test_notEqual_boolean_boolean() {
+ _assertValue(true, "true != false");
+ }
+
+ void test_notEqual_int_int() {
+ _assertValue(true, "2 != 3");
+ }
+
+ void test_notEqual_invalidLeft() {
+ EvaluationResult result = _getExpressionValue("a != 3");
+ expect(result.isValid, isFalse);
+ }
+
+ void test_notEqual_invalidRight() {
+ EvaluationResult result = _getExpressionValue("2 != a");
+ expect(result.isValid, isFalse);
+ }
+
+ void test_notEqual_string_string() {
+ _assertValue(true, "'a' != 'b'");
+ }
+
+ void test_parenthesizedExpression() {
+ _assertValue4("a", "('a')");
+ }
+
+ void test_plus_double_double() {
+ _assertValue2(2.3 + 3.2, "2.3 + 3.2");
+ }
+
+ void test_plus_int_int() {
+ _assertValue3(5, "2 + 3");
+ }
+
+ void test_plus_string_string() {
+ _assertValue4("ab", "'a' + 'b'");
+ }
+
+ void test_remainder_double_double() {
+ _assertValue2(3.2 % 2.3, "3.2 % 2.3");
+ }
+
+ void test_remainder_int_int() {
+ _assertValue3(2, "8 % 3");
+ }
+
+ void test_rightShift() {
+ _assertValue3(16, "64 >> 2");
+ }
+
+ void test_stringLength_complex() {
+ _assertValue3(6, "('qwe' + 'rty').length");
+ }
+
+ void test_stringLength_simple() {
+ _assertValue3(6, "'Dvorak'.length");
+ }
+
+ void test_times_double_double() {
+ _assertValue2(2.3 * 3.2, "2.3 * 3.2");
+ }
+
+ void test_times_int_int() {
+ _assertValue3(6, "2 * 3");
+ }
+
+ void test_truncatingDivide_double_double() {
+ _assertValue3(1, "3.2 ~/ 2.3");
+ }
+
+ void test_truncatingDivide_int_int() {
+ _assertValue3(3, "10 ~/ 3");
+ }
+
+ void _assertValue(bool expectedValue, String contents) {
+ EvaluationResult result = _getExpressionValue(contents);
+ DartObject value = result.value;
+ expect(value.type.name, "bool");
+ expect(value.toBoolValue(), expectedValue);
+ }
+
+ void _assertValue2(double expectedValue, String contents) {
+ EvaluationResult result = _getExpressionValue(contents);
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value.type.name, "double");
+ expect(value.toDoubleValue(), expectedValue);
+ }
+
+ void _assertValue3(int expectedValue, String contents) {
+ EvaluationResult result = _getExpressionValue(contents);
+ expect(result.isValid, isTrue);
+ DartObject value = result.value;
+ expect(value.type.name, "int");
+ expect(value.toIntValue(), expectedValue);
+ }
+
+ void _assertValue4(String expectedValue, String contents) {
+ EvaluationResult result = _getExpressionValue(contents);
+ DartObject value = result.value;
+ expect(value, isNotNull);
+ ParameterizedType type = value.type;
+ expect(type, isNotNull);
+ expect(type.name, "String");
+ expect(value.toStringValue(), expectedValue);
+ }
+
+ EvaluationResult _getExpressionValue(String contents) {
+ Source source = addSource("var x = $contents;");
+ LibraryElement library = resolve2(source);
+ CompilationUnit unit =
+ analysisContext.resolveCompilationUnit(source, library);
+ expect(unit, isNotNull);
+ NodeList<CompilationUnitMember> declarations = unit.declarations;
+ expect(declarations, hasLength(1));
+ CompilationUnitMember declaration = declarations[0];
+ EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableDeclaration,
+ TopLevelVariableDeclaration, declaration);
+ NodeList<VariableDeclaration> variables =
+ (declaration as TopLevelVariableDeclaration).variables.variables;
+ expect(variables, hasLength(1));
+ ConstantEvaluator evaluator = new ConstantEvaluator(
+ source, analysisContext.typeProvider,
+ typeSystem: analysisContext.typeSystem);
+ return evaluator.evaluate(variables[0].initializer);
+ }
+}
+
+@reflectiveTest
+class ConstantFinderTest {
+ AstNode _node;
+ TypeProvider _typeProvider;
+ AnalysisContext _context;
+ Source _source;
+
+ void setUp() {
+ _typeProvider = new TestTypeProvider();
+ _context = new _TestAnalysisContext();
+ _source = new TestSource();
+ }
+
+ /**
+ * Test an annotation that consists solely of an identifier (and hence
+ * represents a reference to a compile-time constant variable).
+ */
+ void test_visitAnnotation_constantVariable() {
+ _node = AstFactory.annotation(AstFactory.identifier3('x'));
+ expect(_findAnnotations(), contains(_node));
+ }
+
+ /**
+ * Test an annotation that represents the invocation of a constant
+ * constructor.
+ */
+ void test_visitAnnotation_invocation() {
+ _node = AstFactory.annotation2(
+ AstFactory.identifier3('A'), null, AstFactory.argumentList());
+ expect(_findAnnotations(), contains(_node));
+ }
+
+ void test_visitConstructorDeclaration_const() {
+ ConstructorElement element = _setupConstructorDeclaration("A", true);
+ expect(_findConstants(), contains(element));
+ }
+
+ void test_visitConstructorDeclaration_nonConst() {
+ _setupConstructorDeclaration("A", false);
+ expect(_findConstants(), isEmpty);
+ }
+
+ void test_visitVariableDeclaration_const() {
+ VariableElement element = _setupVariableDeclaration("v", true, true);
+ expect(_findConstants(), contains(element));
+ }
+
+ void test_visitVariableDeclaration_final_inClass() {
+ _setupFieldDeclaration('C', 'f', Keyword.FINAL);
+ expect(_findConstants(), isEmpty);
+ }
+
+ void test_visitVariableDeclaration_final_inClassWithConstConstructor() {
+ VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
+ hasConstConstructor: true);
+ expect(_findConstants(), contains(field.element));
+ }
+
+ void test_visitVariableDeclaration_final_outsideClass() {
+ _setupVariableDeclaration('v', false, true, isFinal: true);
+ expect(_findConstants(), isEmpty);
+ }
+
+ void test_visitVariableDeclaration_noInitializer() {
+ _setupVariableDeclaration("v", true, false);
+ expect(_findConstants(), isEmpty);
+ }
+
+ void test_visitVariableDeclaration_nonConst() {
+ _setupVariableDeclaration("v", false, true);
+ expect(_findConstants(), isEmpty);
+ }
+
+ void test_visitVariableDeclaration_static_const_inClass() {
+ VariableDeclaration field =
+ _setupFieldDeclaration('C', 'f', Keyword.CONST, isStatic: true);
+ expect(_findConstants(), contains(field.element));
+ }
+
+ void
+ test_visitVariableDeclaration_static_const_inClassWithConstConstructor() {
+ VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.CONST,
+ isStatic: true, hasConstConstructor: true);
+ expect(_findConstants(), contains(field.element));
+ }
+
+ void
+ test_visitVariableDeclaration_static_final_inClassWithConstConstructor() {
+ VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
+ isStatic: true, hasConstConstructor: true);
+ expect(_findConstants(), isNot(contains(field.element)));
+ }
+
+ void
+ test_visitVariableDeclaration_uninitialized_final_inClassWithConstConstructor() {
+ VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
+ isInitialized: false, hasConstConstructor: true);
+ expect(_findConstants(), isNot(contains(field.element)));
+ }
+
+ void test_visitVariableDeclaration_uninitialized_static_const_inClass() {
+ _setupFieldDeclaration('C', 'f', Keyword.CONST,
+ isStatic: true, isInitialized: false);
+ expect(_findConstants(), isEmpty);
+ }
+
+ List<Annotation> _findAnnotations() {
+ Set<Annotation> annotations = new Set<Annotation>();
+ for (ConstantEvaluationTarget target in _findConstants()) {
+ if (target is ConstantEvaluationTarget_Annotation) {
+ expect(target.context, same(_context));
+ expect(target.source, same(_source));
+ annotations.add(target.annotation);
+ }
+ }
+ return new List<Annotation>.from(annotations);
+ }
+
+ Set<ConstantEvaluationTarget> _findConstants() {
+ ConstantFinder finder = new ConstantFinder(_context, _source, _source);
+ _node.accept(finder);
+ Set<ConstantEvaluationTarget> constants = finder.constantsToCompute;
+ expect(constants, isNotNull);
+ return constants;
+ }
+
+ ConstructorElement _setupConstructorDeclaration(String name, bool isConst) {
+ Keyword constKeyword = isConst ? Keyword.CONST : null;
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration2(
+ constKeyword,
+ null,
+ null,
+ name,
+ AstFactory.formalParameterList(),
+ null,
+ AstFactory.blockFunctionBody2());
+ ClassElement classElement = ElementFactory.classElement2(name);
+ ConstructorElement element =
+ ElementFactory.constructorElement(classElement, name, isConst);
+ constructorDeclaration.element = element;
+ _node = constructorDeclaration;
+ return element;
+ }
+
+ VariableDeclaration _setupFieldDeclaration(
+ String className, String fieldName, Keyword keyword,
+ {bool isInitialized: true,
+ bool isStatic: false,
+ bool hasConstConstructor: false}) {
+ VariableDeclaration variableDeclaration = isInitialized
+ ? AstFactory.variableDeclaration2(fieldName, AstFactory.integer(0))
+ : AstFactory.variableDeclaration(fieldName);
+ VariableElement fieldElement = ElementFactory.fieldElement(
+ fieldName,
+ isStatic,
+ keyword == Keyword.FINAL,
+ keyword == Keyword.CONST,
+ _typeProvider.intType);
+ variableDeclaration.name.staticElement = fieldElement;
+ FieldDeclaration fieldDeclaration = AstFactory.fieldDeclaration2(
+ isStatic, keyword, <VariableDeclaration>[variableDeclaration]);
+ ClassDeclaration classDeclaration =
+ AstFactory.classDeclaration(null, className, null, null, null, null);
+ classDeclaration.members.add(fieldDeclaration);
+ _node = classDeclaration;
+ ClassElementImpl classElement = ElementFactory.classElement2(className);
+ classElement.fields = <FieldElement>[fieldElement];
+ classDeclaration.name.staticElement = classElement;
+ if (hasConstConstructor) {
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration2(
+ Keyword.CONST,
+ null,
+ AstFactory.identifier3(className),
+ null,
+ AstFactory.formalParameterList(),
+ null,
+ AstFactory.blockFunctionBody2());
+ classDeclaration.members.add(constructorDeclaration);
+ ConstructorElement constructorElement =
+ ElementFactory.constructorElement(classElement, '', true);
+ constructorDeclaration.element = constructorElement;
+ classElement.constructors = <ConstructorElement>[constructorElement];
+ } else {
+ classElement.constructors = ConstructorElement.EMPTY_LIST;
+ }
+ return variableDeclaration;
+ }
+
+ VariableElement _setupVariableDeclaration(
+ String name, bool isConst, bool isInitialized,
+ {isFinal: false}) {
+ VariableDeclaration variableDeclaration = isInitialized
+ ? AstFactory.variableDeclaration2(name, AstFactory.integer(0))
+ : AstFactory.variableDeclaration(name);
+ SimpleIdentifier identifier = variableDeclaration.name;
+ VariableElement element = ElementFactory.localVariableElement(identifier);
+ identifier.staticElement = element;
+ Keyword keyword = isConst ? Keyword.CONST : isFinal ? Keyword.FINAL : null;
+ AstFactory.variableDeclarationList2(keyword, [variableDeclaration]);
+ _node = variableDeclaration;
+ return element;
+ }
+}
+
+@reflectiveTest
+class ConstantValueComputerTest extends ResolverTestCase {
+ void test_annotation_constConstructor() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ final int i;
+ const A(this.i);
+}
+
+class C {
+ @A(5)
+ f() {}
+}
+''');
+ EvaluationResultImpl result =
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
+ _assertIntField(annotationFields, 'i', 5);
+ }
+
+ void test_annotation_constConstructor_named() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ final int i;
+ const A.named(this.i);
+}
+
+class C {
+ @A.named(5)
+ f() {}
+}
+''');
+ EvaluationResultImpl result =
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
+ _assertIntField(annotationFields, 'i', 5);
+ }
+
+ void test_annotation_constConstructor_noArgs() {
+ // Failing to pass arguments to an annotation which is a constant
+ // constructor is illegal, but shouldn't crash analysis.
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ final int i;
+ const A(this.i);
+}
+
+class C {
+ @A
+ f() {}
+}
+''');
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ }
+
+ void test_annotation_constConstructor_noArgs_named() {
+ // Failing to pass arguments to an annotation which is a constant
+ // constructor is illegal, but shouldn't crash analysis.
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ final int i;
+ const A.named(this.i);
+}
+
+class C {
+ @A.named
+ f() {}
+}
+''');
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ }
+
+ void test_annotation_nonConstConstructor() {
+ // Calling a non-const constructor from an annotation that is illegal, but
+ // shouldn't crash analysis.
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ final int i;
+ A(this.i);
+}
+
+class C {
+ @A(5)
+ f() {}
+}
+''');
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ }
+
+ void test_annotation_staticConst() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+class C {
+ static const int i = 5;
+
+ @i
+ f() {}
+}
+''');
+ EvaluationResultImpl result =
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ expect(_assertValidInt(result), 5);
+ }
+
+ void test_annotation_staticConst_args() {
+ // Applying arguments to an annotation that is a static const is
+ // illegal, but shouldn't crash analysis.
+ CompilationUnit compilationUnit = resolveSource(r'''
+class C {
+ static const int i = 5;
+
+ @i(1)
+ f() {}
+}
+''');
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ }
+
+ void test_annotation_staticConst_otherClass() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ static const int i = 5;
+}
+
+class C {
+ @A.i
+ f() {}
+}
+''');
+ EvaluationResultImpl result =
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ expect(_assertValidInt(result), 5);
+ }
+
+ void test_annotation_staticConst_otherClass_args() {
+ // Applying arguments to an annotation that is a static const is
+ // illegal, but shouldn't crash analysis.
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ static const int i = 5;
+}
+
+class C {
+ @A.i(1)
+ f() {}
+}
+''');
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ }
+
+ void test_annotation_toplevelVariable() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const int i = 5;
+class C {
+ @i
+ f() {}
+}
+''');
+ EvaluationResultImpl result =
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ expect(_assertValidInt(result), 5);
+ }
+
+ void test_annotation_toplevelVariable_args() {
+ // Applying arguments to an annotation that is a toplevel variable is
+ // illegal, but shouldn't crash analysis.
+ CompilationUnit compilationUnit = resolveSource(r'''
+const int i = 5;
+class C {
+ @i(1)
+ f() {}
+}
+''');
+ _evaluateAnnotation(compilationUnit, "C", "f");
+ }
+
+ void test_computeValues_cycle() {
+ TestLogger logger = new TestLogger();
+ AnalysisEngine.instance.logger = logger;
+ try {
+ Source source = addSource(r'''
+ const int a = c;
+ const int b = a;
+ const int c = b;''');
+ LibraryElement libraryElement = resolve2(source);
+ CompilationUnit unit =
+ analysisContext.resolveCompilationUnit(source, libraryElement);
+ analysisContext.computeErrors(source);
+ expect(unit, isNotNull);
+ ConstantValueComputer computer = _makeConstantValueComputer();
+ computer.add(unit, source, source);
+ computer.computeValues();
+ NodeList<CompilationUnitMember> members = unit.declarations;
+ expect(members, hasLength(3));
+ _validate(false, (members[0] as TopLevelVariableDeclaration).variables);
+ _validate(false, (members[1] as TopLevelVariableDeclaration).variables);
+ _validate(false, (members[2] as TopLevelVariableDeclaration).variables);
+ } finally {
+ AnalysisEngine.instance.logger = Logger.NULL;
+ }
+ }
+
+ void test_computeValues_dependentVariables() {
+ Source source = addSource(r'''
+const int b = a;
+const int a = 0;''');
+ LibraryElement libraryElement = resolve2(source);
+ CompilationUnit unit =
+ analysisContext.resolveCompilationUnit(source, libraryElement);
+ expect(unit, isNotNull);
+ ConstantValueComputer computer = _makeConstantValueComputer();
+ computer.add(unit, source, source);
+ computer.computeValues();
+ NodeList<CompilationUnitMember> members = unit.declarations;
+ expect(members, hasLength(2));
+ _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
+ _validate(true, (members[1] as TopLevelVariableDeclaration).variables);
+ }
+
+ void test_computeValues_empty() {
+ ConstantValueComputer computer = _makeConstantValueComputer();
+ computer.computeValues();
+ }
+
+ void test_computeValues_multipleSources() {
+ Source librarySource = addNamedSource(
+ "/lib.dart",
+ r'''
+library lib;
+part 'part.dart';
+const int c = b;
+const int a = 0;''');
+ Source partSource = addNamedSource(
+ "/part.dart",
+ r'''
+part of lib;
+const int b = a;
+const int d = c;''');
+ LibraryElement libraryElement = resolve2(librarySource);
+ CompilationUnit libraryUnit =
+ analysisContext.resolveCompilationUnit(librarySource, libraryElement);
+ expect(libraryUnit, isNotNull);
+ CompilationUnit partUnit =
+ analysisContext.resolveCompilationUnit(partSource, libraryElement);
+ expect(partUnit, isNotNull);
+ ConstantValueComputer computer = _makeConstantValueComputer();
+ computer.add(libraryUnit, librarySource, librarySource);
+ computer.add(partUnit, partSource, librarySource);
+ computer.computeValues();
+ NodeList<CompilationUnitMember> libraryMembers = libraryUnit.declarations;
+ expect(libraryMembers, hasLength(2));
+ _validate(
+ true, (libraryMembers[0] as TopLevelVariableDeclaration).variables);
+ _validate(
+ true, (libraryMembers[1] as TopLevelVariableDeclaration).variables);
+ NodeList<CompilationUnitMember> partMembers = libraryUnit.declarations;
+ expect(partMembers, hasLength(2));
+ _validate(true, (partMembers[0] as TopLevelVariableDeclaration).variables);
+ _validate(true, (partMembers[1] as TopLevelVariableDeclaration).variables);
+ }
+
+ void test_computeValues_singleVariable() {
+ Source source = addSource("const int a = 0;");
+ LibraryElement libraryElement = resolve2(source);
+ CompilationUnit unit =
+ analysisContext.resolveCompilationUnit(source, libraryElement);
+ expect(unit, isNotNull);
+ ConstantValueComputer computer = _makeConstantValueComputer();
+ computer.add(unit, source, source);
+ computer.computeValues();
+ NodeList<CompilationUnitMember> members = unit.declarations;
+ expect(members, hasLength(1));
+ _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
+ }
+
+ void test_computeValues_value_depends_on_enum() {
+ Source source = addSource('''
+enum E { id0, id1 }
+const E e = E.id0;
+''');
+ LibraryElement libraryElement = resolve2(source);
+ CompilationUnit unit =
+ analysisContext.resolveCompilationUnit(source, libraryElement);
+ expect(unit, isNotNull);
+ ConstantValueComputer computer = _makeConstantValueComputer();
+ computer.add(unit, source, source);
+ computer.computeValues();
+ TopLevelVariableDeclaration declaration = unit.declarations
+ .firstWhere((member) => member is TopLevelVariableDeclaration);
+ _validate(true, declaration.variables);
+ }
+
+ void test_dependencyOnConstructor() {
+ // x depends on "const A()"
+ _assertProperDependencies(r'''
+class A {
+ const A();
+}
+const x = const A();''');
+ }
+
+ void test_dependencyOnConstructorArgument() {
+ // "const A(x)" depends on x
+ _assertProperDependencies(r'''
+class A {
+ const A(this.next);
+ final A next;
+}
+const A x = const A(null);
+const A y = const A(x);''');
+ }
+
+ void test_dependencyOnConstructorArgument_unresolvedConstructor() {
+ // "const A.a(x)" depends on x even if the constructor A.a can't be found.
+ _assertProperDependencies(
+ r'''
+class A {
+}
+const int x = 1;
+const A y = const A.a(x);''',
+ [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR]);
+ }
+
+ void test_dependencyOnConstructorInitializer() {
+ // "const A()" depends on x
+ _assertProperDependencies(r'''
+const int x = 1;
+class A {
+ const A() : v = x;
+ final int v;
+}''');
+ }
+
+ void test_dependencyOnExplicitSuperConstructor() {
+ // b depends on B() depends on A()
+ _assertProperDependencies(r'''
+class A {
+ const A(this.x);
+ final int x;
+}
+class B extends A {
+ const B() : super(5);
+}
+const B b = const B();''');
+ }
+
+ void test_dependencyOnExplicitSuperConstructorParameters() {
+ // b depends on B() depends on i
+ _assertProperDependencies(r'''
+class A {
+ const A(this.x);
+ final int x;
+}
+class B extends A {
+ const B() : super(i);
+}
+const B b = const B();
+const int i = 5;''');
+ }
+
+ void test_dependencyOnFactoryRedirect() {
+ // a depends on A.foo() depends on A.bar()
+ _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+ factory const A.foo() = A.bar;
+ const A.bar();
+}''');
+ }
+
+ void test_dependencyOnFactoryRedirectWithTypeParams() {
+ _assertProperDependencies(r'''
+class A {
+ const factory A(var a) = B<int>;
+}
+
+class B<T> implements A {
+ final T x;
+ const B(this.x);
+}
+
+const A a = const A(10);''');
+ }
+
+ void test_dependencyOnImplicitSuperConstructor() {
+ // b depends on B() depends on A()
+ _assertProperDependencies(r'''
+class A {
+ const A() : x = 5;
+ final int x;
+}
+class B extends A {
+ const B();
+}
+const B b = const B();''');
+ }
+
+ void test_dependencyOnInitializedFinal() {
+ // a depends on A() depends on A.x
+ _assertProperDependencies('''
+class A {
+ const A();
+ final int x = 1;
+}
+const A a = const A();
+''');
+ }
+
+ void test_dependencyOnInitializedNonStaticConst() {
+ // Even though non-static consts are not allowed by the language, we need
+ // to handle them for error recovery purposes.
+ // a depends on A() depends on A.x
+ _assertProperDependencies(
+ '''
+class A {
+ const A();
+ const int x = 1;
+}
+const A a = const A();
+''',
+ [CompileTimeErrorCode.CONST_INSTANCE_FIELD]);
+ }
+
+ void test_dependencyOnNonFactoryRedirect() {
+ // a depends on A.foo() depends on A.bar()
+ _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+ const A.foo() : this.bar();
+ const A.bar();
+}''');
+ }
+
+ void test_dependencyOnNonFactoryRedirect_arg() {
+ // a depends on A.foo() depends on b
+ _assertProperDependencies(r'''
+const A a = const A.foo();
+const int b = 1;
+class A {
+ const A.foo() : this.bar(b);
+ const A.bar(x) : y = x;
+ final int y;
+}''');
+ }
+
+ void test_dependencyOnNonFactoryRedirect_defaultValue() {
+ // a depends on A.foo() depends on A.bar() depends on b
+ _assertProperDependencies(r'''
+const A a = const A.foo();
+const int b = 1;
+class A {
+ const A.foo() : this.bar();
+ const A.bar([x = b]) : y = x;
+ final int y;
+}''');
+ }
+
+ void test_dependencyOnNonFactoryRedirect_toMissing() {
+ // a depends on A.foo() which depends on nothing, since A.bar() is
+ // missing.
+ _assertProperDependencies(
+ r'''
+const A a = const A.foo();
+class A {
+ const A.foo() : this.bar();
+}''',
+ [CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR]);
+ }
+
+ void test_dependencyOnNonFactoryRedirect_toNonConst() {
+ // a depends on A.foo() which depends on nothing, since A.bar() is
+ // non-const.
+ _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+ const A.foo() : this.bar();
+ A.bar();
+}''');
+ }
+
+ void test_dependencyOnNonFactoryRedirect_unnamed() {
+ // a depends on A.foo() depends on A()
+ _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+ const A.foo() : this();
+ const A();
+}''');
+ }
+
+ void test_dependencyOnOptionalParameterDefault() {
+ // a depends on A() depends on B()
+ _assertProperDependencies(r'''
+class A {
+ const A([x = const B()]) : b = x;
+ final B b;
+}
+class B {
+ const B();
+}
+const A a = const A();''');
+ }
+
+ void test_dependencyOnVariable() {
+ // x depends on y
+ _assertProperDependencies(r'''
+const x = y + 1;
+const y = 2;''');
+ }
+
+ void test_final_initialized_at_declaration() {
+ CompilationUnit compilationUnit = resolveSource('''
+class A {
+ final int i = 123;
+ const A();
+}
+
+const A a = const A();
+''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, 'a');
+ Map<String, DartObjectImpl> fields = _assertType(result, "A");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "i", 123);
+ }
+
+ void test_fromEnvironment_bool_default_false() {
+ expect(_assertValidBool(_check_fromEnvironment_bool(null, "false")), false);
+ }
+
+ void test_fromEnvironment_bool_default_overridden() {
+ expect(
+ _assertValidBool(_check_fromEnvironment_bool("false", "true")), false);
+ }
+
+ void test_fromEnvironment_bool_default_parseError() {
+ expect(_assertValidBool(_check_fromEnvironment_bool("parseError", "true")),
+ true);
+ }
+
+ void test_fromEnvironment_bool_default_true() {
+ expect(_assertValidBool(_check_fromEnvironment_bool(null, "true")), true);
+ }
+
+ void test_fromEnvironment_bool_false() {
+ expect(_assertValidBool(_check_fromEnvironment_bool("false", null)), false);
+ }
+
+ void test_fromEnvironment_bool_parseError() {
+ expect(_assertValidBool(_check_fromEnvironment_bool("parseError", null)),
+ false);
+ }
+
+ void test_fromEnvironment_bool_true() {
+ expect(_assertValidBool(_check_fromEnvironment_bool("true", null)), true);
+ }
+
+ void test_fromEnvironment_bool_undeclared() {
+ _assertValidUnknown(_check_fromEnvironment_bool(null, null));
+ }
+
+ void test_fromEnvironment_int_default_overridden() {
+ expect(_assertValidInt(_check_fromEnvironment_int("234", "123")), 234);
+ }
+
+ void test_fromEnvironment_int_default_parseError() {
+ expect(
+ _assertValidInt(_check_fromEnvironment_int("parseError", "123")), 123);
+ }
+
+ void test_fromEnvironment_int_default_undeclared() {
+ expect(_assertValidInt(_check_fromEnvironment_int(null, "123")), 123);
+ }
+
+ void test_fromEnvironment_int_ok() {
+ expect(_assertValidInt(_check_fromEnvironment_int("234", null)), 234);
+ }
+
+ void test_fromEnvironment_int_parseError() {
+ _assertValidNull(_check_fromEnvironment_int("parseError", null));
+ }
+
+ void test_fromEnvironment_int_parseError_nullDefault() {
+ _assertValidNull(_check_fromEnvironment_int("parseError", "null"));
+ }
+
+ void test_fromEnvironment_int_undeclared() {
+ _assertValidUnknown(_check_fromEnvironment_int(null, null));
+ }
+
+ void test_fromEnvironment_int_undeclared_nullDefault() {
+ _assertValidNull(_check_fromEnvironment_int(null, "null"));
+ }
+
+ void test_fromEnvironment_string_default_overridden() {
+ expect(_assertValidString(_check_fromEnvironment_string("abc", "'def'")),
+ "abc");
+ }
+
+ void test_fromEnvironment_string_default_undeclared() {
+ expect(_assertValidString(_check_fromEnvironment_string(null, "'def'")),
+ "def");
+ }
+
+ void test_fromEnvironment_string_empty() {
+ expect(_assertValidString(_check_fromEnvironment_string("", null)), "");
+ }
+
+ void test_fromEnvironment_string_ok() {
+ expect(
+ _assertValidString(_check_fromEnvironment_string("abc", null)), "abc");
+ }
+
+ void test_fromEnvironment_string_undeclared() {
+ _assertValidUnknown(_check_fromEnvironment_string(null, null));
+ }
+
+ void test_fromEnvironment_string_undeclared_nullDefault() {
+ _assertValidNull(_check_fromEnvironment_string(null, "null"));
+ }
+
+ void test_instanceCreationExpression_computedField() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(4, 5);
+class A {
+ const A(int i, int j) : k = 2 * i + j;
+ final int k;
+}''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ Map<String, DartObjectImpl> fields = _assertType(result, "A");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "k", 13);
+ }
+
+ void
+ test_instanceCreationExpression_computedField_namedOptionalWithDefault() {
+ _checkInstanceCreationOptionalParams(false, true, true);
+ }
+
+ void
+ test_instanceCreationExpression_computedField_namedOptionalWithoutDefault() {
+ _checkInstanceCreationOptionalParams(false, true, false);
+ }
+
+ void
+ test_instanceCreationExpression_computedField_unnamedOptionalWithDefault() {
+ _checkInstanceCreationOptionalParams(false, false, true);
+ }
+
+ void
+ test_instanceCreationExpression_computedField_unnamedOptionalWithoutDefault() {
+ _checkInstanceCreationOptionalParams(false, false, false);
+ }
+
+ void test_instanceCreationExpression_computedField_usesConstConstructor() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(3);
+class A {
+ const A(int i) : b = const B(4);
+ final int b;
+}
+class B {
+ const B(this.k);
+ final int k;
+}''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ Map<String, DartObjectImpl> fieldsOfA = _assertType(result, "A");
+ expect(fieldsOfA, hasLength(1));
+ Map<String, DartObjectImpl> fieldsOfB =
+ _assertFieldType(fieldsOfA, "b", "B");
+ expect(fieldsOfB, hasLength(1));
+ _assertIntField(fieldsOfB, "k", 4);
+ }
+
+ void test_instanceCreationExpression_computedField_usesStaticConst() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(3);
+class A {
+ const A(int i) : k = i + B.bar;
+ final int k;
+}
+class B {
+ static const bar = 4;
+}''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ Map<String, DartObjectImpl> fields = _assertType(result, "A");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "k", 7);
+ }
+
+ void test_instanceCreationExpression_computedField_usesToplevelConst() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(3);
+const bar = 4;
+class A {
+ const A(int i) : k = i + bar;
+ final int k;
+}''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ Map<String, DartObjectImpl> fields = _assertType(result, "A");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "k", 7);
+ }
+
+ void test_instanceCreationExpression_explicitSuper() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const B(4, 5);
+class A {
+ const A(this.x);
+ final int x;
+}
+class B extends A {
+ const B(int x, this.y) : super(x * 2);
+ final int y;
+}''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ Map<String, DartObjectImpl> fields = _assertType(result, "B");
+ expect(fields, hasLength(2));
+ _assertIntField(fields, "y", 5);
+ Map<String, DartObjectImpl> superclassFields =
+ _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
+ expect(superclassFields, hasLength(1));
+ _assertIntField(superclassFields, "x", 8);
+ }
+
+ void test_instanceCreationExpression_fieldFormalParameter() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(42);
+class A {
+ int x;
+ const A(this.x)
+}''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ Map<String, DartObjectImpl> fields = _assertType(result, "A");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "x", 42);
+ }
+
+ void
+ test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithDefault() {
+ _checkInstanceCreationOptionalParams(true, true, true);
+ }
+
+ void
+ test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithoutDefault() {
+ _checkInstanceCreationOptionalParams(true, true, false);
+ }
+
+ void
+ test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithDefault() {
+ _checkInstanceCreationOptionalParams(true, false, true);
+ }
+
+ void
+ test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithoutDefault() {
+ _checkInstanceCreationOptionalParams(true, false, false);
+ }
+
+ void test_instanceCreationExpression_implicitSuper() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const B(4);
+class A {
+ const A() : x = 3;
+ final int x;
+}
+class B extends A {
+ const B(this.y);
+ final int y;
+}''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ Map<String, DartObjectImpl> fields = _assertType(result, "B");
+ expect(fields, hasLength(2));
+ _assertIntField(fields, "y", 4);
+ Map<String, DartObjectImpl> superclassFields =
+ _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
+ expect(superclassFields, hasLength(1));
+ _assertIntField(superclassFields, "x", 3);
+ }
+
+ void test_instanceCreationExpression_nonFactoryRedirect() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+ const A.a1() : this.a2();
+ const A.a2() : x = 5;
+ final int x;
+}''');
+ Map<String, DartObjectImpl> aFields =
+ _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+ _assertIntField(aFields, 'x', 5);
+ }
+
+ void test_instanceCreationExpression_nonFactoryRedirect_arg() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1(1);
+class A {
+ const A.a1(x) : this.a2(x + 100);
+ const A.a2(x) : y = x + 10;
+ final int y;
+}''');
+ Map<String, DartObjectImpl> aFields =
+ _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+ _assertIntField(aFields, 'y', 111);
+ }
+
+ void test_instanceCreationExpression_nonFactoryRedirect_cycle() {
+ // It is an error to have a cycle in non-factory redirects; however, we
+ // need to make sure that even if the error occurs, attempting to evaluate
+ // the constant will terminate.
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+ const A() : this.b();
+ const A.b() : this();
+}''');
+ _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+ }
+
+ void test_instanceCreationExpression_nonFactoryRedirect_defaultArg() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+ const A.a1() : this.a2();
+ const A.a2([x = 100]) : y = x + 10;
+ final int y;
+}''');
+ Map<String, DartObjectImpl> aFields =
+ _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+ _assertIntField(aFields, 'y', 110);
+ }
+
+ void test_instanceCreationExpression_nonFactoryRedirect_toMissing() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+ const A.a1() : this.a2();
+}''');
+ // We don't care what value foo evaluates to (since there is a compile
+ // error), but we shouldn't crash, and we should figure
+ // out that it evaluates to an instance of class A.
+ _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+ }
+
+ void test_instanceCreationExpression_nonFactoryRedirect_toNonConst() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+ const A.a1() : this.a2();
+ A.a2();
+}''');
+ // We don't care what value foo evaluates to (since there is a compile
+ // error), but we shouldn't crash, and we should figure
+ // out that it evaluates to an instance of class A.
+ _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+ }
+
+ void test_instanceCreationExpression_nonFactoryRedirect_unnamed() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+ const A.a1() : this();
+ const A() : x = 5;
+ final int x;
+}''');
+ Map<String, DartObjectImpl> aFields =
+ _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+ _assertIntField(aFields, 'x', 5);
+ }
+
+ void test_instanceCreationExpression_redirect() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+ const factory A() = B;
+}
+class B implements A {
+ const B();
+}''');
+ _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "B");
+ }
+
+ void test_instanceCreationExpression_redirect_cycle() {
+ // It is an error to have a cycle in factory redirects; however, we need
+ // to make sure that even if the error occurs, attempting to evaluate the
+ // constant will terminate.
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+ const factory A() = A.b;
+ const factory A.b() = A;
+}''');
+ _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+ }
+
+ void test_instanceCreationExpression_redirect_extern() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+ external const factory A();
+}''');
+ _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+ }
+
+ void test_instanceCreationExpression_redirect_nonConst() {
+ // It is an error for a const factory constructor redirect to a non-const
+ // constructor; however, we need to make sure that even if the error
+ // attempting to evaluate the constant won't cause a crash.
+ CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+ const factory A() = A.b;
+ A.b();
+}''');
+ _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+ }
+
+ void test_instanceCreationExpression_redirectWithTypeParams() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+ const factory A(var a) = B<int>;
+}
+
+class B<T> implements A {
+ final T x;
+ const B(this.x);
+}
+
+const A a = const A(10);''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "a");
+ Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "x", 10);
+ }
+
+ void test_instanceCreationExpression_redirectWithTypeSubstitution() {
+ // To evaluate the redirection of A<int>,
+ // A's template argument (T=int) must be substituted
+ // into B's template argument (B<U> where U=T) to get B<int>.
+ CompilationUnit compilationUnit = resolveSource(r'''
+class A<T> {
+ const factory A(var a) = B<T>;
+}
+
+class B<U> implements A {
+ final U x;
+ const B(this.x);
+}
+
+const A<int> a = const A<int>(10);''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, "a");
+ Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "x", 10);
+ }
+
+ void test_instanceCreationExpression_symbol() {
+ CompilationUnit compilationUnit =
+ resolveSource("const foo = const Symbol('a');");
+ EvaluationResultImpl evaluationResult =
+ _evaluateTopLevelVariable(compilationUnit, "foo");
+ expect(evaluationResult.value, isNotNull);
+ DartObjectImpl value = evaluationResult.value;
+ expect(value.type, typeProvider.symbolType);
+ expect(value.toSymbolValue(), "a");
+ }
+
+ void test_instanceCreationExpression_withSupertypeParams_explicit() {
+ _checkInstanceCreation_withSupertypeParams(true);
+ }
+
+ void test_instanceCreationExpression_withSupertypeParams_implicit() {
+ _checkInstanceCreation_withSupertypeParams(false);
+ }
+
+ void test_instanceCreationExpression_withTypeParams() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+class C<E> {
+ const C();
+}
+const c_int = const C<int>();
+const c_num = const C<num>();''');
+ EvaluationResultImpl c_int =
+ _evaluateTopLevelVariable(compilationUnit, "c_int");
+ _assertType(c_int, "C<int>");
+ DartObjectImpl c_int_value = c_int.value;
+ EvaluationResultImpl c_num =
+ _evaluateTopLevelVariable(compilationUnit, "c_num");
+ _assertType(c_num, "C<num>");
+ DartObjectImpl c_num_value = c_num.value;
+ expect(c_int_value == c_num_value, isFalse);
+ }
+
+ void test_isValidSymbol() {
+ expect(ConstantEvaluationEngine.isValidPublicSymbol(""), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$bar"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("iff"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("gif"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("if\$"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("\$if"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo="), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar="), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.+"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("void"), isTrue);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo.bar"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo._bar"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("if"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("if.foo"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.if"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo=.bar"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo."), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("+.foo"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("void.foo"), isFalse);
+ expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.void"), isFalse);
+ }
+
+ void test_length_of_improperly_typed_string_expression() {
+ // Since type annotations are ignored in unchecked mode, the improper
+ // types on s1 and s2 shouldn't prevent us from evaluating i to
+ // 'alpha'.length.
+ CompilationUnit compilationUnit = resolveSource('''
+const int s1 = 'alpha';
+const int s2 = 'beta';
+const int i = (true ? s1 : s2).length;
+''');
+ ConstTopLevelVariableElementImpl element =
+ findTopLevelDeclaration(compilationUnit, 'i').element;
+ EvaluationResultImpl result = element.evaluationResult;
+ expect(_assertValidInt(result), 5);
+ }
+
+ void test_length_of_improperly_typed_string_identifier() {
+ // Since type annotations are ignored in unchecked mode, the improper type
+ // on s shouldn't prevent us from evaluating i to 'alpha'.length.
+ CompilationUnit compilationUnit = resolveSource('''
+const int s = 'alpha';
+const int i = s.length;
+''');
+ ConstTopLevelVariableElementImpl element =
+ findTopLevelDeclaration(compilationUnit, 'i').element;
+ EvaluationResultImpl result = element.evaluationResult;
+ expect(_assertValidInt(result), 5);
+ }
+
+ void test_non_static_const_initialized_at_declaration() {
+ // Even though non-static consts are not allowed by the language, we need
+ // to handle them for error recovery purposes.
+ CompilationUnit compilationUnit = resolveSource('''
+class A {
+ const int i = 123;
+ const A();
+}
+
+const A a = const A();
+''');
+ EvaluationResultImpl result =
+ _evaluateTopLevelVariable(compilationUnit, 'a');
+ Map<String, DartObjectImpl> fields = _assertType(result, "A");
+ expect(fields, hasLength(1));
+ _assertIntField(fields, "i", 123);
+ }
+
+ void test_symbolLiteral_void() {
+ CompilationUnit compilationUnit =
+ resolveSource("const voidSymbol = #void;");
+ VariableDeclaration voidSymbol =
+ findTopLevelDeclaration(compilationUnit, "voidSymbol");
+ EvaluationResultImpl voidSymbolResult =
+ (voidSymbol.element as VariableElementImpl).evaluationResult;
+ DartObjectImpl value = voidSymbolResult.value;
+ expect(value.type, typeProvider.symbolType);
+ expect(value.toSymbolValue(), "void");
+ }
+
+ Map<String, DartObjectImpl> _assertFieldType(
+ Map<String, DartObjectImpl> fields,
+ String fieldName,
+ String expectedType) {
+ DartObjectImpl field = fields[fieldName];
+ expect(field.type.displayName, expectedType);
+ return field.fields;
+ }
+
+ void _assertIntField(
+ Map<String, DartObjectImpl> fields, String fieldName, int expectedValue) {
+ DartObjectImpl field = fields[fieldName];
+ expect(field.type.name, "int");
+ expect(field.toIntValue(), expectedValue);
+ }
+
+ void _assertNullField(Map<String, DartObjectImpl> fields, String fieldName) {
+ DartObjectImpl field = fields[fieldName];
+ expect(field.isNull, isTrue);
+ }
+
+ void _assertProperDependencies(String sourceText,
+ [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
+ Source source = addSource(sourceText);
+ LibraryElement element = resolve2(source);
+ CompilationUnit unit =
+ analysisContext.resolveCompilationUnit(source, element);
+ expect(unit, isNotNull);
+ ConstantValueComputer computer = _makeConstantValueComputer();
+ computer.add(unit, source, source);
+ computer.computeValues();
+ assertErrors(source, expectedErrorCodes);
+ }
+
+ Map<String, DartObjectImpl> _assertType(
+ EvaluationResultImpl result, String typeName) {
+ expect(result.value, isNotNull);
+ DartObjectImpl value = result.value;
+ expect(value.type.displayName, typeName);
+ return value.fields;
+ }
+
+ bool _assertValidBool(EvaluationResultImpl result) {
+ expect(result.value, isNotNull);
+ DartObjectImpl value = result.value;
+ expect(value.type, typeProvider.boolType);
+ bool boolValue = value.toBoolValue();
+ expect(boolValue, isNotNull);
+ return boolValue;
+ }
+
+ int _assertValidInt(EvaluationResultImpl result) {
+ expect(result.value, isNotNull);
+ DartObjectImpl value = result.value;
+ expect(value.type, typeProvider.intType);
+ return value.toIntValue();
+ }
+
+ void _assertValidNull(EvaluationResultImpl result) {
+ expect(result.value, isNotNull);
+ DartObjectImpl value = result.value;
+ expect(value.type, typeProvider.nullType);
+ }
+
+ String _assertValidString(EvaluationResultImpl result) {
+ expect(result.value, isNotNull);
+ DartObjectImpl value = result.value;
+ expect(value.type, typeProvider.stringType);
+ return value.toStringValue();
+ }
+
+ void _assertValidUnknown(EvaluationResultImpl result) {
+ expect(result.value, isNotNull);
+ DartObjectImpl value = result.value;
+ expect(value.isUnknown, isTrue);
+ }
+
+ EvaluationResultImpl _check_fromEnvironment_bool(
+ String valueInEnvironment, String defaultExpr) {
+ String envVarName = "x";
+ String varName = "foo";
+ if (valueInEnvironment != null) {
+ analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
+ }
+ String defaultArg =
+ defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
+ CompilationUnit compilationUnit = resolveSource(
+ "const $varName = const bool.fromEnvironment('$envVarName'$defaultArg);");
+ return _evaluateTopLevelVariable(compilationUnit, varName);
+ }
+
+ EvaluationResultImpl _check_fromEnvironment_int(
+ String valueInEnvironment, String defaultExpr) {
+ String envVarName = "x";
+ String varName = "foo";
+ if (valueInEnvironment != null) {
+ analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
+ }
+ String defaultArg =
+ defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
+ CompilationUnit compilationUnit = resolveSource(
+ "const $varName = const int.fromEnvironment('$envVarName'$defaultArg);");
+ return _evaluateTopLevelVariable(compilationUnit, varName);
+ }
+
+ EvaluationResultImpl _check_fromEnvironment_string(
+ String valueInEnvironment, String defaultExpr) {
+ String envVarName = "x";
+ String varName = "foo";
+ if (valueInEnvironment != null) {
+ analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
+ }
+ String defaultArg =
+ defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
+ CompilationUnit compilationUnit = resolveSource(
+ "const $varName = const String.fromEnvironment('$envVarName'$defaultArg);");
+ return _evaluateTopLevelVariable(compilationUnit, varName);
+ }
+
+ void _checkInstanceCreation_withSupertypeParams(bool isExplicit) {
+ String superCall = isExplicit ? " : super()" : "";
+ CompilationUnit compilationUnit = resolveSource("""
+class A<T> {
+ const A();
+}
+class B<T, U> extends A<T> {
+ const B()$superCall;
+}
+class C<T, U> extends A<U> {
+ const C()$superCall;
+}
+const b_int_num = const B<int, num>();
+const c_int_num = const C<int, num>();""");
+ EvaluationResultImpl b_int_num =
+ _evaluateTopLevelVariable(compilationUnit, "b_int_num");
+ Map<String, DartObjectImpl> b_int_num_fields =
+ _assertType(b_int_num, "B<int, num>");
+ _assertFieldType(b_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<int>");
+ EvaluationResultImpl c_int_num =
+ _evaluateTopLevelVariable(compilationUnit, "c_int_num");
+ Map<String, DartObjectImpl> c_int_num_fields =
+ _assertType(c_int_num, "C<int, num>");
+ _assertFieldType(c_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<num>");
+ }
+
+ void _checkInstanceCreationOptionalParams(
+ bool isFieldFormal, bool isNamed, bool hasDefault) {
+ String fieldName = "j";
+ String paramName = isFieldFormal ? fieldName : "i";
+ String formalParam =
+ "${isFieldFormal ? "this." : "int "}$paramName${hasDefault ? " = 3" : ""}";
+ CompilationUnit compilationUnit = resolveSource("""
+const x = const A();
+const y = const A(${isNamed ? '$paramName: ' : ''}10);
+class A {
+ const A(${isNamed ? "{$formalParam}" : "[$formalParam]"})${isFieldFormal ? "" : " : $fieldName = $paramName"};
+ final int $fieldName;
+}""");
+ EvaluationResultImpl x = _evaluateTopLevelVariable(compilationUnit, "x");
+ Map<String, DartObjectImpl> fieldsOfX = _assertType(x, "A");
+ expect(fieldsOfX, hasLength(1));
+ if (hasDefault) {
+ _assertIntField(fieldsOfX, fieldName, 3);
+ } else {
+ _assertNullField(fieldsOfX, fieldName);
+ }
+ EvaluationResultImpl y = _evaluateTopLevelVariable(compilationUnit, "y");
+ Map<String, DartObjectImpl> fieldsOfY = _assertType(y, "A");
+ expect(fieldsOfY, hasLength(1));
+ _assertIntField(fieldsOfY, fieldName, 10);
+ }
+
+ /**
+ * Search [compilationUnit] for a class named [className], containing a
+ * method [methodName], with exactly one annotation. Return the constant
+ * value of the annotation.
+ */
+ EvaluationResultImpl _evaluateAnnotation(
+ CompilationUnit compilationUnit, String className, String memberName) {
+ for (CompilationUnitMember member in compilationUnit.declarations) {
+ if (member is ClassDeclaration && member.name.name == className) {
+ for (ClassMember classMember in member.members) {
+ if (classMember is MethodDeclaration &&
+ classMember.name.name == memberName) {
+ expect(classMember.metadata, hasLength(1));
+ ElementAnnotationImpl elementAnnotation =
+ classMember.metadata[0].elementAnnotation;
+ return elementAnnotation.evaluationResult;
+ }
+ }
+ }
+ }
+ fail('Class member not found');
+ return null;
+ }
+
+ EvaluationResultImpl _evaluateTopLevelVariable(
+ CompilationUnit compilationUnit, String name) {
+ VariableDeclaration varDecl =
+ findTopLevelDeclaration(compilationUnit, name);
+ ConstTopLevelVariableElementImpl varElement = varDecl.element;
+ return varElement.evaluationResult;
+ }
+
+ ConstantValueComputer _makeConstantValueComputer() {
+ ConstantEvaluationValidator_ForTest validator =
+ new ConstantEvaluationValidator_ForTest(analysisContext2);
+ validator.computer = new ConstantValueComputer(
+ analysisContext2,
+ analysisContext2.typeProvider,
+ analysisContext2.declaredVariables,
+ validator,
+ analysisContext2.typeSystem);
+ return validator.computer;
+ }
+
+ void _validate(bool shouldBeValid, VariableDeclarationList declarationList) {
+ for (VariableDeclaration declaration in declarationList.variables) {
+ VariableElementImpl element = declaration.element as VariableElementImpl;
+ expect(element, isNotNull);
+ EvaluationResultImpl result = element.evaluationResult;
+ if (shouldBeValid) {
+ expect(result.value, isNotNull);
+ } else {
+ expect(result.value, isNull);
+ }
+ }
+ }
+}
+
+@reflectiveTest
+class ConstantVisitorTest extends ResolverTestCase {
+ void test_visitBinaryExpression_questionQuestion_notNull_notNull() {
+ Expression left = AstFactory.string2('a');
+ Expression right = AstFactory.string2('b');
+ Expression expression =
+ AstFactory.binaryExpression(left, TokenType.QUESTION_QUESTION, right);
+
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ DartObjectImpl result = _evaluate(expression, errorReporter);
+ expect(result, isNotNull);
+ expect(result.isNull, isFalse);
+ expect(result.toStringValue(), 'a');
+ errorListener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_questionQuestion_null_notNull() {
+ Expression left = AstFactory.nullLiteral();
+ Expression right = AstFactory.string2('b');
+ Expression expression =
+ AstFactory.binaryExpression(left, TokenType.QUESTION_QUESTION, right);
+
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ DartObjectImpl result = _evaluate(expression, errorReporter);
+ expect(result, isNotNull);
+ expect(result.isNull, isFalse);
+ expect(result.toStringValue(), 'b');
+ errorListener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_questionQuestion_null_null() {
+ Expression left = AstFactory.nullLiteral();
+ Expression right = AstFactory.nullLiteral();
+ Expression expression =
+ AstFactory.binaryExpression(left, TokenType.QUESTION_QUESTION, right);
+
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ DartObjectImpl result = _evaluate(expression, errorReporter);
+ expect(result, isNotNull);
+ expect(result.isNull, isTrue);
+ errorListener.assertNoErrors();
+ }
+
+ void test_visitConditionalExpression_false() {
+ Expression thenExpression = AstFactory.integer(1);
+ Expression elseExpression = AstFactory.integer(0);
+ ConditionalExpression expression = AstFactory.conditionalExpression(
+ AstFactory.booleanLiteral(false), thenExpression, elseExpression);
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ _assertValue(0, _evaluate(expression, errorReporter));
+ errorListener.assertNoErrors();
+ }
+
+ void test_visitConditionalExpression_nonBooleanCondition() {
+ Expression thenExpression = AstFactory.integer(1);
+ Expression elseExpression = AstFactory.integer(0);
+ NullLiteral conditionExpression = AstFactory.nullLiteral();
+ ConditionalExpression expression = AstFactory.conditionalExpression(
+ conditionExpression, thenExpression, elseExpression);
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ DartObjectImpl result = _evaluate(expression, errorReporter);
+ expect(result, isNull);
+ errorListener
+ .assertErrorsWithCodes([CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL]);
+ }
+
+ void test_visitConditionalExpression_nonConstantElse() {
+ Expression thenExpression = AstFactory.integer(1);
+ Expression elseExpression = AstFactory.identifier3("x");
+ ConditionalExpression expression = AstFactory.conditionalExpression(
+ AstFactory.booleanLiteral(true), thenExpression, elseExpression);
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ DartObjectImpl result = _evaluate(expression, errorReporter);
+ expect(result, isNull);
+ errorListener
+ .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
+ }
+
+ void test_visitConditionalExpression_nonConstantThen() {
+ Expression thenExpression = AstFactory.identifier3("x");
+ Expression elseExpression = AstFactory.integer(0);
+ ConditionalExpression expression = AstFactory.conditionalExpression(
+ AstFactory.booleanLiteral(true), thenExpression, elseExpression);
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ DartObjectImpl result = _evaluate(expression, errorReporter);
+ expect(result, isNull);
+ errorListener
+ .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
+ }
+
+ void test_visitConditionalExpression_true() {
+ Expression thenExpression = AstFactory.integer(1);
+ Expression elseExpression = AstFactory.integer(0);
+ ConditionalExpression expression = AstFactory.conditionalExpression(
+ AstFactory.booleanLiteral(true), thenExpression, elseExpression);
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter =
+ new ErrorReporter(errorListener, _dummySource());
+ _assertValue(1, _evaluate(expression, errorReporter));
+ errorListener.assertNoErrors();
+ }
+
+ void test_visitSimpleIdentifier_className() {
+ CompilationUnit compilationUnit = resolveSource('''
+const a = C;
+class C {}
+''');
+ DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
+ expect(result.type, typeProvider.typeType);
+ expect(result.toTypeValue().name, 'C');
+ }
+
+ void test_visitSimpleIdentifier_dynamic() {
+ CompilationUnit compilationUnit = resolveSource('''
+const a = dynamic;
+''');
+ DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
+ expect(result.type, typeProvider.typeType);
+ expect(result.toTypeValue(), typeProvider.dynamicType);
+ }
+
+ void test_visitSimpleIdentifier_inEnvironment() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const a = b;
+const b = 3;''');
+ Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
+ DartObjectImpl six =
+ new DartObjectImpl(typeProvider.intType, new IntState(6));
+ environment["b"] = six;
+ _assertValue(6, _evaluateConstant(compilationUnit, "a", environment));
+ }
+
+ void test_visitSimpleIdentifier_notInEnvironment() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const a = b;
+const b = 3;''');
+ Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
+ DartObjectImpl six =
+ new DartObjectImpl(typeProvider.intType, new IntState(6));
+ environment["c"] = six;
+ _assertValue(3, _evaluateConstant(compilationUnit, "a", environment));
+ }
+
+ void test_visitSimpleIdentifier_withoutEnvironment() {
+ CompilationUnit compilationUnit = resolveSource(r'''
+const a = b;
+const b = 3;''');
+ _assertValue(3, _evaluateConstant(compilationUnit, "a", null));
+ }
+
+ void _assertValue(int expectedValue, DartObjectImpl result) {
+ expect(result, isNotNull);
+ expect(result.type.name, "int");
+ expect(result.toIntValue(), expectedValue);
+ }
+
+ NonExistingSource _dummySource() {
+ String path = '/test.dart';
+ return new NonExistingSource(path, toUri(path), UriKind.FILE_URI);
+ }
+
+ DartObjectImpl _evaluate(Expression expression, ErrorReporter errorReporter) {
+ return expression.accept(new ConstantVisitor(
+ new ConstantEvaluationEngine(
+ new TestTypeProvider(), new DeclaredVariables(),
+ typeSystem: new TypeSystemImpl()),
+ errorReporter));
+ }
+
+ DartObjectImpl _evaluateConstant(CompilationUnit compilationUnit, String name,
+ Map<String, DartObjectImpl> lexicalEnvironment) {
+ Source source = compilationUnit.element.source;
+ Expression expression =
+ findTopLevelConstantExpression(compilationUnit, name);
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+ DartObjectImpl result = expression.accept(new ConstantVisitor(
+ new ConstantEvaluationEngine(typeProvider, new DeclaredVariables(),
+ typeSystem: typeSystem),
+ errorReporter,
+ lexicalEnvironment: lexicalEnvironment));
+ errorListener.assertNoErrors();
+ return result;
+ }
+}
+
+@reflectiveTest
+class ReferenceFinderTest {
+ DirectedGraph<ConstantEvaluationTarget> _referenceGraph;
+ VariableElement _head;
+ Element _tail;
+
+ void setUp() {
+ _referenceGraph = new DirectedGraph<ConstantEvaluationTarget>();
+ _head = ElementFactory.topLevelVariableElement2("v1");
+ }
+
+ void test_visitSimpleIdentifier_const() {
+ _visitNode(_makeTailVariable("v2", true));
+ _assertOneArc(_tail);
+ }
+
+ void test_visitSuperConstructorInvocation_const() {
+ _visitNode(_makeTailSuperConstructorInvocation("A", true));
+ _assertOneArc(_tail);
+ }
+
+ void test_visitSuperConstructorInvocation_nonConst() {
+ _visitNode(_makeTailSuperConstructorInvocation("A", false));
+ _assertOneArc(_tail);
+ }
+
+ void test_visitSuperConstructorInvocation_unresolved() {
+ SuperConstructorInvocation superConstructorInvocation =
+ AstFactory.superConstructorInvocation();
+ _visitNode(superConstructorInvocation);
+ _assertNoArcs();
+ }
+
+ void _assertNoArcs() {
+ Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
+ expect(tails, hasLength(0));
+ }
+
+ void _assertOneArc(Element tail) {
+ Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
+ expect(tails, hasLength(1));
+ expect(tails.first, same(tail));
+ }
+
+ ReferenceFinder _createReferenceFinder(ConstantEvaluationTarget source) =>
+ new ReferenceFinder((ConstantEvaluationTarget dependency) {
+ _referenceGraph.addEdge(source, dependency);
+ });
+ SuperConstructorInvocation _makeTailSuperConstructorInvocation(
+ String name, bool isConst) {
+ List<ConstructorInitializer> initializers =
+ new List<ConstructorInitializer>();
+ ConstructorDeclaration constructorDeclaration =
+ AstFactory.constructorDeclaration(AstFactory.identifier3(name), null,
+ AstFactory.formalParameterList(), initializers);
+ if (isConst) {
+ constructorDeclaration.constKeyword = new KeywordToken(Keyword.CONST, 0);
+ }
+ ClassElementImpl classElement = ElementFactory.classElement2(name);
+ SuperConstructorInvocation superConstructorInvocation =
+ AstFactory.superConstructorInvocation();
+ ConstructorElementImpl constructorElement =
+ ElementFactory.constructorElement(classElement, name, isConst);
+ _tail = constructorElement;
+ superConstructorInvocation.staticElement = constructorElement;
+ return superConstructorInvocation;
+ }
+
+ SimpleIdentifier _makeTailVariable(String name, bool isConst) {
+ VariableDeclaration variableDeclaration =
+ AstFactory.variableDeclaration(name);
+ ConstLocalVariableElementImpl variableElement =
+ ElementFactory.constLocalVariableElement(name);
+ _tail = variableElement;
+ variableElement.const3 = isConst;
+ AstFactory.variableDeclarationList2(
+ isConst ? Keyword.CONST : Keyword.VAR, [variableDeclaration]);
+ SimpleIdentifier identifier = AstFactory.identifier3(name);
+ identifier.staticElement = variableElement;
+ return identifier;
+ }
+
+ void _visitNode(AstNode node) {
+ node.accept(_createReferenceFinder(_head));
+ }
+}
+
+class _TestAnalysisContext extends TestAnalysisContext {
+ @override
+ InternalAnalysisContext getContextFor(Source source) => this;
+}
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
index 3dfae2b..188cc26 100644
--- a/pkg/analyzer/test/generated/declaration_resolver_test.dart
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -4,8 +4,9 @@
library engine.declaration_resolver_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:unittest/unittest.dart';
@@ -35,6 +36,27 @@
@reflectiveTest
class DeclarationResolverTest extends ResolverTestCase {
+ void fail_visitMethodDeclaration_setter_duplicate() {
+ // https://github.com/dart-lang/sdk/issues/25601
+ String code = r'''
+class C {
+ set zzz(x) {}
+ set zzz(y) {}
+}
+''';
+ CompilationUnit unit = resolveSource(code);
+ PropertyAccessorElement firstElement =
+ _findSimpleIdentifier(unit, code, 'zzz(x)').staticElement;
+ PropertyAccessorElement secondElement =
+ _findSimpleIdentifier(unit, code, 'zzz(y)').staticElement;
+ // re-resolve
+ CompilationUnit unit2 = _cloneResolveUnit(unit);
+ SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz(x)');
+ SimpleIdentifier secondName = _findSimpleIdentifier(unit2, code, 'zzz(y)');
+ expect(firstName.staticElement, same(firstElement));
+ expect(secondName.staticElement, same(secondElement));
+ }
+
@override
void setUp() {
super.setUp();
@@ -97,6 +119,47 @@
SimpleIdentifier setterName = _findSimpleIdentifier(unit2, code, 'zzz(x)');
expect(setterName.staticElement, same(setterElement));
}
+
+ void test_visitMethodDeclaration_getter_duplicate() {
+ String code = r'''
+class C {
+ int get zzz => 1;
+ String get zzz => null;
+}
+''';
+ CompilationUnit unit = resolveSource(code);
+ PropertyAccessorElement firstElement =
+ _findSimpleIdentifier(unit, code, 'zzz => 1').staticElement;
+ PropertyAccessorElement secondElement =
+ _findSimpleIdentifier(unit, code, 'zzz => null').staticElement;
+ // re-resolve
+ CompilationUnit unit2 = _cloneResolveUnit(unit);
+ SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz => 1');
+ SimpleIdentifier secondName =
+ _findSimpleIdentifier(unit2, code, 'zzz => null');
+ expect(firstName.staticElement, same(firstElement));
+ expect(secondName.staticElement, same(secondElement));
+ }
+
+ void test_visitMethodDeclaration_method_duplicate() {
+ String code = r'''
+class C {
+ void zzz(x) {}
+ void zzz(y) {}
+}
+''';
+ CompilationUnit unit = resolveSource(code);
+ MethodElement firstElement =
+ _findSimpleIdentifier(unit, code, 'zzz(x)').staticElement;
+ MethodElement secondElement =
+ _findSimpleIdentifier(unit, code, 'zzz(y)').staticElement;
+ // re-resolve
+ CompilationUnit unit2 = _cloneResolveUnit(unit);
+ SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz(x)');
+ SimpleIdentifier secondName = _findSimpleIdentifier(unit2, code, 'zzz(y)');
+ expect(firstName.staticElement, same(firstElement));
+ expect(secondName.staticElement, same(secondElement));
+ }
}
/**
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index e2b20b3..ce630b1 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -6,10 +6,11 @@
import 'dart:async';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/source/embedder.dart';
import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -192,6 +193,9 @@
*/
class TestAnalysisContext implements InternalAnalysisContext {
@override
+ ResultProvider resultProvider;
+
+ @override
AnalysisCache get analysisCache {
fail("Unexpected invocation of analysisCache");
return null;
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 6a52fce..3f3390b 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -4,13 +4,14 @@
library analyzer.test.generated.incremental_resolver_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/incremental_logger.dart' as log;
+import 'package:analyzer/src/generated/incremental_logger.dart' as logging;
import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
import 'package:analyzer/src/generated/incremental_resolver.dart';
import 'package:analyzer/src/generated/java_engine.dart';
@@ -495,6 +496,20 @@
''');
}
+ void test_false_constructor_parameters_name() {
+ _assertDoesNotMatch(
+ r'''
+class A {
+ A(int a);
+}
+''',
+ r'''
+class A {
+ A(int b);
+}
+''');
+ }
+
void test_false_constructor_parameters_type_edit() {
_assertDoesNotMatch(
r'''
@@ -835,6 +850,22 @@
''');
}
+ void test_false_fieldFormalParameter_changeName_wasUnresolvedField() {
+ _assertDoesNotMatch(
+ r'''
+class A {
+ final fff;
+ A(this.unresolved);
+}
+''',
+ r'''
+class A {
+ final fff;
+ A(this.fff);
+}
+''');
+ }
+
void test_false_fieldFormalParameter_differentField() {
_assertDoesNotMatch(
r'''
@@ -2506,22 +2537,6 @@
''');
}
- void test_true_fieldFormalParameter_changeName_wasUnresolvedField() {
- _assertMatches(
- r'''
-class A {
- final fff;
- A(this.unresolved);
-}
-''',
- r'''
-class A {
- final fff;
- A(this.fff);
-}
-''');
- }
-
void test_true_fieldFormalParameter_function() {
_assertMatches(
r'''
@@ -3092,7 +3107,7 @@
void setUp() {
super.setUp();
test_resolveApiChanges = true;
- log.logger = log.NULL_LOGGER;
+ logging.logger = logging.NULL_LOGGER;
}
void test_classMemberAccessor_body() {
@@ -3170,15 +3185,6 @@
_resolve(_editString('+', '*'), _isExpression);
}
- void test_fieldFormalParameter() {
- _resolveUnit(r'''
-class A {
- int xy;
- A(this.x);
-}''');
- _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
- }
-
void test_function_localFunction_add() {
_resolveUnit(r'''
int main() {
@@ -3523,6 +3529,8 @@
*/
@reflectiveTest
class PoorMansIncrementalResolutionTest extends ResolverTestCase {
+ final _TestLogger logger = new _TestLogger();
+
Source source;
String code;
LibraryElement oldLibrary;
@@ -3800,23 +3808,6 @@
''');
}
- void test_endOfLineComment_localFunction_inTopLevelVariable() {
- _resolveUnit(r'''
-typedef int Binary(one, two, three);
-
-int Global = f((a, b, c) {
- return 0; // Some comment
-});
-''');
- _updateAndValidate(r'''
-typedef int Binary(one, two, three);
-
-int Global = f((a, b, c) {
- return 0; // Some comment
-});
-''');
- }
-
void test_endOfLineComment_outBody_add() {
_resolveUnit(r'''
main() {
@@ -3886,6 +3877,25 @@
''');
}
+ void test_endOfLineComment_toDartDoc() {
+ _resolveUnit(r'''
+class A {
+ // text
+ main() {
+ print(42);
+ }
+}''');
+ _updateAndValidate(
+ r'''
+class A {
+ /// text
+ main() {
+ print(42);
+ }
+}''',
+ expectedSuccess: false);
+ }
+
void test_false_constConstructor_initializer() {
_resolveUnit(r'''
class C {
@@ -3911,6 +3921,74 @@
expectedSuccess: false);
}
+ void test_false_constructor_initializer_damage() {
+ _resolveUnit(r'''
+class Problem {
+ final Map location;
+ final String message;
+
+ Problem(Map json)
+ : location = json["location"],
+ message = json["message"];
+}''');
+ _updateAndValidate(
+ r'''
+class Problem {
+ final Map location;
+ final String message;
+
+ Problem(Map json)
+ : location = json["location],
+ message = json["message"];
+}''',
+ expectedSuccess: false);
+ }
+
+ void test_false_constructor_initializer_remove() {
+ _resolveUnit(r'''
+class Problem {
+ final String severity;
+ final Map location;
+ final String message;
+
+ Problem(Map json)
+ : severity = json["severity"],
+ location = json["location"],
+ message = json["message"];
+}''');
+ _updateAndValidate(
+ r'''
+class Problem {
+ final String severity;
+ final Map location;
+ final String message;
+
+ Problem(Map json)
+ : severity = json["severity"],
+ message = json["message"];
+}''',
+ expectedSuccess: false);
+ }
+
+ void test_false_endOfLineComment_localFunction_inTopLevelVariable() {
+ _resolveUnit(r'''
+typedef int Binary(one, two, three);
+
+int Global = f((a, b, c) {
+ return 0; // Some comment
+});
+''');
+ _updateAndValidate(
+ r'''
+typedef int Binary(one, two, three);
+
+int Global = f((a, b, c) {
+ return 0; // Some comment
+});
+''',
+ expectedSuccess: false);
+ }
+
void test_false_expressionBody() {
_resolveUnit(r'''
class A {
@@ -3926,6 +4004,44 @@
expectedSuccess: false);
}
+ void test_false_expressionBody2() {
+ _resolveUnit(r'''
+class A {
+ int m() => 10 * 10;
+}
+''');
+ _updateAndValidate(
+ r'''
+class A {
+ int m() => 10 * 100;
+}
+''',
+ expectedSuccess: false);
+ }
+
+ void test_false_inBody_functionExpression() {
+ _resolveUnit(r'''
+class C extends D {
+ static final f = () {
+ var x = 0;
+ }();
+}
+
+class D {}
+''');
+ _updateAndValidate(
+ r'''
+class C extends D {
+ static final f = () {
+ var x = 01;
+ }();
+}
+
+class D {}
+''',
+ expectedSuccess: false);
+ }
+
void test_false_topLevelFunction_name() {
_resolveUnit(r'''
a() {}
@@ -3995,6 +4111,25 @@
expectedSuccess: false);
}
+ void test_false_wholeConstructor() {
+ _resolveUnit(r'''
+class A {
+ A(int a) {
+ print(a);
+ }
+}
+''');
+ _updateAndValidate(
+ r'''
+class A {
+ A(int b) {
+ print(b);
+ }
+}
+''',
+ expectedSuccess: false);
+ }
+
void test_fieldClassField_propagatedType() {
_resolveUnit(r'''
class A {
@@ -4045,27 +4180,6 @@
''');
}
- void test_inBody_functionExpression() {
- _resolveUnit(r'''
-class C extends D {
- static final f = () {
- var x = 0;
- }();
-}
-
-class D {}
-''');
- _updateAndValidate(r'''
-class C extends D {
- static final f = () {
- var x = 01;
- }();
-}
-
-class D {}
-''');
- }
-
void test_inBody_insertStatement() {
_resolveUnit(r'''
main() {
@@ -4238,23 +4352,6 @@
_assertEqualErrors(newErrors, oldErrors);
}
- void test_true_wholeConstructor() {
- _resolveUnit(r'''
-class A {
- A(int a) {
- print(a);
- }
-}
-''');
- _updateAndValidate(r'''
-class A {
- A(int b) {
- print(b);
- }
-}
-''');
- }
-
void test_true_wholeConstructor_addInitializer() {
_resolveUnit(r'''
class A {
@@ -4697,8 +4794,7 @@
AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
analysisOptions.incremental = enable;
analysisOptions.incrementalApi = enable;
-// log.logger = log.PRINT_LOGGER;
- log.logger = log.NULL_LOGGER;
+ logging.logger = logger;
analysisContext2.analysisOptions = analysisOptions;
}
@@ -4730,6 +4826,7 @@
_resetWithIncremental(true);
analysisContext2.setContents(source, newCode);
CompilationUnit newUnit = resolveCompilationUnit(source, oldLibrary);
+ expect(logger.hasError, isFalse);
List<AnalysisError> newErrors = analysisContext.computeErrors(source);
LineInfo newLineInfo = analysisContext.getLineInfo(source);
// check for expected failure
@@ -5022,3 +5119,26 @@
final String replacement;
_Edit(this.offset, this.length, this.replacement);
}
+
+class _TestLogger implements logging.Logger {
+ bool hasError = false;
+
+ @override
+ void enter(String name) {}
+
+ @override
+ void exit() {}
+
+ @override
+ void log(Object obj) {}
+
+ @override
+ void logException(Object exception, [Object stackTrace]) {
+ hasError = true;
+ }
+
+ @override
+ logging.LoggingTimer startTimer() {
+ return new logging.LoggingTimer(this);
+ }
+}
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 6792467..9ce75c6 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -4,8 +4,8 @@
library analyzer.test.generated.non_error_resolver_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
@@ -35,24 +35,6 @@
verify([source]);
}
- void test_class_type_alias_documentationComment() {
- Source source = addSource('''
-/**
- * Documentation
- */
-class C = D with E;
-
-class D {}
-class E {}''');
- computeLibrarySourceErrors(source);
- computeLibrarySourceErrors(source);
- assertNoErrors(source);
- verify([source]);
- CompilationUnit unit = _getResolvedLibraryUnit(source);
- ClassElement classC = unit.element.getType('C');
- expect(classC.documentationComment, isNotNull);
- }
-
void test_ambiguousExport() {
Source source = addSource(r'''
library L;
@@ -932,6 +914,24 @@
verify([source]);
}
+ void test_class_type_alias_documentationComment() {
+ Source source = addSource('''
+/**
+ * Documentation
+ */
+class C = D with E;
+
+class D {}
+class E {}''');
+ computeLibrarySourceErrors(source);
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = _getResolvedLibraryUnit(source);
+ ClassElement classC = unit.element.getType('C');
+ expect(classC.documentationComment, isNotNull);
+ }
+
void test_commentReference_beforeConstructor() {
String code = r'''
abstract class A {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 5d304c7..2855c21 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4,10 +4,12 @@
library analyzer.test.generated.parser_test;
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/incremental_scanner.dart';
@@ -937,21 +939,42 @@
[ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT]);
}
+ void test_emptyEnumBody() {
+ parse3("parseEnumDeclaration", <Object>[emptyCommentAndMetadata()],
+ "enum E {}", [ParserErrorCode.EMPTY_ENUM_BODY]);
+ }
+
void test_enableAsync_false_1() {
parseAsync = false;
- parse4("parseFunctionDeclarationStatement",
- "foo() async {}", [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+ FunctionDeclarationStatement stmt = parse4(
+ "parseFunctionDeclarationStatement",
+ "foo() async {}",
+ [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+ FunctionExpression expr = stmt.functionDeclaration.functionExpression;
+ expect(expr.body.isAsynchronous, isTrue);
+ expect(expr.body.isGenerator, isFalse);
}
void test_enableAsync_false_2() {
parseAsync = false;
- parse4("parseFunctionDeclarationStatement",
- "foo() sync* {}", [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+ FunctionDeclarationStatement stmt = parse4(
+ "parseFunctionDeclarationStatement",
+ "foo() async => 0;",
+ [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+ FunctionExpression expr = stmt.functionDeclaration.functionExpression;
+ expect(expr.body.isAsynchronous, isTrue);
+ expect(expr.body.isGenerator, isFalse);
}
- void test_emptyEnumBody() {
- parse3("parseEnumDeclaration", <Object>[emptyCommentAndMetadata()],
- "enum E {}", [ParserErrorCode.EMPTY_ENUM_BODY]);
+ void test_enableAsync_false_3() {
+ parseAsync = false;
+ FunctionDeclarationStatement stmt = parse4(
+ "parseFunctionDeclarationStatement",
+ "foo() sync* {}",
+ [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+ FunctionExpression expr = stmt.functionDeclaration.functionExpression;
+ expect(expr.body.isAsynchronous, isFalse);
+ expect(expr.body.isGenerator, isTrue);
}
void test_enumInClass() {
@@ -3687,6 +3710,55 @@
expect(statement.toSource(), 'List<String> v;');
}
+ void test_incompleteTypeArguments_field() {
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+ r'''
+class C {
+ final List<int f;
+}''',
+ [ParserErrorCode.EXPECTED_TOKEN]);
+ // one class
+ List<CompilationUnitMember> declarations = unit.declarations;
+ expect(declarations, hasLength(1));
+ ClassDeclaration classDecl = declarations[0] as ClassDeclaration;
+ // one field declaration
+ List<ClassMember> members = classDecl.members;
+ expect(members, hasLength(1));
+ FieldDeclaration fieldDecl = members[0] as FieldDeclaration;
+ // one field
+ VariableDeclarationList fieldList = fieldDecl.fields;
+ List<VariableDeclaration> fields = fieldList.variables;
+ expect(fields, hasLength(1));
+ VariableDeclaration field = fields[0];
+ expect(field.name.name, 'f');
+ // validate the type
+ TypeArgumentList typeArguments = fieldList.type.typeArguments;
+ expect(typeArguments.arguments, hasLength(1));
+ // synthetic '>'
+ Token token = typeArguments.endToken;
+ expect(token.type, TokenType.GT);
+ expect(token.isSynthetic, isTrue);
+ }
+
+ void test_incompleteTypeParameters() {
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+ r'''
+class C<K {
+}''',
+ [ParserErrorCode.EXPECTED_TOKEN]);
+ // one class
+ List<CompilationUnitMember> declarations = unit.declarations;
+ expect(declarations, hasLength(1));
+ ClassDeclaration classDecl = declarations[0] as ClassDeclaration;
+ // validate the type parameters
+ TypeParameterList typeParameters = classDecl.typeParameters;
+ expect(typeParameters.typeParameters, hasLength(1));
+ // synthetic '>'
+ Token token = typeParameters.endToken;
+ expect(token.type, TokenType.GT);
+ expect(token.isSynthetic, isTrue);
+ }
+
void test_invalidFunctionBodyModifier() {
ParserTestCase.parseCompilationUnit(
"f() sync {}", [ParserErrorCode.MISSING_STAR_AFTER_SYNC]);
@@ -7334,6 +7406,16 @@
expect(literal.rightBracket, isNotNull);
}
+ void test_parseConstExpression_listLiteral_typed_genericComment() {
+ enableGenericMethodComments = true;
+ ListLiteral literal = parse4("parseConstExpression", "const /*<A>*/ []");
+ expect(literal.constKeyword, isNotNull);
+ expect(literal.typeArguments, isNotNull);
+ expect(literal.leftBracket, isNotNull);
+ expect(literal.elements, hasLength(0));
+ expect(literal.rightBracket, isNotNull);
+ }
+
void test_parseConstExpression_listLiteral_untyped() {
ListLiteral literal = parse4("parseConstExpression", "const []");
expect(literal.constKeyword, isNotNull);
@@ -7351,6 +7433,15 @@
expect(literal.typeArguments, isNotNull);
}
+ void test_parseConstExpression_mapLiteral_typed_genericComment() {
+ enableGenericMethodComments = true;
+ MapLiteral literal = parse4("parseConstExpression", "const /*<A, B>*/ {}");
+ expect(literal.leftBracket, isNotNull);
+ expect(literal.entries, hasLength(0));
+ expect(literal.rightBracket, isNotNull);
+ expect(literal.typeArguments, isNotNull);
+ }
+
void test_parseConstExpression_mapLiteral_untyped() {
MapLiteral literal = parse4("parseConstExpression", "const {}");
expect(literal.leftBracket, isNotNull);
@@ -9856,6 +9947,13 @@
expect(literal.typeArguments.arguments, hasLength(1));
}
+ void test_parsePrimaryExpression_listLiteral_typed_genericComment() {
+ enableGenericMethodComments = true;
+ ListLiteral literal = parse4("parsePrimaryExpression", "/*<A>*/[ ]");
+ expect(literal.typeArguments, isNotNull);
+ expect(literal.typeArguments.arguments, hasLength(1));
+ }
+
void test_parsePrimaryExpression_mapLiteral() {
MapLiteral literal = parse4("parsePrimaryExpression", "{}");
expect(literal, isNotNull);
@@ -9867,6 +9965,13 @@
expect(literal.typeArguments.arguments, hasLength(2));
}
+ void test_parsePrimaryExpression_mapLiteral_typed_genericComment() {
+ enableGenericMethodComments = true;
+ MapLiteral literal = parse4("parsePrimaryExpression", "/*<A, B>*/{}");
+ expect(literal.typeArguments, isNotNull);
+ expect(literal.typeArguments.arguments, hasLength(2));
+ }
+
void test_parsePrimaryExpression_new() {
InstanceCreationExpression expression =
parse4("parsePrimaryExpression", "new A()");
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 4722a65..fe755ed8 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -6,13 +6,14 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -43,6 +44,7 @@
initializeTestEnvironment();
runReflectiveTests(AnalysisDeltaTest);
runReflectiveTests(ChangeSetTest);
+ runReflectiveTests(DisableAsyncTestCase);
runReflectiveTests(EnclosedScopeTest);
runReflectiveTests(LibraryImportScopeTest);
runReflectiveTests(LibraryScopeTest);
@@ -108,11 +110,14 @@
static InternalAnalysisContext initContextWithCore(
InternalAnalysisContext context) {
DirectoryBasedDartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
- new JavaFile("/fake/sdk"));
+ new JavaFile("/fake/sdk"),
+ enableAsync: context.analysisOptions.enableAsync);
SourceFactory sourceFactory =
new SourceFactory([new DartUriResolver(sdk), new FileUriResolver()]);
context.sourceFactory = sourceFactory;
AnalysisContext coreContext = sdk.context;
+ (coreContext.analysisOptions as AnalysisOptionsImpl).strongMode =
+ context.analysisOptions.strongMode;
//
// dart:core
//
@@ -124,8 +129,9 @@
coreUnit.librarySource = coreUnit.source = coreSource;
ClassElementImpl proxyClassElement = ElementFactory.classElement2("_Proxy");
proxyClassElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(proxyClassElement, null, true)
+ ElementFactory.constructorElement(proxyClassElement, '', true)
..isCycleFree = true
+ ..constantInitializers = <ConstructorInitializer>[]
];
ClassElement objectClassElement = provider.objectType.element;
coreUnit.types = <ClassElement>[
@@ -158,11 +164,18 @@
ConstTopLevelVariableElementImpl deprecatedTopLevelVariableElt =
ElementFactory.topLevelVariableElement3(
"deprecated", true, false, provider.deprecatedType);
- deprecatedTopLevelVariableElt.constantInitializer = AstFactory
- .instanceCreationExpression2(
- Keyword.CONST,
- AstFactory.typeName(provider.deprecatedType.element),
- [AstFactory.string2('next release')]);
+ {
+ ClassElement deprecatedElement = provider.deprecatedType.element;
+ InstanceCreationExpression initializer = AstFactory
+ .instanceCreationExpression2(
+ Keyword.CONST,
+ AstFactory.typeName(deprecatedElement),
+ [AstFactory.string2('next release')]);
+ ConstructorElement constructor = deprecatedElement.constructors.single;
+ initializer.staticElement = constructor;
+ initializer.constructorName.staticElement = constructor;
+ deprecatedTopLevelVariableElt.constantInitializer = initializer;
+ }
coreUnit.accessors = <PropertyAccessorElement>[
proxyTopLevelVariableElt.getter,
deprecatedTopLevelVariableElt.getter
@@ -177,89 +190,97 @@
//
// dart:async
//
- CompilationUnitElementImpl asyncUnit =
- new CompilationUnitElementImpl("async.dart");
- Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
- coreContext.setContents(asyncSource, "");
- asyncUnit.librarySource = asyncUnit.source = asyncSource;
- // Future
- ClassElementImpl futureElement =
- ElementFactory.classElement2("Future", ["T"]);
- // factory Future.value([value])
- ConstructorElementImpl futureConstructor =
- ElementFactory.constructorElement2(futureElement, "value");
- futureConstructor.parameters = <ParameterElement>[
- ElementFactory.positionalParameter2("value", provider.dynamicType)
- ];
- futureConstructor.factory = true;
- futureElement.constructors = <ConstructorElement>[futureConstructor];
- // Future then(onValue(T value), { Function onError });
- TypeDefiningElement futureThenR = DynamicElementImpl.instance;
- if (context.analysisOptions.strongMode) {
- futureThenR = ElementFactory.typeParameterWithType('R');
+ Source asyncSource;
+ LibraryElementImpl asyncLibrary;
+ if (context.analysisOptions.enableAsync) {
+ asyncLibrary = new LibraryElementImpl.forNode(
+ coreContext, AstFactory.libraryIdentifier2(["dart", "async"]));
+ CompilationUnitElementImpl asyncUnit =
+ new CompilationUnitElementImpl("async.dart");
+ asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
+ coreContext.setContents(asyncSource, "");
+ asyncUnit.librarySource = asyncUnit.source = asyncSource;
+ asyncLibrary.definingCompilationUnit = asyncUnit;
+ // Future
+ ClassElementImpl futureElement =
+ ElementFactory.classElement2("Future", ["T"]);
+ futureElement.enclosingElement = asyncUnit;
+ // factory Future.value([value])
+ ConstructorElementImpl futureConstructor =
+ ElementFactory.constructorElement2(futureElement, "value");
+ futureConstructor.parameters = <ParameterElement>[
+ ElementFactory.positionalParameter2("value", provider.dynamicType)
+ ];
+ futureConstructor.factory = true;
+ futureElement.constructors = <ConstructorElement>[futureConstructor];
+ // Future then(onValue(T value), { Function onError });
+ TypeDefiningElement futureThenR = DynamicElementImpl.instance;
+ if (context.analysisOptions.strongMode) {
+ futureThenR = ElementFactory.typeParameterWithType('R');
+ }
+ FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
+ 'onValue', futureThenR, [futureElement.typeParameters[0]], null);
+
+ DartType futureRType = futureElement.type.substitute4([futureThenR.type]);
+ MethodElementImpl thenMethod = ElementFactory
+ .methodElementWithParameters(futureElement, "then", futureRType, [
+ ElementFactory.requiredParameter2("onValue", thenOnValue.type),
+ ElementFactory.namedParameter2("onError", provider.functionType)
+ ]);
+ if (!futureThenR.type.isDynamic) {
+ thenMethod.typeParameters = [futureThenR];
+ }
+ thenOnValue.enclosingElement = thenMethod;
+ thenOnValue.type = new FunctionTypeImpl(thenOnValue);
+ (thenMethod.parameters[0] as ParameterElementImpl).type =
+ thenOnValue.type;
+ thenMethod.type = new FunctionTypeImpl(thenMethod);
+
+ futureElement.methods = <MethodElement>[thenMethod];
+ // Completer
+ ClassElementImpl completerElement =
+ ElementFactory.classElement2("Completer", ["T"]);
+ ConstructorElementImpl completerConstructor =
+ ElementFactory.constructorElement2(completerElement, null);
+ completerElement.constructors = <ConstructorElement>[
+ completerConstructor
+ ];
+ // StreamSubscription
+ ClassElementImpl streamSubscriptionElement =
+ ElementFactory.classElement2("StreamSubscription", ["T"]);
+ // Stream
+ ClassElementImpl streamElement =
+ ElementFactory.classElement2("Stream", ["T"]);
+ streamElement.constructors = <ConstructorElement>[
+ ElementFactory.constructorElement2(streamElement, null)
+ ];
+ DartType returnType = streamSubscriptionElement.type
+ .substitute4(streamElement.type.typeArguments);
+ List<DartType> parameterTypes = <DartType>[
+ ElementFactory
+ .functionElement3('onData', VoidTypeImpl.instance.element,
+ <TypeDefiningElement>[streamElement.typeParameters[0]], null)
+ .type,
+ ];
+ // TODO(brianwilkerson) This is missing the optional parameters.
+ MethodElementImpl listenMethod =
+ ElementFactory.methodElement('listen', returnType, parameterTypes);
+ streamElement.methods = <MethodElement>[listenMethod];
+ listenMethod.type = new FunctionTypeImpl(listenMethod);
+
+ FunctionElementImpl listenParamFunction = parameterTypes[0].element;
+ listenParamFunction.enclosingElement = listenMethod;
+ listenParamFunction.type = new FunctionTypeImpl(listenParamFunction);
+ ParameterElementImpl listenParam = listenMethod.parameters[0];
+ listenParam.type = listenParamFunction.type;
+
+ asyncUnit.types = <ClassElement>[
+ completerElement,
+ futureElement,
+ streamElement,
+ streamSubscriptionElement
+ ];
}
- FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
- 'onValue', futureThenR, [futureElement.typeParameters[0]], null);
-
- DartType futureRType = futureElement.type.substitute4([futureThenR.type]);
- MethodElementImpl thenMethod = ElementFactory
- .methodElementWithParameters(futureElement, "then", futureRType, [
- ElementFactory.requiredParameter2("onValue", thenOnValue.type),
- ElementFactory.namedParameter2("onError", provider.functionType)
- ]);
- if (!futureThenR.type.isDynamic) {
- thenMethod.typeParameters = [futureThenR];
- }
- thenOnValue.enclosingElement = thenMethod;
- thenOnValue.type = new FunctionTypeImpl(thenOnValue);
- (thenMethod.parameters[0] as ParameterElementImpl).type = thenOnValue.type;
- thenMethod.type = new FunctionTypeImpl(thenMethod);
-
- futureElement.methods = <MethodElement>[thenMethod];
- // Completer
- ClassElementImpl completerElement =
- ElementFactory.classElement2("Completer", ["T"]);
- ConstructorElementImpl completerConstructor =
- ElementFactory.constructorElement2(completerElement, null);
- completerElement.constructors = <ConstructorElement>[completerConstructor];
- // StreamSubscription
- ClassElementImpl streamSubscriptionElement =
- ElementFactory.classElement2("StreamSubscription", ["T"]);
- // Stream
- ClassElementImpl streamElement =
- ElementFactory.classElement2("Stream", ["T"]);
- streamElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement2(streamElement, null)
- ];
- DartType returnType = streamSubscriptionElement.type
- .substitute4(streamElement.type.typeArguments);
- List<DartType> parameterTypes = <DartType>[
- ElementFactory
- .functionElement3('onData', VoidTypeImpl.instance.element,
- <TypeDefiningElement>[streamElement.typeParameters[0]], null)
- .type,
- ];
- // TODO(brianwilkerson) This is missing the optional parameters.
- MethodElementImpl listenMethod =
- ElementFactory.methodElement('listen', returnType, parameterTypes);
- streamElement.methods = <MethodElement>[listenMethod];
- listenMethod.type = new FunctionTypeImpl(listenMethod);
-
- FunctionElementImpl listenParamFunction = parameterTypes[0].element;
- listenParamFunction.enclosingElement = listenMethod;
- listenParamFunction.type = new FunctionTypeImpl(listenParamFunction);
- ParameterElementImpl listenParam = listenMethod.parameters[0];
- listenParam.type = listenParamFunction.type;
-
- asyncUnit.types = <ClassElement>[
- completerElement,
- futureElement,
- streamElement,
- streamSubscriptionElement
- ];
- LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
- coreContext, AstFactory.libraryIdentifier2(["dart", "async"]));
- asyncLibrary.definingCompilationUnit = asyncUnit;
//
// dart:html
//
@@ -395,7 +416,9 @@
HashMap<Source, LibraryElement> elementMap =
new HashMap<Source, LibraryElement>();
elementMap[coreSource] = coreLibrary;
- elementMap[asyncSource] = asyncLibrary;
+ if (asyncSource != null) {
+ elementMap[asyncSource] = asyncLibrary;
+ }
elementMap[htmlSource] = htmlLibrary;
elementMap[mathSource] = mathLibrary;
//
@@ -407,6 +430,10 @@
library.publicNamespace = new PublicNamespaceBuilder().build(library);
}
context.recordLibraryElements(elementMap);
+ // Create the synthetic element for `loadLibrary`.
+ for (LibraryElementImpl library in elementMap.values) {
+ library.createLoadLibraryFunction(context.typeProvider);
+ }
return context;
}
}
@@ -1206,6 +1233,51 @@
}
@reflectiveTest
+class DisableAsyncTestCase extends ResolverTestCase {
+ @override
+ void setUp() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableAsync = false;
+ resetWithOptions(options);
+ }
+
+ void test_resolve() {
+ Source source = addSource(r'''
+class C {
+ foo() {
+ bar();
+ }
+ bar() {
+ //
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ }
+
+ void test_resolve_async() {
+ Source source = addSource(r'''
+class C {
+ Future foo() async {
+ await bar();
+ return null;
+ }
+ Future bar() {
+ return new Future.delayed(new Duration(milliseconds: 10));
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ StaticWarningCode.UNDEFINED_CLASS,
+ StaticWarningCode.UNDEFINED_CLASS,
+ StaticWarningCode.UNDEFINED_CLASS,
+ StaticWarningCode.UNDEFINED_CLASS,
+ ParserErrorCode.ASYNC_NOT_SUPPORTED
+ ]);
+ }
+}
+
+@reflectiveTest
class ElementResolverTest extends EngineTestCase {
/**
* The error listener to which errors will be reported.
@@ -2272,6 +2344,44 @@
}
}
+/**
+ * Tests for generic method and function resolution that do not use strong mode.
+ */
+@reflectiveTest
+class GenericMethodResolverTest extends _StaticTypeAnalyzer2TestShared {
+ void setUp() {
+ super.setUp();
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableGenericMethods = true;
+ resetWithOptions(options);
+ }
+
+ void test_genericMethod_propagatedType_promotion() {
+ // Regression test for:
+ // https://github.com/dart-lang/sdk/issues/25340
+ //
+ // Note, after https://github.com/dart-lang/sdk/issues/25486 the original
+ // strong mode example won't work, as we now compute a static type and
+ // therefore discard the propagated type.
+ //
+ // So this test does not use strong mode.
+ _resolveTestUnit(r'''
+abstract class Iter {
+ List<S> map<S>(S f(x));
+}
+class C {}
+C toSpan(dynamic element) {
+ if (element is Iter) {
+ var y = element.map(toSpan);
+ }
+ return null;
+}''');
+ SimpleIdentifier y = _findIdentifier('y = ');
+ expect(y.staticType.toString(), 'dynamic');
+ expect(y.propagatedType.toString(), 'List<dynamic>');
+ }
+}
+
@reflectiveTest
class HintCodeTest extends ResolverTestCase {
void fail_deadCode_statementAfterRehrow() {
@@ -6546,6 +6656,18 @@
verify([source]);
}
+ void test_deprecatedAnnotationUse_classWithConstructor() {
+ Source source = addSource(r'''
+@deprecated
+class C {
+ C();
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_divisionOptimization() {
Source source = addSource(r'''
f(int x, int y) {
@@ -9274,14 +9396,30 @@
void test_isValidMixin_badSuperclass() {
Source source = addSource(r'''
class A extends B {}
-class B {}''');
+class B {}
+class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
- List<ClassElement> classes = unit.types;
- expect(classes, hasLength(2));
- expect(classes[0].isValidMixin, isFalse);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isFalse);
+ assertErrors(source, [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT]);
+ verify([source]);
+ }
+
+ void test_isValidMixin_badSuperclass_withSuperMixins() {
+ resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+ Source source = addSource(r'''
+class A extends B {}
+class B {}
+class C = Object with A;''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isTrue);
assertNoErrors(source);
verify([source]);
}
@@ -9290,14 +9428,64 @@
Source source = addSource(r'''
class A {
A() {}
-}''');
+}
+class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
- List<ClassElement> classes = unit.types;
- expect(classes, hasLength(1));
- expect(classes[0].isValidMixin, isFalse);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isFalse);
+ assertErrors(source, [CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR]);
+ verify([source]);
+ }
+
+ void test_isValidMixin_constructor_withSuperMixins() {
+ resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+ Source source = addSource(r'''
+class A {
+ A() {}
+}
+class C = Object with A;''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isFalse);
+ assertErrors(source, [CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR]);
+ verify([source]);
+ }
+
+ void test_isValidMixin_factoryConstructor() {
+ Source source = addSource(r'''
+class A {
+ factory A() => null;
+}
+class C = Object with A;''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isTrue);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_isValidMixin_factoryConstructor_withSuperMixins() {
+ resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+ Source source = addSource(r'''
+class A {
+ factory A() => null;
+}
+class C = Object with A;''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isTrue);
assertNoErrors(source);
verify([source]);
}
@@ -9308,27 +9496,62 @@
toString() {
return super.toString();
}
-}''');
+}
+class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
- List<ClassElement> classes = unit.types;
- expect(classes, hasLength(1));
- expect(classes[0].isValidMixin, isFalse);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isFalse);
+ assertErrors(source, [CompileTimeErrorCode.MIXIN_REFERENCES_SUPER]);
+ verify([source]);
+ }
+
+ void test_isValidMixin_super_withSuperMixins() {
+ resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+ Source source = addSource(r'''
+class A {
+ toString() {
+ return super.toString();
+ }
+}
+class C = Object with A;''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isTrue);
assertNoErrors(source);
verify([source]);
}
void test_isValidMixin_valid() {
- Source source = addSource("class A {}");
+ Source source = addSource('''
+class A {}
+class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
- List<ClassElement> classes = unit.types;
- expect(classes, hasLength(1));
- expect(classes[0].isValidMixin, isTrue);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isTrue);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_isValidMixin_valid_withSuperMixins() {
+ resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+ Source source = addSource('''
+class A {}
+class C = Object with A;''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ ClassElement a = unit.getType('A');
+ expect(a.isValidMixin, isTrue);
assertNoErrors(source);
verify([source]);
}
@@ -10019,6 +10242,11 @@
*/
TestTypeProvider _typeProvider;
+ /**
+ * The type system used to analyze the test cases.
+ */
+ TypeSystem get _typeSystem => _visitor.typeSystem;
+
void fail_visitFunctionExpressionInvocation() {
fail("Not yet tested");
_listener.assertNoErrors();
@@ -10038,7 +10266,6 @@
void setUp() {
super.setUp();
_listener = new GatheringErrorListener();
- _typeProvider = new TestTypeProvider();
_analyzer = _createAnalyzer();
}
@@ -11304,6 +11531,7 @@
LibraryElementImpl definingLibrary =
new LibraryElementImpl.forNode(context, null);
definingLibrary.definingCompilationUnit = definingCompilationUnit;
+ _typeProvider = new TestTypeProvider(context);
_visitor = new ResolverVisitor(
definingLibrary, source, _typeProvider, _listener,
nameScope: new LibraryScope(definingLibrary, _listener));
@@ -11316,8 +11544,7 @@
}
}
- DartType _flatten(DartType type) =>
- StaticTypeAnalyzer.flattenFutures(_typeProvider, type);
+ DartType _flatten(DartType type) => type.flattenFutures(_typeSystem);
/**
* Return a simple identifier that has been resolved to a variable element with the given type.
@@ -13030,105 +13257,6 @@
*/
@reflectiveTest
class StrongModeStaticTypeAnalyzer2Test extends _StaticTypeAnalyzer2TestShared {
- void test_genericMethod_functionExpressionInvocation_explicit() {
- _resolveTestUnit(r'''
-class C<E> {
- /*=T*/ f/*<T>*/(/*=T*/ e) => null;
- static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
- static final h = g;
-}
-
-/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
-var topG = topF;
-void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
- var c = new C<int>();
- /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
-
- var lambdaCall = (/*<E>*/(/*=E*/ e) => e)/*<int>*/(3);
- var methodCall = (c.f)/*<int>*/(3);
- var staticCall = (C.g)/*<int>*/(3);
- var staticFieldCall = (C.h)/*<int>*/(3);
- var topFunCall = (topF)/*<int>*/(3);
- var topFieldCall = (topG)/*<int>*/(3);
- var localCall = (lf)/*<int>*/(3);
- var paramCall = (pf)/*<int>*/(3);
-}
-''');
- expect(_findIdentifier('methodCall').staticType.toString(), "int");
- expect(_findIdentifier('staticCall').staticType.toString(), "int");
- expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
- expect(_findIdentifier('topFunCall').staticType.toString(), "int");
- expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
- expect(_findIdentifier('localCall').staticType.toString(), "int");
- expect(_findIdentifier('paramCall').staticType.toString(), "int");
- expect(_findIdentifier('lambdaCall').staticType.toString(), "int");
- }
-
- void fail_genericMethod_functionExpressionInvocation_inferred() {
- _resolveTestUnit(r'''
-class C<E> {
- /*=T*/ f/*<T>*/(/*=T*/ e) => null;
- static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
- static final h = g;
-}
-
-/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
-var topG = topF;
-void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
- var c = new C<int>();
- /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
-
- var lambdaCall = (/*<E>*/(/*=E*/ e) => e)(3);
- var methodCall = (c.f)(3);
- var staticCall = (C.g)(3);
- var staticFieldCall = (C.h)(3);
- var topFunCall = (topF)(3);
- var topFieldCall = (topG)(3);
- var localCall = (lf)(3);
- var paramCall = (pf)(3);
-}
-''');
- expect(_findIdentifier('methodCall').staticType.toString(), "int");
- expect(_findIdentifier('staticCall').staticType.toString(), "int");
- expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
- expect(_findIdentifier('topFunCall').staticType.toString(), "int");
- expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
- expect(_findIdentifier('localCall').staticType.toString(), "int");
- expect(_findIdentifier('paramCall').staticType.toString(), "int");
- expect(_findIdentifier('lambdaCall').staticType.toString(), "int");
- }
-
- void fail_genericMethod_functionInvocation_inferred() {
- _resolveTestUnit(r'''
-class C<E> {
- /*=T*/ f/*<T>*/(/*=T*/ e) => null;
- static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
- static final h = g;
-}
-
-/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
-var topG = topF;
-void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
- var c = new C<int>();
- /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
- var methodCall = c.f(3);
- var staticCall = C.g(3);
- var staticFieldCall = C.h(3);
- var topFunCall = topF(3);
- var topFieldCall = topG(3);
- var localCall = lf(3);
- var paramCall = pf(3);
-}
-''');
- expect(_findIdentifier('methodCall').staticType.toString(), "int");
- expect(_findIdentifier('staticCall').staticType.toString(), "int");
- expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
- expect(_findIdentifier('topFunCall').staticType.toString(), "int");
- expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
- expect(_findIdentifier('localCall').staticType.toString(), "int");
- expect(_findIdentifier('paramCall').staticType.toString(), "int");
- }
-
void fail_genericMethod_tearoff_instantiated() {
_resolveTestUnit(r'''
class C<E> {
@@ -13384,6 +13512,74 @@
typeProvider.listType.substitute4([typeProvider.intType]));
}
+ void test_genericMethod_functionExpressionInvocation_explicit() {
+ _resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+
+ var lambdaCall = (/*<E>*/(/*=E*/ e) => e)/*<int>*/(3);
+ var methodCall = (c.f)/*<int>*/(3);
+ var staticCall = (C.g)/*<int>*/(3);
+ var staticFieldCall = (C.h)/*<int>*/(3);
+ var topFunCall = (topF)/*<int>*/(3);
+ var topFieldCall = (topG)/*<int>*/(3);
+ var localCall = (lf)/*<int>*/(3);
+ var paramCall = (pf)/*<int>*/(3);
+}
+''');
+ expect(_findIdentifier('methodCall').staticType.toString(), "int");
+ expect(_findIdentifier('staticCall').staticType.toString(), "int");
+ expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
+ expect(_findIdentifier('topFunCall').staticType.toString(), "int");
+ expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
+ expect(_findIdentifier('localCall').staticType.toString(), "int");
+ expect(_findIdentifier('paramCall').staticType.toString(), "int");
+ expect(_findIdentifier('lambdaCall').staticType.toString(), "int");
+ }
+
+ void test_genericMethod_functionExpressionInvocation_inferred() {
+ _resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+
+ var lambdaCall = (/*<E>*/(/*=E*/ e) => e)(3);
+ var methodCall = (c.f)(3);
+ var staticCall = (C.g)(3);
+ var staticFieldCall = (C.h)(3);
+ var topFunCall = (topF)(3);
+ var topFieldCall = (topG)(3);
+ var localCall = (lf)(3);
+ var paramCall = (pf)(3);
+}
+''');
+ expect(_findIdentifier('methodCall').staticType.toString(), "int");
+ expect(_findIdentifier('staticCall').staticType.toString(), "int");
+ expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
+ expect(_findIdentifier('topFunCall').staticType.toString(), "int");
+ expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
+ expect(_findIdentifier('localCall').staticType.toString(), "int");
+ expect(_findIdentifier('paramCall').staticType.toString(), "int");
+ expect(_findIdentifier('lambdaCall').staticType.toString(), "int");
+ }
+
void test_genericMethod_functionInvocation_explicit() {
_resolveTestUnit(r'''
class C<E> {
@@ -13415,6 +13611,37 @@
expect(_findIdentifier('paramCall').staticType.toString(), "int");
}
+ void test_genericMethod_functionInvocation_inferred() {
+ _resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+ var methodCall = c.f(3);
+ var staticCall = C.g(3);
+ var staticFieldCall = C.h(3);
+ var topFunCall = topF(3);
+ var topFieldCall = topG(3);
+ var localCall = lf(3);
+ var paramCall = pf(3);
+}
+''');
+ expect(_findIdentifier('methodCall').staticType.toString(), "int");
+ expect(_findIdentifier('staticCall').staticType.toString(), "int");
+ expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
+ expect(_findIdentifier('topFunCall').staticType.toString(), "int");
+ expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
+ expect(_findIdentifier('localCall').staticType.toString(), "int");
+ expect(_findIdentifier('paramCall').staticType.toString(), "int");
+ }
+
void test_genericMethod_functionTypedParameter() {
_resolveTestUnit(r'''
class C<E> {
@@ -13456,15 +13683,95 @@
SimpleIdentifier map1 = _findIdentifier('map((e) => e);');
MethodInvocation m1 = map1.parent;
expect(m1.staticInvokeType.toString(), '((dynamic) → dynamic) → dynamic');
- expect(map1.staticType, isNull);
+ expect(map1.staticType.toString(), '<T>((dynamic) → T) → T');
expect(map1.propagatedType, isNull);
SimpleIdentifier map2 = _findIdentifier('map((e) => 3);');
MethodInvocation m2 = map2.parent;
expect(m2.staticInvokeType.toString(), '((dynamic) → int) → int');
- expect(map2.staticType, isNull);
+ expect(map2.staticType.toString(), '<T>((dynamic) → T) → T');
expect(map2.propagatedType, isNull);
}
+ void test_genericMethod_max_doubleDouble() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1.0, 2.0);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'double');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_genericMethod_max_doubleDouble_prefixed() {
+ String code = r'''
+import 'dart:math' as math;
+main() {
+ var foo = math.max(1.0, 2.0);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'double');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_genericMethod_max_doubleInt() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1.0, 2);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'num');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_genericMethod_max_intDouble() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2.0);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'num');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_genericMethod_max_intInt() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
void test_genericMethod_nestedCapture() {
_resolveTestUnit(r'''
class C<T> {
@@ -13564,10 +13871,11 @@
// TODO(jmesserly): this is modified code from assertErrors, which we can't
// use directly because STRONG_MODE_* errors don't have working equality.
List<AnalysisError> errors = analysisContext2.computeErrors(source);
- expect(errors.map((e) => e.errorCode.name), [
- 'STRONG_MODE_INVALID_METHOD_OVERRIDE',
- 'INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND'
- ]);
+ List errorNames = errors.map((e) => e.errorCode.name).toList();
+ expect(errorNames, hasLength(2));
+ expect(errorNames, contains('STRONG_MODE_INVALID_METHOD_OVERRIDE'));
+ expect(
+ errorNames, contains('INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND'));
verify([source]);
}
@@ -13589,6 +13897,30 @@
verify([source]);
}
+ void test_genericMethod_propagatedType_promotion() {
+ // Regression test for:
+ // https://github.com/dart-lang/sdk/issues/25340
+
+ // Note, after https://github.com/dart-lang/sdk/issues/25486 the original
+ // example won't work, as we now compute a static type and therefore discard
+ // the propagated type. So a new test was created that doesn't run under
+ // strong mode.
+ _resolveTestUnit(r'''
+abstract class Iter {
+ List/*<S>*/ map/*<S>*/(/*=S*/ f(x));
+}
+class C {}
+C toSpan(dynamic element) {
+ if (element is Iter) {
+ var y = element.map(toSpan);
+ }
+ return null;
+}''');
+ SimpleIdentifier y = _findIdentifier('y = ');
+ expect(y.staticType.toString(), 'List<C>');
+ expect(y.propagatedType, isNull);
+ }
+
void test_genericMethod_tearoff() {
_resolveTestUnit(r'''
class C<E> {
@@ -13625,87 +13957,7 @@
expect(_findIdentifier('paramTearOff').staticType.toString(), "<T>(T) → T");
}
- void test_pseudoGeneric_max_doubleDouble() {
- String code = r'''
-import 'dart:math';
-main() {
- var foo = max(1.0, 2.0);
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'double');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
- void test_pseudoGeneric_max_doubleDouble_prefixed() {
- String code = r'''
-import 'dart:math' as math;
-main() {
- var foo = math.max(1.0, 2.0);
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'double');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
- void test_pseudoGeneric_max_doubleInt() {
- String code = r'''
-import 'dart:math';
-main() {
- var foo = max(1.0, 2);
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'num');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
- void test_pseudoGeneric_max_intDouble() {
- String code = r'''
-import 'dart:math';
-main() {
- var foo = max(1, 2.0);
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'num');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
- void test_pseudoGeneric_max_intInt() {
- String code = r'''
-import 'dart:math';
-main() {
- var foo = max(1, 2);
-}
-''';
- _resolveTestUnit(code);
-
- SimpleIdentifier identifier = _findIdentifier('foo');
- VariableDeclaration declaration =
- identifier.getAncestor((node) => node is VariableDeclaration);
- expect(declaration.initializer.staticType.name, 'int');
- expect(declaration.initializer.propagatedType, isNull);
- }
-
- void test_pseudoGeneric_then() {
+ void test_genericMethod_then() {
String code = r'''
import 'dart:async';
String toString(int x) => x.toString();
@@ -13724,7 +13976,7 @@
expect(declaration.initializer.propagatedType, isNull);
}
- void test_pseudoGeneric_then_prefixed() {
+ void test_genericMethod_then_prefixed() {
String code = r'''
import 'dart:async' as async;
String toString(int x) => x.toString();
@@ -13743,6 +13995,22 @@
expect(declaration.initializer.propagatedType, isNull);
}
+ void test_genericMethod_then_propagatedType() {
+ // Regression test for https://github.com/dart-lang/sdk/issues/25482.
+ String code = r'''
+import 'dart:async';
+void main() {
+ Future<String> p;
+ var foo = p.then((r) => new Future<String>.value(3));
+}
+''';
+ // This should produce no hints or warnings.
+ _resolveTestUnit(code);
+ VariableDeclaration foo = _findIdentifier('foo').parent;
+ expect(foo.initializer.staticType.toString(), "Future<String>");
+ expect(foo.initializer.propagatedType, isNull);
+ }
+
void test_setterWithDynamicTypeIsError() {
Source source = addSource(r'''
class A {
@@ -15747,7 +16015,7 @@
}''';
SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
MethodInvocation methodInvoke = methodName.parent;
- expect(methodName.staticType, null, reason: 'library prefix has no type');
+ expect(methodName.staticType, typeProvider.dynamicType);
expect(methodInvoke.staticType, typeProvider.dynamicType);
}
@@ -15953,11 +16221,81 @@
expect(provider.mapType, same(mapType));
expect(provider.objectType, same(objectType));
expect(provider.stackTraceType, same(stackTraceType));
+ expect(provider.streamType, same(streamType));
expect(provider.stringType, same(stringType));
expect(provider.symbolType, same(symbolType));
expect(provider.typeType, same(typeType));
}
+ void test_creation_no_async() {
+ //
+ // Create a mock library element with the types expected to be in dart:core.
+ // We cannot use either ElementFactory or TestTypeProvider (which uses
+ // ElementFactory) because we side-effect the elements in ways that would
+ // break other tests.
+ //
+ InterfaceType objectType = _classElement("Object", null).type;
+ InterfaceType boolType = _classElement("bool", objectType).type;
+ InterfaceType numType = _classElement("num", objectType).type;
+ InterfaceType doubleType = _classElement("double", numType).type;
+ InterfaceType functionType = _classElement("Function", objectType).type;
+ InterfaceType intType = _classElement("int", numType).type;
+ InterfaceType iterableType =
+ _classElement("Iterable", objectType, ["T"]).type;
+ InterfaceType listType = _classElement("List", objectType, ["E"]).type;
+ InterfaceType mapType = _classElement("Map", objectType, ["K", "V"]).type;
+ InterfaceType stackTraceType = _classElement("StackTrace", objectType).type;
+ InterfaceType stringType = _classElement("String", objectType).type;
+ InterfaceType symbolType = _classElement("Symbol", objectType).type;
+ InterfaceType typeType = _classElement("Type", objectType).type;
+ CompilationUnitElementImpl coreUnit =
+ new CompilationUnitElementImpl("core.dart");
+ coreUnit.types = <ClassElement>[
+ boolType.element,
+ doubleType.element,
+ functionType.element,
+ intType.element,
+ iterableType.element,
+ listType.element,
+ mapType.element,
+ objectType.element,
+ stackTraceType.element,
+ stringType.element,
+ symbolType.element,
+ typeType.element
+ ];
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
+ context, AstFactory.libraryIdentifier2(["dart.core"]));
+ coreLibrary.definingCompilationUnit = coreUnit;
+
+ LibraryElementImpl mockAsyncLib =
+ (context as AnalysisContextImpl).createMockAsyncLib(coreLibrary);
+ expect(mockAsyncLib.publicNamespace, isNotNull);
+
+ //
+ // Create a type provider and ensure that it can return the expected types.
+ //
+ TypeProviderImpl provider = new TypeProviderImpl(coreLibrary, mockAsyncLib);
+ expect(provider.boolType, same(boolType));
+ expect(provider.bottomType, isNotNull);
+ expect(provider.doubleType, same(doubleType));
+ expect(provider.dynamicType, isNotNull);
+ expect(provider.functionType, same(functionType));
+ InterfaceType mockFutureType = mockAsyncLib.getType('Future').type;
+ expect(provider.futureType, same(mockFutureType));
+ expect(provider.intType, same(intType));
+ expect(provider.listType, same(listType));
+ expect(provider.mapType, same(mapType));
+ expect(provider.objectType, same(objectType));
+ expect(provider.stackTraceType, same(stackTraceType));
+ expect(provider.stringType, same(stringType));
+ expect(provider.symbolType, same(symbolType));
+ InterfaceType mockStreamType = mockAsyncLib.getType('Stream').type;
+ expect(provider.streamType, same(mockStreamType));
+ expect(provider.typeType, same(typeType));
+ }
+
ClassElement _classElement(String typeName, InterfaceType superclassType,
[List<String> parameterNames]) {
ClassElementImpl element =
@@ -16612,12 +16950,17 @@
class _AnalysisContextFactory_initContextWithCore
extends DirectoryBasedDartSdk {
- _AnalysisContextFactory_initContextWithCore(JavaFile arg0) : super(arg0);
+ final bool enableAsync;
+ _AnalysisContextFactory_initContextWithCore(JavaFile arg0,
+ {this.enableAsync: true})
+ : super(arg0);
@override
LibraryMap initialLibraryMap(bool useDart2jsPaths) {
LibraryMap map = new LibraryMap();
- _addLibrary(map, DartSdk.DART_ASYNC, false, "async.dart");
+ if (enableAsync) {
+ _addLibrary(map, DartSdk.DART_ASYNC, false, "async.dart");
+ }
_addLibrary(map, DartSdk.DART_CORE, false, "core.dart");
_addLibrary(map, DartSdk.DART_HTML, false, "html_dartium.dart");
_addLibrary(map, AnalysisContextFactory._DART_MATH, false, "math.dart");
diff --git a/pkg/analyzer/test/generated/test_all.dart b/pkg/analyzer/test/generated/test_all.dart
index e737b56..8a0b3d2 100644
--- a/pkg/analyzer/test/generated/test_all.dart
+++ b/pkg/analyzer/test/generated/test_all.dart
@@ -8,8 +8,8 @@
import '../utils.dart';
import 'all_the_rest_test.dart' as all_the_rest;
-import 'ast_test.dart' as ast_test;
import 'compile_time_error_code_test.dart' as compile_time_error_code_test;
+import 'constant_test.dart' as constant_test;
import 'declaration_resolver_test.dart' as declaration_resolver_test;
import 'engine_test.dart' as engine_test;
import 'incremental_resolver_test.dart' as incremental_resolver_test;
@@ -31,8 +31,8 @@
initializeTestEnvironment();
group('generated tests', () {
all_the_rest.main();
- ast_test.main();
compile_time_error_code_test.main();
+ constant_test.main();
declaration_resolver_test.main();
engine_test.main();
incremental_resolver_test.main();
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 87b1282..adccead 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -6,10 +6,11 @@
import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart'
+ show AstNode, NodeLocator, SimpleIdentifier;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart'
- show AstNode, NodeLocator, SimpleIdentifier;
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -423,9 +424,9 @@
*/
bool _equalErrors(AnalysisError firstError, AnalysisError secondError) =>
identical(firstError.errorCode, secondError.errorCode) &&
- firstError.offset == secondError.offset &&
- firstError.length == secondError.length &&
- _equalSources(firstError.source, secondError.source);
+ firstError.offset == secondError.offset &&
+ firstError.length == secondError.length &&
+ _equalSources(firstError.source, secondError.source);
/**
* Return `true` if the two sources are equivalent.
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index bd5876b..d07f422 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -6,7 +6,8 @@
import 'dart:collection';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/scanner.dart';
@@ -1506,8 +1507,8 @@
}
void test_visitSwitchCase_noLabels() {
- _assertClone(AstFactory.switchCase(
- AstFactory.identifier3("a"), [AstFactory.block()]));
+ _assertClone(AstFactory
+ .switchCase(AstFactory.identifier3("a"), [AstFactory.block()]));
}
void test_visitSwitchCase_singleLabel() {
@@ -1531,8 +1532,8 @@
}
void test_visitSwitchDefault_singleLabel() {
- _assertClone(AstFactory.switchDefault(
- [AstFactory.label2("l1")], [AstFactory.block()]));
+ _assertClone(AstFactory
+ .switchDefault([AstFactory.label2("l1")], [AstFactory.block()]));
}
void test_visitSwitchStatement() {
@@ -3534,8 +3535,8 @@
AstFactory.extendsClause(AstFactory.typeName4("B")),
AstFactory.withClause([AstFactory.typeName4("C")]),
AstFactory.implementsClause([AstFactory.typeName4("D")]), [
- AstFactory.fieldDeclaration2(
- false, null, [AstFactory.variableDeclaration("f")])
+ AstFactory
+ .fieldDeclaration2(false, null, [AstFactory.variableDeclaration("f")])
]);
node.documentationComment =
Comment.createEndOfLineComment(EMPTY_TOKEN_LIST);
@@ -3981,8 +3982,8 @@
}
void test_labeledStatement() {
- LabeledStatement node = AstFactory.labeledStatement(
- [AstFactory.label2("l")], AstFactory.block());
+ LabeledStatement node = AstFactory
+ .labeledStatement([AstFactory.label2("l")], AstFactory.block());
_assertReplace(
node, new ListGetter_NodeReplacerTest_test_labeledStatement(0));
_assertReplace(node, new Getter_NodeReplacerTest_test_labeledStatement());
@@ -4181,8 +4182,8 @@
}
void test_switchDefault() {
- SwitchDefault node = AstFactory.switchDefault(
- [AstFactory.label2("l")], [AstFactory.block()]);
+ SwitchDefault node = AstFactory
+ .switchDefault([AstFactory.label2("l")], [AstFactory.block()]);
_testSwitchMember(node);
}
@@ -4235,8 +4236,8 @@
}
void test_typeName() {
- TypeName node = AstFactory.typeName4(
- "T", [AstFactory.typeName4("E"), AstFactory.typeName4("F")]);
+ TypeName node = AstFactory
+ .typeName4("T", [AstFactory.typeName4("E"), AstFactory.typeName4("F")]);
_assertReplace(node, new Getter_NodeReplacerTest_test_typeName_2());
_assertReplace(node, new Getter_NodeReplacerTest_test_typeName());
}
diff --git a/pkg/analyzer/test/reflective_tests.dart b/pkg/analyzer/test/reflective_tests.dart
index 24c36cb..970743d 100644
--- a/pkg/analyzer/test/reflective_tests.dart
+++ b/pkg/analyzer/test/reflective_tests.dart
@@ -73,14 +73,15 @@
Future _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) {
var invocationResult = null;
+ InstanceMirror closure;
try {
- invocationResult = instanceMirror.invoke(symbol, []).reflectee;
+ closure = instanceMirror.getField(symbol);
} on NoSuchMethodError {}
- if (invocationResult is Future) {
- return invocationResult;
- } else {
- return new Future.value(invocationResult);
+
+ if (closure is ClosureMirror) {
+ invocationResult = closure.apply([]).reflectee;
}
+ return new Future.value(invocationResult);
}
/**
diff --git a/pkg/analyzer/test/source/embedder_test.dart b/pkg/analyzer/test/source/embedder_test.dart
index c152773..cf96040 100644
--- a/pkg/analyzer/test/source/embedder_test.dart
+++ b/pkg/analyzer/test/source/embedder_test.dart
@@ -6,6 +6,8 @@
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/embedder.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/source.dart';
import 'package:unittest/unittest.dart';
import '../utils.dart';
@@ -34,13 +36,20 @@
'fox': [resourceProvider.getResource('/tmp')]
});
var resolver = new EmbedderUriResolver(locator.embedderYamls);
+
+ expectResolved(dartUri, filePath) {
+ Source source = resolver.resolveAbsolute(Uri.parse(dartUri));
+ expect(source, isNotNull, reason: dartUri);
+ expect(source.fullName, filePath.replaceAll('/', JavaFile.separator));
+ }
+
// We have four mappings.
expect(resolver.length, equals(4));
// Check that they map to the correct paths.
- expect(resolver['dart:fox'], equals("/tmp/slippy.dart"));
- expect(resolver['dart:bear'], equals("/tmp/grizzly.dart"));
- expect(resolver['dart:relative'], equals("/relative.dart"));
- expect(resolver['dart:deep'], equals("/tmp/deep/directory/file.dart"));
+ expectResolved('dart:fox', '/tmp/slippy.dart');
+ expectResolved('dart:bear', '/tmp/grizzly.dart');
+ expectResolved('dart:relative', '/relative.dart');
+ expectResolved('dart:deep', '/tmp/deep/directory/file.dart');
});
test('test_BadYAML', () {
var locator = new EmbedderYamlLocator(null);
@@ -52,15 +61,91 @@
'fox': [resourceProvider.getResource('/tmp')]
});
var resolver = new EmbedderUriResolver(locator.embedderYamls);
- var source = resolver.resolveAbsolute(Uri.parse('dart:fox'));
- expect(source, isNotNull);
- // Restore source's uri.
- var restoreUri = resolver.restoreAbsolute(source);
- expect(restoreUri, isNotNull);
- // Verify that it is 'dart:fox'.
- expect(restoreUri.toString(), equals('dart:fox'));
- expect(restoreUri.scheme, equals('dart'));
- expect(restoreUri.path, equals('fox'));
+
+ expectRestore(String dartUri, [String expected]) {
+ var source = resolver.resolveAbsolute(Uri.parse(dartUri));
+ expect(source, isNotNull);
+ // Restore source's uri.
+ var restoreUri = resolver.restoreAbsolute(source);
+ expect(restoreUri, isNotNull, reason: dartUri);
+ // Verify that it is 'dart:fox'.
+ expect(restoreUri.toString(), equals(expected ?? dartUri));
+ List<String> split = (expected ?? dartUri).split(':');
+ expect(restoreUri.scheme, equals(split[0]));
+ expect(restoreUri.path, equals(split[1]));
+ }
+
+ try {
+ expectRestore('dart:deep');
+ expectRestore('dart:deep/file.dart', 'dart:deep');
+ expectRestore('dart:deep/part.dart');
+ expectRestore('dart:deep/deep/file.dart');
+ if (JavaFile.separator == '\\') {
+ // See https://github.com/dart-lang/sdk/issues/25498
+ fail('expected to fail on Windows');
+ }
+ } catch (_) {
+ // Test is broken on Windows, but should run elsewhere
+ if (JavaFile.separator != '\\') {
+ rethrow;
+ }
+ }
+ });
+
+ test('test_EmbedderSdk_fromFileUri', () {
+ var locator = new EmbedderYamlLocator({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ var resolver = new EmbedderUriResolver(locator.embedderYamls);
+ var sdk = resolver.dartSdk;
+
+ expectSource(String filePath, String dartUri) {
+ var uri = Uri.parse(filePath);
+ var source = sdk.fromFileUri(uri);
+ expect(source, isNotNull, reason: filePath);
+ expect(source.uri.toString(), dartUri);
+ expect(source.fullName, filePath.replaceAll('/', JavaFile.separator));
+ }
+
+ //TODO(danrubel) fix embedder on Windows
+ isWindows() => JavaFile.separator == '\\';
+ try {
+ expectSource('/tmp/slippy.dart', 'dart:fox');
+ expectSource('/tmp/deep/directory/file.dart', 'dart:deep');
+ expectSource('/tmp/deep/directory/part.dart', 'dart:deep/part.dart');
+ if (isWindows()) fail('expected to fail on windows');
+ } catch (e) {
+ if (!isWindows()) rethrow;
+ }
+ });
+ test('test_EmbedderSdk_getSdkLibrary', () {
+ var locator = new EmbedderYamlLocator({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ var resolver = new EmbedderUriResolver(locator.embedderYamls);
+ var sdk = resolver.dartSdk;
+ var lib = sdk.getSdkLibrary('dart:fox');
+ expect(lib, isNotNull);
+ expect(lib.path, '/tmp/slippy.dart');
+ expect(lib.shortName, 'fox');
+ });
+ test('test_EmbedderSdk_mapDartUri', () {
+ var locator = new EmbedderYamlLocator({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ var resolver = new EmbedderUriResolver(locator.embedderYamls);
+ var sdk = resolver.dartSdk;
+
+ expectSource(String dartUri, String filePath) {
+ var source = sdk.mapDartUri(dartUri);
+ expect(source, isNotNull, reason: filePath);
+ expect(source.uri.toString(), dartUri);
+ expect(source.fullName, filePath.replaceAll('/', JavaFile.separator));
+ }
+
+ expectSource('dart:fox', '/tmp/slippy.dart');
+ expectSource('dart:deep', '/tmp/deep/directory/file.dart');
+ expectSource('dart:deep/part.dart', '/tmp/deep/directory/part.dart');
});
});
}
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index 41feb593..d37179a 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -5,15 +5,17 @@
library analyzer.test.src.context.context_test;
import 'dart:async';
+import 'dart:collection';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/cancelable_future.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
@@ -2002,6 +2004,72 @@
_assertNoExceptions();
}
+ void test_resolveCompilationUnit_existingElementModel() {
+ Source source = addSource(
+ '/test.dart',
+ r'''
+library test;
+
+String topLevelVariable;
+int get topLevelGetter => 0;
+void set topLevelSetter(int value) {}
+String topLevelFunction(int i) => '';
+
+typedef String FunctionTypeAlias(int i);
+
+enum EnumeratedType {Invalid, Valid}
+
+class ClassOne {
+ int instanceField;
+ static int staticField;
+
+ ClassOne();
+ ClassOne.named();
+
+ int get instanceGetter => 0;
+ static String get staticGetter => '';
+
+ void set instanceSetter(int value) {}
+ static void set staticSetter(int value) {}
+
+ int instanceMethod(int first, [int second = 0]) {
+ int localVariable;
+ int localFunction(String s) {}
+ }
+ static String staticMethod(int first, {int second: 0}) => '';
+}
+
+class ClassTwo {
+ // Implicit no-argument constructor
+}
+''');
+ context.resolveCompilationUnit2(source, source);
+ LibraryElement firstElement = context.computeLibraryElement(source);
+ _ElementGatherer gatherer = new _ElementGatherer();
+ firstElement.accept(gatherer);
+
+ CacheEntry entry =
+ context.analysisCache.get(new LibrarySpecificUnit(source, source));
+ entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT6, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
+
+ context.resolveCompilationUnit2(source, source);
+ LibraryElement secondElement = context.computeLibraryElement(source);
+ _ElementComparer comparer = new _ElementComparer(gatherer.elements);
+ secondElement.accept(comparer);
+ comparer.expectNoDifferences();
+ }
+
void test_resolveCompilationUnit_import_relative() {
Source sourceA =
addSource("/libA.dart", "library libA; import 'libB.dart'; class A{}");
@@ -2731,3 +2799,82 @@
@override
bool contains(Source source) => source == libB;
}
+
+/**
+ * A visitor that can be used to compare all of the elements in an element model
+ * with a previously created map of elements. The class [ElementGatherer] can be
+ * used to create the map of elements.
+ */
+class _ElementComparer extends GeneralizingElementVisitor {
+ /**
+ * The previously created map of elements.
+ */
+ final Map<Element, Element> previousElements;
+
+ /**
+ * The number of elements that were found to have been overwritten.
+ */
+ int overwrittenCount = 0;
+
+ /**
+ * A buffer to which a description of the overwritten elements will be written.
+ */
+ final StringBuffer buffer = new StringBuffer();
+
+ /**
+ * Initialize a newly created visitor.
+ */
+ _ElementComparer(this.previousElements);
+
+ /**
+ * Expect that no differences were found, causing the test to fail if that
+ * wasn't the case.
+ */
+ void expectNoDifferences() {
+ if (overwrittenCount > 0) {
+ fail('Found $overwrittenCount overwritten elements.$buffer');
+ }
+ }
+
+ @override
+ void visitElement(Element element) {
+ Element previousElement = previousElements[element];
+ if (!identical(previousElement, element)) {
+ if (overwrittenCount == 0) {
+ buffer.writeln();
+ }
+ overwrittenCount++;
+ buffer.writeln('Overwritten element:');
+ Element currentElement = element;
+ while (currentElement != null) {
+ buffer.write(' ');
+ buffer.writeln(currentElement.toString());
+ currentElement = currentElement.enclosingElement;
+ }
+ }
+ super.visitElement(element);
+ }
+}
+
+/**
+ * A visitor that can be used to collect all of the elements in an element
+ * model.
+ */
+class _ElementGatherer extends GeneralizingElementVisitor {
+ /**
+ * The map in which the elements are collected. The value of each key is the
+ * key itself.
+ */
+ Map<Element, Element> elements = new HashMap<Element, Element>();
+
+ /**
+ * Initialize the visitor.
+ */
+ _ElementGatherer();
+
+ @override
+ void visitElement(Element element) {
+ elements[element] = element;
+ super.visitElement(element);
+ }
+}
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 5cf93dd..b67c4a5 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -228,12 +228,6 @@
_analysisContext = new _SdkAnalysisContext(this);
SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
_analysisContext.sourceFactory = factory;
- ChangeSet changeSet = new ChangeSet();
- for (String uri in uris) {
- Source source = factory.forUri(uri);
- changeSet.addedSource(source);
- }
- _analysisContext.applyChanges(changeSet);
}
return _analysisContext;
}
diff --git a/pkg/analyzer/test/src/dart/ast/test_all.dart b/pkg/analyzer/test/src/dart/ast/test_all.dart
new file mode 100644
index 0000000..f0648c4
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/ast/test_all.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.dart.ast.test_all;
+
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'utilities_test.dart' as utilities;
+
+/// Utility for manually running all tests.
+main() {
+ initializeTestEnvironment();
+ group('ast tests', () {
+ utilities.main();
+ });
+}
diff --git a/pkg/analyzer/test/generated/ast_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
similarity index 63%
rename from pkg/analyzer/test/generated/ast_test.dart
rename to pkg/analyzer/test/src/dart/ast/utilities_test.dart
index bff9b8b..8531637 100644
--- a/pkg/analyzer/test/generated/ast_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -2,9 +2,10 @@
// 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 analyzer.test.generated.ast_test;
+library analyzer.test.src.dart.ast.utilities_test;
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/java_engine.dart' show Predicate;
import 'package:analyzer/src/generated/java_engine.dart';
@@ -13,211 +14,17 @@
import 'package:analyzer/src/generated/testing/token_factory.dart';
import 'package:unittest/unittest.dart';
-import '../reflective_tests.dart';
-import '../utils.dart';
-import 'parser_test.dart' show ParserTestCase;
-import 'test_support.dart';
+import '../../../generated/parser_test.dart' show ParserTestCase;
+import '../../../generated/test_support.dart';
+import '../../../reflective_tests.dart';
+import '../../../utils.dart';
main() {
initializeTestEnvironment();
- runReflectiveTests(BreadthFirstVisitorTest);
- runReflectiveTests(ClassDeclarationTest);
- runReflectiveTests(ClassTypeAliasTest);
runReflectiveTests(ConstantEvaluatorTest);
- runReflectiveTests(ConstructorDeclarationTest);
- runReflectiveTests(FieldFormalParameterTest);
- runReflectiveTests(IndexExpressionTest);
- runReflectiveTests(NodeListTest);
runReflectiveTests(NodeLocatorTest);
runReflectiveTests(NodeLocator2Test);
- runReflectiveTests(SimpleIdentifierTest);
- runReflectiveTests(SimpleStringLiteralTest);
- runReflectiveTests(StringInterpolationTest);
runReflectiveTests(ToSourceVisitorTest);
- runReflectiveTests(VariableDeclarationTest);
-}
-
-class AssignmentKind extends Enum<AssignmentKind> {
- static const AssignmentKind BINARY = const AssignmentKind('BINARY', 0);
-
- static const AssignmentKind COMPOUND_LEFT =
- const AssignmentKind('COMPOUND_LEFT', 1);
-
- static const AssignmentKind COMPOUND_RIGHT =
- const AssignmentKind('COMPOUND_RIGHT', 2);
-
- static const AssignmentKind POSTFIX_INC =
- const AssignmentKind('POSTFIX_INC', 3);
-
- static const AssignmentKind PREFIX_DEC =
- const AssignmentKind('PREFIX_DEC', 4);
-
- static const AssignmentKind PREFIX_INC =
- const AssignmentKind('PREFIX_INC', 5);
-
- static const AssignmentKind PREFIX_NOT =
- const AssignmentKind('PREFIX_NOT', 6);
-
- static const AssignmentKind SIMPLE_LEFT =
- const AssignmentKind('SIMPLE_LEFT', 7);
-
- static const AssignmentKind SIMPLE_RIGHT =
- const AssignmentKind('SIMPLE_RIGHT', 8);
-
- static const AssignmentKind NONE = const AssignmentKind('NONE', 9);
-
- static const List<AssignmentKind> values = const [
- BINARY,
- COMPOUND_LEFT,
- COMPOUND_RIGHT,
- POSTFIX_INC,
- PREFIX_DEC,
- PREFIX_INC,
- PREFIX_NOT,
- SIMPLE_LEFT,
- SIMPLE_RIGHT,
- NONE
- ];
-
- const AssignmentKind(String name, int ordinal) : super(name, ordinal);
-}
-
-class BreadthFirstVisitor_BreadthFirstVisitorTest_testIt
- extends BreadthFirstVisitor<Object> {
- List<AstNode> nodes;
-
- BreadthFirstVisitor_BreadthFirstVisitorTest_testIt(this.nodes) : super();
-
- @override
- Object visitNode(AstNode node) {
- nodes.add(node);
- return super.visitNode(node);
- }
-}
-
-@reflectiveTest
-class BreadthFirstVisitorTest extends ParserTestCase {
- void test_it() {
- String source = r'''
-class A {
- bool get g => true;
-}
-class B {
- int f() {
- num q() {
- return 3;
- }
- return q() + 4;
- }
-}
-A f(var p) {
- if ((p as A).g) {
- return p;
- } else {
- return null;
- }
-}''';
- CompilationUnit unit = ParserTestCase.parseCompilationUnit(source);
- List<AstNode> nodes = new List<AstNode>();
- BreadthFirstVisitor<Object> visitor =
- new BreadthFirstVisitor_BreadthFirstVisitorTest_testIt(nodes);
- visitor.visitAllNodes(unit);
- expect(nodes, hasLength(59));
- EngineTestCase.assertInstanceOf(
- (obj) => obj is CompilationUnit, CompilationUnit, nodes[0]);
- EngineTestCase.assertInstanceOf(
- (obj) => obj is ClassDeclaration, ClassDeclaration, nodes[2]);
- EngineTestCase.assertInstanceOf(
- (obj) => obj is FunctionDeclaration, FunctionDeclaration, nodes[3]);
- EngineTestCase.assertInstanceOf(
- (obj) => obj is FunctionDeclarationStatement,
- FunctionDeclarationStatement,
- nodes[27]);
- EngineTestCase.assertInstanceOf(
- (obj) => obj is IntegerLiteral, IntegerLiteral, nodes[58]);
- //3
- }
-}
-
-@reflectiveTest
-class ClassDeclarationTest extends ParserTestCase {
- void test_getConstructor() {
- List<ConstructorInitializer> initializers =
- new List<ConstructorInitializer>();
- ConstructorDeclaration defaultConstructor = AstFactory
- .constructorDeclaration(AstFactory.identifier3("Test"), null,
- AstFactory.formalParameterList(), initializers);
- ConstructorDeclaration aConstructor = AstFactory.constructorDeclaration(
- AstFactory.identifier3("Test"),
- "a",
- AstFactory.formalParameterList(),
- initializers);
- ConstructorDeclaration bConstructor = AstFactory.constructorDeclaration(
- AstFactory.identifier3("Test"),
- "b",
- AstFactory.formalParameterList(),
- initializers);
- ClassDeclaration clazz = AstFactory.classDeclaration(null, "Test", null,
- null, null, null, [defaultConstructor, aConstructor, bConstructor]);
- expect(clazz.getConstructor(null), same(defaultConstructor));
- expect(clazz.getConstructor("a"), same(aConstructor));
- expect(clazz.getConstructor("b"), same(bConstructor));
- expect(clazz.getConstructor("noSuchConstructor"), same(null));
- }
-
- void test_getField() {
- VariableDeclaration aVar = AstFactory.variableDeclaration("a");
- VariableDeclaration bVar = AstFactory.variableDeclaration("b");
- VariableDeclaration cVar = AstFactory.variableDeclaration("c");
- ClassDeclaration clazz =
- AstFactory.classDeclaration(null, "Test", null, null, null, null, [
- AstFactory.fieldDeclaration2(false, null, [aVar]),
- AstFactory.fieldDeclaration2(false, null, [bVar, cVar])
- ]);
- expect(clazz.getField("a"), same(aVar));
- expect(clazz.getField("b"), same(bVar));
- expect(clazz.getField("c"), same(cVar));
- expect(clazz.getField("noSuchField"), same(null));
- }
-
- void test_getMethod() {
- MethodDeclaration aMethod = AstFactory.methodDeclaration(null, null, null,
- null, AstFactory.identifier3("a"), AstFactory.formalParameterList());
- MethodDeclaration bMethod = AstFactory.methodDeclaration(null, null, null,
- null, AstFactory.identifier3("b"), AstFactory.formalParameterList());
- ClassDeclaration clazz = AstFactory.classDeclaration(
- null, "Test", null, null, null, null, [aMethod, bMethod]);
- expect(clazz.getMethod("a"), same(aMethod));
- expect(clazz.getMethod("b"), same(bMethod));
- expect(clazz.getMethod("noSuchMethod"), same(null));
- }
-
- void test_isAbstract() {
- expect(
- AstFactory
- .classDeclaration(null, "A", null, null, null, null)
- .isAbstract,
- isFalse);
- expect(
- AstFactory
- .classDeclaration(Keyword.ABSTRACT, "B", null, null, null, null)
- .isAbstract,
- isTrue);
- }
-}
-
-@reflectiveTest
-class ClassTypeAliasTest extends ParserTestCase {
- void test_isAbstract() {
- expect(
- AstFactory.classTypeAlias("A", null, null, null, null, null).isAbstract,
- isFalse);
- expect(
- AstFactory
- .classTypeAlias("B", null, Keyword.ABSTRACT, null, null, null)
- .isAbstract,
- isTrue);
- }
}
@reflectiveTest
@@ -525,427 +332,6 @@
}
@reflectiveTest
-class ConstructorDeclarationTest extends EngineTestCase {
- void test_firstTokenAfterCommentAndMetadata_all_inverted() {
- Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
- externalKeyword.offset = 14;
- ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
- Keyword.CONST,
- Keyword.FACTORY,
- AstFactory.identifier3('int'),
- null,
- null,
- null,
- null);
- declaration.externalKeyword = externalKeyword;
- declaration.constKeyword.offset = 8;
- Token factoryKeyword = declaration.factoryKeyword;
- factoryKeyword.offset = 0;
- expect(declaration.firstTokenAfterCommentAndMetadata, factoryKeyword);
- }
-
- void test_firstTokenAfterCommentAndMetadata_all_normal() {
- Token token = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
- token.offset = 0;
- ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
- Keyword.CONST,
- Keyword.FACTORY,
- AstFactory.identifier3('int'),
- null,
- null,
- null,
- null);
- declaration.externalKeyword = token;
- declaration.constKeyword.offset = 9;
- declaration.factoryKeyword.offset = 15;
- expect(declaration.firstTokenAfterCommentAndMetadata, token);
- }
-
- void test_firstTokenAfterCommentAndMetadata_constOnly() {
- ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
- Keyword.CONST,
- null,
- AstFactory.identifier3('int'),
- null,
- null,
- null,
- null);
- expect(declaration.firstTokenAfterCommentAndMetadata,
- declaration.constKeyword);
- }
-
- void test_firstTokenAfterCommentAndMetadata_externalOnly() {
- Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
- ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
- null, null, AstFactory.identifier3('int'), null, null, null, null);
- declaration.externalKeyword = externalKeyword;
- expect(declaration.firstTokenAfterCommentAndMetadata, externalKeyword);
- }
-
- void test_firstTokenAfterCommentAndMetadata_factoryOnly() {
- ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
- null,
- Keyword.FACTORY,
- AstFactory.identifier3('int'),
- null,
- null,
- null,
- null);
- expect(declaration.firstTokenAfterCommentAndMetadata,
- declaration.factoryKeyword);
- }
-}
-
-@reflectiveTest
-class FieldFormalParameterTest extends EngineTestCase {
- void test_endToken_noParameters() {
- FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('field');
- expect(parameter.endToken, parameter.identifier.endToken);
- }
-
- void test_endToken_parameters() {
- FieldFormalParameter parameter = AstFactory.fieldFormalParameter(
- null, null, 'field', AstFactory.formalParameterList([]));
- expect(parameter.endToken, parameter.parameters.endToken);
- }
-}
-
-@reflectiveTest
-class IndexExpressionTest extends EngineTestCase {
- void test_inGetterContext_assignment_compound_left() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // a[b] += c
- AstFactory.assignmentExpression(
- expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
- expect(expression.inGetterContext(), isTrue);
- }
-
- void test_inGetterContext_assignment_simple_left() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // a[b] = c
- AstFactory.assignmentExpression(
- expression, TokenType.EQ, AstFactory.identifier3("c"));
- expect(expression.inGetterContext(), isFalse);
- }
-
- void test_inGetterContext_nonAssignment() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // a[b] + c
- AstFactory.binaryExpression(
- expression, TokenType.PLUS, AstFactory.identifier3("c"));
- expect(expression.inGetterContext(), isTrue);
- }
-
- void test_inSetterContext_assignment_compound_left() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // a[b] += c
- AstFactory.assignmentExpression(
- expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
- expect(expression.inSetterContext(), isTrue);
- }
-
- void test_inSetterContext_assignment_compound_right() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // c += a[b]
- AstFactory.assignmentExpression(
- AstFactory.identifier3("c"), TokenType.PLUS_EQ, expression);
- expect(expression.inSetterContext(), isFalse);
- }
-
- void test_inSetterContext_assignment_simple_left() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // a[b] = c
- AstFactory.assignmentExpression(
- expression, TokenType.EQ, AstFactory.identifier3("c"));
- expect(expression.inSetterContext(), isTrue);
- }
-
- void test_inSetterContext_assignment_simple_right() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // c = a[b]
- AstFactory.assignmentExpression(
- AstFactory.identifier3("c"), TokenType.EQ, expression);
- expect(expression.inSetterContext(), isFalse);
- }
-
- void test_inSetterContext_nonAssignment() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- AstFactory.binaryExpression(
- expression, TokenType.PLUS, AstFactory.identifier3("c"));
- // a[b] + cc
- expect(expression.inSetterContext(), isFalse);
- }
-
- void test_inSetterContext_postfix() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
- // a[b]++
- expect(expression.inSetterContext(), isTrue);
- }
-
- void test_inSetterContext_prefix_bang() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // !a[b]
- AstFactory.prefixExpression(TokenType.BANG, expression);
- expect(expression.inSetterContext(), isFalse);
- }
-
- void test_inSetterContext_prefix_minusMinus() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // --a[b]
- AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
- expect(expression.inSetterContext(), isTrue);
- }
-
- void test_inSetterContext_prefix_plusPlus() {
- IndexExpression expression = AstFactory.indexExpression(
- AstFactory.identifier3("a"), AstFactory.identifier3("b"));
- // ++a[b]
- AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
- expect(expression.inSetterContext(), isTrue);
- }
-}
-
-@reflectiveTest
-class NodeListTest extends EngineTestCase {
- void test_add() {
- AstNode parent = AstFactory.argumentList();
- AstNode firstNode = AstFactory.booleanLiteral(true);
- AstNode secondNode = AstFactory.booleanLiteral(false);
- NodeList<AstNode> list = new NodeList<AstNode>(parent);
- list.insert(0, secondNode);
- list.insert(0, firstNode);
- expect(list, hasLength(2));
- expect(list[0], same(firstNode));
- expect(list[1], same(secondNode));
- expect(firstNode.parent, same(parent));
- expect(secondNode.parent, same(parent));
- AstNode thirdNode = AstFactory.booleanLiteral(false);
- list.insert(1, thirdNode);
- expect(list, hasLength(3));
- expect(list[0], same(firstNode));
- expect(list[1], same(thirdNode));
- expect(list[2], same(secondNode));
- expect(firstNode.parent, same(parent));
- expect(secondNode.parent, same(parent));
- expect(thirdNode.parent, same(parent));
- }
-
- void test_add_negative() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- list.insert(-1, AstFactory.booleanLiteral(true));
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-
- void test_add_tooBig() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- list.insert(1, AstFactory.booleanLiteral(true));
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-
- void test_addAll() {
- AstNode parent = AstFactory.argumentList();
- List<AstNode> firstNodes = new List<AstNode>();
- AstNode firstNode = AstFactory.booleanLiteral(true);
- AstNode secondNode = AstFactory.booleanLiteral(false);
- firstNodes.add(firstNode);
- firstNodes.add(secondNode);
- NodeList<AstNode> list = new NodeList<AstNode>(parent);
- list.addAll(firstNodes);
- expect(list, hasLength(2));
- expect(list[0], same(firstNode));
- expect(list[1], same(secondNode));
- expect(firstNode.parent, same(parent));
- expect(secondNode.parent, same(parent));
- List<AstNode> secondNodes = new List<AstNode>();
- AstNode thirdNode = AstFactory.booleanLiteral(true);
- AstNode fourthNode = AstFactory.booleanLiteral(false);
- secondNodes.add(thirdNode);
- secondNodes.add(fourthNode);
- list.addAll(secondNodes);
- expect(list, hasLength(4));
- expect(list[0], same(firstNode));
- expect(list[1], same(secondNode));
- expect(list[2], same(thirdNode));
- expect(list[3], same(fourthNode));
- expect(firstNode.parent, same(parent));
- expect(secondNode.parent, same(parent));
- expect(thirdNode.parent, same(parent));
- expect(fourthNode.parent, same(parent));
- }
-
- void test_creation() {
- AstNode owner = AstFactory.argumentList();
- NodeList<AstNode> list = new NodeList<AstNode>(owner);
- expect(list, isNotNull);
- expect(list, hasLength(0));
- expect(list.owner, same(owner));
- }
-
- void test_get_negative() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- list[-1];
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-
- void test_get_tooBig() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- list[1];
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-
- void test_getBeginToken_empty() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- expect(list.beginToken, isNull);
- }
-
- void test_getBeginToken_nonEmpty() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- AstNode node =
- AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
- list.add(node);
- expect(list.beginToken, same(node.beginToken));
- }
-
- void test_getEndToken_empty() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- expect(list.endToken, isNull);
- }
-
- void test_getEndToken_nonEmpty() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- AstNode node =
- AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
- list.add(node);
- expect(list.endToken, same(node.endToken));
- }
-
- void test_indexOf() {
- List<AstNode> nodes = new List<AstNode>();
- AstNode firstNode = AstFactory.booleanLiteral(true);
- AstNode secondNode = AstFactory.booleanLiteral(false);
- AstNode thirdNode = AstFactory.booleanLiteral(true);
- AstNode fourthNode = AstFactory.booleanLiteral(false);
- nodes.add(firstNode);
- nodes.add(secondNode);
- nodes.add(thirdNode);
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- list.addAll(nodes);
- expect(list, hasLength(3));
- expect(list.indexOf(firstNode), 0);
- expect(list.indexOf(secondNode), 1);
- expect(list.indexOf(thirdNode), 2);
- expect(list.indexOf(fourthNode), -1);
- expect(list.indexOf(null), -1);
- }
-
- void test_remove() {
- List<AstNode> nodes = new List<AstNode>();
- AstNode firstNode = AstFactory.booleanLiteral(true);
- AstNode secondNode = AstFactory.booleanLiteral(false);
- AstNode thirdNode = AstFactory.booleanLiteral(true);
- nodes.add(firstNode);
- nodes.add(secondNode);
- nodes.add(thirdNode);
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- list.addAll(nodes);
- expect(list, hasLength(3));
- expect(list.removeAt(1), same(secondNode));
- expect(list, hasLength(2));
- expect(list[0], same(firstNode));
- expect(list[1], same(thirdNode));
- }
-
- void test_remove_negative() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- list.removeAt(-1);
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-
- void test_remove_tooBig() {
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- list.removeAt(1);
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-
- void test_set() {
- List<AstNode> nodes = new List<AstNode>();
- AstNode firstNode = AstFactory.booleanLiteral(true);
- AstNode secondNode = AstFactory.booleanLiteral(false);
- AstNode thirdNode = AstFactory.booleanLiteral(true);
- nodes.add(firstNode);
- nodes.add(secondNode);
- nodes.add(thirdNode);
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- list.addAll(nodes);
- expect(list, hasLength(3));
- AstNode fourthNode = AstFactory.integer(0);
- expect(javaListSet(list, 1, fourthNode), same(secondNode));
- expect(list, hasLength(3));
- expect(list[0], same(firstNode));
- expect(list[1], same(fourthNode));
- expect(list[2], same(thirdNode));
- }
-
- void test_set_negative() {
- AstNode node = AstFactory.booleanLiteral(true);
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- javaListSet(list, -1, node);
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-
- void test_set_tooBig() {
- AstNode node = AstFactory.booleanLiteral(true);
- NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
- try {
- javaListSet(list, 1, node);
- fail("Expected IndexOutOfBoundsException");
- } on RangeError {
- // Expected
- }
- }
-}
-
-@reflectiveTest
class NodeLocator2Test extends ParserTestCase {
void test_onlyStartOffset() {
String code = ' int vv; ';
@@ -1042,659 +428,6 @@
}
@reflectiveTest
-class SimpleIdentifierTest extends ParserTestCase {
- void test_inDeclarationContext_catch_exception() {
- SimpleIdentifier identifier =
- AstFactory.catchClause("e").exceptionParameter;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_catch_stack() {
- SimpleIdentifier identifier =
- AstFactory.catchClause2("e", "s").stackTraceParameter;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_classDeclaration() {
- SimpleIdentifier identifier =
- AstFactory.classDeclaration(null, "C", null, null, null, null).name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_classTypeAlias() {
- SimpleIdentifier identifier =
- AstFactory.classTypeAlias("C", null, null, null, null, null).name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_constructorDeclaration() {
- SimpleIdentifier identifier = AstFactory
- .constructorDeclaration(AstFactory.identifier3("C"), "c", null, null)
- .name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_declaredIdentifier() {
- DeclaredIdentifier declaredIdentifier = AstFactory.declaredIdentifier3("v");
- SimpleIdentifier identifier = declaredIdentifier.identifier;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_enumConstantDeclaration() {
- EnumDeclaration enumDeclaration =
- AstFactory.enumDeclaration2('MyEnum', ['CONST']);
- SimpleIdentifier identifier = enumDeclaration.constants[0].name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_enumDeclaration() {
- EnumDeclaration enumDeclaration =
- AstFactory.enumDeclaration2('MyEnum', ['A', 'B', 'C']);
- SimpleIdentifier identifier = enumDeclaration.name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_fieldFormalParameter() {
- SimpleIdentifier identifier =
- AstFactory.fieldFormalParameter2("p").identifier;
- expect(identifier.inDeclarationContext(), isFalse);
- }
-
- void test_inDeclarationContext_functionDeclaration() {
- SimpleIdentifier identifier =
- AstFactory.functionDeclaration(null, null, "f", null).name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_functionTypeAlias() {
- SimpleIdentifier identifier =
- AstFactory.typeAlias(null, "F", null, null).name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_label_false() {
- SimpleIdentifier identifier =
- AstFactory.namedExpression2("l", AstFactory.integer(0)).name.label;
- expect(identifier.inDeclarationContext(), isFalse);
- }
-
- void test_inDeclarationContext_label_true() {
- Label label = AstFactory.label2("l");
- SimpleIdentifier identifier = label.label;
- AstFactory.labeledStatement([label], AstFactory.emptyStatement());
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_methodDeclaration() {
- SimpleIdentifier identifier = AstFactory.identifier3("m");
- AstFactory.methodDeclaration2(
- null, null, null, null, identifier, null, null);
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_prefix() {
- SimpleIdentifier identifier =
- AstFactory.importDirective3("uri", "pref").prefix;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_simpleFormalParameter() {
- SimpleIdentifier identifier =
- AstFactory.simpleFormalParameter3("p").identifier;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_typeParameter_bound() {
- TypeName bound = AstFactory.typeName4("A");
- SimpleIdentifier identifier = bound.name as SimpleIdentifier;
- AstFactory.typeParameter2("E", bound);
- expect(identifier.inDeclarationContext(), isFalse);
- }
-
- void test_inDeclarationContext_typeParameter_name() {
- SimpleIdentifier identifier = AstFactory.typeParameter("E").name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inDeclarationContext_variableDeclaration() {
- SimpleIdentifier identifier = AstFactory.variableDeclaration("v").name;
- expect(identifier.inDeclarationContext(), isTrue);
- }
-
- void test_inGetterContext() {
- for (WrapperKind wrapper in WrapperKind.values) {
- for (AssignmentKind assignment in AssignmentKind.values) {
- SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
- if (assignment == AssignmentKind.SIMPLE_LEFT &&
- wrapper != WrapperKind.PREFIXED_LEFT &&
- wrapper != WrapperKind.PROPERTY_LEFT) {
- if (identifier.inGetterContext()) {
- fail("Expected ${_topMostNode(identifier).toSource()} to be false");
- }
- } else {
- if (!identifier.inGetterContext()) {
- fail("Expected ${_topMostNode(identifier).toSource()} to be true");
- }
- }
- }
- }
- }
-
- void test_inGetterContext_forEachLoop() {
- SimpleIdentifier identifier = AstFactory.identifier3("a");
- Expression iterator = AstFactory.listLiteral();
- Statement body = AstFactory.block();
- AstFactory.forEachStatement2(identifier, iterator, body);
- expect(identifier.inGetterContext(), isFalse);
- }
-
- void test_inReferenceContext() {
- SimpleIdentifier identifier = AstFactory.identifier3("id");
- AstFactory.namedExpression(
- AstFactory.label(identifier), AstFactory.identifier3("_"));
- expect(identifier.inGetterContext(), isFalse);
- expect(identifier.inSetterContext(), isFalse);
- }
-
- void test_inSetterContext() {
- for (WrapperKind wrapper in WrapperKind.values) {
- for (AssignmentKind assignment in AssignmentKind.values) {
- SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
- if (wrapper == WrapperKind.PREFIXED_LEFT ||
- wrapper == WrapperKind.PROPERTY_LEFT ||
- assignment == AssignmentKind.BINARY ||
- assignment == AssignmentKind.COMPOUND_RIGHT ||
- assignment == AssignmentKind.PREFIX_NOT ||
- assignment == AssignmentKind.SIMPLE_RIGHT ||
- assignment == AssignmentKind.NONE) {
- if (identifier.inSetterContext()) {
- fail("Expected ${_topMostNode(identifier).toSource()} to be false");
- }
- } else {
- if (!identifier.inSetterContext()) {
- fail("Expected ${_topMostNode(identifier).toSource()} to be true");
- }
- }
- }
- }
- }
-
- void test_inSetterContext_forEachLoop() {
- SimpleIdentifier identifier = AstFactory.identifier3("a");
- Expression iterator = AstFactory.listLiteral();
- Statement body = AstFactory.block();
- AstFactory.forEachStatement2(identifier, iterator, body);
- expect(identifier.inSetterContext(), isTrue);
- }
-
- void test_isQualified_inMethodInvocation_noTarget() {
- MethodInvocation invocation =
- AstFactory.methodInvocation2("test", [AstFactory.identifier3("arg0")]);
- SimpleIdentifier identifier = invocation.methodName;
- expect(identifier.isQualified, isFalse);
- }
-
- void test_isQualified_inMethodInvocation_withTarget() {
- MethodInvocation invocation = AstFactory.methodInvocation(
- AstFactory.identifier3("target"),
- "test",
- [AstFactory.identifier3("arg0")]);
- SimpleIdentifier identifier = invocation.methodName;
- expect(identifier.isQualified, isTrue);
- }
-
- void test_isQualified_inPrefixedIdentifier_name() {
- SimpleIdentifier identifier = AstFactory.identifier3("test");
- AstFactory.identifier4("prefix", identifier);
- expect(identifier.isQualified, isTrue);
- }
-
- void test_isQualified_inPrefixedIdentifier_prefix() {
- SimpleIdentifier identifier = AstFactory.identifier3("test");
- AstFactory.identifier(identifier, AstFactory.identifier3("name"));
- expect(identifier.isQualified, isFalse);
- }
-
- void test_isQualified_inPropertyAccess_name() {
- SimpleIdentifier identifier = AstFactory.identifier3("test");
- AstFactory.propertyAccess(AstFactory.identifier3("target"), identifier);
- expect(identifier.isQualified, isTrue);
- }
-
- void test_isQualified_inPropertyAccess_target() {
- SimpleIdentifier identifier = AstFactory.identifier3("test");
- AstFactory.propertyAccess(identifier, AstFactory.identifier3("name"));
- expect(identifier.isQualified, isFalse);
- }
-
- void test_isQualified_inReturnStatement() {
- SimpleIdentifier identifier = AstFactory.identifier3("test");
- AstFactory.returnStatement2(identifier);
- expect(identifier.isQualified, isFalse);
- }
-
- SimpleIdentifier _createIdentifier(
- WrapperKind wrapper, AssignmentKind assignment) {
- SimpleIdentifier identifier = AstFactory.identifier3("a");
- Expression expression = identifier;
- while (true) {
- if (wrapper == WrapperKind.PREFIXED_LEFT) {
- expression =
- AstFactory.identifier(identifier, AstFactory.identifier3("_"));
- } else if (wrapper == WrapperKind.PREFIXED_RIGHT) {
- expression =
- AstFactory.identifier(AstFactory.identifier3("_"), identifier);
- } else if (wrapper == WrapperKind.PROPERTY_LEFT) {
- expression = AstFactory.propertyAccess2(expression, "_");
- } else if (wrapper == WrapperKind.PROPERTY_RIGHT) {
- expression =
- AstFactory.propertyAccess(AstFactory.identifier3("_"), identifier);
- } else if (wrapper == WrapperKind.NONE) {}
- break;
- }
- while (true) {
- if (assignment == AssignmentKind.BINARY) {
- AstFactory.binaryExpression(
- expression, TokenType.PLUS, AstFactory.identifier3("_"));
- } else if (assignment == AssignmentKind.COMPOUND_LEFT) {
- AstFactory.assignmentExpression(
- expression, TokenType.PLUS_EQ, AstFactory.identifier3("_"));
- } else if (assignment == AssignmentKind.COMPOUND_RIGHT) {
- AstFactory.assignmentExpression(
- AstFactory.identifier3("_"), TokenType.PLUS_EQ, expression);
- } else if (assignment == AssignmentKind.POSTFIX_INC) {
- AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
- } else if (assignment == AssignmentKind.PREFIX_DEC) {
- AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
- } else if (assignment == AssignmentKind.PREFIX_INC) {
- AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
- } else if (assignment == AssignmentKind.PREFIX_NOT) {
- AstFactory.prefixExpression(TokenType.BANG, expression);
- } else if (assignment == AssignmentKind.SIMPLE_LEFT) {
- AstFactory.assignmentExpression(
- expression, TokenType.EQ, AstFactory.identifier3("_"));
- } else if (assignment == AssignmentKind.SIMPLE_RIGHT) {
- AstFactory.assignmentExpression(
- AstFactory.identifier3("_"), TokenType.EQ, expression);
- } else if (assignment == AssignmentKind.NONE) {}
- break;
- }
- return identifier;
- }
-
- /**
- * Return the top-most node in the AST structure containing the given identifier.
- *
- * @param identifier the identifier in the AST structure being traversed
- * @return the root of the AST structure containing the identifier
- */
- AstNode _topMostNode(SimpleIdentifier identifier) {
- AstNode child = identifier;
- AstNode parent = identifier.parent;
- while (parent != null) {
- child = parent;
- parent = parent.parent;
- }
- return child;
- }
-}
-
-@reflectiveTest
-class SimpleStringLiteralTest extends ParserTestCase {
- void test_contentsEnd() {
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
- .contentsEnd,
- 2);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString('"X"'), "X")
- .contentsEnd,
- 2);
-
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString('"""X"""'), "X")
- .contentsEnd,
- 4);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
- .contentsEnd,
- 4);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("''' \nX'''"), "X").contentsEnd,
- 7);
-
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
- .contentsEnd,
- 3);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString('r"X"'), "X")
- .contentsEnd,
- 3);
-
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString('r"""X"""'), "X")
- .contentsEnd,
- 5);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
- .contentsEnd,
- 5);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("r''' \nX'''"), "X").contentsEnd,
- 8);
- }
-
- void test_contentsOffset() {
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
- .contentsOffset,
- 1);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
- .contentsOffset,
- 1);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X").contentsOffset,
- 3);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
- .contentsOffset,
- 3);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
- .contentsOffset,
- 2);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
- .contentsOffset,
- 2);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").contentsOffset,
- 4);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
- .contentsOffset,
- 4);
- // leading whitespace
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("''' \ \nX''"), "X").contentsOffset,
- 6);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString('r""" \ \nX"""'), "X").contentsOffset,
- 7);
- }
-
- void test_isMultiline() {
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
- .isMultiline,
- isFalse);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
- .isMultiline,
- isFalse);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
- .isMultiline,
- isFalse);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
- .isMultiline,
- isFalse);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
- .isMultiline,
- isTrue);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
- .isMultiline,
- isTrue);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X").isMultiline,
- isTrue);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").isMultiline,
- isTrue);
- }
-
- void test_isRaw() {
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X").isRaw,
- isFalse);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
- .isRaw,
- isFalse);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X").isRaw,
- isFalse);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
- .isRaw,
- isFalse);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
- .isRaw,
- isTrue);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
- .isRaw,
- isTrue);
- expect(
- new SimpleStringLiteral(
- TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").isRaw,
- isTrue);
- expect(
- new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
- .isRaw,
- isTrue);
- }
-
- void test_isSingleQuoted() {
- // '
- {
- var token = TokenFactory.tokenFromString("'X'");
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isTrue);
- }
- // '''
- {
- var token = TokenFactory.tokenFromString("'''X'''");
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isTrue);
- }
- // "
- {
- var token = TokenFactory.tokenFromString('"X"');
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isFalse);
- }
- // """
- {
- var token = TokenFactory.tokenFromString('"""X"""');
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isFalse);
- }
- }
-
- void test_isSingleQuoted_raw() {
- // r'
- {
- var token = TokenFactory.tokenFromString("r'X'");
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isTrue);
- }
- // r'''
- {
- var token = TokenFactory.tokenFromString("r'''X'''");
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isTrue);
- }
- // r"
- {
- var token = TokenFactory.tokenFromString('r"X"');
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isFalse);
- }
- // r"""
- {
- var token = TokenFactory.tokenFromString('r"""X"""');
- var node = new SimpleStringLiteral(token, null);
- expect(node.isSingleQuoted, isFalse);
- }
- }
-
- void test_simple() {
- Token token = TokenFactory.tokenFromString("'value'");
- SimpleStringLiteral stringLiteral = new SimpleStringLiteral(token, "value");
- expect(stringLiteral.literal, same(token));
- expect(stringLiteral.beginToken, same(token));
- expect(stringLiteral.endToken, same(token));
- expect(stringLiteral.value, "value");
- }
-}
-
-@reflectiveTest
-class StringInterpolationTest extends ParserTestCase {
- void test_contentsOffsetEnd() {
- AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
- // 'a${bb}ccc'
- {
- var ae = AstFactory.interpolationString("'a", "a");
- var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
- var cElement = new InterpolationString(cToken, 'ccc');
- StringInterpolation node = AstFactory.string([ae, ae, cElement]);
- expect(node.contentsOffset, 1);
- expect(node.contentsEnd, 10 + 4 - 1);
- }
- // '''a${bb}ccc'''
- {
- var ae = AstFactory.interpolationString("'''a", "a");
- var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
- var cElement = new InterpolationString(cToken, 'ccc');
- StringInterpolation node = AstFactory.string([ae, ae, cElement]);
- expect(node.contentsOffset, 3);
- expect(node.contentsEnd, 10 + 4 - 1);
- }
- // """a${bb}ccc"""
- {
- var ae = AstFactory.interpolationString('"""a', "a");
- var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
- var cElement = new InterpolationString(cToken, 'ccc');
- StringInterpolation node = AstFactory.string([ae, ae, cElement]);
- expect(node.contentsOffset, 3);
- expect(node.contentsEnd, 10 + 4 - 1);
- }
- // r'a${bb}ccc'
- {
- var ae = AstFactory.interpolationString("r'a", "a");
- var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
- var cElement = new InterpolationString(cToken, 'ccc');
- StringInterpolation node = AstFactory.string([ae, ae, cElement]);
- expect(node.contentsOffset, 2);
- expect(node.contentsEnd, 10 + 4 - 1);
- }
- // r'''a${bb}ccc'''
- {
- var ae = AstFactory.interpolationString("r'''a", "a");
- var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
- var cElement = new InterpolationString(cToken, 'ccc');
- StringInterpolation node = AstFactory.string([ae, ae, cElement]);
- expect(node.contentsOffset, 4);
- expect(node.contentsEnd, 10 + 4 - 1);
- }
- // r"""a${bb}ccc"""
- {
- var ae = AstFactory.interpolationString('r"""a', "a");
- var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
- var cElement = new InterpolationString(cToken, 'ccc');
- StringInterpolation node = AstFactory.string([ae, ae, cElement]);
- expect(node.contentsOffset, 4);
- expect(node.contentsEnd, 10 + 4 - 1);
- }
- }
-
- void test_isMultiline() {
- var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
- // '
- {
- var a = AstFactory.interpolationString("'a", "a");
- var c = AstFactory.interpolationString("ccc'", "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isMultiline, isFalse);
- }
- // '''
- {
- var a = AstFactory.interpolationString("'''a", "a");
- var c = AstFactory.interpolationString("ccc'''", "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isMultiline, isTrue);
- }
- // "
- {
- var a = AstFactory.interpolationString('"a', "a");
- var c = AstFactory.interpolationString('ccc"', "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isMultiline, isFalse);
- }
- // """
- {
- var a = AstFactory.interpolationString('"""a', "a");
- var c = AstFactory.interpolationString('ccc"""', "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isMultiline, isTrue);
- }
- }
-
- void test_isRaw() {
- StringInterpolation node = AstFactory.string();
- expect(node.isRaw, isFalse);
- }
-
- void test_isSingleQuoted() {
- var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
- // "
- {
- var a = AstFactory.interpolationString('"a', "a");
- var c = AstFactory.interpolationString('ccc"', "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isSingleQuoted, isFalse);
- }
- // """
- {
- var a = AstFactory.interpolationString('"""a', "a");
- var c = AstFactory.interpolationString('ccc"""', "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isSingleQuoted, isFalse);
- }
- // '
- {
- var a = AstFactory.interpolationString("'a", "a");
- var c = AstFactory.interpolationString("ccc'", "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isSingleQuoted, isTrue);
- }
- // '''
- {
- var a = AstFactory.interpolationString("'''a", "a");
- var c = AstFactory.interpolationString("ccc'''", "ccc");
- StringInterpolation node = AstFactory.string([a, b, c]);
- expect(node.isSingleQuoted, isTrue);
- }
- }
-}
-
-@reflectiveTest
class ToSourceVisitorTest extends EngineTestCase {
void test_visitAdjacentStrings() {
_assertSource(
@@ -3648,8 +2381,8 @@
void test_visitSwitchCase_noLabels() {
_assertSource(
"case a: {}",
- AstFactory.switchCase(
- AstFactory.identifier3("a"), [AstFactory.block()]));
+ AstFactory
+ .switchCase(AstFactory.identifier3("a"), [AstFactory.block()]));
}
void test_visitSwitchCase_singleLabel() {
@@ -3680,8 +2413,8 @@
void test_visitSwitchDefault_singleLabel() {
_assertSource(
"l1: default: {}",
- AstFactory.switchDefault(
- [AstFactory.label2("l1")], [AstFactory.block()]));
+ AstFactory
+ .switchDefault([AstFactory.label2("l1")], [AstFactory.block()]));
}
void test_visitSwitchStatement() {
@@ -3932,50 +2665,3 @@
expect(writer.toString(), expectedSource);
}
}
-
-@reflectiveTest
-class VariableDeclarationTest extends ParserTestCase {
- void test_getDocumentationComment_onGrandParent() {
- VariableDeclaration varDecl = AstFactory.variableDeclaration("a");
- TopLevelVariableDeclaration decl =
- AstFactory.topLevelVariableDeclaration2(Keyword.VAR, [varDecl]);
- Comment comment = Comment.createDocumentationComment(new List<Token>(0));
- expect(varDecl.documentationComment, isNull);
- decl.documentationComment = comment;
- expect(varDecl.documentationComment, isNotNull);
- expect(decl.documentationComment, isNotNull);
- }
-
- void test_getDocumentationComment_onNode() {
- VariableDeclaration decl = AstFactory.variableDeclaration("a");
- Comment comment = Comment.createDocumentationComment(new List<Token>(0));
- decl.documentationComment = comment;
- expect(decl.documentationComment, isNotNull);
- }
-}
-
-class WrapperKind extends Enum<WrapperKind> {
- static const WrapperKind PREFIXED_LEFT =
- const WrapperKind('PREFIXED_LEFT', 0);
-
- static const WrapperKind PREFIXED_RIGHT =
- const WrapperKind('PREFIXED_RIGHT', 1);
-
- static const WrapperKind PROPERTY_LEFT =
- const WrapperKind('PROPERTY_LEFT', 2);
-
- static const WrapperKind PROPERTY_RIGHT =
- const WrapperKind('PROPERTY_RIGHT', 3);
-
- static const WrapperKind NONE = const WrapperKind('NONE', 4);
-
- static const List<WrapperKind> values = const [
- PREFIXED_LEFT,
- PREFIXED_RIGHT,
- PROPERTY_LEFT,
- PROPERTY_RIGHT,
- NONE
- ];
-
- const WrapperKind(String name, int ordinal) : super(name, ordinal);
-}
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index bf01506..3f0aa84 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -2,13 +2,13 @@
// 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 analyzer.test.generated.element_test;
+library analyzer.test.src.dart.element.element_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/java_core.dart';
diff --git a/pkg/analyzer/test/src/dart/element/test_all.dart b/pkg/analyzer/test/src/dart/element/test_all.dart
index c401919..1997466 100644
--- a/pkg/analyzer/test/src/dart/element/test_all.dart
+++ b/pkg/analyzer/test/src/dart/element/test_all.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.
-library analyzer.test.generated.test_all;
+library analyzer.test.src.dart.element.test_all;
import 'package:unittest/unittest.dart';
diff --git a/pkg/analyzer/test/src/dart/test_all.dart b/pkg/analyzer/test/src/dart/test_all.dart
index f0c4598..ec4f182 100644
--- a/pkg/analyzer/test/src/dart/test_all.dart
+++ b/pkg/analyzer/test/src/dart/test_all.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.
-library analyzer.test.generated.test_all;
+library analyzer.test.src.dart.test_all;
import 'package:unittest/unittest.dart';
diff --git a/pkg/analyzer/test/src/mock_sdk.dart b/pkg/analyzer/test/src/mock_sdk.dart
index b08e293..bfef108 100644
--- a/pkg/analyzer/test/src/mock_sdk.dart
+++ b/pkg/analyzer/test/src/mock_sdk.dart
@@ -184,6 +184,10 @@
LIB_HTML,
];
+ static const List<SdkLibrary> LIBRARIES_NO_ASYNC = const [
+ LIB_CORE,
+ ];
+
final resource.MemoryResourceProvider provider =
new resource.MemoryResourceProvider();
@@ -192,8 +196,9 @@
*/
InternalAnalysisContext _analysisContext;
- MockSdk() {
- LIBRARIES.forEach((_MockSdkLibrary library) {
+ MockSdk({bool dartAsync: true}) {
+ List<SdkLibrary> libraries = dartAsync ? LIBRARIES : LIBRARIES_NO_ASYNC;
+ libraries.forEach((_MockSdkLibrary library) {
provider.newFile(library.path, library.content);
});
}
@@ -204,12 +209,6 @@
_analysisContext = new SdkAnalysisContext();
SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
_analysisContext.sourceFactory = factory;
- ChangeSet changeSet = new ChangeSet();
- for (String uri in uris) {
- Source source = factory.forUri(uri);
- changeSet.addedSource(source);
- }
- _analysisContext.applyChanges(changeSet);
}
return _analysisContext;
}
diff --git a/pkg/analyzer/test/src/summary/flat_buffers_test.dart b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
index e7b7804..7ceed57 100644
--- a/pkg/analyzer/test/src/summary/flat_buffers_test.dart
+++ b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
@@ -97,6 +97,7 @@
builder.addInt32(2, 20);
builder.addOffset(3, stringOffset);
builder.addInt32(4, 40);
+ builder.addUint32(5, 0x9ABCDEF0);
Offset offset = builder.endTable();
byteList = builder.finish(offset);
}
@@ -107,6 +108,23 @@
expect(const Int32Reader().vTableGet(object, 2), 20);
expect(const StringReader().vTableGet(object, 3), '12345');
expect(const Int32Reader().vTableGet(object, 4), 40);
+ expect(const Uint32Reader().vTableGet(object, 5), 0x9ABCDEF0);
+ }
+
+ void test_writeList_ofFloat64() {
+ List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ Offset offset = builder.writeListFloat64(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferPointer root = new BufferPointer.fromBytes(byteList);
+ List<double> items = const Float64ListReader().read(root);
+ expect(items, hasLength(5));
+ expect(items, orderedEquals(values));
}
void test_writeList_ofInt32() {
@@ -195,6 +213,20 @@
expect(items, contains('12345'));
expect(items, contains('ABC'));
}
+
+ void test_writeList_ofUint32() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ Offset offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferPointer root = new BufferPointer.fromBytes(byteList);
+ List<int> items = const ListReader<int>(const Uint32Reader()).read(root);
+ expect(items, hasLength(3));
+ expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
+ }
}
class StringListWrapperImpl {
diff --git a/pkg/analyzer/test/src/summary/name_filter_test.dart b/pkg/analyzer/test/src/summary/name_filter_test.dart
index a3c9ae5..5f5ca4f 100644
--- a/pkg/analyzer/test/src/summary/name_filter_test.dart
+++ b/pkg/analyzer/test/src/summary/name_filter_test.dart
@@ -14,28 +14,11 @@
runReflectiveTests(NameFilterTest);
}
-class MockUnlinkedCombinator implements UnlinkedCombinator {
- @override
- final List<String> hides;
-
- @override
- final List<String> shows;
-
- MockUnlinkedCombinator(
- {this.hides: const <String>[], this.shows: const <String>[]});
-
- @override
- Map<String, Object> toMap() {
- fail('toMap() called unexpectedly');
- return null;
- }
-}
-
@reflectiveTest
class NameFilterTest {
test_accepts_accessors_hide() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['bar']));
+ new UnlinkedCombinatorBuilder(hides: ['bar']));
expect(filter.accepts('foo'), isTrue);
expect(filter.accepts('foo='), isTrue);
expect(filter.accepts('bar'), isFalse);
@@ -44,7 +27,7 @@
test_accepts_accessors_show() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo']));
+ new UnlinkedCombinatorBuilder(shows: ['foo']));
expect(filter.accepts('foo'), isTrue);
expect(filter.accepts('foo='), isTrue);
expect(filter.accepts('bar'), isFalse);
@@ -88,7 +71,7 @@
test_forUnlinkedCombinator_hide() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['foo', 'bar']));
+ new UnlinkedCombinatorBuilder(hides: ['foo', 'bar']));
expect(filter.accepts('foo'), isFalse);
expect(filter.accepts('bar'), isFalse);
expect(filter.accepts('baz'), isTrue);
@@ -99,7 +82,7 @@
test_forUnlinkedCombinator_show() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo', 'bar']));
+ new UnlinkedCombinatorBuilder(shows: ['foo', 'bar']));
expect(filter.accepts('foo'), isTrue);
expect(filter.accepts('bar'), isTrue);
expect(filter.accepts('baz'), isFalse);
@@ -110,8 +93,8 @@
test_forUnlinkedCombinators() {
NameFilter filter = new NameFilter.forUnlinkedCombinators([
- new MockUnlinkedCombinator(hides: ['foo']),
- new MockUnlinkedCombinator(hides: ['bar'])
+ new UnlinkedCombinatorBuilder(hides: ['foo']),
+ new UnlinkedCombinatorBuilder(hides: ['bar'])
]);
expect(filter.accepts('foo'), isFalse);
expect(filter.accepts('bar'), isFalse);
@@ -130,9 +113,9 @@
test_merge_hides_hides() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['foo'])).merge(
+ new UnlinkedCombinatorBuilder(hides: ['foo'])).merge(
new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['bar'])));
+ new UnlinkedCombinatorBuilder(hides: ['bar'])));
expect(filter.accepts('foo'), isFalse);
expect(filter.accepts('bar'), isFalse);
expect(filter.accepts('baz'), isTrue);
@@ -143,7 +126,7 @@
test_merge_hides_identity() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['foo', 'bar']))
+ new UnlinkedCombinatorBuilder(hides: ['foo', 'bar']))
.merge(NameFilter.identity);
expect(filter.accepts('foo'), isFalse);
expect(filter.accepts('bar'), isFalse);
@@ -155,9 +138,9 @@
test_merge_hides_shows() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['bar', 'baz'])).merge(
+ new UnlinkedCombinatorBuilder(hides: ['bar', 'baz'])).merge(
new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo', 'bar'])));
+ new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])));
expect(filter.accepts('foo'), isTrue);
expect(filter.accepts('bar'), isFalse);
expect(filter.accepts('baz'), isFalse);
@@ -169,7 +152,7 @@
test_merge_identity_hides() {
NameFilter filter = NameFilter.identity.merge(
new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['foo', 'bar'])));
+ new UnlinkedCombinatorBuilder(hides: ['foo', 'bar'])));
expect(filter.accepts('foo'), isFalse);
expect(filter.accepts('bar'), isFalse);
expect(filter.accepts('baz'), isTrue);
@@ -189,7 +172,7 @@
test_merge_identity_shows() {
NameFilter filter = NameFilter.identity.merge(
new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo', 'bar'])));
+ new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])));
expect(filter.accepts('foo'), isTrue);
expect(filter.accepts('bar'), isTrue);
expect(filter.accepts('baz'), isFalse);
@@ -200,9 +183,9 @@
test_merge_shows_hides() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo', 'bar'])).merge(
+ new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])).merge(
new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(hides: ['bar', 'baz'])));
+ new UnlinkedCombinatorBuilder(hides: ['bar', 'baz'])));
expect(filter.accepts('foo'), isTrue);
expect(filter.accepts('bar'), isFalse);
expect(filter.accepts('baz'), isFalse);
@@ -213,7 +196,7 @@
test_merge_shows_identity() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo', 'bar']))
+ new UnlinkedCombinatorBuilder(shows: ['foo', 'bar']))
.merge(NameFilter.identity);
expect(filter.accepts('foo'), isTrue);
expect(filter.accepts('bar'), isTrue);
@@ -225,9 +208,9 @@
test_merge_shows_shows() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo', 'bar'])).merge(
+ new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])).merge(
new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['bar', 'baz'])));
+ new UnlinkedCombinatorBuilder(shows: ['bar', 'baz'])));
expect(filter.accepts('foo'), isFalse);
expect(filter.accepts('bar'), isTrue);
expect(filter.accepts('baz'), isFalse);
@@ -238,9 +221,9 @@
test_merge_shows_shows_emptyResult() {
NameFilter filter = new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['foo'])).merge(
+ new UnlinkedCombinatorBuilder(shows: ['foo'])).merge(
new NameFilter.forUnlinkedCombinator(
- new MockUnlinkedCombinator(shows: ['bar'])));
+ new UnlinkedCombinatorBuilder(shows: ['bar'])));
expect(filter.accepts('foo'), isFalse);
expect(filter.accepts('bar'), isFalse);
expect(filter.accepts('baz'), isFalse);
diff --git a/pkg/analyzer/test/src/summary/prelinker_test.dart b/pkg/analyzer/test/src/summary/prelinker_test.dart
new file mode 100644
index 0000000..39e43bd
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/prelinker_test.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2016, 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 analyzer.test.src.summary.prelinker_test;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/prelink.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'summarize_elements_test.dart';
+import 'summary_common.dart';
+
+main() {
+ groupSep = ' | ';
+ runReflectiveTests(PrelinkerTest);
+}
+
+/**
+ * Override of [SummaryTest] which verifies the correctness of the prelinker by
+ * creating summaries from the element model, discarding their prelinked
+ * information, and then recreating it using the prelinker.
+ */
+@reflectiveTest
+class PrelinkerTest extends SummarizeElementsTest {
+ final Map<String, UnlinkedPublicNamespace> uriToPublicNamespace =
+ <String, UnlinkedPublicNamespace>{};
+
+ @override
+ bool get expectAbsoluteUrisInDependencies => false;
+
+ @override
+ bool get skipFullyLinkedData => true;
+
+ @override
+ bool get strongMode => false;
+
+ @override
+ Source addNamedSource(String filePath, String contents) {
+ Source source = super.addNamedSource(filePath, contents);
+ uriToPublicNamespace[absUri(filePath)] =
+ computePublicNamespaceFromText(contents, source);
+ return source;
+ }
+
+ String resolveToAbsoluteUri(LibraryElement library, String relativeUri) {
+ Source resolvedSource =
+ analysisContext.sourceFactory.resolveUri(library.source, relativeUri);
+ if (resolvedSource == null) {
+ fail('Failed to resolve relative uri "$relativeUri"');
+ }
+ return resolvedSource.uri.toString();
+ }
+
+ @override
+ void serializeLibraryElement(LibraryElement library) {
+ super.serializeLibraryElement(library);
+ Map<String, UnlinkedUnit> uriToUnit = <String, UnlinkedUnit>{};
+ expect(unlinkedUnits.length, unitUris.length);
+ for (int i = 1; i < unlinkedUnits.length; i++) {
+ uriToUnit[unitUris[i]] = unlinkedUnits[i];
+ }
+ UnlinkedUnit getPart(String relativeUri) {
+ String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
+ UnlinkedUnit unit = uriToUnit[absoluteUri];
+ if (unit == null) {
+ fail('Prelinker unexpectedly requested unit for "$relativeUri"'
+ ' (resolves to "$absoluteUri").');
+ }
+ return unit;
+ }
+ UnlinkedPublicNamespace getImport(String relativeUri) {
+ String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
+ UnlinkedPublicNamespace namespace = sdkPublicNamespace[absoluteUri];
+ if (namespace == null) {
+ namespace = uriToPublicNamespace[absoluteUri];
+ }
+ if (namespace == null && !allowMissingFiles) {
+ fail('Prelinker unexpectedly requested namespace for "$relativeUri"'
+ ' (resolves to "$absoluteUri").'
+ ' Namespaces available: ${uriToPublicNamespace.keys}');
+ }
+ return namespace;
+ }
+ linked = new LinkedLibrary.fromBuffer(
+ prelink(unlinkedUnits[0], getPart, getImport).toBuffer());
+ }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
new file mode 100644
index 0000000..b6a9258
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, 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 analyzer.test.src.summary.resynthesize_strong_test;
+
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'resynthesize_test.dart';
+
+main() {
+ groupSep = ' | ';
+ runReflectiveTests(ResynthStrongTest);
+}
+
+@reflectiveTest
+class ResynthStrongTest extends ResynthTest {
+ @override
+ AnalysisOptionsImpl get options => super.options..strongMode = true;
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index c27b507..c4692fc 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -4,9 +4,14 @@
library test.src.serialization.elements_test;
-import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/element_handle.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart' show Namespace;
+import 'package:analyzer/src/generated/resolver.dart'
+ show Namespace, TypeProvider;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
@@ -25,6 +30,12 @@
class ResynthTest extends ResolverTestCase {
Set<Source> otherLibrarySources = new Set<Source>();
+ /**
+ * Determine the analysis options that should be used for this test.
+ */
+ AnalysisOptionsImpl get options =>
+ new AnalysisOptionsImpl()..enableGenericMethods = true;
+
void addLibrary(String uri) {
otherLibrarySources.add(analysisContext2.sourceFactory.forUri(uri));
}
@@ -33,13 +44,12 @@
otherLibrarySources.add(addNamedSource(filePath, contents));
}
- void checkLibrary(String text,
- {bool allowErrors: false, int resynthesisCount: 1}) {
+ void checkLibrary(String text, {bool allowErrors: false}) {
Source source = addSource(text);
LibraryElementImpl original = resolve2(source);
- LibraryElementImpl resynthesized = resynthesizeLibrary(
- source, original, allowErrors,
- resynthesisCount: resynthesisCount);
+ LibraryElementImpl resynthesized = resynthesizeLibraryElement(
+ encodeLibrary(original, allowErrors: allowErrors),
+ source.uri.toString());
checkLibraryElements(original, resynthesized);
}
@@ -67,6 +77,10 @@
'export ${original.exports[i].uri}');
}
expect(resynthesized.nameLength, original.nameLength);
+ compareNamespaces(resynthesized.publicNamespace, original.publicNamespace,
+ '(public namespace)');
+ compareNamespaces(resynthesized.exportNamespace, original.exportNamespace,
+ '(export namespace)');
if (original.entryPoint == null) {
expect(resynthesized.entryPoint, isNull);
} else {
@@ -74,10 +88,14 @@
compareFunctionElements(
resynthesized.entryPoint, original.entryPoint, '(entry point)');
}
- compareNamespaces(resynthesized.publicNamespace, original.publicNamespace,
- '(public namespace)');
- compareNamespaces(resynthesized.exportNamespace, original.exportNamespace,
- '(export namespace)');
+ // The libraries `dart:core` and `dart:async` cannot create their
+ // `loadLibrary` functions until after both are created.
+ if (original.name != 'dart.core' && original.name != 'dart.async') {
+ compareExecutableElements(
+ resynthesized.loadLibraryFunction as ExecutableElementImpl,
+ original.loadLibraryFunction as ExecutableElementImpl,
+ '(loadLibraryFunction)');
+ }
// TODO(paulberry): test metadata.
}
@@ -88,8 +106,8 @@
reason: '$desc fields.length');
for (int i = 0; i < resynthesized.fields.length; i++) {
String name = original.fields[i].name;
- compareFieldElements(resynthesized.getField(name), original.fields[i],
- '$desc.field $name');
+ compareFieldElements(
+ resynthesized.fields[i], original.fields[i], '$desc.field $name');
}
compareTypes(
resynthesized.supertype, original.supertype, '$desc supertype');
@@ -120,18 +138,10 @@
}
expect(resynthesized.accessors.length, original.accessors.length);
for (int i = 0; i < resynthesized.accessors.length; i++) {
- String name = original.accessors[i].name;
- if (name.endsWith('=')) {
- comparePropertyAccessorElements(
- resynthesized.getSetter(name),
- original.accessors[i],
- '$desc setter ${original.accessors[i].name}');
- } else {
- comparePropertyAccessorElements(
- resynthesized.getGetter(name),
- original.accessors[i],
- '$desc getter ${original.accessors[i].name}');
- }
+ comparePropertyAccessorElements(
+ resynthesized.accessors[i],
+ original.accessors[i],
+ '$desc accessor ${original.accessors[i].name}');
}
expect(resynthesized.methods.length, original.methods.length);
for (int i = 0; i < resynthesized.methods.length; i++) {
@@ -197,8 +207,7 @@
// TODO(paulberry): test redirectedConstructor and constantInitializers
}
- void compareElements(
- ElementImpl resynthesized, ElementImpl original, String desc) {
+ void compareElements(Element resynthesized, Element original, String desc) {
expect(resynthesized, isNotNull);
expect(resynthesized.kind, original.kind);
expect(resynthesized.location, original.location, reason: desc);
@@ -207,20 +216,20 @@
expect(resynthesized.documentationComment, original.documentationComment,
reason: desc);
expect(resynthesized.docRange, original.docRange, reason: desc);
+ // Modifiers are a pain to test via handles. So just test them via the
+ // actual element.
+ ElementImpl actualResynthesized = getActualElement(resynthesized, desc);
+ ElementImpl actualOriginal = getActualElement(original, desc);
for (Modifier modifier in Modifier.values) {
- if (modifier == Modifier.MIXIN) {
- // Skipping for now. TODO(paulberry): fix.
- continue;
- }
- bool got = resynthesized.hasModifier(modifier);
- bool want = original.hasModifier(modifier);
+ bool got = actualResynthesized.hasModifier(modifier);
+ bool want = actualOriginal.hasModifier(modifier);
expect(got, want,
reason: 'Mismatch in $desc.$modifier: got $got, want $want');
}
}
- void compareExecutableElements(ExecutableElementImpl resynthesized,
- ExecutableElementImpl original, String desc) {
+ void compareExecutableElements(ExecutableElement resynthesized,
+ ExecutableElement original, String desc) {
compareElements(resynthesized, original, desc);
expect(resynthesized.parameters.length, original.parameters.length);
for (int i = 0; i < resynthesized.parameters.length; i++) {
@@ -252,8 +261,8 @@
// TODO(paulberry): test evaluationResult
}
- void compareFunctionElements(FunctionElementImpl resynthesized,
- FunctionElementImpl original, String desc) {
+ void compareFunctionElements(
+ FunctionElement resynthesized, FunctionElement original, String desc) {
compareExecutableElements(resynthesized, original, desc);
}
@@ -286,6 +295,7 @@
compareUriReferencedElements(resynthesized, original, desc);
expect(resynthesized.importedLibrary.location,
original.importedLibrary.location);
+ expect(resynthesized.prefixOffset, original.prefixOffset);
if (original.prefix == null) {
expect(resynthesized.prefix, isNull);
} else {
@@ -347,6 +357,20 @@
'$desc parameter ${original.parameters[i].name}');
}
expect(resynthesized.parameterKind, original.parameterKind);
+ expect(resynthesized.isInitializingFormal, original.isInitializingFormal,
+ reason: desc);
+ expect(resynthesized is FieldFormalParameterElementImpl,
+ original is FieldFormalParameterElementImpl);
+ if (resynthesized is FieldFormalParameterElementImpl &&
+ original is FieldFormalParameterElementImpl) {
+ if (original.field == null) {
+ expect(resynthesized.field, isNull, reason: '$desc field');
+ } else {
+ expect(resynthesized.field, isNotNull, reason: '$desc field');
+ compareFieldElements(
+ resynthesized.field, original.field, '$desc field');
+ }
+ }
}
void comparePrefixElements(PrefixElementImpl resynthesized,
@@ -371,6 +395,7 @@
PropertyInducingElementImpl original,
String desc) {
compareVariableElements(resynthesized, original, desc);
+ compareTypes(resynthesized.propagatedType, original.propagatedType, desc);
if (original.getter == null) {
expect(resynthesized.getter, isNull);
} else {
@@ -487,75 +512,106 @@
// TODO(paulberry): test initializer
}
- fail_library_hasExtUri() {
- checkLibrary('import "dart-ext:doesNotExist.dart";');
- }
-
- LibraryElementImpl resynthesizeLibrary(
- Source source, LibraryElementImpl original, bool allowErrors,
- {int resynthesisCount: 1}) {
+ /**
+ * Serialize the given [library] into a summary. Then create a
+ * [_TestSummaryResynthesizer] which can deserialize it, along with any
+ * references it makes to `dart:core`.
+ *
+ * Errors will lead to a test failure unless [allowErrors] is `true`.
+ */
+ _TestSummaryResynthesizer encodeLibrary(LibraryElementImpl library,
+ {bool allowErrors: false}) {
if (!allowErrors) {
- assertNoErrors(source);
+ assertNoErrors(library.source);
}
- String uri = source.uri.toString();
addLibrary('dart:core');
- return resynthesizeLibraryElement(uri, original,
- resynthesisCount: resynthesisCount);
+ return encodeLibraryElement(library);
}
- LibraryElementImpl resynthesizeLibraryElement(
- String uri, LibraryElementImpl original,
- {int resynthesisCount: 1}) {
+ /**
+ * Convert the library element [library] into a summary, and then create a
+ * [_TestSummaryResynthesizer] which can deserialize it.
+ *
+ * Caller is responsible for checking the library for errors, and adding any
+ * dependent libraries using [addLibrary].
+ */
+ _TestSummaryResynthesizer encodeLibraryElement(LibraryElementImpl library) {
Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{};
- PrelinkedLibrary getPrelinkedSummaryFor(LibraryElement lib) {
- LibrarySerializationResult serialized =
- serializeLibrary(lib, typeProvider);
+ LinkedLibrary getLinkedSummaryFor(LibraryElement lib) {
+ LibrarySerializationResult serialized = serializeLibrary(
+ lib, typeProvider, analysisContext.analysisOptions.strongMode);
for (int i = 0; i < serialized.unlinkedUnits.length; i++) {
unlinkedSummaries[serialized.unitUris[i]] =
new UnlinkedUnit.fromBuffer(serialized.unlinkedUnits[i].toBuffer());
}
- return new PrelinkedLibrary.fromBuffer(serialized.prelinked.toBuffer());
+ return new LinkedLibrary.fromBuffer(serialized.linked.toBuffer());
}
- Map<String, PrelinkedLibrary> prelinkedSummaries =
- <String, PrelinkedLibrary>{uri: getPrelinkedSummaryFor(original)};
+ Map<String, LinkedLibrary> linkedSummaries = <String, LinkedLibrary>{
+ library.source.uri.toString(): getLinkedSummaryFor(library)
+ };
for (Source source in otherLibrarySources) {
LibraryElement original = resolve2(source);
String uri = source.uri.toString();
- prelinkedSummaries[uri] = getPrelinkedSummaryFor(original);
+ linkedSummaries[uri] = getLinkedSummaryFor(original);
}
- PrelinkedLibrary getPrelinkedSummary(String uri) {
- PrelinkedLibrary serializedLibrary = prelinkedSummaries[uri];
- if (serializedLibrary == null) {
- fail('Unexpectedly tried to get prelinked summary for $uri');
- }
- return serializedLibrary;
- }
- UnlinkedUnit getUnlinkedSummary(String uri) {
- UnlinkedUnit serializedUnit = unlinkedSummaries[uri];
- if (serializedUnit == null) {
- fail('Unexpectedly tried to get unlinked summary for $uri');
- }
- return serializedUnit;
- }
- SummaryResynthesizer resynthesizer = new SummaryResynthesizer(
+ return new _TestSummaryResynthesizer(
+ null,
analysisContext,
analysisContext.typeProvider,
- getPrelinkedSummary,
- getUnlinkedSummary,
- analysisContext.sourceFactory);
+ analysisContext.sourceFactory,
+ unlinkedSummaries,
+ linkedSummaries,
+ options.strongMode);
+ }
+
+ fail_library_hasExtUri() {
+ checkLibrary('import "dart-ext:doesNotExist.dart";');
+ }
+
+ ElementImpl getActualElement(Element element, String desc) {
+ if (element is ElementHandle) {
+ return element.actualElement;
+ } else if (element is ElementImpl) {
+ return element;
+ } else {
+ fail('Unexpected type for resynthesized ($desc):'
+ ' ${element.runtimeType}');
+ return null;
+ }
+ }
+
+ /**
+ * Resynthesize the library element associated with [uri] using
+ * [resynthesizer], and verify that it only had to consult one summary in
+ * order to do so.
+ */
+ LibraryElementImpl resynthesizeLibraryElement(
+ _TestSummaryResynthesizer resynthesizer, String uri) {
LibraryElementImpl resynthesized = resynthesizer.getLibraryElement(uri);
// Check that no other summaries needed to be resynthesized to resynthesize
// the library element.
- // TODO(paulberry): once export namespaces are resynthesized from
- // prelinked data, resynthesisCount should be hardcoded to 1.
- expect(resynthesizer.resynthesisCount, resynthesisCount);
+ expect(resynthesizer.resynthesisCount, 1);
return resynthesized;
}
+ @override
+ void setUp() {
+ super.setUp();
+ resetWithOptions(options);
+ }
+
+ test_class_abstract() {
+ checkLibrary('abstract class C {}');
+ }
+
test_class_alias() {
checkLibrary('class C = D with E, F; class D {} class E {} class F {}');
}
+ test_class_alias_abstract() {
+ checkLibrary('abstract class C = D with E; class D {} class E {}');
+ }
+
test_class_alias_documented() {
checkLibrary('''
// Extra comment so doc comment offset != 0
@@ -662,8 +718,18 @@
checkLibrary('class C { dynamic x; C(this.x); }');
}
+ test_class_constructor_field_formal_multiple_matching_fields() {
+ // This is a compile-time error but it should still analyze consistently.
+ checkLibrary('class C { C(this.x); int x; String x; }', allowErrors: true);
+ }
+
+ test_class_constructor_field_formal_no_matching_field() {
+ // This is a compile-time error but it should still analyze consistently.
+ checkLibrary('class C { C(this.x); }', allowErrors: true);
+ }
+
test_class_constructor_field_formal_typed_dynamic() {
- checkLibrary('class C { num x; C(dynamic this.x); }');
+ checkLibrary('class C { num x; C(dynamic this.x); }', allowErrors: true);
}
test_class_constructor_field_formal_typed_typed() {
@@ -742,6 +808,10 @@
checkLibrary('class C { int i; int j; }');
}
+ test_class_getter_abstract() {
+ checkLibrary('abstract class C { int get x; }');
+ }
+
test_class_getter_external() {
checkLibrary('class C { external int get x; }');
}
@@ -770,6 +840,10 @@
checkLibrary('class C implements D, E {} class D {} class E {}');
}
+ test_class_method_abstract() {
+ checkLibrary('abstract class C { f(); }');
+ }
+
test_class_method_external() {
checkLibrary('class C { external f(); }');
}
@@ -790,6 +864,10 @@
checkLibrary('class C extends Object with D, E {} class D {} class E {}');
}
+ test_class_setter_abstract() {
+ checkLibrary('abstract class C { void set x(int value); }');
+ }
+
test_class_setter_external() {
checkLibrary('class C { external void set x(int value); }');
}
@@ -849,7 +927,7 @@
LibraryElementImpl original =
resolve2(analysisContext2.sourceFactory.forUri(uri));
LibraryElementImpl resynthesized =
- resynthesizeLibraryElement(uri, original);
+ resynthesizeLibraryElement(encodeLibraryElement(original), uri);
checkLibraryElements(original, resynthesized);
}
@@ -880,28 +958,71 @@
checkLibrary('enum E1 { v1 } enum E2 { v2 }');
}
+ test_export_class() {
+ addLibrarySource('/a.dart', 'class C {}');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_export_class_type_alias() {
+ addLibrarySource(
+ '/a.dart', 'class C {} exends _D with _E; class _D {} class _E {}');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_export_function() {
+ addLibrarySource('/a.dart', 'f() {}');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_export_getter() {
+ addLibrarySource('/a.dart', 'get f() => null;');
+ checkLibrary('export "a.dart";');
+ }
+
test_export_hide() {
addLibrary('dart:async');
- checkLibrary('export "dart:async" hide Stream, Future;',
- resynthesisCount: 2);
+ checkLibrary('export "dart:async" hide Stream, Future;');
}
test_export_multiple_combinators() {
addLibrary('dart:async');
- checkLibrary('export "dart:async" hide Stream show Future;',
- resynthesisCount: 2);
+ checkLibrary('export "dart:async" hide Stream show Future;');
+ }
+
+ test_export_setter() {
+ addLibrarySource('/a.dart', 'void set f(value) {}');
+ checkLibrary('export "a.dart";');
}
test_export_show() {
addLibrary('dart:async');
- checkLibrary('export "dart:async" show Future, Stream;',
- resynthesisCount: 2);
+ checkLibrary('export "dart:async" show Future, Stream;');
+ }
+
+ test_export_typedef() {
+ addLibrarySource('/a.dart', 'typedef F();');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_export_variable() {
+ addLibrarySource('/a.dart', 'var x;');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_export_variable_const() {
+ addLibrarySource('/a.dart', 'const x = 0;');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_export_variable_final() {
+ addLibrarySource('/a.dart', 'final x = 0;');
+ checkLibrary('export "a.dart";');
}
test_exports() {
addLibrarySource('/a.dart', 'library a;');
addLibrarySource('/b.dart', 'library b;');
- checkLibrary('export "a.dart"; export "b.dart";', resynthesisCount: 3);
+ checkLibrary('export "a.dart"; export "b.dart";');
}
test_field_documented() {
@@ -914,6 +1035,68 @@
}''');
}
+ test_field_formal_param_inferred_type_implicit() {
+ checkLibrary('class C extends D { var v; C(this.v); }'
+ ' abstract class D { int get v; }');
+ }
+
+ test_field_inferred_type_nonstatic_explicit_initialized() {
+ checkLibrary('class C { num v = 0; }');
+ }
+
+ test_field_inferred_type_nonstatic_implicit_initialized() {
+ checkLibrary('class C { var v = 0; }');
+ }
+
+ test_field_inferred_type_nonstatic_implicit_uninitialized() {
+ checkLibrary(
+ 'class C extends D { var v; } abstract class D { int get v; }');
+ }
+
+ test_field_inferred_type_static_implicit_initialized() {
+ checkLibrary('class C { static var v = 0; }');
+ }
+
+ test_field_propagatedType_const_noDep() {
+ checkLibrary('''
+class C {
+ static const x = 0;
+}''');
+ }
+
+ test_field_propagatedType_final_dep_inLib() {
+ addNamedSource('/a.dart', 'final a = 1;');
+ checkLibrary('''
+import "a.dart";
+class C {
+ final b = a / 2;
+}''');
+ }
+
+ test_field_propagatedType_final_dep_inPart() {
+ addNamedSource('/a.dart', 'part of lib; final a = 1;');
+ checkLibrary('''
+library lib;
+part "a.dart";
+class C {
+ final b = a / 2;
+}''');
+ }
+
+ test_field_propagatedType_final_noDep_instance() {
+ checkLibrary('''
+class C {
+ final x = 0;
+}''');
+ }
+
+ test_field_propagatedType_final_noDep_static() {
+ checkLibrary('''
+class C {
+ static final x = 0;
+}''');
+ }
+
test_function_documented() {
checkLibrary('''
// Extra comment so doc comment offset != 0
@@ -929,12 +1112,12 @@
test_function_entry_point_in_export() {
addLibrarySource('/a.dart', 'library a; main() {}');
- checkLibrary('export "a.dart";', resynthesisCount: 2);
+ checkLibrary('export "a.dart";');
}
test_function_entry_point_in_export_hidden() {
addLibrarySource('/a.dart', 'library a; main() {}');
- checkLibrary('export "a.dart" hide main;', resynthesisCount: 2);
+ checkLibrary('export "a.dart" hide main;');
}
test_function_entry_point_in_part() {
@@ -1006,6 +1189,69 @@
checkLibrary('f() {} g() {}');
}
+ test_getElement_constructor_named() {
+ ConstructorElement original = resolve2(addSource('class C { C.named(); }'))
+ .getType('C')
+ .getNamedConstructor('named');
+ expect(original, isNotNull);
+ ConstructorElement resynthesized = validateGetElement(original);
+ compareConstructorElements(resynthesized, original, 'C.constructor named');
+ }
+
+ test_getElement_constructor_unnamed() {
+ ConstructorElement original =
+ resolve2(addSource('class C { C(); }')).getType('C').unnamedConstructor;
+ expect(original, isNotNull);
+ ConstructorElement resynthesized = validateGetElement(original);
+ compareConstructorElements(resynthesized, original, 'C.constructor');
+ }
+
+ test_getElement_field() {
+ FieldElement original =
+ resolve2(addSource('class C { var f; }')).getType('C').getField('f');
+ expect(original, isNotNull);
+ FieldElement resynthesized = validateGetElement(original);
+ compareFieldElements(resynthesized, original, 'C.field f');
+ }
+
+ test_getElement_getter() {
+ PropertyAccessorElement original =
+ resolve2(addSource('class C { get f => null; }'))
+ .getType('C')
+ .getGetter('f');
+ expect(original, isNotNull);
+ PropertyAccessorElement resynthesized = validateGetElement(original);
+ comparePropertyAccessorElements(resynthesized, original, 'C.getter f');
+ }
+
+ test_getElement_method() {
+ MethodElement original =
+ resolve2(addSource('class C { f() {} }')).getType('C').getMethod('f');
+ expect(original, isNotNull);
+ MethodElement resynthesized = validateGetElement(original);
+ compareMethodElements(resynthesized, original, 'C.method f');
+ }
+
+ test_getElement_operator() {
+ MethodElement original =
+ resolve2(addSource('class C { operator+(x) => null; }'))
+ .getType('C')
+ .getMethod('+');
+ expect(original, isNotNull);
+ MethodElement resynthesized = validateGetElement(original);
+ compareMethodElements(resynthesized, original, 'C.operator+');
+ }
+
+ test_getElement_setter() {
+ PropertyAccessorElement original =
+ resolve2(addSource('class C { void set f(value) {} }'))
+ .getType('C')
+ .getSetter('f');
+ expect(original, isNotNull);
+ PropertyAccessorElement resynthesized = validateGetElement(original);
+ comparePropertyAccessorElements(resynthesized, original, 'C.setter f');
+ }
+
test_getter_documented() {
checkLibrary('''
// Extra comment so doc comment offset != 0
@@ -1019,6 +1265,11 @@
checkLibrary('external int get x;');
}
+ test_getter_inferred_type_nonstatic_implicit_return() {
+ checkLibrary(
+ 'class C extends D { get f => null; } abstract class D { int get f; }');
+ }
+
test_getters() {
checkLibrary('int get x => null; get y => null;');
}
@@ -1031,6 +1282,11 @@
checkLibrary('void set x(int value) {} int get x => 0;');
}
+ test_import_deferred() {
+ addLibrarySource('/a.dart', 'f() {}');
+ checkLibrary('import "a.dart" deferred as p; main() { p.f(); }');
+ }
+
test_import_hide() {
addLibrary('dart:async');
checkLibrary('import "dart:async" hide Stream, Completer; Future f;');
@@ -1057,6 +1313,26 @@
checkLibrary('import "a.dart"; import "b.dart"; C c; D d;');
}
+ test_inferred_type_is_typedef() {
+ checkLibrary('typedef int F(String s);'
+ ' class C extends D { var v; }'
+ ' abstract class D { F get v; }');
+ }
+
+ test_inferred_type_refers_to_bound_type_param() {
+ checkLibrary('class C<T> extends D<int, T> { var v; }'
+ ' abstract class D<U, V> { Map<V, U> get v; }');
+ }
+
+ test_inferred_type_via_function_typed_param() {
+ if (options.strongMode) {
+ // TODO(paulberry): get this test to pass.
+ return;
+ }
+ checkLibrary('class C extends D { f(g) {} }'
+ ' abstract class D { void f(int g(String)); }');
+ }
+
test_library() {
checkLibrary('');
}
@@ -1078,6 +1354,51 @@
checkLibrary('library foo.bar;');
}
+ test_main_class() {
+ checkLibrary('class main {}');
+ }
+
+ test_main_class_alias() {
+ checkLibrary('class main = C with D; class C {} class D {}');
+ }
+
+ test_main_class_alias_via_export() {
+ addLibrarySource('/a.dart', 'class main = C with D; class C {} class D {}');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_main_class_via_export() {
+ addLibrarySource('/a.dart', 'class main {}');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_main_getter() {
+ checkLibrary('get main => null;');
+ }
+
+ test_main_getter_via_export() {
+ addLibrarySource('/a.dart', 'get main => null;');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_main_typedef() {
+ checkLibrary('typedef main();');
+ }
+
+ test_main_typedef_via_export() {
+ addLibrarySource('/a.dart', 'typedef main();');
+ checkLibrary('export "a.dart";');
+ }
+
+ test_main_variable() {
+ checkLibrary('var main;');
+ }
+
+ test_main_variable_via_export() {
+ addLibrarySource('/a.dart', 'var main;');
+ checkLibrary('export "a.dart";');
+ }
+
test_method_documented() {
checkLibrary('''
class C {
@@ -1088,6 +1409,16 @@
}''');
}
+ test_method_inferred_type_nonstatic_implicit_param() {
+ checkLibrary('class C extends D { void f(value) {} }'
+ ' abstract class D { void f(int value); }');
+ }
+
+ test_method_inferred_type_nonstatic_implicit_return() {
+ checkLibrary(
+ 'class C extends D { f() => null; } abstract class D { int f(); }');
+ }
+
test_method_parameter_parameters() {
checkLibrary('class C { f(g(x, y)) {} }');
}
@@ -1124,7 +1455,7 @@
}
test_operator_equal() {
- checkLibrary('class C { bool operator==(C other) => false; }');
+ checkLibrary('class C { bool operator==(Object other) => false; }');
}
test_operator_external() {
@@ -1166,11 +1497,36 @@
checkLibrary('external void set x(int value);');
}
+ test_setter_inferred_type_nonstatic_implicit_param() {
+ checkLibrary('class C extends D { void set f(value) {} }'
+ ' abstract class D { void set f(int value); }');
+ }
+
+ test_setter_inferred_type_static_implicit_return() {
+ checkLibrary('class C { static set f(int value) {} }');
+ }
+
+ test_setter_inferred_type_top_level_implicit_return() {
+ checkLibrary('set f(int value) {}');
+ }
+
test_setters() {
checkLibrary('void set x(int value) {} set y(value) {}');
}
- test_type_arguments_explicit() {
+ test_type_arguments_explicit_dynamic_dynamic() {
+ checkLibrary('Map<dynamic, dynamic> m;');
+ }
+
+ test_type_arguments_explicit_dynamic_int() {
+ checkLibrary('Map<dynamic, int> m;');
+ }
+
+ test_type_arguments_explicit_String_dynamic() {
+ checkLibrary('Map<String, dynamic> m;');
+ }
+
+ test_type_arguments_explicit_String_int() {
checkLibrary('Map<String, int> m;');
}
@@ -1386,11 +1742,120 @@
var x;''');
}
+ test_variable_final() {
+ checkLibrary('final int x = 0;');
+ }
+
+ test_variable_getterInLib_setterInPart() {
+ addNamedSource('/a.dart', 'part of my.lib; void set x(int _) {}');
+ checkLibrary('library my.lib; part "a.dart"; int get x => 42;');
+ }
+
+ test_variable_getterInPart_setterInLib() {
+ addNamedSource('/a.dart', 'part of my.lib; int get x => 42;');
+ checkLibrary('library my.lib; part "a.dart"; void set x(int _) {}');
+ }
+
+ test_variable_getterInPart_setterInPart() {
+ addNamedSource('/a.dart', 'part of my.lib; int get x => 42;');
+ addNamedSource('/b.dart', 'part of my.lib; void set x(int _) {}');
+ checkLibrary('library my.lib; part "a.dart"; part "b.dart";');
+ }
+
test_variable_implicit_type() {
checkLibrary('var x;');
}
+ test_variable_inferred_type_implicit_initialized() {
+ checkLibrary('var v = 0;');
+ }
+
+ test_variable_propagatedType_const_noDep() {
+ checkLibrary('const i = 0;');
+ }
+
+ test_variable_propagatedType_final_dep_inLib() {
+ addNamedSource('/a.dart', 'final a = 1;');
+ checkLibrary('import "a.dart"; final b = a / 2;');
+ }
+
+ test_variable_propagatedType_final_dep_inPart() {
+ addNamedSource('/a.dart', 'part of lib; final a = 1;');
+ checkLibrary('library lib; part "a.dart"; final b = a / 2;');
+ }
+
+ test_variable_propagatedType_final_noDep() {
+ checkLibrary('final i = 0;');
+ }
+
+ test_variable_propagatedType_implicit_dep() {
+ // The propagated type is defined in a library that is not imported.
+ addNamedSource('/a.dart', 'class C {}');
+ addNamedSource('/b.dart', 'import "a.dart"; C f() => null;');
+ checkLibrary('import "b.dart"; final x = f();');
+ }
+
+ test_variable_setterInPart_getterInPart() {
+ addNamedSource('/a.dart', 'part of my.lib; void set x(int _) {}');
+ addNamedSource('/b.dart', 'part of my.lib; int get x => 42;');
+ checkLibrary('library my.lib; part "a.dart"; part "b.dart";');
+ }
+
test_variables() {
checkLibrary('int i; int j;');
}
+
+ /**
+ * Encode the library containing [original] into a summary and then use
+ * [_TestSummaryResynthesizer.getElement] to retrieve just the original
+ * element from the resynthesized summary.
+ */
+ Element validateGetElement(Element original) {
+ _TestSummaryResynthesizer resynthesizer = encodeLibrary(original.library);
+ ElementLocationImpl location = original.location;
+ Element result = resynthesizer.getElement(location);
+ // Check that no other summaries needed to be resynthesized to resynthesize
+ // the library element.
+ expect(resynthesizer.resynthesisCount, 1);
+ expect(result.location, location);
+ return result;
+ }
+}
+
+class _TestSummaryResynthesizer extends SummaryResynthesizer {
+ final Map<String, UnlinkedUnit> unlinkedSummaries;
+ final Map<String, LinkedLibrary> linkedSummaries;
+
+ _TestSummaryResynthesizer(
+ SummaryResynthesizer parent,
+ AnalysisContext context,
+ TypeProvider typeProvider,
+ SourceFactory sourceFactory,
+ this.unlinkedSummaries,
+ this.linkedSummaries,
+ bool strongMode)
+ : super(parent, context, typeProvider, sourceFactory, strongMode);
+
+ @override
+ LinkedLibrary getLinkedSummary(String uri) {
+ LinkedLibrary serializedLibrary = linkedSummaries[uri];
+ if (serializedLibrary == null) {
+ fail('Unexpectedly tried to get linked summary for $uri');
+ }
+ return serializedLibrary;
+ }
+
+ @override
+ UnlinkedUnit getUnlinkedSummary(String uri) {
+ UnlinkedUnit serializedUnit = unlinkedSummaries[uri];
+ if (serializedUnit == null) {
+ fail('Unexpectedly tried to get unlinked summary for $uri');
+ }
+ return serializedUnit;
+ }
+
+ @override
+ bool hasLibrarySummary(String uri) {
+ return true;
+ }
}
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
new file mode 100644
index 0000000..aa7dff0
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2016, 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 analyzer.test.src.summary.summarize_ast_test;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/prelink.dart';
+import 'package:analyzer/src/summary/summarize_ast.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'summary_common.dart';
+
+main() {
+ groupSep = ' | ';
+ runReflectiveTests(UnlinkedSummarizeAstTest);
+}
+
+/**
+ * Override of [SummaryTest] which creates unlinked summaries directly from the
+ * AST.
+ */
+@reflectiveTest
+class UnlinkedSummarizeAstTest extends Object with SummaryTest {
+ @override
+ LinkedLibrary linked;
+
+ @override
+ List<UnlinkedUnit> unlinkedUnits;
+
+ /**
+ * Map from absolute URI to the [UnlinkedUnit] for each compilation unit
+ * passed to [addNamedSource].
+ */
+ Map<String, UnlinkedUnit> uriToUnit = <String, UnlinkedUnit>{};
+
+ @override
+ bool get checkAstDerivedData => true;
+
+ @override
+ bool get expectAbsoluteUrisInDependencies => false;
+
+ @override
+ bool get skipFullyLinkedData => true;
+
+ @override
+ bool get strongMode => false;
+
+ @override
+ addNamedSource(String filePath, String contents) {
+ CompilationUnit unit = _parseText(contents);
+ UnlinkedUnit unlinkedUnit =
+ new UnlinkedUnit.fromBuffer(serializeAstUnlinked(unit).toBuffer());
+ uriToUnit[absUri(filePath)] = unlinkedUnit;
+ }
+
+ @override
+ void serializeLibraryText(String text, {bool allowErrors: false}) {
+ Uri testDartUri = Uri.parse(absUri('/test.dart'));
+ String resolveToAbsoluteUri(String relativeUri) =>
+ testDartUri.resolve(relativeUri).toString();
+ CompilationUnit unit = _parseText(text);
+ UnlinkedUnit definingUnit =
+ new UnlinkedUnit.fromBuffer(serializeAstUnlinked(unit).toBuffer());
+ UnlinkedUnit getPart(String relativeUri) {
+ String absoluteUri = resolveToAbsoluteUri(relativeUri);
+ UnlinkedUnit unit = uriToUnit[absoluteUri];
+ if (unit == null && !allowMissingFiles) {
+ fail('Prelinker unexpectedly requested unit for "$relativeUri"'
+ ' (resolves to "$absoluteUri").');
+ }
+ return unit;
+ }
+ UnlinkedPublicNamespace getImport(String relativeUri) {
+ String absoluteUri = resolveToAbsoluteUri(relativeUri);
+ UnlinkedPublicNamespace namespace = sdkPublicNamespace[absoluteUri];
+ if (namespace == null) {
+ namespace = uriToUnit[absoluteUri]?.publicNamespace;
+ }
+ if (namespace == null && !allowMissingFiles) {
+ fail('Prelinker unexpectedly requested namespace for "$relativeUri"'
+ ' (resolves to "$absoluteUri").'
+ ' Namespaces available: ${uriToUnit.keys}');
+ }
+ return namespace;
+ }
+ linked = new LinkedLibrary.fromBuffer(
+ prelink(definingUnit, getPart, getImport).toBuffer());
+ unlinkedUnits = <UnlinkedUnit>[definingUnit];
+ for (String relativeUri in definingUnit.publicNamespace.parts) {
+ UnlinkedUnit unit = uriToUnit[resolveToAbsoluteUri(relativeUri)];
+ if (unit == null) {
+ if (!allowMissingFiles) {
+ fail('Test referred to unknown unit $relativeUri');
+ }
+ } else {
+ unlinkedUnits.add(unit);
+ }
+ }
+ }
+
+ CompilationUnit _parseText(String text) {
+ CharSequenceReader reader = new CharSequenceReader(text);
+ Scanner scanner =
+ new Scanner(null, reader, AnalysisErrorListener.NULL_LISTENER);
+ Token token = scanner.tokenize();
+ Parser parser = new Parser(null, AnalysisErrorListener.NULL_LISTENER);
+ parser.parseGenericMethods = true;
+ return parser.parseCompilationUnit(token);
+ }
+}
diff --git a/pkg/analyzer/test/src/summary/summarize_elements_strong_test.dart b/pkg/analyzer/test/src/summary/summarize_elements_strong_test.dart
new file mode 100644
index 0000000..8a8bfe6
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summarize_elements_strong_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, 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 analyzer.test.src.summary.summarize_elements_strong_test;
+
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'summarize_elements_test.dart';
+import 'summary_common.dart';
+
+main() {
+ groupSep = ' | ';
+ runReflectiveTests(SummarizeElementsStrongTest);
+}
+
+/**
+ * Override of [SummaryTest] which creates summaries from the element model
+ * using strong mode.
+ */
+@reflectiveTest
+class SummarizeElementsStrongTest extends SummarizeElementsTest {
+ @override
+ AnalysisOptionsImpl get options => super.options..strongMode = true;
+
+ @override
+ bool get strongMode => true;
+}
diff --git a/pkg/analyzer/test/src/summary/summarize_elements_test.dart b/pkg/analyzer/test/src/summary/summarize_elements_test.dart
new file mode 100644
index 0000000..7b679b9
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summarize_elements_test.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2016, 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 analyzer.test.src.summary.summarize_elements_test;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/public_namespace_computer.dart'
+ as public_namespace;
+import 'package:analyzer/src/summary/summarize_elements.dart'
+ as summarize_elements;
+import 'package:unittest/unittest.dart';
+
+import '../../generated/resolver_test.dart';
+import '../../reflective_tests.dart';
+import 'summary_common.dart';
+
+main() {
+ groupSep = ' | ';
+ runReflectiveTests(SummarizeElementsTest);
+}
+
+/**
+ * Override of [SummaryTest] which creates summaries from the element model.
+ */
+@reflectiveTest
+class SummarizeElementsTest extends ResolverTestCase with SummaryTest {
+ /**
+ * The list of absolute unit URIs corresponding to the compilation units in
+ * [unlinkedUnits].
+ */
+ List<String> unitUris;
+
+ /**
+ * Map containing all source files in this test, and their corresponding file
+ * contents.
+ */
+ final Map<Source, String> _fileContents = <Source, String>{};
+
+ @override
+ LinkedLibrary linked;
+
+ @override
+ List<UnlinkedUnit> unlinkedUnits;
+
+ @override
+ bool get checkAstDerivedData => false;
+
+ @override
+ bool get expectAbsoluteUrisInDependencies => true;
+
+ /**
+ * Determine the analysis options that should be used for this test.
+ */
+ AnalysisOptionsImpl get options =>
+ new AnalysisOptionsImpl()..enableGenericMethods = true;
+
+ @override
+ bool get skipFullyLinkedData => false;
+
+ @override
+ bool get strongMode => false;
+
+ @override
+ Source addNamedSource(String filePath, String contents) {
+ Source source = super.addNamedSource(filePath, contents);
+ _fileContents[source] = contents;
+ return source;
+ }
+
+ /**
+ * Serialize the library containing the given class [element], then
+ * deserialize it and return the summary of the class.
+ */
+ UnlinkedClass serializeClassElement(ClassElement element) {
+ serializeLibraryElement(element.library);
+ return findClass(element.name, failIfAbsent: true);
+ }
+
+ /**
+ * Serialize the given [library] element, then deserialize it and store the
+ * resulting summary in [linked] and [unlinkedUnits].
+ */
+ void serializeLibraryElement(LibraryElement library) {
+ summarize_elements.LibrarySerializationResult serializedLib =
+ summarize_elements.serializeLibrary(
+ library, typeProvider, analysisContext.analysisOptions.strongMode);
+ {
+ List<int> buffer = serializedLib.linked.toBuffer();
+ linked = new LinkedLibrary.fromBuffer(buffer);
+ }
+ unlinkedUnits = serializedLib.unlinkedUnits.map((UnlinkedUnitBuilder b) {
+ List<int> buffer = b.toBuffer();
+ return new UnlinkedUnit.fromBuffer(buffer);
+ }).toList();
+ unitUris = serializedLib.unitUris;
+ }
+
+ @override
+ void serializeLibraryText(String text, {bool allowErrors: false}) {
+ Source source = addSource(text);
+ _fileContents[source] = text;
+ LibraryElement library = resolve2(source);
+ if (!allowErrors) {
+ assertNoErrors(source);
+ }
+ serializeLibraryElement(library);
+ expect(unlinkedUnits[0].imports.length, linked.importDependencies.length);
+ expect(linked.units.length, unlinkedUnits.length);
+ for (int i = 0; i < linked.units.length; i++) {
+ expect(unlinkedUnits[i].references.length,
+ lessThanOrEqualTo(linked.units[i].references.length));
+ }
+ verifyPublicNamespace();
+ }
+
+ @override
+ void setUp() {
+ super.setUp();
+ resetWithOptions(options);
+ }
+
+ test_class_no_superclass() {
+ UnlinkedClass cls = serializeClassElement(typeProvider.objectType.element);
+ expect(cls.supertype, isNull);
+ expect(cls.hasNoSupertype, isTrue);
+ }
+
+ /**
+ * Verify that [public_namespace.computePublicNamespace] produces data that's
+ * equivalent to that produced by [summarize_elements.serializeLibrary].
+ */
+ void verifyPublicNamespace() {
+ for (int i = 0; i < unlinkedUnits.length; i++) {
+ Source source = analysisContext.sourceFactory.forUri(unitUris[i]);
+ String text = _fileContents[source];
+ if (text == null) {
+ if (!allowMissingFiles) {
+ fail('Could not find file while verifying public namespace: '
+ '${unitUris[i]}');
+ }
+ } else {
+ UnlinkedPublicNamespace namespace =
+ computePublicNamespaceFromText(text, source);
+ expect(canonicalize(namespace),
+ canonicalize(unlinkedUnits[i].publicNamespace),
+ reason: 'publicNamespace(${unitUris[i]})');
+ }
+ }
+ }
+}
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
new file mode 100644
index 0000000..2122771
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -0,0 +1,5002 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.summary.summary_common;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine_io.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/summary/base.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/public_namespace_computer.dart'
+ as public_namespace;
+import 'package:analyzer/src/summary/summarize_elements.dart'
+ as summarize_elements;
+import 'package:unittest/unittest.dart';
+
+import '../../generated/resolver_test.dart';
+
+/**
+ * The public namespaces of the sdk are computed once so that we don't bog
+ * down the test. Structured as a map from absolute URI to the corresponding
+ * public namespace.
+ *
+ * Note: should an exception occur during computation of this variable, it
+ * will silently be set to null to allow other tests to run.
+ */
+final Map<String, UnlinkedPublicNamespace> sdkPublicNamespace = () {
+ try {
+ AnalysisContext analysisContext = AnalysisContextFactory.contextWithCore();
+ Map<String, UnlinkedPublicNamespace> uriToNamespace =
+ <String, UnlinkedPublicNamespace>{};
+ List<LibraryElement> libraries = [
+ analysisContext.typeProvider.objectType.element.library,
+ analysisContext.typeProvider.futureType.element.library
+ ];
+ for (LibraryElement library in libraries) {
+ summarize_elements.LibrarySerializationResult serializedLibrary =
+ summarize_elements.serializeLibrary(
+ library, analysisContext.typeProvider, false);
+ for (int i = 0; i < serializedLibrary.unlinkedUnits.length; i++) {
+ uriToNamespace[serializedLibrary.unitUris[i]] =
+ new UnlinkedUnit.fromBuffer(
+ serializedLibrary.unlinkedUnits[i].toBuffer())
+ .publicNamespace;
+ }
+ }
+ return uriToNamespace;
+ } catch (_) {
+ return null;
+ }
+}();
+
+/**
+ * Convert a summary object (or a portion of one) into a canonical form that
+ * can be easily compared using [expect]. If [orderByName] is true, and the
+ * object is a [List], it is sorted by the `name` field of its elements.
+ */
+Object canonicalize(Object obj, {bool orderByName: false}) {
+ if (obj is SummaryClass) {
+ Map<String, Object> result = <String, Object>{};
+ obj.toMap().forEach((String key, Object value) {
+ bool orderByName = false;
+ if (obj is UnlinkedPublicNamespace && key == 'names') {
+ orderByName = true;
+ }
+ result[key] = canonicalize(value, orderByName: orderByName);
+ });
+ return result;
+ } else if (obj is List) {
+ List<Object> result = <Object>[];
+ for (Object item in obj) {
+ result.add(canonicalize(item));
+ }
+ if (orderByName) {
+ result.sort((Object a, Object b) {
+ if (a is Map && b is Map) {
+ return Comparable.compare(a['name'], b['name']);
+ } else {
+ return 0;
+ }
+ });
+ }
+ return result;
+ } else if (obj is String || obj is num || obj is bool) {
+ return obj;
+ } else {
+ return obj.toString();
+ }
+}
+
+UnlinkedPublicNamespace computePublicNamespaceFromText(
+ String text, Source source) {
+ CharacterReader reader = new CharSequenceReader(text);
+ Scanner scanner =
+ new Scanner(source, reader, AnalysisErrorListener.NULL_LISTENER);
+ Parser parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
+ parser.parseGenericMethods = true;
+ CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
+ UnlinkedPublicNamespace namespace = new UnlinkedPublicNamespace.fromBuffer(
+ public_namespace.computePublicNamespace(unit).toBuffer());
+ return namespace;
+}
+
+/**
+ * Type of a function that validates an [EntityRef].
+ */
+typedef void _EntityRefValidator(EntityRef entityRef);
+
+/**
+ * Base class containing most summary tests. This allows summary tests to be
+ * re-used to exercise all the different ways in which summaries can be
+ * generated (e.g. direct from the AST, from the element model, from a
+ * "relinking" process, etc.)
+ */
+abstract class SummaryTest {
+ /**
+ * A test will set this to `true` if it contains `import`, `export`, or
+ * `part` declarations that deliberately refer to non-existent files.
+ */
+ bool allowMissingFiles = false;
+
+ /**
+ * `true` if the summary was created directly from the AST (and hence
+ * contains information that is not obtainable from the element model alone).
+ * TODO(paulberry): modify the element model so that it contains all the data
+ * that summaries need, so that this flag is no longer needed.
+ */
+ bool get checkAstDerivedData;
+
+ /**
+ * Get access to the linked defining compilation unit.
+ */
+ LinkedUnit get definingUnit => linked.units[0];
+
+ /**
+ * `true` if the linked portion of the summary is expected to contain
+ * absolute URIs. This happens because the element model doesn't (yet) store
+ * enough information to recover relative URIs, TODO(paulberry): fix this.
+ */
+ bool get expectAbsoluteUrisInDependencies;
+
+ /**
+ * Get access to the linked summary that results from serializing and
+ * then deserializing the library under test.
+ */
+ LinkedLibrary get linked;
+
+ /**
+ * `true` if the linked portion of the summary only contains prelinked data.
+ * This happens because we don't yet have a full linker; only a prelinker.
+ */
+ bool get skipFullyLinkedData;
+
+ /**
+ * `true` if the linked portion of the summary contains the result of strong
+ * mode analysis.
+ */
+ bool get strongMode;
+
+ /**
+ * Get access to the unlinked compilation unit summaries that result from
+ * serializing and deserializing the library under test.
+ */
+ List<UnlinkedUnit> get unlinkedUnits;
+
+ /**
+ * Convert [path] to a suitably formatted absolute path URI for the current
+ * platform.
+ */
+ String absUri(String path) {
+ return FileUtilities2.createFile(path).toURI().toString();
+ }
+
+ /**
+ * Add the given source file so that it may be referenced by the file under
+ * test.
+ */
+ Source addNamedSource(String filePath, String contents);
+
+ /**
+ * Verify that the [dependency]th element of the dependency table represents
+ * a file reachable via the given [absoluteUri] and [relativeUri].
+ */
+ void checkDependency(int dependency, String absoluteUri, String relativeUri) {
+ if (expectAbsoluteUrisInDependencies) {
+ // The element model doesn't (yet) store enough information to recover
+ // relative URIs, so we have to use the absolute URI.
+ // TODO(paulberry): fix this.
+ relativeUri = absoluteUri;
+ }
+ expect(dependency, new isInstanceOf<int>());
+ expect(linked.dependencies[dependency].uri, relativeUri);
+ }
+
+ /**
+ * Verify that the given [dependency] lists the given [absoluteUris] or
+ * [relativeUris] as its parts.
+ */
+ void checkDependencyParts(LinkedDependency dependency,
+ List<String> absoluteUris, List<String> relativeUris) {
+ if (expectAbsoluteUrisInDependencies) {
+ // The element model doesn't (yet) store enough information to recover
+ // relative URIs, so we have to use the absolute URI.
+ // TODO(paulberry): fix this.
+ relativeUris = absoluteUris;
+ }
+ expect(dependency.parts, relativeUris);
+ }
+
+ /**
+ * Check that the given [documentationComment] matches the first
+ * Javadoc-style comment found in [text].
+ *
+ * Note that the algorithm for finding the Javadoc-style comment in [text] is
+ * a simple-minded text search; it is easily confused by corner cases such as
+ * strings containing comments, nested comments, etc.
+ */
+ void checkDocumentationComment(
+ UnlinkedDocumentationComment documentationComment, String text) {
+ expect(documentationComment, isNotNull);
+ int commentStart = text.indexOf('/*');
+ expect(commentStart, isNot(-1));
+ int commentEnd = text.indexOf('*/');
+ expect(commentEnd, isNot(-1));
+ commentEnd += 2;
+ String expectedCommentText =
+ text.substring(commentStart, commentEnd).replaceAll('\r\n', '\n');
+ expect(documentationComment.text, expectedCommentText);
+ expect(documentationComment.offset, commentStart);
+ expect(documentationComment.length, commentEnd - commentStart);
+ }
+
+ /**
+ * Verify that the given [typeRef] represents the type `dynamic`.
+ */
+ void checkDynamicTypeRef(EntityRef typeRef) {
+ checkTypeRef(typeRef, null, null, 'dynamic');
+ }
+
+ /**
+ * Verify that the given [exportName] represents a reference to an entity
+ * declared in a file reachable via [absoluteUri] and [relativeUri], having
+ * name [expectedName]. [expectedKind] is the kind of object referenced.
+ * [expectedTargetUnit] is the index of the compilation unit in which the
+ * target of the [exportName] is expected to appear; if not specified it is
+ * assumed to be the defining compilation unit.
+ */
+ void checkExportName(LinkedExportName exportName, String absoluteUri,
+ String relativeUri, String expectedName, ReferenceKind expectedKind,
+ {int expectedTargetUnit: 0}) {
+ expect(exportName, new isInstanceOf<LinkedExportName>());
+ // Exported names must come from other libraries.
+ expect(exportName.dependency, isNot(0));
+ checkDependency(exportName.dependency, absoluteUri, relativeUri);
+ expect(exportName.name, expectedName);
+ expect(exportName.kind, expectedKind);
+ expect(exportName.unit, expectedTargetUnit);
+ }
+
+ /**
+ * Verify that the dependency table contains an entry for a file reachable
+ * via the given [absoluteUri] and [relativeUri]. If [fullyLinked] is
+ * `true`, then the dependency should be a fully-linked dependency; otherwise
+ * it should be a prelinked dependency.
+ *
+ * The index of the [LinkedDependency] is returned.
+ */
+ int checkHasDependency(String absoluteUri, String relativeUri,
+ {bool fullyLinked: false}) {
+ if (expectAbsoluteUrisInDependencies) {
+ // The element model doesn't (yet) store enough information to recover
+ // relative URIs, so we have to use the absolute URI.
+ // TODO(paulberry): fix this.
+ relativeUri = absoluteUri;
+ }
+ List<String> found = <String>[];
+ for (int i = 0; i < linked.dependencies.length; i++) {
+ LinkedDependency dep = linked.dependencies[i];
+ if (dep.uri == relativeUri) {
+ if (fullyLinked) {
+ expect(i, greaterThanOrEqualTo(linked.numPrelinkedDependencies));
+ } else {
+ expect(i, lessThan(linked.numPrelinkedDependencies));
+ }
+ return i;
+ }
+ found.add(dep.uri);
+ }
+ fail('Did not find dependency $relativeUri. Found: $found');
+ return null;
+ }
+
+ /**
+ * Test an inferred type. If strong mode is disabled, verify that the given
+ * [slotId] exists and has no associated type. Otherwise, behave as in
+ * [checkLinkedTypeSlot].
+ */
+ void checkInferredTypeSlot(
+ int slotId, String absoluteUri, String relativeUri, String expectedName,
+ {bool allowTypeParameters: false,
+ ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+ int expectedTargetUnit: 0,
+ LinkedUnit linkedSourceUnit,
+ UnlinkedUnit unlinkedSourceUnit,
+ int numTypeParameters: 0}) {
+ if (strongMode) {
+ checkLinkedTypeSlot(slotId, absoluteUri, relativeUri, expectedName,
+ allowTypeParameters: allowTypeParameters,
+ expectedKind: expectedKind,
+ expectedTargetUnit: expectedTargetUnit,
+ linkedSourceUnit: linkedSourceUnit,
+ unlinkedSourceUnit: unlinkedSourceUnit,
+ numTypeParameters: numTypeParameters);
+ } else {
+ // A slot id should have been assigned but it should not be associated
+ // with any type.
+ expect(slotId, isNot(0));
+ expect(getTypeRefForSlot(slotId, linkedSourceUnit: linkedSourceUnit),
+ isNull);
+ }
+ }
+
+ /**
+ * Verify that the dependency table *does not* contain any entries for a file
+ * reachable via the given [absoluteUri] and [relativeUri].
+ */
+ void checkLacksDependency(String absoluteUri, String relativeUri) {
+ if (expectAbsoluteUrisInDependencies) {
+ // The element model doesn't (yet) store enough information to recover
+ // relative URIs, so we have to use the absolute URI.
+ // TODO(paulberry): fix this.
+ relativeUri = absoluteUri;
+ }
+ for (LinkedDependency dep in linked.dependencies) {
+ if (dep.uri == relativeUri) {
+ fail('Unexpected dependency found: $relativeUri');
+ }
+ }
+ }
+
+ /**
+ * Verify that the given [typeRef] represents a reference to a type declared
+ * in a file reachable via [absoluteUri] and [relativeUri], having name
+ * [expectedName]. If [allowTypeParameters] is true, allow the type
+ * reference to supply type parameters. [expectedKind] is the kind of object
+ * referenced. [linkedSourceUnit] and [unlinkedSourceUnit] refer to the
+ * compilation unit within which the [typeRef] appears; if not specified they
+ * are assumed to refer to the defining compilation unit.
+ * [expectedTargetUnit] is the index of the compilation unit in which the
+ * target of the [typeRef] is expected to appear; if not specified it is
+ * assumed to be the defining compilation unit. [numTypeParameters] is the
+ * number of type parameters of the thing being referred to.
+ */
+ void checkLinkedTypeRef(EntityRef typeRef, String absoluteUri,
+ String relativeUri, String expectedName,
+ {bool allowTypeParameters: false,
+ ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+ int expectedTargetUnit: 0,
+ LinkedUnit linkedSourceUnit,
+ UnlinkedUnit unlinkedSourceUnit,
+ int numTypeParameters: 0}) {
+ linkedSourceUnit ??= definingUnit;
+ expect(typeRef, isNotNull,
+ reason: 'No entry in linkedSourceUnit.types matching slotId');
+ expect(typeRef.paramReference, 0);
+ int index = typeRef.reference;
+ if (!allowTypeParameters) {
+ expect(typeRef.typeArguments, isEmpty);
+ }
+ checkTypeRefCommonElements(
+ index,
+ absoluteUri,
+ relativeUri,
+ expectedName,
+ expectedKind,
+ expectedTargetUnit,
+ linkedSourceUnit,
+ unlinkedSourceUnit,
+ numTypeParameters);
+ }
+
+ /**
+ * Verify that the given [slotId] represents a reference to a type declared
+ * in a file reachable via [absoluteUri] and [relativeUri], having name
+ * [expectedName]. If [allowTypeParameters] is true, allow the type
+ * reference to supply type parameters. [expectedKind] is the kind of object
+ * referenced. [linkedSourceUnit] and [unlinkedSourceUnit] refer to the
+ * compilation unit within which the [typeRef] appears; if not specified they
+ * are assumed to refer to the defining compilation unit.
+ * [expectedTargetUnit] is the index of the compilation unit in which the
+ * target of the [typeRef] is expected to appear; if not specified it is
+ * assumed to be the defining compilation unit. [numTypeParameters] is the
+ * number of type parameters of the thing being referred to.
+ */
+ void checkLinkedTypeSlot(
+ int slotId, String absoluteUri, String relativeUri, String expectedName,
+ {bool allowTypeParameters: false,
+ ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+ int expectedTargetUnit: 0,
+ LinkedUnit linkedSourceUnit,
+ UnlinkedUnit unlinkedSourceUnit,
+ int numTypeParameters: 0}) {
+ // Slot ids should be nonzero, since zero means "no associated slot".
+ expect(slotId, isNot(0));
+ if (skipFullyLinkedData) {
+ return;
+ }
+ linkedSourceUnit ??= definingUnit;
+ checkLinkedTypeRef(
+ getTypeRefForSlot(slotId, linkedSourceUnit: linkedSourceUnit),
+ absoluteUri,
+ relativeUri,
+ expectedName,
+ allowTypeParameters: allowTypeParameters,
+ expectedKind: expectedKind,
+ expectedTargetUnit: expectedTargetUnit,
+ linkedSourceUnit: linkedSourceUnit,
+ unlinkedSourceUnit: unlinkedSourceUnit,
+ numTypeParameters: numTypeParameters);
+ }
+
+ /**
+ * Verify that the given [typeRef] represents a reference to a type parameter
+ * having the given [deBruijnIndex].
+ */
+ void checkParamTypeRef(EntityRef typeRef, int deBruijnIndex) {
+ expect(typeRef, new isInstanceOf<EntityRef>());
+ expect(typeRef.reference, 0);
+ expect(typeRef.typeArguments, isEmpty);
+ expect(typeRef.paramReference, deBruijnIndex);
+ }
+
+ /**
+ * Verify that [prefixReference] is a valid reference to a prefix having the
+ * given [name].
+ */
+ void checkPrefix(int prefixReference, String name) {
+ expect(prefixReference, isNot(0));
+ expect(unlinkedUnits[0].references[prefixReference].prefixReference, 0);
+ expect(unlinkedUnits[0].references[prefixReference].name, name);
+ expect(definingUnit.references[prefixReference].dependency, 0);
+ expect(definingUnit.references[prefixReference].kind, ReferenceKind.prefix);
+ expect(definingUnit.references[prefixReference].unit, 0);
+ }
+
+ /**
+ * Verify that the given [typeRef] represents a reference to a type declared
+ * in a file reachable via [absoluteUri] and [relativeUri], having name
+ * [expectedName]. If [expectedPrefix] is supplied, verify that the type is
+ * reached via the given prefix. If [allowTypeParameters] is true, allow the
+ * type reference to supply type parameters. [expectedKind] is the kind of
+ * object referenced. [linkedSourceUnit] and [unlinkedSourceUnit] refer
+ * to the compilation unit within which the [typeRef] appears; if not
+ * specified they are assumed to refer to the defining compilation unit.
+ * [expectedTargetUnit] is the index of the compilation unit in which the
+ * target of the [typeRef] is expected to appear; if not specified it is
+ * assumed to be the defining compilation unit. [numTypeParameters] is the
+ * number of type parameters of the thing being referred to.
+ */
+ void checkTypeRef(EntityRef typeRef, String absoluteUri, String relativeUri,
+ String expectedName,
+ {String expectedPrefix,
+ List<_PrefixExpectation> prefixExpectations,
+ bool allowTypeParameters: false,
+ ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+ int expectedTargetUnit: 0,
+ LinkedUnit linkedSourceUnit,
+ UnlinkedUnit unlinkedSourceUnit,
+ int numTypeParameters: 0}) {
+ linkedSourceUnit ??= definingUnit;
+ expect(typeRef, new isInstanceOf<EntityRef>());
+ expect(typeRef.paramReference, 0);
+ int index = typeRef.reference;
+ if (!allowTypeParameters) {
+ expect(typeRef.typeArguments, isEmpty);
+ }
+ UnlinkedReference reference = checkTypeRefCommonElements(
+ index,
+ absoluteUri,
+ relativeUri,
+ expectedName,
+ expectedKind,
+ expectedTargetUnit,
+ linkedSourceUnit,
+ unlinkedSourceUnit,
+ numTypeParameters);
+ expect(reference, isNotNull,
+ reason: 'Unlinked type refs must refer to an explicit reference');
+ if (expectedKind == ReferenceKind.unresolved && !checkAstDerivedData) {
+ // summarize_elements.dart isn't yet able to record the prefix of
+ // unresolved references. TODO(paulberry): fix this.
+ expect(reference.prefixReference, 0);
+ } else if (expectedPrefix != null) {
+ checkPrefix(reference.prefixReference, expectedPrefix);
+ } else if (prefixExpectations != null) {
+ for (_PrefixExpectation expectation in prefixExpectations) {
+ expect(reference.prefixReference, isNot(0));
+ reference = checkTypeRefCommonElements(
+ reference.prefixReference,
+ expectation.inLibraryDefiningUnit
+ ? null
+ : expectation.absoluteUri ?? absoluteUri,
+ expectation.inLibraryDefiningUnit
+ ? null
+ : expectation.relativeUri ?? relativeUri,
+ expectation.name,
+ expectation.kind,
+ expectedTargetUnit,
+ linkedSourceUnit,
+ unlinkedSourceUnit,
+ expectation.numTypeParameters);
+ }
+ expect(reference.prefixReference, 0);
+ } else {
+ expect(reference.prefixReference, 0);
+ }
+ }
+
+ /**
+ * Check the data structures that are common between [checkTypeRef] and
+ * [checkLinkedTypeRef]. If the type reference in question is an explicit
+ * reference, return the [UnlinkedReference] that is used to make the
+ * explicit reference. If the type reference in question is an implicit
+ * reference, return `null`.
+ */
+ UnlinkedReference checkTypeRefCommonElements(
+ int referenceIndex,
+ String absoluteUri,
+ String relativeUri,
+ String expectedName,
+ ReferenceKind expectedKind,
+ int expectedTargetUnit,
+ LinkedUnit linkedSourceUnit,
+ UnlinkedUnit unlinkedSourceUnit,
+ int numTypeParameters) {
+ unlinkedSourceUnit ??= unlinkedUnits[0];
+ LinkedReference referenceResolution =
+ linkedSourceUnit.references[referenceIndex];
+ String name;
+ UnlinkedReference reference;
+ if (referenceIndex < unlinkedSourceUnit.references.length) {
+ // This is an explicit reference, so its name and prefix should be in
+ // [UnlinkedUnit.references].
+ expect(referenceResolution.name, isEmpty);
+ reference = unlinkedSourceUnit.references[referenceIndex];
+ name = reference.name;
+ if (reference.prefixReference != 0) {
+ // Prefixes should appear in the references table before any reference
+ // that uses them.
+ expect(reference.prefixReference, lessThan(referenceIndex));
+ }
+ } else {
+ // This is an implicit reference, so its name should be in
+ // [LinkedUnit.references].
+ name = referenceResolution.name;
+ }
+ // Index 0 is reserved.
+ expect(referenceIndex, isNot(0));
+ if (absoluteUri == null) {
+ expect(referenceResolution.dependency, 0);
+ } else {
+ checkDependency(referenceResolution.dependency, absoluteUri, relativeUri);
+ }
+ if (expectedKind == ReferenceKind.unresolved && !checkAstDerivedData) {
+ // summarize_elements.dart isn't yet able to record the name of
+ // unresolved references. TODO(paulberry): fix this.
+ expect(name, '*unresolved*');
+ } else {
+ if (expectedName == null) {
+ expect(name, isEmpty);
+ } else {
+ expect(name, expectedName);
+ }
+ }
+ expect(referenceResolution.kind, expectedKind);
+ expect(referenceResolution.unit, expectedTargetUnit);
+ expect(referenceResolution.numTypeParameters, numTypeParameters);
+ return reference;
+ }
+
+ /**
+ * Verify that the given [typeRef] represents a reference to an unresolved
+ * type.
+ */
+ void checkUnresolvedTypeRef(
+ EntityRef typeRef, String expectedPrefix, String expectedName,
+ {LinkedUnit linkedSourceUnit, UnlinkedUnit unlinkedSourceUnit}) {
+ // When serializing from the element model, unresolved type refs lose their
+ // name.
+ checkTypeRef(typeRef, null, null, checkAstDerivedData ? expectedName : null,
+ expectedPrefix: expectedPrefix,
+ expectedKind: ReferenceKind.unresolved,
+ linkedSourceUnit: linkedSourceUnit,
+ unlinkedSourceUnit: unlinkedSourceUnit);
+ }
+
+ /**
+ * Verify that the given [typeRef] represents the type `void`.
+ */
+ void checkVoidTypeRef(EntityRef typeRef) {
+ checkTypeRef(typeRef, null, null, 'void');
+ }
+
+ fail_enum_value_documented() {
+ // TODO(paulberry): currently broken because of dartbug.com/25385
+ String text = '''
+enum E {
+ /**
+ * Docs
+ */
+ v
+}''';
+ UnlinkedEnumValue value = serializeEnumText(text).values[0];
+ expect(value.documentationComment, isNotNull);
+ checkDocumentationComment(value.documentationComment, text);
+ }
+
+ /**
+ * Find the class with the given [className] in the summary, and return its
+ * [UnlinkedClass] data structure. If [unit] is not given, the class is
+ * looked for in the defining compilation unit.
+ */
+ UnlinkedClass findClass(String className,
+ {bool failIfAbsent: false, UnlinkedUnit unit}) {
+ unit ??= unlinkedUnits[0];
+ UnlinkedClass result;
+ for (UnlinkedClass cls in unit.classes) {
+ if (cls.name == className) {
+ if (result != null) {
+ fail('Duplicate class $className');
+ }
+ result = cls;
+ }
+ }
+ if (result == null && failIfAbsent) {
+ fail('Class $className not found in serialized output');
+ }
+ return result;
+ }
+
+ /**
+ * Find the enum with the given [enumName] in the summary, and return its
+ * [UnlinkedEnum] data structure. If [unit] is not given, the enum is looked
+ * for in the defining compilation unit.
+ */
+ UnlinkedEnum findEnum(String enumName,
+ {bool failIfAbsent: false, UnlinkedUnit unit}) {
+ unit ??= unlinkedUnits[0];
+ UnlinkedEnum result;
+ for (UnlinkedEnum e in unit.enums) {
+ if (e.name == enumName) {
+ if (result != null) {
+ fail('Duplicate enum $enumName');
+ }
+ result = e;
+ }
+ }
+ if (result == null && failIfAbsent) {
+ fail('Enum $enumName not found in serialized output');
+ }
+ return result;
+ }
+
+ /**
+ * Find the executable with the given [executableName] in the summary, and
+ * return its [UnlinkedExecutable] data structure. If [executables] is not
+ * given, then the executable is searched for in the defining compilation
+ * unit.
+ */
+ UnlinkedExecutable findExecutable(String executableName,
+ {List<UnlinkedExecutable> executables, bool failIfAbsent: false}) {
+ executables ??= unlinkedUnits[0].executables;
+ UnlinkedExecutable result;
+ for (UnlinkedExecutable executable in executables) {
+ if (executable.name == executableName) {
+ if (result != null) {
+ fail('Duplicate executable $executableName');
+ }
+ result = executable;
+ }
+ }
+ if (result == null && failIfAbsent) {
+ fail('Executable $executableName not found in serialized output');
+ }
+ return result;
+ }
+
+ /**
+ * Find the typedef with the given [typedefName] in the summary, and return
+ * its [UnlinkedTypedef] data structure. If [unit] is not given, the typedef
+ * is looked for in the defining compilation unit.
+ */
+ UnlinkedTypedef findTypedef(String typedefName,
+ {bool failIfAbsent: false, UnlinkedUnit unit}) {
+ unit ??= unlinkedUnits[0];
+ UnlinkedTypedef result;
+ for (UnlinkedTypedef type in unit.typedefs) {
+ if (type.name == typedefName) {
+ if (result != null) {
+ fail('Duplicate typedef $typedefName');
+ }
+ result = type;
+ }
+ }
+ if (result == null && failIfAbsent) {
+ fail('Typedef $typedefName not found in serialized output');
+ }
+ return result;
+ }
+
+ /**
+ * Find the top level variable with the given [variableName] in the summary,
+ * and return its [UnlinkedVariable] data structure. If [variables] is not
+ * specified, the variable is looked for in the defining compilation unit.
+ */
+ UnlinkedVariable findVariable(String variableName,
+ {List<UnlinkedVariable> variables, bool failIfAbsent: false}) {
+ variables ??= unlinkedUnits[0].variables;
+ UnlinkedVariable result;
+ for (UnlinkedVariable variable in variables) {
+ if (variable.name == variableName) {
+ if (result != null) {
+ fail('Duplicate variable $variableName');
+ }
+ result = variable;
+ }
+ }
+ if (result == null && failIfAbsent) {
+ fail('Variable $variableName not found in serialized output');
+ }
+ return result;
+ }
+
+ /**
+ * Find the entry in [linkedSourceUnit.types] matching [slotId].
+ */
+ EntityRef getTypeRefForSlot(int slotId, {LinkedUnit linkedSourceUnit}) {
+ linkedSourceUnit ??= definingUnit;
+ for (EntityRef typeRef in linkedSourceUnit.types) {
+ if (typeRef.slot == slotId) {
+ return typeRef;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Serialize the given library [text] and return the summary of the class
+ * with the given [className].
+ */
+ UnlinkedClass serializeClassText(String text,
+ {String className: 'C', bool allowErrors: false}) {
+ serializeLibraryText(text, allowErrors: allowErrors);
+ return findClass(className, failIfAbsent: true);
+ }
+
+ /**
+ * Serialize the given library [text] and return the summary of the enum with
+ * the given [enumName].
+ */
+ UnlinkedEnum serializeEnumText(String text, [String enumName = 'E']) {
+ serializeLibraryText(text);
+ return findEnum(enumName, failIfAbsent: true);
+ }
+
+ /**
+ * Serialize the given library [text] and return the summary of the
+ * executable with the given [executableName].
+ */
+ UnlinkedExecutable serializeExecutableText(String text,
+ [String executableName = 'f']) {
+ serializeLibraryText(text);
+ return findExecutable(executableName, failIfAbsent: true);
+ }
+
+ /**
+ * Serialize the given library [text], then deserialize it and store its
+ * summary in [lib].
+ */
+ void serializeLibraryText(String text, {bool allowErrors: false});
+
+ /**
+ * Serialize the given method [text] and return the summary of the executable
+ * with the given [executableName].
+ */
+ UnlinkedExecutable serializeMethodText(String text,
+ [String executableName = 'f']) {
+ serializeLibraryText('class C { $text }');
+ return findExecutable(executableName,
+ executables: findClass('C', failIfAbsent: true).executables,
+ failIfAbsent: true);
+ }
+
+ /**
+ * Serialize the given library [text] and return the summary of the typedef
+ * with the given [typedefName].
+ */
+ UnlinkedTypedef serializeTypedefText(String text,
+ [String typedefName = 'F']) {
+ serializeLibraryText(text);
+ return findTypedef(typedefName, failIfAbsent: true);
+ }
+
+ /**
+ * Serialize a type declaration using the given [text] as a type name, and
+ * return a summary of the corresponding [EntityRef]. If the type
+ * declaration needs to refer to types that are not available in core, those
+ * types may be declared in [otherDeclarations].
+ */
+ EntityRef serializeTypeText(String text,
+ {String otherDeclarations: '', bool allowErrors: false}) {
+ return serializeVariableText('$otherDeclarations\n$text v;',
+ allowErrors: allowErrors)
+ .type;
+ }
+
+ /**
+ * Serialize the given library [text] and return the summary of the variable
+ * with the given [variableName].
+ */
+ UnlinkedVariable serializeVariableText(String text,
+ {String variableName: 'v', bool allowErrors: false}) {
+ serializeLibraryText(text, allowErrors: allowErrors);
+ return findVariable(variableName, failIfAbsent: true);
+ }
+
+ test_cascaded_export_hide_hide() {
+ addNamedSource('/lib1.dart', 'export "lib2.dart" hide C hide B, C;');
+ addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(
+ findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_cascaded_export_hide_show() {
+ addNamedSource('/lib1.dart', 'export "lib2.dart" hide C show A, C;');
+ addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(
+ findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_cascaded_export_show_hide() {
+ addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B hide B, C;');
+ addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(
+ findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_cascaded_export_show_show() {
+ addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B show A, C;');
+ addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(
+ findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_cascaded_import_hide_hide() {
+ addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib.dart' hide C hide B, C;
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_cascaded_import_hide_show() {
+ addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib.dart' hide C show A, C;
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_cascaded_import_show_hide() {
+ addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib.dart' show A, B hide B, C;
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_cascaded_import_show_show() {
+ addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+ serializeLibraryText(
+ '''
+import 'lib.dart' show A, B show A, C;
+A a;
+B b;
+C c;
+ ''',
+ allowErrors: true);
+ checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+ checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+ checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+ }
+
+ test_class_abstract() {
+ UnlinkedClass cls = serializeClassText('abstract class C {}');
+ expect(cls.isAbstract, true);
+ }
+
+ test_class_alias_abstract() {
+ UnlinkedClass cls = serializeClassText(
+ 'abstract class C = D with E; class D {} class E {}');
+ expect(cls.isAbstract, true);
+ }
+
+ test_class_alias_concrete() {
+ UnlinkedClass cls =
+ serializeClassText('class C = _D with _E; class _D {} class _E {}');
+ expect(cls.isAbstract, false);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+ ReferenceKind.classOrEnum);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+ }
+
+ test_class_alias_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+class C = D with E;
+
+class D {}
+class E {}''';
+ UnlinkedClass cls = serializeClassText(text);
+ expect(cls.documentationComment, isNotNull);
+ checkDocumentationComment(cls.documentationComment, text);
+ }
+
+ test_class_alias_flag() {
+ UnlinkedClass cls =
+ serializeClassText('class C = D with E; class D {} class E {}');
+ expect(cls.isMixinApplication, true);
+ }
+
+ test_class_alias_generic() {
+ serializeClassText('class C<A, B> = _D with _E; class _D {} class _E {}');
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 2);
+ }
+
+ test_class_alias_mixin_order() {
+ UnlinkedClass cls = serializeClassText('''
+class C = D with E, F;
+class D {}
+class E {}
+class F {}
+''');
+ expect(cls.mixins, hasLength(2));
+ checkTypeRef(cls.mixins[0], null, null, 'E');
+ checkTypeRef(cls.mixins[1], null, null, 'F');
+ }
+
+ test_class_alias_no_implicit_constructors() {
+ UnlinkedClass cls = serializeClassText('''
+class C = D with E;
+class D {
+ D.foo();
+ D.bar();
+}
+class E {}
+''');
+ expect(cls.executables, isEmpty);
+ }
+
+ test_class_alias_private() {
+ serializeClassText('class _C = _D with _E; class _D {} class _E {}',
+ className: '_C');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_class_alias_reference_generic() {
+ EntityRef typeRef = serializeTypeText('C',
+ otherDeclarations: 'class C<D, E> = F with G; class F {} class G {}');
+ checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
+ }
+
+ test_class_alias_reference_generic_imported() {
+ addNamedSource(
+ '/lib.dart', 'class C<D, E> = F with G; class F {} class G {}');
+ EntityRef typeRef =
+ serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
+ checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
+ numTypeParameters: 2);
+ }
+
+ test_class_alias_supertype() {
+ UnlinkedClass cls =
+ serializeClassText('class C = D with E; class D {} class E {}');
+ checkTypeRef(cls.supertype, null, null, 'D');
+ expect(cls.hasNoSupertype, isFalse);
+ }
+
+ test_class_concrete() {
+ UnlinkedClass cls = serializeClassText('class C {}');
+ expect(cls.isAbstract, false);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+ ReferenceKind.classOrEnum);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+ }
+
+ test_class_constMembers() {
+ UnlinkedClass cls = serializeClassText('''
+class C {
+ int fieldInstance = 0;
+ final int fieldInstanceFinal = 0;
+ static int fieldStatic = 0;
+ static final int fieldStaticFinal = 0;
+ static const int fieldStaticConst = 0;
+ static const int _fieldStaticConstPrivate = 0;
+ static void methodStaticPublic() {}
+ static void _methodStaticPrivate() {}
+ void methodInstancePublic() {}
+ C operator+(C c) => null;
+}
+''');
+ expect(cls.isAbstract, false);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ UnlinkedPublicName className = unlinkedUnits[0].publicNamespace.names[0];
+ expect(className.kind, ReferenceKind.classOrEnum);
+ expect(className.name, 'C');
+ expect(className.numTypeParameters, 0);
+ // executables
+ Map<String, UnlinkedPublicName> executablesMap =
+ <String, UnlinkedPublicName>{};
+ className.constMembers.forEach((e) => executablesMap[e.name] = e);
+ expect(executablesMap, hasLength(2));
+ {
+ UnlinkedPublicName executable = executablesMap['fieldStaticConst'];
+ expect(executable.kind, ReferenceKind.constField);
+ expect(executable.constMembers, isEmpty);
+ }
+ {
+ UnlinkedPublicName executable = executablesMap['methodStaticPublic'];
+ expect(executable.kind, ReferenceKind.staticMethod);
+ expect(executable.constMembers, isEmpty);
+ }
+ }
+
+ test_class_constMembers_constructors() {
+ UnlinkedClass cls = serializeClassText('''
+class C {
+ const C();
+ const C.constructorNamedPublicConst();
+ C.constructorNamedPublic();
+ C._constructorNamedPrivate();
+}
+''');
+ expect(cls.isAbstract, false);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ UnlinkedPublicName className = unlinkedUnits[0].publicNamespace.names[0];
+ expect(className.kind, ReferenceKind.classOrEnum);
+ expect(className.name, 'C');
+ expect(className.numTypeParameters, 0);
+ // executables
+ Map<String, UnlinkedPublicName> executablesMap =
+ <String, UnlinkedPublicName>{};
+ className.constMembers.forEach((e) => executablesMap[e.name] = e);
+ expect(executablesMap, hasLength(2));
+ {
+ UnlinkedPublicName executable = executablesMap[''];
+ expect(executable.kind, ReferenceKind.constructor);
+ expect(executable.constMembers, isEmpty);
+ }
+ {
+ UnlinkedPublicName executable =
+ executablesMap['constructorNamedPublicConst'];
+ expect(executable.kind, ReferenceKind.constructor);
+ expect(executable.constMembers, isEmpty);
+ }
+ }
+
+ test_class_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+class C {}''';
+ UnlinkedClass cls = serializeClassText(text);
+ expect(cls.documentationComment, isNotNull);
+ checkDocumentationComment(cls.documentationComment, text);
+ }
+
+ test_class_documented_with_references() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs referring to [D] and [E]
+ */
+class C {}
+
+class D {}
+class E {}''';
+ UnlinkedClass cls = serializeClassText(text);
+ expect(cls.documentationComment, isNotNull);
+ checkDocumentationComment(cls.documentationComment, text);
+ }
+
+ test_class_documented_with_with_windows_line_endings() {
+ String text = '/**\r\n * Docs\r\n */\r\nclass C {}';
+ UnlinkedClass cls = serializeClassText(text);
+ expect(cls.documentationComment, isNotNull);
+ checkDocumentationComment(cls.documentationComment, text);
+ }
+
+ test_class_interface() {
+ UnlinkedClass cls = serializeClassText('''
+class C implements D {}
+class D {}
+''');
+ expect(cls.interfaces, hasLength(1));
+ checkTypeRef(cls.interfaces[0], null, null, 'D');
+ }
+
+ test_class_interface_order() {
+ UnlinkedClass cls = serializeClassText('''
+class C implements D, E {}
+class D {}
+class E {}
+''');
+ expect(cls.interfaces, hasLength(2));
+ checkTypeRef(cls.interfaces[0], null, null, 'D');
+ checkTypeRef(cls.interfaces[1], null, null, 'E');
+ }
+
+ test_class_mixin() {
+ UnlinkedClass cls = serializeClassText('''
+class C extends Object with D {}
+class D {}
+''');
+ expect(cls.mixins, hasLength(1));
+ checkTypeRef(cls.mixins[0], null, null, 'D');
+ }
+
+ test_class_mixin_order() {
+ UnlinkedClass cls = serializeClassText('''
+class C extends Object with D, E {}
+class D {}
+class E {}
+''');
+ expect(cls.mixins, hasLength(2));
+ checkTypeRef(cls.mixins[0], null, null, 'D');
+ checkTypeRef(cls.mixins[1], null, null, 'E');
+ }
+
+ test_class_name() {
+ var classText = 'class C {}';
+ UnlinkedClass cls = serializeClassText(classText);
+ expect(cls.name, 'C');
+ expect(cls.nameOffset, classText.indexOf('C'));
+ }
+
+ test_class_no_flags() {
+ UnlinkedClass cls = serializeClassText('class C {}');
+ expect(cls.isAbstract, false);
+ expect(cls.isMixinApplication, false);
+ }
+
+ test_class_no_interface() {
+ UnlinkedClass cls = serializeClassText('class C {}');
+ expect(cls.interfaces, isEmpty);
+ }
+
+ test_class_no_mixins() {
+ UnlinkedClass cls = serializeClassText('class C {}');
+ expect(cls.mixins, isEmpty);
+ }
+
+ test_class_no_type_param() {
+ UnlinkedClass cls = serializeClassText('class C {}');
+ expect(cls.typeParameters, isEmpty);
+ }
+
+ test_class_non_alias_flag() {
+ UnlinkedClass cls = serializeClassText('class C {}');
+ expect(cls.isMixinApplication, false);
+ }
+
+ test_class_private() {
+ serializeClassText('class _C {}', className: '_C');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_class_reference_generic() {
+ EntityRef typeRef =
+ serializeTypeText('C', otherDeclarations: 'class C<D, E> {}');
+ checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
+ }
+
+ test_class_reference_generic_imported() {
+ addNamedSource('/lib.dart', 'class C<D, E> {}');
+ EntityRef typeRef =
+ serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
+ checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
+ numTypeParameters: 2);
+ }
+
+ test_class_superclass() {
+ UnlinkedClass cls = serializeClassText('class C {}');
+ expect(cls.supertype, isNull);
+ expect(cls.hasNoSupertype, isFalse);
+ }
+
+ test_class_superclass_explicit() {
+ UnlinkedClass cls = serializeClassText('class C extends D {} class D {}');
+ expect(cls.supertype, isNotNull);
+ checkTypeRef(cls.supertype, null, null, 'D');
+ expect(cls.hasNoSupertype, isFalse);
+ }
+
+ test_class_type_param_bound() {
+ UnlinkedClass cls = serializeClassText('class C<T extends List> {}');
+ expect(cls.typeParameters, hasLength(1));
+ expect(cls.typeParameters[0].name, 'T');
+ expect(cls.typeParameters[0].bound, isNotNull);
+ checkTypeRef(cls.typeParameters[0].bound, 'dart:core', 'dart:core', 'List',
+ allowTypeParameters: true, numTypeParameters: 1);
+ }
+
+ test_class_type_param_f_bound() {
+ UnlinkedClass cls = serializeClassText('class C<T, U extends List<T>> {}');
+ EntityRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
+ checkParamTypeRef(typeArgument, 2);
+ }
+
+ test_class_type_param_f_bound_self_ref() {
+ UnlinkedClass cls = serializeClassText('class C<T, U extends List<U>> {}');
+ EntityRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
+ checkParamTypeRef(typeArgument, 1);
+ }
+
+ test_class_type_param_no_bound() {
+ String text = 'class C<T> {}';
+ UnlinkedClass cls = serializeClassText(text);
+ expect(cls.typeParameters, hasLength(1));
+ expect(cls.typeParameters[0].name, 'T');
+ expect(cls.typeParameters[0].nameOffset, text.indexOf('T'));
+ expect(cls.typeParameters[0].bound, isNull);
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
+ }
+
+ test_constExpr_binary_add() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 + 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.add
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_and() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = true && false;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushTrue,
+ UnlinkedConstOperation.pushFalse,
+ UnlinkedConstOperation.and
+ ]);
+ }
+
+ test_constExpr_binary_bitAnd() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 & 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.bitAnd
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_bitOr() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 | 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.bitOr
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_bitShiftLeft() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 << 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.bitShiftLeft
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_bitShiftRight() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 >> 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.bitShiftRight
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_bitXor() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 ^ 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.bitXor
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_divide() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 / 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.divide
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_equal() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 == 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.equal
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_equal_not() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 != 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.equal,
+ UnlinkedConstOperation.not
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_floorDivide() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 ~/ 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.floorDivide
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_greater() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 > 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.greater
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_greaterEqual() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 >= 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.greaterEqual
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_less() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 < 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.less
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_lessEqual() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 <= 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.lessEqual
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_modulo() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 % 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.modulo
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_multiply() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 * 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.multiply
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_binary_or() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = false || true;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushFalse,
+ UnlinkedConstOperation.pushTrue,
+ UnlinkedConstOperation.or
+ ]);
+ }
+
+ test_constExpr_binary_subtract() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1 - 2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.subtract
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_conditional() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = true ? 1 : 2;', allowErrors: true);
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushTrue,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.conditional
+ ], ints: [
+ 1,
+ 2
+ ]);
+ }
+
+ test_constExpr_identical() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = identical(42, null);');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushNull,
+ UnlinkedConstOperation.identical
+ ], ints: [
+ 42
+ ]);
+ }
+
+ test_constExpr_invokeConstructor_named() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {
+ const C.named();
+}
+const v = const C.named();
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'named',
+ expectedKind: ReferenceKind.constructor,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_invokeConstructor_named_imported() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ const C.named();
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = const C.named();
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'named',
+ expectedKind: ReferenceKind.constructor,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_invokeConstructor_named_imported_withPrefix() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ const C.named();
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = const p.C.named();
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'named',
+ expectedKind: ReferenceKind.constructor,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'p',
+ inLibraryDefiningUnit: true)
+ ])
+ ]);
+ }
+
+ test_constExpr_invokeConstructor_unnamed() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {
+ const C(a, b, c, d, {e, f, g});
+}
+const v = const C(11, 22, 3.3, '444', e: 55, g: '777', f: 66);
+''');
+ // Stack: 11 22 3.3 '444' 55 '777' 66 ^head
+ // Ints: ^pointer 3 4
+ // Doubles: ^pointer
+ // Strings: ^pointer 'e' 'g' 'f' ''
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushDouble,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 11,
+ 22,
+ 55,
+ 66,
+ 3,
+ 4,
+ ], doubles: [
+ 3.3
+ ], strings: [
+ '444',
+ '777',
+ 'e',
+ 'g',
+ 'f'
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'C',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_invokeConstructor_unnamed_imported() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ const C();
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = const C();
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'C',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_invokeConstructor_unnamed_imported_withPrefix() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ const C();
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = const p.C();
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'C',
+ expectedKind: ReferenceKind.classOrEnum,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.prefix, 'p',
+ inLibraryDefiningUnit: true)
+ ])
+ ]);
+ }
+
+ test_constExpr_length_classConstField() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {
+ static const int length = 0;
+}
+const int v = C.length;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'length',
+ expectedKind: ReferenceKind.constField,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_length_classConstField_imported_withPrefix() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ static const int length = 0;
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const int v = p.C.length;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'length',
+ expectedKind: ReferenceKind.constField,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+ absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'p',
+ inLibraryDefiningUnit: true)
+ ])
+ ]);
+ }
+
+ test_constExpr_length_identifierTarget() {
+ UnlinkedVariable variable = serializeVariableText('''
+const String a = 'aaa';
+const int v = a.length;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'length',
+ expectedKind: ReferenceKind.length,
+ prefixExpectations: [
+ new _PrefixExpectation(
+ ReferenceKind.topLevelPropertyAccessor, 'a')
+ ])
+ ]);
+ }
+
+ test_constExpr_length_identifierTarget_classConstField() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {
+ static const String F = '';
+}
+const int v = C.F.length;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'length',
+ expectedKind: ReferenceKind.length,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.constField, 'F'),
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+ ])
+ ]);
+ }
+
+ test_constExpr_length_identifierTarget_imported() {
+ addNamedSource(
+ '/a.dart',
+ '''
+const String a = 'aaa';
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const int v = a.length;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'length',
+ expectedKind: ReferenceKind.length,
+ prefixExpectations: [
+ new _PrefixExpectation(
+ ReferenceKind.topLevelPropertyAccessor, 'a',
+ absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
+ ])
+ ]);
+ }
+
+ test_constExpr_length_identifierTarget_imported_withPrefix() {
+ addNamedSource(
+ '/a.dart',
+ '''
+const String a = 'aaa';
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const int v = p.a.length;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'length',
+ expectedKind: ReferenceKind.length,
+ prefixExpectations: [
+ new _PrefixExpectation(
+ ReferenceKind.topLevelPropertyAccessor, 'a',
+ absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'p',
+ inLibraryDefiningUnit: true)
+ ])
+ ]);
+ }
+
+ test_constExpr_length_parenthesizedBinaryTarget() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = ("abc" + "edf").length;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.add,
+ UnlinkedConstOperation.length
+ ], strings: [
+ 'abc',
+ 'edf'
+ ]);
+ }
+
+ test_constExpr_length_parenthesizedStringTarget() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = ("abc").length;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.length
+ ], strings: [
+ 'abc'
+ ]);
+ }
+
+ test_constExpr_length_stringLiteralTarget() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = "abc".length;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.length
+ ], strings: [
+ 'abc'
+ ]);
+ }
+
+ test_constExpr_makeSymbol() {
+ UnlinkedVariable variable = serializeVariableText('const v = #a.bb.ccc;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.makeSymbol
+ ], strings: [
+ 'a.bb.ccc'
+ ]);
+ }
+
+ test_constExpr_makeTypedList() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = const <int>[11, 22, 33];');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.makeTypedList
+ ], ints: [
+ 11,
+ 22,
+ 33,
+ 3
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_makeTypedList_dynamic() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = const <dynamic>[11, 22, 33];');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.makeTypedList
+ ], ints: [
+ 11,
+ 22,
+ 33,
+ 3
+ ], referenceValidators: [
+ (EntityRef r) => checkDynamicTypeRef(r)
+ ]);
+ }
+
+ test_constExpr_makeTypedMap() {
+ UnlinkedVariable variable = serializeVariableText(
+ 'const v = const <int, String>{11: "aaa", 22: "bbb", 33: "ccc"};');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.makeTypedMap
+ ], ints: [
+ 11,
+ 22,
+ 33,
+ 3
+ ], strings: [
+ 'aaa',
+ 'bbb',
+ 'ccc'
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'dart:core', 'String',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_makeTypedMap_dynamic() {
+ UnlinkedVariable variable = serializeVariableText(
+ 'const v = const <dynamic, dynamic>{11: "aaa", 22: "bbb", 33: "ccc"};');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.makeTypedMap
+ ], ints: [
+ 11,
+ 22,
+ 33,
+ 3
+ ], strings: [
+ 'aaa',
+ 'bbb',
+ 'ccc'
+ ], referenceValidators: [
+ (EntityRef r) => checkDynamicTypeRef(r),
+ (EntityRef r) => checkDynamicTypeRef(r)
+ ]);
+ }
+
+ test_constExpr_makeUntypedList() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = const [11, 22, 33];');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.makeUntypedList
+ ], ints: [
+ 11,
+ 22,
+ 33,
+ 3
+ ]);
+ }
+
+ test_constExpr_makeUntypedMap() {
+ UnlinkedVariable variable = serializeVariableText(
+ 'const v = const {11: "aaa", 22: "bbb", 33: "ccc"};');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.makeUntypedMap
+ ], ints: [
+ 11,
+ 22,
+ 33,
+ 3
+ ], strings: [
+ 'aaa',
+ 'bbb',
+ 'ccc'
+ ]);
+ }
+
+ test_constExpr_parenthesized() {
+ UnlinkedVariable variable = serializeVariableText('const v = (1 + 2) * 3;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.add,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.multiply,
+ ], ints: [
+ 1,
+ 2,
+ 3
+ ]);
+ }
+
+ test_constExpr_prefix_complement() {
+ UnlinkedVariable variable = serializeVariableText('const v = ~2;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.complement
+ ], ints: [
+ 2
+ ]);
+ }
+
+ test_constExpr_prefix_negate() {
+ UnlinkedVariable variable = serializeVariableText('const v = -(2);');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.negate
+ ], ints: [
+ 2
+ ]);
+ }
+
+ test_constExpr_prefix_not() {
+ UnlinkedVariable variable = serializeVariableText('const v = !true;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushTrue,
+ UnlinkedConstOperation.not
+ ]);
+ }
+
+ test_constExpr_pushDouble() {
+ UnlinkedVariable variable = serializeVariableText('const v = 123.4567;');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushDouble], doubles: [123.4567]);
+ }
+
+ test_constExpr_pushFalse() {
+ UnlinkedVariable variable = serializeVariableText('const v = false;');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushFalse]);
+ }
+
+ test_constExpr_pushInt() {
+ UnlinkedVariable variable = serializeVariableText('const v = 1;');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+ }
+
+ test_constExpr_pushInt_max() {
+ UnlinkedVariable variable = serializeVariableText('const v = 0xFFFFFFFF;');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushInt,], ints: [0xFFFFFFFF]);
+ }
+
+ test_constExpr_pushInt_negative() {
+ UnlinkedVariable variable = serializeVariableText('const v = -5;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.negate
+ ], ints: [
+ 5
+ ]);
+ }
+
+ test_constExpr_pushInt_shiftOr_long() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = 0xA123456789ABCDEF012345678;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.shiftOr,
+ UnlinkedConstOperation.shiftOr,
+ UnlinkedConstOperation.shiftOr
+ ], ints: [
+ 0xA,
+ 0x12345678,
+ 0x9ABCDEF0,
+ 0x12345678
+ ]);
+ }
+
+ test_constExpr_pushInt_shiftOr_min() {
+ UnlinkedVariable variable = serializeVariableText('const v = 0x100000000;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.shiftOr,
+ ], ints: [
+ 1,
+ 0,
+ ]);
+ }
+
+ test_constExpr_pushInt_shiftOr_min2() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = 0x10000000000000000;');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.shiftOr,
+ UnlinkedConstOperation.shiftOr,
+ ], ints: [
+ 1,
+ 0,
+ 0,
+ ]);
+ }
+
+ test_constExpr_pushNull() {
+ UnlinkedVariable variable = serializeVariableText('const v = null;');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushNull]);
+ }
+
+ test_constExpr_pushReference_class() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {}
+const v = C;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'C',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_pushReference_enum() {
+ UnlinkedVariable variable = serializeVariableText('''
+enum C {V1, V2, V3}
+const v = C;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'C',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_pushReference_field() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {
+ static const int F = 1;
+}
+const v = C.F;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'F',
+ expectedKind: ReferenceKind.constField,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_field_imported() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ static const int F = 1;
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = C.F;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'F',
+ expectedKind: ReferenceKind.constField,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_field_imported_withPrefix() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ static const int F = 1;
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.C.F;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'F',
+ expectedKind: ReferenceKind.constField,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'p',
+ inLibraryDefiningUnit: true),
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_staticMethod() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {
+ static m() {}
+}
+const v = C.m;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'm',
+ expectedKind: ReferenceKind.staticMethod,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_staticMethod_imported() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ static m() {}
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = C.m;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'm',
+ expectedKind: ReferenceKind.staticMethod,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_staticMethod_imported_withPrefix() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ static m() {}
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.C.m;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'm',
+ expectedKind: ReferenceKind.staticMethod,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'p',
+ inLibraryDefiningUnit: true)
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_topLevelVariable() {
+ UnlinkedVariable variable = serializeVariableText('''
+const int a = 1;
+const v = a;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'a',
+ expectedKind: ReferenceKind.topLevelPropertyAccessor)
+ ]);
+ }
+
+ test_constExpr_pushReference_topLevelVariable_imported() {
+ addNamedSource('/a.dart', 'const int a = 1;');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = a;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'a',
+ expectedKind: ReferenceKind.topLevelPropertyAccessor)
+ ]);
+ }
+
+ test_constExpr_pushReference_topLevelVariable_imported_withPrefix() {
+ addNamedSource('/a.dart', 'const int a = 1;');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.a;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) {
+ return checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'a',
+ expectedKind: ReferenceKind.topLevelPropertyAccessor,
+ expectedPrefix: 'p');
+ }
+ ]);
+ }
+
+ test_constExpr_pushString_adjacent() {
+ UnlinkedVariable variable =
+ serializeVariableText('const v = "aaa" "b" "ccc";');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushString], strings: ['aaabccc']);
+ }
+
+ test_constExpr_pushString_adjacent_interpolation() {
+ UnlinkedVariable variable =
+ serializeVariableText(r'const v = "aaa" "bb ${42} bbb" "cccc";');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.concatenate,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.concatenate,
+ ], ints: [
+ 42,
+ 3,
+ 3,
+ ], strings: [
+ 'aaa',
+ 'bb ',
+ ' bbb',
+ 'cccc'
+ ]);
+ }
+
+ test_constExpr_pushString_interpolation() {
+ UnlinkedVariable variable =
+ serializeVariableText(r'const v = "aaa ${42} bbb";');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.pushInt,
+ UnlinkedConstOperation.pushString,
+ UnlinkedConstOperation.concatenate
+ ], ints: [
+ 42,
+ 3
+ ], strings: [
+ 'aaa ',
+ ' bbb'
+ ]);
+ }
+
+ test_constExpr_pushString_simple() {
+ UnlinkedVariable variable = serializeVariableText('const v = "abc";');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushString], strings: ['abc']);
+ }
+
+ test_constExpr_pushTrue() {
+ UnlinkedVariable variable = serializeVariableText('const v = true;');
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushTrue]);
+ }
+
+ test_constructor() {
+ String text = 'class C { C(); }';
+ UnlinkedExecutable executable =
+ findExecutable('', executables: serializeClassText(text).executables);
+ expect(executable.kind, UnlinkedExecutableKind.constructor);
+ expect(executable.returnType, isNull);
+ expect(executable.isExternal, isFalse);
+ expect(executable.nameOffset, text.indexOf('C();'));
+ }
+
+ test_constructor_anonymous() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(); }').executables);
+ expect(executable.name, isEmpty);
+ }
+
+ test_constructor_const() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { const C(); }').executables);
+ expect(executable.isConst, isTrue);
+ expect(executable.isExternal, isFalse);
+ }
+
+ test_constructor_const_external() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { external const C(); }').executables);
+ expect(executable.isConst, isTrue);
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_constructor_documented() {
+ String text = '''
+class C {
+ /**
+ * Docs
+ */
+ C();
+}''';
+ UnlinkedExecutable executable = serializeClassText(text).executables[0];
+ expect(executable.documentationComment, isNotNull);
+ checkDocumentationComment(executable.documentationComment, text);
+ }
+
+ test_constructor_external() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { external C(); }').executables);
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_constructor_factory() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { factory C() => null; }').executables);
+ expect(executable.isFactory, isTrue);
+ }
+
+ test_constructor_implicit() {
+ // Implicit constructors are not serialized.
+ UnlinkedExecutable executable = findExecutable(null,
+ executables: serializeClassText('class C { C(); }').executables,
+ failIfAbsent: false);
+ expect(executable, isNull);
+ }
+
+ test_constructor_initializing_formal() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { C(this.x); final x; }').executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.isInitializingFormal, isTrue);
+ }
+
+ test_constructor_initializing_formal_explicit_type() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(int this.x); final x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_constructor_initializing_formal_function_typed() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(this.x()); final x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.isFunctionTyped, isTrue);
+ }
+
+ test_constructor_initializing_formal_function_typed_explicit_return_type() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { C(int this.x()); Function x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_constructor_initializing_formal_function_typed_implicit_return_type() {
+ if (!checkAstDerivedData) {
+ // TODO(paulberry): this test fails when building the summary from the
+ // element model because the elment model doesn't record whether a
+ // function-typed parameter's return type is implicit.
+ return;
+ }
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(this.x()); Function x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.isFunctionTyped, isTrue);
+ expect(parameter.type, isNull);
+ }
+
+ test_constructor_initializing_formal_function_typed_no_parameters() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(this.x()); final x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.parameters, isEmpty);
+ }
+
+ test_constructor_initializing_formal_function_typed_parameter() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(this.x(a)); final x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.parameters, hasLength(1));
+ }
+
+ test_constructor_initializing_formal_function_typed_parameter_order() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(this.x(a, b)); final x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.parameters, hasLength(2));
+ expect(parameter.parameters[0].name, 'a');
+ expect(parameter.parameters[1].name, 'b');
+ }
+
+ test_constructor_initializing_formal_implicit_type() {
+ // Note: the implicit type of an initializing formal is the type of the
+ // field.
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { C(this.x); int x; }').executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.type, isNull);
+ }
+
+ test_constructor_initializing_formal_name() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { C(this.x); final x; }').executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.name, 'x');
+ }
+
+ test_constructor_initializing_formal_named() {
+ // TODO(paulberry): also test default value
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C({this.x}); final x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.kind, UnlinkedParamKind.named);
+ }
+
+ test_constructor_initializing_formal_non_function_typed() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { C(this.x); final x; }').executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.isFunctionTyped, isFalse);
+ }
+
+ test_constructor_initializing_formal_positional() {
+ // TODO(paulberry): also test default value
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C([this.x]); final x; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.kind, UnlinkedParamKind.positional);
+ }
+
+ test_constructor_initializing_formal_required() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables:
+ serializeClassText('class C { C(this.x); final x; }').executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.kind, UnlinkedParamKind.required);
+ }
+
+ test_constructor_initializing_formal_typedef() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText(
+ 'typedef F<T>(T x); class C<X> { C(this.f); F<X> f; }')
+ .executables);
+ UnlinkedParam parameter = executable.parameters[0];
+ expect(parameter.isFunctionTyped, isFalse);
+ expect(parameter.parameters, isEmpty);
+ }
+
+ test_constructor_named() {
+ String text = 'class C { C.foo(); }';
+ UnlinkedExecutable executable = findExecutable('foo',
+ executables: serializeClassText(text).executables);
+ expect(executable.name, 'foo');
+ expect(executable.nameOffset, text.indexOf('foo'));
+ }
+
+ test_constructor_non_const() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(); }').executables);
+ expect(executable.isConst, isFalse);
+ }
+
+ test_constructor_non_factory() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(); }').executables);
+ expect(executable.isFactory, isFalse);
+ }
+
+ test_constructor_param_inferred_type_explicit() {
+ UnlinkedExecutable ctor =
+ serializeClassText('class C { C(int v); }').executables[0];
+ expect(ctor.kind, UnlinkedExecutableKind.constructor);
+ expect(ctor.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_constructor_param_inferred_type_implicit() {
+ UnlinkedExecutable ctor =
+ serializeClassText('class C { C(v); }').executables[0];
+ expect(ctor.kind, UnlinkedExecutableKind.constructor);
+ expect(ctor.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_constructor_return_type() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C { C(); }').executables);
+ expect(executable.returnType, isNull);
+ }
+
+ test_constructor_return_type_parameterized() {
+ UnlinkedExecutable executable = findExecutable('',
+ executables: serializeClassText('class C<T, U> { C(); }').executables);
+ expect(executable.returnType, isNull);
+ }
+
+ test_dependencies_export_to_export_unused() {
+ addNamedSource('/a.dart', 'export "b.dart";');
+ addNamedSource('/b.dart', '');
+ serializeLibraryText('export "a.dart";');
+ // The main test library depends on b.dart, even though it doesn't
+ // re-export any names defined in b.dart, because a change to b.dart might
+ // cause it to start exporting a name that the main test library *does*
+ // use.
+ checkHasDependency(absUri('/b.dart'), 'b.dart');
+ }
+
+ test_dependencies_export_unused() {
+ addNamedSource('/a.dart', '');
+ serializeLibraryText('export "a.dart";');
+ // The main test library depends on a.dart, even though it doesn't
+ // re-export any names defined in a.dart, because a change to a.dart might
+ // cause it to start exporting a name that the main test library *will*
+ // re-export.
+ checkHasDependency(absUri('/a.dart'), 'a.dart');
+ }
+
+ test_dependencies_import_to_export() {
+ addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
+ addNamedSource('/b.dart', 'library b;');
+ serializeLibraryText('import "a.dart"; A a;');
+ checkHasDependency(absUri('/a.dart'), 'a.dart');
+ // The main test library depends on b.dart, because names defined in
+ // b.dart are exported by a.dart.
+ checkHasDependency(absUri('/b.dart'), 'b.dart');
+ }
+
+ test_dependencies_import_to_export_in_subdirs_absolute_export() {
+ addNamedSource('/a/a.dart',
+ 'library a; export "${absUri('/a/b/b.dart')}"; class A {}');
+ addNamedSource('/a/b/b.dart', 'library b;');
+ serializeLibraryText('import "a/a.dart"; A a;');
+ checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
+ // The main test library depends on b.dart, because names defined in
+ // b.dart are exported by a.dart.
+ checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
+ }
+
+ test_dependencies_import_to_export_in_subdirs_absolute_import() {
+ addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
+ addNamedSource('/a/b/b.dart', 'library b;');
+ serializeLibraryText('import "${absUri('/a/a.dart')}"; A a;');
+ checkHasDependency(absUri('/a/a.dart'), absUri('/a/a.dart'));
+ // The main test library depends on b.dart, because names defined in
+ // b.dart are exported by a.dart.
+ checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
+ }
+
+ test_dependencies_import_to_export_in_subdirs_relative() {
+ addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
+ addNamedSource('/a/b/b.dart', 'library b;');
+ serializeLibraryText('import "a/a.dart"; A a;');
+ checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
+ // The main test library depends on b.dart, because names defined in
+ // b.dart are exported by a.dart.
+ checkHasDependency(absUri('/a/b/b.dart'), 'a/b/b.dart');
+ }
+
+ test_dependencies_import_to_export_loop() {
+ addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
+ addNamedSource('/b.dart', 'library b; export "a.dart";');
+ serializeLibraryText('import "a.dart"; A a;');
+ checkHasDependency(absUri('/a.dart'), 'a.dart');
+ // Serialization should have been able to walk the transitive export
+ // dependencies to b.dart without going into an infinite loop.
+ checkHasDependency(absUri('/b.dart'), 'b.dart');
+ }
+
+ test_dependencies_import_to_export_transitive_closure() {
+ addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
+ addNamedSource('/b.dart', 'library b; export "c.dart";');
+ addNamedSource('/c.dart', 'library c;');
+ serializeLibraryText('import "a.dart"; A a;');
+ checkHasDependency(absUri('/a.dart'), 'a.dart');
+ // The main test library depends on c.dart, because names defined in
+ // c.dart are exported by b.dart and then re-exported by a.dart.
+ checkHasDependency(absUri('/c.dart'), 'c.dart');
+ }
+
+ test_dependencies_import_to_export_unused() {
+ addNamedSource('/a.dart', 'export "b.dart";');
+ addNamedSource('/b.dart', '');
+ serializeLibraryText('import "a.dart";', allowErrors: true);
+ // The main test library depends on b.dart, even though it doesn't use any
+ // names defined in b.dart, because a change to b.dart might cause it to
+ // start exporting a name that the main test library *does* use.
+ checkHasDependency(absUri('/b.dart'), 'b.dart');
+ }
+
+ test_dependencies_import_transitive_closure() {
+ addNamedSource(
+ '/a.dart', 'library a; import "b.dart"; class A extends B {}');
+ addNamedSource('/b.dart', 'library b; class B {}');
+ serializeLibraryText('import "a.dart"; A a;');
+ checkHasDependency(absUri('/a.dart'), 'a.dart');
+ // The main test library doesn't depend on b.dart, because no change to
+ // b.dart can possibly affect the serialized element model for it.
+ checkLacksDependency(absUri('/b.dart'), 'b.dart');
+ }
+
+ test_dependencies_import_unused() {
+ addNamedSource('/a.dart', '');
+ serializeLibraryText('import "a.dart";', allowErrors: true);
+ // The main test library depends on a.dart, even though it doesn't use any
+ // names defined in a.dart, because a change to a.dart might cause it to
+ // start exporting a name that the main test library *does* use.
+ checkHasDependency(absUri('/a.dart'), 'a.dart');
+ }
+
+ test_dependencies_parts() {
+ addNamedSource(
+ '/a.dart', 'library a; part "b.dart"; part "c.dart"; class A {}');
+ addNamedSource('/b.dart', 'part of a;');
+ addNamedSource('/c.dart', 'part of a;');
+ serializeLibraryText('import "a.dart"; A a;');
+ int dep = checkHasDependency(absUri('/a.dart'), 'a.dart');
+ checkDependencyParts(linked.dependencies[dep],
+ [absUri('/b.dart'), absUri('/c.dart')], ['b.dart', 'c.dart']);
+ }
+
+ test_dependencies_parts_relative_to_importing_library() {
+ addNamedSource('/a/b.dart', 'export "c/d.dart";');
+ addNamedSource('/a/c/d.dart',
+ 'library d; part "e/f.dart"; part "g/h.dart"; class D {}');
+ addNamedSource('/a/c/e/f.dart', 'part of d;');
+ addNamedSource('/a/c/g/h.dart', 'part of d;');
+ serializeLibraryText('import "a/b.dart"; D d;');
+ int dep = checkHasDependency(absUri('/a/c/d.dart'), 'a/c/d.dart');
+ checkDependencyParts(
+ linked.dependencies[dep],
+ [absUri('/a/c/e/f.dart'), absUri('/a/c/g/h.dart')],
+ ['a/c/e/f.dart', 'a/c/g/h.dart']);
+ }
+
+ test_elements_in_part() {
+ addNamedSource(
+ '/part1.dart',
+ '''
+part of my.lib;
+
+class C {}
+enum E { v }
+var v;
+f() {}
+typedef F();
+''');
+ serializeLibraryText('library my.lib; part "part1.dart";');
+ UnlinkedUnit unit = unlinkedUnits[1];
+ expect(findClass('C', unit: unit), isNotNull);
+ expect(findEnum('E', unit: unit), isNotNull);
+ expect(findVariable('v', variables: unit.variables), isNotNull);
+ expect(findExecutable('f', executables: unit.executables), isNotNull);
+ expect(findTypedef('F', unit: unit), isNotNull);
+ }
+
+ test_enum() {
+ String text = 'enum E { v1 }';
+ UnlinkedEnum e = serializeEnumText(text);
+ expect(e.name, 'E');
+ expect(e.nameOffset, text.indexOf('E'));
+ expect(e.values, hasLength(1));
+ expect(e.values[0].name, 'v1');
+ expect(e.values[0].nameOffset, text.indexOf('v1'));
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+ ReferenceKind.classOrEnum);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'E');
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+ }
+
+ test_enum_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+enum E { v }''';
+ UnlinkedEnum enm = serializeEnumText(text);
+ expect(enm.documentationComment, isNotNull);
+ checkDocumentationComment(enm.documentationComment, text);
+ }
+
+ test_enum_order() {
+ UnlinkedEnum e = serializeEnumText('enum E { v1, v2 }');
+ expect(e.values, hasLength(2));
+ expect(e.values[0].name, 'v1');
+ expect(e.values[1].name, 'v2');
+ }
+
+ test_enum_private() {
+ serializeEnumText('enum _E { v1 }', '_E');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_executable_abstract() {
+ UnlinkedExecutable executable =
+ serializeClassText('abstract class C { f(); }').executables[0];
+ expect(executable.isAbstract, isTrue);
+ }
+
+ test_executable_concrete() {
+ UnlinkedExecutable executable =
+ serializeClassText('abstract class C { f() {} }').executables[0];
+ expect(executable.isAbstract, isFalse);
+ }
+
+ test_executable_function() {
+ String text = ' f() {}';
+ UnlinkedExecutable executable = serializeExecutableText(text);
+ expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+ expect(executable.returnType, isNull);
+ expect(executable.isExternal, isFalse);
+ expect(executable.nameOffset, text.indexOf('f'));
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+ ReferenceKind.topLevelFunction);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+ }
+
+ test_executable_function_explicit_return() {
+ UnlinkedExecutable executable =
+ serializeExecutableText('dynamic f() => null;');
+ checkDynamicTypeRef(executable.returnType);
+ }
+
+ test_executable_function_external() {
+ UnlinkedExecutable executable = serializeExecutableText('external f();');
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_executable_function_private() {
+ serializeExecutableText('_f() {}', '_f');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_executable_getter() {
+ String text = 'int get f => 1;';
+ UnlinkedExecutable executable = serializeExecutableText(text);
+ expect(executable.kind, UnlinkedExecutableKind.getter);
+ expect(executable.returnType, isNotNull);
+ expect(executable.isExternal, isFalse);
+ expect(executable.nameOffset, text.indexOf('f'));
+ expect(findVariable('f'), isNull);
+ expect(findExecutable('f='), isNull);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+ ReferenceKind.topLevelPropertyAccessor);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
+ }
+
+ test_executable_getter_external() {
+ UnlinkedExecutable executable =
+ serializeExecutableText('external int get f;');
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_executable_getter_private() {
+ serializeExecutableText('int get _f => 1;', '_f');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_executable_getter_type() {
+ UnlinkedExecutable executable = serializeExecutableText('int get f => 1;');
+ checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
+ expect(executable.parameters, isEmpty);
+ }
+
+ test_executable_getter_type_implicit() {
+ UnlinkedExecutable executable = serializeExecutableText('get f => 1;');
+ expect(executable.returnType, isNull);
+ expect(executable.parameters, isEmpty);
+ }
+
+ test_executable_member_function() {
+ UnlinkedExecutable executable = findExecutable('f',
+ executables: serializeClassText('class C { f() {} }').executables);
+ expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+ expect(executable.returnType, isNull);
+ expect(executable.isExternal, isFalse);
+ }
+
+ test_executable_member_function_explicit_return() {
+ UnlinkedExecutable executable = findExecutable('f',
+ executables:
+ serializeClassText('class C { dynamic f() => null; }').executables);
+ expect(executable.returnType, isNotNull);
+ }
+
+ test_executable_member_function_external() {
+ UnlinkedExecutable executable = findExecutable('f',
+ executables:
+ serializeClassText('class C { external f(); }').executables);
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_executable_member_getter() {
+ UnlinkedClass cls = serializeClassText('class C { int get f => 1; }');
+ UnlinkedExecutable executable =
+ findExecutable('f', executables: cls.executables, failIfAbsent: true);
+ expect(executable.kind, UnlinkedExecutableKind.getter);
+ expect(executable.returnType, isNotNull);
+ expect(executable.isExternal, isFalse);
+ expect(findVariable('f', variables: cls.fields), isNull);
+ expect(findExecutable('f=', executables: cls.executables), isNull);
+ }
+
+ test_executable_member_getter_external() {
+ UnlinkedClass cls = serializeClassText('class C { external int get f; }');
+ UnlinkedExecutable executable =
+ findExecutable('f', executables: cls.executables, failIfAbsent: true);
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_executable_member_setter() {
+ UnlinkedClass cls = serializeClassText('class C { void set f(value) {} }');
+ UnlinkedExecutable executable =
+ findExecutable('f=', executables: cls.executables, failIfAbsent: true);
+ expect(executable.kind, UnlinkedExecutableKind.setter);
+ expect(executable.returnType, isNotNull);
+ expect(executable.isExternal, isFalse);
+ expect(findVariable('f', variables: cls.fields), isNull);
+ expect(findExecutable('f', executables: cls.executables), isNull);
+ }
+
+ test_executable_member_setter_external() {
+ UnlinkedClass cls =
+ serializeClassText('class C { external void set f(value); }');
+ UnlinkedExecutable executable =
+ findExecutable('f=', executables: cls.executables, failIfAbsent: true);
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_executable_member_setter_implicit_return() {
+ UnlinkedClass cls = serializeClassText('class C { set f(value) {} }');
+ UnlinkedExecutable executable =
+ findExecutable('f=', executables: cls.executables, failIfAbsent: true);
+ expect(executable.returnType, isNull);
+ }
+
+ test_executable_name() {
+ UnlinkedExecutable executable = serializeExecutableText('f() {}');
+ expect(executable.name, 'f');
+ }
+
+ test_executable_no_flags() {
+ UnlinkedExecutable executable = serializeExecutableText('f() {}');
+ expect(executable.isAbstract, isFalse);
+ expect(executable.isConst, isFalse);
+ expect(executable.isFactory, isFalse);
+ expect(executable.isStatic, isFalse);
+ }
+
+ test_executable_non_static() {
+ UnlinkedExecutable executable =
+ serializeClassText('class C { f() {} }').executables[0];
+ expect(executable.isStatic, isFalse);
+ }
+
+ test_executable_non_static_top_level() {
+ // Top level executables are considered non-static.
+ UnlinkedExecutable executable = serializeExecutableText('f() {}');
+ expect(executable.isStatic, isFalse);
+ }
+
+ test_executable_operator() {
+ UnlinkedExecutable executable =
+ serializeClassText('class C { C operator+(C c) => null; }').executables[
+ 0];
+ expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+ expect(executable.name, '+');
+ expect(executable.returnType, isNotNull);
+ expect(executable.isAbstract, false);
+ expect(executable.isConst, false);
+ expect(executable.isFactory, false);
+ expect(executable.isStatic, false);
+ expect(executable.parameters, hasLength(1));
+ checkTypeRef(executable.returnType, null, null, 'C');
+ expect(executable.typeParameters, isEmpty);
+ expect(executable.isExternal, false);
+ }
+
+ test_executable_operator_equal() {
+ UnlinkedExecutable executable = serializeClassText(
+ 'class C { bool operator==(Object other) => false; }')
+ .executables[0];
+ expect(executable.name, '==');
+ }
+
+ test_executable_operator_external() {
+ UnlinkedExecutable executable =
+ serializeClassText('class C { external C operator+(C c); }')
+ .executables[0];
+ expect(executable.isExternal, true);
+ }
+
+ test_executable_operator_greater_equal() {
+ UnlinkedExecutable executable =
+ serializeClassText('class C { bool operator>=(C other) => false; }')
+ .executables[0];
+ expect(executable.name, '>=');
+ }
+
+ test_executable_operator_index() {
+ UnlinkedExecutable executable =
+ serializeClassText('class C { bool operator[](int i) => null; }')
+ .executables[0];
+ expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+ expect(executable.name, '[]');
+ expect(executable.returnType, isNotNull);
+ expect(executable.isAbstract, false);
+ expect(executable.isConst, false);
+ expect(executable.isFactory, false);
+ expect(executable.isStatic, false);
+ expect(executable.parameters, hasLength(1));
+ checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'bool');
+ expect(executable.typeParameters, isEmpty);
+ }
+
+ test_executable_operator_index_set() {
+ UnlinkedExecutable executable = serializeClassText(
+ 'class C { void operator[]=(int i, bool v) => null; }')
+ .executables[0];
+ expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+ expect(executable.name, '[]=');
+ expect(executable.returnType, isNotNull);
+ expect(executable.isAbstract, false);
+ expect(executable.isConst, false);
+ expect(executable.isFactory, false);
+ expect(executable.isStatic, false);
+ expect(executable.parameters, hasLength(2));
+ checkVoidTypeRef(executable.returnType);
+ expect(executable.typeParameters, isEmpty);
+ }
+
+ test_executable_operator_less_equal() {
+ UnlinkedExecutable executable =
+ serializeClassText('class C { bool operator<=(C other) => false; }')
+ .executables[0];
+ expect(executable.name, '<=');
+ }
+
+ test_executable_param_function_typed() {
+ if (!checkAstDerivedData) {
+ // TODO(paulberry): this test fails when building the summary from the
+ // element model because the elment model doesn't record whether a
+ // function-typed parameter's return type is implicit.
+ return;
+ }
+ UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
+ expect(executable.parameters[0].isFunctionTyped, isTrue);
+ expect(executable.parameters[0].type, isNull);
+ }
+
+ test_executable_param_function_typed_explicit_return_type() {
+ UnlinkedExecutable executable =
+ serializeExecutableText('f(dynamic g()) {}');
+ expect(executable.parameters[0].type, isNotNull);
+ }
+
+ test_executable_param_function_typed_param() {
+ UnlinkedExecutable executable = serializeExecutableText('f(g(x)) {}');
+ expect(executable.parameters[0].parameters, hasLength(1));
+ }
+
+ test_executable_param_function_typed_param_none() {
+ UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
+ expect(executable.parameters[0].parameters, isEmpty);
+ }
+
+ test_executable_param_function_typed_param_order() {
+ UnlinkedExecutable executable = serializeExecutableText('f(g(x, y)) {}');
+ expect(executable.parameters[0].parameters, hasLength(2));
+ expect(executable.parameters[0].parameters[0].name, 'x');
+ expect(executable.parameters[0].parameters[1].name, 'y');
+ }
+
+ test_executable_param_function_typed_return_type() {
+ UnlinkedExecutable executable = serializeExecutableText('f(int g()) {}');
+ checkTypeRef(
+ executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_executable_param_function_typed_return_type_implicit() {
+ if (!checkAstDerivedData) {
+ // TODO(paulberry): this test fails when building the summary from the
+ // element model because the elment model doesn't record whether a
+ // function-typed parameter's return type is implicit.
+ return;
+ }
+ UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
+ expect(executable.parameters[0].isFunctionTyped, isTrue);
+ expect(executable.parameters[0].type, isNull);
+ }
+
+ test_executable_param_function_typed_return_type_void() {
+ UnlinkedExecutable executable = serializeExecutableText('f(void g()) {}');
+ checkVoidTypeRef(executable.parameters[0].type);
+ }
+
+ test_executable_param_kind_named() {
+ UnlinkedExecutable executable = serializeExecutableText('f({x}) {}');
+ expect(executable.parameters[0].kind, UnlinkedParamKind.named);
+ }
+
+ test_executable_param_kind_positional() {
+ UnlinkedExecutable executable = serializeExecutableText('f([x]) {}');
+ expect(executable.parameters[0].kind, UnlinkedParamKind.positional);
+ }
+
+ test_executable_param_kind_required() {
+ UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
+ expect(executable.parameters[0].kind, UnlinkedParamKind.required);
+ }
+
+ test_executable_param_name() {
+ String text = 'f(x) {}';
+ UnlinkedExecutable executable = serializeExecutableText(text);
+ expect(executable.parameters, hasLength(1));
+ expect(executable.parameters[0].name, 'x');
+ expect(executable.parameters[0].nameOffset, text.indexOf('x'));
+ }
+
+ test_executable_param_no_flags() {
+ UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
+ expect(executable.parameters[0].isFunctionTyped, isFalse);
+ expect(executable.parameters[0].isInitializingFormal, isFalse);
+ }
+
+ test_executable_param_non_function_typed() {
+ UnlinkedExecutable executable = serializeExecutableText('f(g) {}');
+ expect(executable.parameters[0].isFunctionTyped, isFalse);
+ }
+
+ test_executable_param_none() {
+ UnlinkedExecutable executable = serializeExecutableText('f() {}');
+ expect(executable.parameters, isEmpty);
+ }
+
+ test_executable_param_order() {
+ UnlinkedExecutable executable = serializeExecutableText('f(x, y) {}');
+ expect(executable.parameters, hasLength(2));
+ expect(executable.parameters[0].name, 'x');
+ expect(executable.parameters[1].name, 'y');
+ }
+
+ test_executable_param_type_explicit() {
+ UnlinkedExecutable executable = serializeExecutableText('f(dynamic x) {}');
+ checkDynamicTypeRef(executable.parameters[0].type);
+ }
+
+ test_executable_param_type_implicit() {
+ UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
+ expect(executable.parameters[0].type, isNull);
+ }
+
+ test_executable_return_type() {
+ UnlinkedExecutable executable = serializeExecutableText('int f() => 1;');
+ checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_executable_return_type_implicit() {
+ UnlinkedExecutable executable = serializeExecutableText('f() {}');
+ expect(executable.returnType, isNull);
+ }
+
+ test_executable_return_type_void() {
+ UnlinkedExecutable executable = serializeExecutableText('void f() {}');
+ checkVoidTypeRef(executable.returnType);
+ }
+
+ test_executable_setter() {
+ String text = 'void set f(value) {}';
+ UnlinkedExecutable executable = serializeExecutableText(text, 'f=');
+ expect(executable.kind, UnlinkedExecutableKind.setter);
+ expect(executable.returnType, isNotNull);
+ expect(executable.isExternal, isFalse);
+ expect(executable.nameOffset, text.indexOf('f'));
+ expect(findVariable('f'), isNull);
+ expect(findExecutable('f'), isNull);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+ ReferenceKind.topLevelPropertyAccessor);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f=');
+ }
+
+ test_executable_setter_external() {
+ UnlinkedExecutable executable =
+ serializeExecutableText('external void set f(value);', 'f=');
+ expect(executable.isExternal, isTrue);
+ }
+
+ test_executable_setter_implicit_return() {
+ UnlinkedExecutable executable =
+ serializeExecutableText('set f(value) {}', 'f=');
+ expect(executable.returnType, isNull);
+ }
+
+ test_executable_setter_private() {
+ serializeExecutableText('void set _f(value) {}', '_f=');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_executable_setter_type() {
+ UnlinkedExecutable executable =
+ serializeExecutableText('void set f(int value) {}', 'f=');
+ checkVoidTypeRef(executable.returnType);
+ expect(executable.parameters, hasLength(1));
+ expect(executable.parameters[0].name, 'value');
+ checkTypeRef(
+ executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_executable_static() {
+ UnlinkedExecutable executable =
+ serializeClassText('class C { static f() {} }').executables[0];
+ expect(executable.isStatic, isTrue);
+ }
+
+ test_executable_type_param_f_bound_function() {
+ UnlinkedExecutable ex =
+ serializeExecutableText('void f<T, U extends List<T>>() {}');
+ EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+ checkParamTypeRef(typeArgument, 2);
+ }
+
+ test_executable_type_param_f_bound_method() {
+ UnlinkedExecutable ex =
+ serializeMethodText('void f<T, U extends List<T>>() {}');
+ EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+ checkParamTypeRef(typeArgument, 2);
+ }
+
+ test_executable_type_param_f_bound_self_ref_function() {
+ UnlinkedExecutable ex =
+ serializeExecutableText('void f<T, U extends List<U>>() {}');
+ EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+ checkParamTypeRef(typeArgument, 1);
+ }
+
+ test_executable_type_param_f_bound_self_ref_method() {
+ UnlinkedExecutable ex =
+ serializeMethodText('void f<T, U extends List<U>>() {}');
+ EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+ checkParamTypeRef(typeArgument, 1);
+ }
+
+ test_executable_type_param_in_parameter_function() {
+ UnlinkedExecutable ex = serializeExecutableText('void f<T>(T t) {}');
+ checkParamTypeRef(ex.parameters[0].type, 1);
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
+ }
+
+ test_executable_type_param_in_parameter_method() {
+ UnlinkedExecutable ex = serializeMethodText('void f<T>(T t) {}');
+ checkParamTypeRef(ex.parameters[0].type, 1);
+ }
+
+ test_executable_type_param_in_return_type_function() {
+ UnlinkedExecutable ex = serializeExecutableText('T f<T>() => null;');
+ checkParamTypeRef(ex.returnType, 1);
+ }
+
+ test_executable_type_param_in_return_type_method() {
+ UnlinkedExecutable ex = serializeMethodText('T f<T>() => null;');
+ checkParamTypeRef(ex.returnType, 1);
+ }
+
+ test_export_class() {
+ addNamedSource('/a.dart', 'class C {}');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'C',
+ ReferenceKind.classOrEnum);
+ }
+
+ test_export_class_alias() {
+ addNamedSource(
+ '/a.dart', 'class C extends _D with _E {} class _D {} class _E {}');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'C',
+ ReferenceKind.classOrEnum);
+ }
+
+ test_export_enum() {
+ addNamedSource('/a.dart', 'enum E { v }');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'E',
+ ReferenceKind.classOrEnum);
+ }
+
+ test_export_from_part() {
+ addNamedSource('/a.dart', 'library foo; part "b.dart";');
+ addNamedSource('/b.dart', 'part of foo; f() {}');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+ ReferenceKind.topLevelFunction,
+ expectedTargetUnit: 1);
+ }
+
+ test_export_function() {
+ addNamedSource('/a.dart', 'f() {}');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+ ReferenceKind.topLevelFunction);
+ }
+
+ test_export_getter() {
+ addNamedSource('/a.dart', 'get f => null');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+ ReferenceKind.topLevelPropertyAccessor);
+ }
+
+ test_export_hide() {
+ addNamedSource('/a.dart', 'f() {} g() {}');
+ serializeLibraryText('export "a.dart" hide g;');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+ ReferenceKind.topLevelFunction);
+ }
+
+ test_export_hide_order() {
+ serializeLibraryText('export "dart:async" hide Future, Stream;');
+ expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+ expect(
+ unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
+ isEmpty);
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
+ hasLength(2));
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[0],
+ 'Future');
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[1],
+ 'Stream');
+ expect(linked.exportNames, isNotEmpty);
+ }
+
+ test_export_names_excludes_names_from_library() {
+ addNamedSource('/a.dart', 'part of my.lib; int y; int _y;');
+ serializeLibraryText('library my.lib; part "a.dart"; int x; int _x;');
+ expect(linked.exportNames, isEmpty);
+ }
+
+ test_export_no_combinators() {
+ serializeLibraryText('export "dart:async";');
+ expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators, isEmpty);
+ }
+
+ test_export_not_shadowed_by_prefix() {
+ addNamedSource('/a.dart', 'f() {}');
+ serializeLibraryText('export "a.dart"; import "dart:core" as f; f.int _x;');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+ ReferenceKind.topLevelFunction);
+ }
+
+ test_export_offset() {
+ String libraryText = ' export "dart:async";';
+ serializeLibraryText(libraryText);
+ expect(unlinkedUnits[0].exports[0].uriOffset,
+ libraryText.indexOf('"dart:async"'));
+ expect(unlinkedUnits[0].exports[0].uriEnd, libraryText.indexOf(';'));
+ expect(unlinkedUnits[0].exports[0].offset, libraryText.indexOf('export'));
+ }
+
+ test_export_private() {
+ // Private names should not be exported.
+ addNamedSource('/a.dart', '_f() {}');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, isEmpty);
+ }
+
+ test_export_setter() {
+ addNamedSource('/a.dart', 'void set f(value) {}');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f=',
+ ReferenceKind.topLevelPropertyAccessor);
+ }
+
+ test_export_shadowed() {
+ // f() is not shown in exportNames because it is already defined at top
+ // level in the library.
+ addNamedSource('/a.dart', 'f() {}');
+ serializeLibraryText('export "a.dart"; f() {}');
+ expect(linked.exportNames, isEmpty);
+ }
+
+ test_export_shadowed_variable() {
+ // Neither `v` nor `v=` is shown in exportNames because both are defined at
+ // top level in the library by the declaration `var v;`.
+ addNamedSource('/a.dart', 'var v;');
+ serializeLibraryText('export "a.dart"; var v;');
+ expect(linked.exportNames, isEmpty);
+ }
+
+ test_export_shadowed_variable_const() {
+ // `v=` is shown in exportNames because the top level declaration
+ // `const v = 0;` only shadows `v`, not `v=`.
+ addNamedSource('/a.dart', 'var v;');
+ serializeLibraryText('export "a.dart"; const v = 0;');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'v=',
+ ReferenceKind.topLevelPropertyAccessor);
+ }
+
+ test_export_shadowed_variable_final() {
+ // `v=` is shown in exportNames because the top level declaration
+ // `final v = 0;` only shadows `v`, not `v=`.
+ addNamedSource('/a.dart', 'var v;');
+ serializeLibraryText('export "a.dart"; final v = 0;');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'v=',
+ ReferenceKind.topLevelPropertyAccessor);
+ }
+
+ test_export_show() {
+ addNamedSource('/a.dart', 'f() {} g() {}');
+ serializeLibraryText('export "a.dart" show f;');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+ ReferenceKind.topLevelFunction);
+ }
+
+ test_export_show_order() {
+ serializeLibraryText('export "dart:async" show Future, Stream;');
+ expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+ expect(
+ unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
+ hasLength(2));
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
+ isEmpty);
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[0],
+ 'Future');
+ expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[1],
+ 'Stream');
+ }
+
+ test_export_typedef() {
+ addNamedSource('/a.dart', 'typedef F();');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(1));
+ checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'F',
+ ReferenceKind.typedef);
+ }
+
+ test_export_uri() {
+ addNamedSource('/a.dart', 'library my.lib;');
+ String uriString = '"a.dart"';
+ String libraryText = 'export $uriString;';
+ serializeLibraryText(libraryText);
+ expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.exports[0].uri, 'a.dart');
+ }
+
+ test_export_variable() {
+ addNamedSource('/a.dart', 'var v;');
+ serializeLibraryText('export "a.dart";');
+ expect(linked.exportNames, hasLength(2));
+ LinkedExportName getter =
+ linked.exportNames.firstWhere((e) => e.name == 'v');
+ expect(getter, isNotNull);
+ checkExportName(getter, absUri('/a.dart'), 'a.dart', 'v',
+ ReferenceKind.topLevelPropertyAccessor);
+ LinkedExportName setter =
+ linked.exportNames.firstWhere((e) => e.name == 'v=');
+ expect(setter, isNotNull);
+ checkExportName(setter, absUri('/a.dart'), 'a.dart', 'v=',
+ ReferenceKind.topLevelPropertyAccessor);
+ }
+
+ test_field() {
+ UnlinkedClass cls = serializeClassText('class C { int i; }');
+ UnlinkedVariable variable = findVariable('i', variables: cls.fields);
+ expect(variable, isNotNull);
+ expect(variable.isConst, isFalse);
+ expect(variable.isStatic, isFalse);
+ expect(variable.isFinal, isFalse);
+ expect(findExecutable('i', executables: cls.executables), isNull);
+ expect(findExecutable('i=', executables: cls.executables), isNull);
+ }
+
+ test_field_const() {
+ UnlinkedVariable variable =
+ serializeClassText('class C { static const int i = 0; }').fields[0];
+ expect(variable.isConst, isTrue);
+ _assertUnlinkedConst(variable.constExpr,
+ operators: [UnlinkedConstOperation.pushInt], ints: [0]);
+ }
+
+ test_field_documented() {
+ String text = '''
+class C {
+ /**
+ * Docs
+ */
+ var v;
+}''';
+ UnlinkedVariable variable = serializeClassText(text).fields[0];
+ expect(variable.documentationComment, isNotNull);
+ checkDocumentationComment(variable.documentationComment, text);
+ }
+
+ test_field_final() {
+ UnlinkedVariable variable =
+ serializeClassText('class C { final int i = 0; }').fields[0];
+ expect(variable.isFinal, isTrue);
+ }
+
+ test_field_formal_param_inferred_type_explicit() {
+ UnlinkedClass cls = serializeClassText(
+ 'class C extends D { var v; C(int this.v); }'
+ ' abstract class D { num get v; }',
+ className: 'C');
+ checkInferredTypeSlot(
+ cls.fields[0].inferredTypeSlot, 'dart:core', 'dart:core', 'num');
+ expect(cls.executables[0].kind, UnlinkedExecutableKind.constructor);
+ expect(cls.executables[0].parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_field_formal_param_inferred_type_implicit() {
+ // Both the field `v` and the constructor argument `this.v` will have their
+ // type inferred by strong mode. But only the field should have its
+ // inferred type stored in the summary, since the standard rules for field
+ // formal parameters will take care of the rest (they implicitly inherit
+ // the type of the associated field).
+ UnlinkedClass cls = serializeClassText(
+ 'class C extends D { var v; C(this.v); }'
+ ' abstract class D { int get v; }',
+ className: 'C');
+ checkInferredTypeSlot(
+ cls.fields[0].inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+ expect(cls.executables[0].kind, UnlinkedExecutableKind.constructor);
+ expect(cls.executables[0].parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_field_inferred_type_nonstatic_explicit_initialized() {
+ UnlinkedVariable v = serializeClassText('class C { num v = 0; }').fields[0];
+ expect(v.inferredTypeSlot, 0);
+ }
+
+ test_field_inferred_type_nonstatic_explicit_uninitialized() {
+ UnlinkedVariable v = serializeClassText(
+ 'class C extends D { num v; } abstract class D { int get v; }',
+ className: 'C',
+ allowErrors: true)
+ .fields[0];
+ expect(v.inferredTypeSlot, 0);
+ }
+
+ test_field_inferred_type_nonstatic_implicit_initialized() {
+ UnlinkedVariable v = serializeClassText('class C { var v = 0; }').fields[0];
+ checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_field_inferred_type_nonstatic_implicit_uninitialized() {
+ UnlinkedVariable v = serializeClassText(
+ 'class C extends D { var v; } abstract class D { int get v; }',
+ className: 'C')
+ .fields[0];
+ checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_field_inferred_type_static_explicit_initialized() {
+ UnlinkedVariable v =
+ serializeClassText('class C { static int v = 0; }').fields[0];
+ expect(v.inferredTypeSlot, 0);
+ }
+
+ test_field_inferred_type_static_implicit_initialized() {
+ UnlinkedVariable v =
+ serializeClassText('class C { static var v = 0; }').fields[0];
+ checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_field_inferred_type_static_implicit_uninitialized() {
+ UnlinkedVariable v =
+ serializeClassText('class C { static var v; }').fields[0];
+ expect(v.inferredTypeSlot, 0);
+ }
+
+ test_field_propagated_type_final_immediate() {
+ UnlinkedVariable v =
+ serializeClassText('class C { final v = 0; }').fields[0];
+ checkLinkedTypeSlot(v.propagatedTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_field_static() {
+ UnlinkedVariable variable =
+ serializeClassText('class C { static int i; }').fields[0];
+ expect(variable.isStatic, isTrue);
+ }
+
+ test_fully_linked_references_follow_other_references() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ serializeLibraryText('final x = 0; String y;');
+ checkLinkedTypeSlot(unlinkedUnits[0].variables[0].propagatedTypeSlot,
+ 'dart:core', 'dart:core', 'int');
+ checkTypeRef(
+ unlinkedUnits[0].variables[1].type, 'dart:core', 'dart:core', 'String');
+ // Even though the definition of y follows the definition of x, the linked
+ // type reference for x should use a higher numbered reference than the
+ // unlinked type reference for y.
+ EntityRef propagatedType =
+ getTypeRefForSlot(unlinkedUnits[0].variables[0].propagatedTypeSlot);
+ expect(unlinkedUnits[0].variables[1].type.reference,
+ lessThan(propagatedType.reference));
+ }
+
+ test_function_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+f() {}''';
+ UnlinkedExecutable executable = serializeExecutableText(text);
+ expect(executable.documentationComment, isNotNull);
+ checkDocumentationComment(executable.documentationComment, text);
+ }
+
+ test_function_inferred_type_implicit_param() {
+ UnlinkedExecutable f = serializeExecutableText('void f(value) {}');
+ expect(f.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_function_inferred_type_implicit_return() {
+ UnlinkedExecutable f = serializeExecutableText('f() => null;');
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_generic_method_in_generic_class() {
+ UnlinkedClass cls = serializeClassText(
+ 'class C<T, U> { void m<V, W>(T t, U u, V v, W w) {} }');
+ List<UnlinkedParam> params = cls.executables[0].parameters;
+ checkParamTypeRef(params[0].type, 4);
+ checkParamTypeRef(params[1].type, 3);
+ checkParamTypeRef(params[2].type, 2);
+ checkParamTypeRef(params[3].type, 1);
+ }
+
+ test_getter_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+get f => null;''';
+ UnlinkedExecutable executable = serializeExecutableText(text);
+ expect(executable.documentationComment, isNotNull);
+ checkDocumentationComment(executable.documentationComment, text);
+ }
+
+ test_getter_inferred_type_nonstatic_explicit_return() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { num get f => null; }'
+ ' abstract class D { int get f; }',
+ className: 'C',
+ allowErrors: true)
+ .executables[0];
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_getter_inferred_type_nonstatic_implicit_return() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { get f => null; } abstract class D { int get f; }',
+ className: 'C')
+ .executables[0];
+ checkInferredTypeSlot(
+ f.inferredReturnTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_getter_inferred_type_static_implicit_return() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { static get f => null; }'
+ ' class D { static int get f => null; }',
+ className: 'C')
+ .executables[0];
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_implicit_dependencies_follow_other_dependencies() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ addNamedSource('/a.dart', 'import "b.dart"; class C {} D f() => null;');
+ addNamedSource('/b.dart', 'class D {}');
+ serializeLibraryText('import "a.dart"; final x = f(); C y;');
+ // The dependency on b.dart is implicit, so it should be placed at the end
+ // of the dependency list, after a.dart, even though the code that refers
+ // to b.dart comes before the code that refers to a.dart.
+ int aDep =
+ checkHasDependency(absUri('/a.dart'), 'a.dart', fullyLinked: false);
+ int bDep =
+ checkHasDependency(absUri('/b.dart'), 'b.dart', fullyLinked: true);
+ expect(aDep, lessThan(bDep));
+ }
+
+ test_import_deferred() {
+ serializeLibraryText(
+ 'import "dart:async" deferred as a; main() { print(a.Future); }');
+ expect(unlinkedUnits[0].imports[0].isDeferred, isTrue);
+ }
+
+ test_import_dependency() {
+ serializeLibraryText('import "dart:async"; Future x;');
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ checkDependency(linked.importDependencies[0], 'dart:async', 'dart:async');
+ }
+
+ test_import_explicit() {
+ serializeLibraryText('import "dart:core"; int i;');
+ expect(unlinkedUnits[0].imports, hasLength(1));
+ expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
+ }
+
+ test_import_hide_order() {
+ serializeLibraryText(
+ 'import "dart:async" hide Future, Stream; Completer c;');
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
+ expect(unlinkedUnits[0].imports[0].combinators[0].shows, isEmpty);
+ expect(unlinkedUnits[0].imports[0].combinators[0].hides, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].combinators[0].hides[0], 'Future');
+ expect(unlinkedUnits[0].imports[0].combinators[0].hides[1], 'Stream');
+ }
+
+ test_import_implicit() {
+ // The implicit import of dart:core is represented in the model.
+ serializeLibraryText('');
+ expect(unlinkedUnits[0].imports, hasLength(1));
+ checkDependency(linked.importDependencies[0], 'dart:core', 'dart:core');
+ expect(unlinkedUnits[0].imports[0].uri, isEmpty);
+ expect(unlinkedUnits[0].imports[0].uriOffset, 0);
+ expect(unlinkedUnits[0].imports[0].uriEnd, 0);
+ expect(unlinkedUnits[0].imports[0].prefixReference, 0);
+ expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
+ expect(unlinkedUnits[0].imports[0].isImplicit, isTrue);
+ }
+
+ test_import_missing() {
+ if (!checkAstDerivedData) {
+ // TODO(paulberry): At the moment unresolved imports are not included in
+ // the element model, so we can't pass this test.
+ return;
+ }
+ // Unresolved imports are included since this is necessary for proper
+ // dependency tracking.
+ allowMissingFiles = true;
+ serializeLibraryText('import "foo.dart";', allowErrors: true);
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ checkDependency(
+ linked.importDependencies[0], absUri('/foo.dart'), 'foo.dart');
+ }
+
+ test_import_no_combinators() {
+ serializeLibraryText('import "dart:async"; Future x;');
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
+ }
+
+ test_import_no_flags() {
+ serializeLibraryText('import "dart:async"; Future x;');
+ expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
+ expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
+ }
+
+ test_import_non_deferred() {
+ serializeLibraryText(
+ 'import "dart:async" as a; main() { print(a.Future); }');
+ expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
+ }
+
+ test_import_of_file_with_missing_part() {
+ // Other references in foo.dart should be resolved even though foo.dart's
+ // part declaration for bar.dart refers to a non-existent file.
+ allowMissingFiles = true;
+ addNamedSource('/foo.dart', 'part "bar.dart"; class C {}');
+ serializeLibraryText('import "foo.dart"; C x;');
+ checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
+ }
+
+ test_import_of_missing_export() {
+ // Other references in foo.dart should be resolved even though foo.dart's
+ // re-export of bar.dart refers to a non-existent file.
+ allowMissingFiles = true;
+ addNamedSource('/foo.dart', 'export "bar.dart"; class C {}');
+ serializeLibraryText('import "foo.dart"; C x;');
+ checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
+ }
+
+ test_import_offset() {
+ String libraryText = ' import "dart:async"; Future x;';
+ serializeLibraryText(libraryText);
+ expect(unlinkedUnits[0].imports[0].offset, libraryText.indexOf('import'));
+ expect(unlinkedUnits[0].imports[0].uriOffset,
+ libraryText.indexOf('"dart:async"'));
+ expect(unlinkedUnits[0].imports[0].uriEnd, libraryText.indexOf('; Future'));
+ }
+
+ test_import_prefix_name() {
+ String libraryText = 'import "dart:async" as a; a.Future x;';
+ serializeLibraryText(libraryText);
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ checkPrefix(unlinkedUnits[0].imports[0].prefixReference, 'a');
+ expect(unlinkedUnits[0].imports[0].prefixOffset, libraryText.indexOf('a;'));
+ }
+
+ test_import_prefix_none() {
+ serializeLibraryText('import "dart:async"; Future x;');
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].prefixReference, 0);
+ }
+
+ test_import_prefix_not_in_public_namespace() {
+ serializeLibraryText('import "dart:async" as a; a.Future v;');
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'v');
+ expect(unlinkedUnits[0].publicNamespace.names[1].name, 'v=');
+ }
+
+ test_import_prefix_reference() {
+ UnlinkedVariable variable =
+ serializeVariableText('import "dart:async" as a; a.Future v;');
+ checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
+ expectedPrefix: 'a', numTypeParameters: 1);
+ }
+
+ test_import_prefixes_take_precedence_over_imported_names() {
+ addNamedSource('/a.dart', 'class b {} class A');
+ addNamedSource('/b.dart', 'class Cls {}');
+ addNamedSource('/c.dart', 'class Cls {}');
+ addNamedSource('/d.dart', 'class c {} class D');
+ serializeLibraryText('''
+import 'a.dart';
+import 'b.dart' as b;
+import 'c.dart' as c;
+import 'd.dart';
+A aCls;
+b.Cls bCls;
+c.Cls cCls;
+D dCls;
+''');
+ checkTypeRef(findVariable('aCls').type, absUri('/a.dart'), 'a.dart', 'A');
+ checkTypeRef(findVariable('bCls').type, absUri('/b.dart'), 'b.dart', 'Cls',
+ expectedPrefix: 'b');
+ checkTypeRef(findVariable('cCls').type, absUri('/c.dart'), 'c.dart', 'Cls',
+ expectedPrefix: 'c');
+ checkTypeRef(findVariable('dCls').type, absUri('/d.dart'), 'd.dart', 'D');
+ }
+
+ test_import_reference() {
+ UnlinkedVariable variable =
+ serializeVariableText('import "dart:async"; Future v;');
+ checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
+ numTypeParameters: 1);
+ }
+
+ test_import_reference_merged_no_prefix() {
+ serializeLibraryText('''
+import "dart:async" show Future;
+import "dart:async" show Stream;
+
+Future f;
+Stream s;
+''');
+ checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
+ numTypeParameters: 1);
+ checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
+ numTypeParameters: 1);
+ }
+
+ test_import_reference_merged_prefixed() {
+ serializeLibraryText('''
+import "dart:async" as a show Future;
+import "dart:async" as a show Stream;
+
+a.Future f;
+a.Stream s;
+''');
+ checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
+ expectedPrefix: 'a', numTypeParameters: 1);
+ checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
+ expectedPrefix: 'a', numTypeParameters: 1);
+ }
+
+ test_import_reference_merged_prefixed_separate_libraries() {
+ addNamedSource('/a.dart', 'class A {}');
+ addNamedSource('/b.dart', 'class B {}');
+ serializeLibraryText('''
+import 'a.dart' as p;
+import 'b.dart' as p;
+
+p.A a;
+p.B b;
+''');
+ checkTypeRef(findVariable('a').type, absUri('/a.dart'), 'a.dart', 'A',
+ expectedPrefix: 'p');
+ checkTypeRef(findVariable('b').type, absUri('/b.dart'), 'b.dart', 'B',
+ expectedPrefix: 'p');
+ }
+
+ test_import_show_order() {
+ String libraryText =
+ 'import "dart:async" show Future, Stream; Future x; Stream y;';
+ serializeLibraryText(libraryText);
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
+ expect(unlinkedUnits[0].imports[0].combinators[0].shows, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].combinators[0].hides, isEmpty);
+ expect(unlinkedUnits[0].imports[0].combinators[0].shows[0], 'Future');
+ expect(unlinkedUnits[0].imports[0].combinators[0].shows[1], 'Stream');
+ }
+
+ test_import_uri() {
+ String uriString = '"dart:async"';
+ String libraryText = 'import $uriString; Future x;';
+ serializeLibraryText(libraryText);
+ // Second import is the implicit import of dart:core
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].uri, 'dart:async');
+ }
+
+ test_inferred_type_refers_to_bound_type_param() {
+ if (!strongMode || skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedClass cls = serializeClassText(
+ 'class C<T> extends D<int, T> { var v; }'
+ ' abstract class D<U, V> { Map<V, U> get v; }',
+ className: 'C');
+ EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
+ // Check that v has inferred type Map<T, int>.
+ checkLinkedTypeRef(type, 'dart:core', 'dart:core', 'Map',
+ allowTypeParameters: true, numTypeParameters: 2);
+ checkParamTypeRef(type.typeArguments[0], 1);
+ checkLinkedTypeRef(type.typeArguments[1], 'dart:core', 'dart:core', 'int');
+ }
+
+ test_invalid_prefix_dynamic() {
+ if (checkAstDerivedData) {
+ // TODO(paulberry): get this to work properly.
+ return;
+ }
+ checkUnresolvedTypeRef(
+ serializeTypeText('dynamic.T', allowErrors: true), 'dynamic', 'T');
+ }
+
+ test_invalid_prefix_type_parameter() {
+ if (checkAstDerivedData) {
+ // TODO(paulberry): get this to work properly.
+ return;
+ }
+ checkUnresolvedTypeRef(
+ serializeClassText('class C<T> { T.U x; }', allowErrors: true)
+ .fields[0]
+ .type,
+ 'T',
+ 'U');
+ }
+
+ test_invalid_prefix_void() {
+ if (checkAstDerivedData) {
+ // TODO(paulberry): get this to work properly.
+ return;
+ }
+ checkUnresolvedTypeRef(
+ serializeTypeText('void.T', allowErrors: true), 'void', 'T');
+ }
+
+ test_library_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+library foo;''';
+ serializeLibraryText(text);
+ expect(unlinkedUnits[0].libraryDocumentationComment, isNotNull);
+ checkDocumentationComment(
+ unlinkedUnits[0].libraryDocumentationComment, text);
+ }
+
+ test_library_name_with_spaces() {
+ String text = 'library foo . bar ;';
+ serializeLibraryText(text);
+ expect(unlinkedUnits[0].libraryName, 'foo.bar');
+ expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo . bar'));
+ expect(unlinkedUnits[0].libraryNameLength, 'foo . bar'.length);
+ }
+
+ test_library_named() {
+ String text = 'library foo.bar;';
+ serializeLibraryText(text);
+ expect(unlinkedUnits[0].libraryName, 'foo.bar');
+ expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo.bar'));
+ expect(unlinkedUnits[0].libraryNameLength, 'foo.bar'.length);
+ }
+
+ test_library_unnamed() {
+ serializeLibraryText('');
+ expect(unlinkedUnits[0].libraryName, isEmpty);
+ expect(unlinkedUnits[0].libraryNameOffset, 0);
+ expect(unlinkedUnits[0].libraryNameLength, 0);
+ }
+
+ test_library_with_missing_part() {
+ // References to other parts should still be resolved.
+ allowMissingFiles = true;
+ addNamedSource('/bar.dart', 'part of my.lib; class C {}');
+ serializeLibraryText(
+ 'library my.lib; part "foo.dart"; part "bar.dart"; C c;',
+ allowErrors: true);
+ checkTypeRef(findVariable('c').type, null, null, 'C',
+ expectedTargetUnit: 2);
+ }
+
+ test_linked_reference_reuse() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ // When the reference for a linked type is the same as an explicitly
+ // referenced type, the explicit reference should be re-used.
+ addNamedSource('/a.dart', 'class C {}');
+ addNamedSource('/b.dart', 'import "a.dart"; C f() => null;');
+ serializeLibraryText(
+ 'import "a.dart"; import "b.dart"; C c1; final c2 = f();');
+ int explicitReference = findVariable('c1').type.reference;
+ expect(getTypeRefForSlot(findVariable('c2').propagatedTypeSlot).reference,
+ explicitReference);
+ }
+
+ test_linked_type_dependency_reuse() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ // When the dependency for a linked type is the same as an explicit
+ // dependency, the explicit dependency should be re-used.
+ addNamedSource('/a.dart', 'class C {} class D {}');
+ addNamedSource('/b.dart', 'import "a.dart"; D f() => null;');
+ serializeLibraryText(
+ 'import "a.dart"; import "b.dart"; C c; final d = f();');
+ int cReference = findVariable('c').type.reference;
+ int explicitDependency = linked.units[0].references[cReference].dependency;
+ int dReference =
+ getTypeRefForSlot(findVariable('d').propagatedTypeSlot).reference;
+ expect(
+ linked.units[0].references[dReference].dependency, explicitDependency);
+ }
+
+ test_local_names_take_precedence_over_imported_names() {
+ addNamedSource('/a.dart', 'class C {} class D {}');
+ serializeLibraryText('''
+import 'a.dart';
+class C {}
+C c;
+D d;''');
+ checkTypeRef(findVariable('c').type, null, null, 'C');
+ checkTypeRef(findVariable('d').type, absUri('/a.dart'), 'a.dart', 'D');
+ }
+
+ test_method_documented() {
+ String text = '''
+class C {
+ /**
+ * Docs
+ */
+ f() {}
+}''';
+ UnlinkedExecutable executable = serializeClassText(text).executables[0];
+ expect(executable.documentationComment, isNotNull);
+ checkDocumentationComment(executable.documentationComment, text);
+ }
+
+ test_method_inferred_type_nonstatic_explicit_param() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { void f(num value) {} }'
+ ' abstract class D { void f(int value); }',
+ className: 'C')
+ .executables[0];
+ expect(f.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_method_inferred_type_nonstatic_explicit_return() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { num f() => null; } abstract class D { int f(); }',
+ className: 'C',
+ allowErrors: true)
+ .executables[0];
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_method_inferred_type_nonstatic_implicit_param() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { void f(value) {} }'
+ ' abstract class D { void f(int value); }',
+ className: 'C')
+ .executables[0];
+ checkInferredTypeSlot(
+ f.parameters[0].inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_method_inferred_type_nonstatic_implicit_return() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { f() => null; } abstract class D { int f(); }',
+ className: 'C')
+ .executables[0];
+ checkInferredTypeSlot(
+ f.inferredReturnTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_method_inferred_type_static_implicit_param() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { static void f(value) {} }'
+ ' class D { static void f(int value) {} }',
+ className: 'C')
+ .executables[0];
+ expect(f.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_method_inferred_type_static_implicit_return() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { static f() => null; }'
+ ' class D { static int f() => null; }',
+ className: 'C')
+ .executables[0];
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_part_declaration() {
+ addNamedSource('/a.dart', 'part of my.lib;');
+ String text = 'library my.lib; part "a.dart"; // <-part';
+ serializeLibraryText(text);
+ expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.parts[0], 'a.dart');
+ expect(unlinkedUnits[0].parts, hasLength(1));
+ expect(unlinkedUnits[0].parts[0].uriOffset, text.indexOf('"a.dart"'));
+ expect(unlinkedUnits[0].parts[0].uriEnd, text.indexOf('; // <-part'));
+ }
+
+ test_parts_defining_compilation_unit() {
+ serializeLibraryText('');
+ expect(linked.units, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.parts, isEmpty);
+ }
+
+ test_parts_included() {
+ addNamedSource('/part1.dart', 'part of my.lib;');
+ String partString = '"part1.dart"';
+ String libraryText = 'library my.lib; part $partString;';
+ serializeLibraryText(libraryText);
+ expect(linked.units, hasLength(2));
+ expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.parts[0], 'part1.dart');
+ }
+
+ test_public_namespace_of_part() {
+ addNamedSource('/a.dart', 'part of foo; class C {}');
+ serializeLibraryText('library foo; part "a.dart";');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ expect(unlinkedUnits[1].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[1].publicNamespace.names[0].name, 'C');
+ }
+
+ test_setter_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+void set f(value) {}''';
+ UnlinkedExecutable executable = serializeExecutableText(text, 'f=');
+ expect(executable.documentationComment, isNotNull);
+ checkDocumentationComment(executable.documentationComment, text);
+ }
+
+ test_setter_inferred_type_nonstatic_explicit_param() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { void set f(num value) {} }'
+ ' abstract class D { void set f(int value); }',
+ className: 'C')
+ .executables[0];
+ expect(f.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_setter_inferred_type_nonstatic_explicit_return() {
+ UnlinkedExecutable f =
+ serializeClassText('class C { void set f(int value) {} }').executables[
+ 0];
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_setter_inferred_type_nonstatic_implicit_param() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { void set f(value) {} }'
+ ' abstract class D { void set f(int value); }',
+ className: 'C')
+ .executables[0];
+ checkInferredTypeSlot(
+ f.parameters[0].inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_setter_inferred_type_nonstatic_implicit_return() {
+ UnlinkedExecutable f =
+ serializeClassText('class C { set f(int value) {} }').executables[0];
+ checkInferredTypeSlot(f.inferredReturnTypeSlot, null, null, 'void');
+ }
+
+ test_setter_inferred_type_static_implicit_param() {
+ UnlinkedExecutable f = serializeClassText(
+ 'class C extends D { static void set f(value) {} }'
+ ' class D { static void set f(int value) {} }',
+ className: 'C')
+ .executables[0];
+ expect(f.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_setter_inferred_type_static_implicit_return() {
+ UnlinkedExecutable f =
+ serializeClassText('class C { static set f(int value) {} }')
+ .executables[0];
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_setter_inferred_type_top_level_implicit_param() {
+ UnlinkedExecutable f =
+ serializeExecutableText('void set f(value) {}', 'f=');
+ expect(f.parameters[0].inferredTypeSlot, 0);
+ }
+
+ test_setter_inferred_type_top_level_implicit_return() {
+ UnlinkedExecutable f = serializeExecutableText('set f(int value) {}', 'f=');
+ expect(f.inferredReturnTypeSlot, 0);
+ }
+
+ test_slot_reuse() {
+ // Different compilation units have independent notions of slot id, so slot
+ // ids should be reused.
+ addNamedSource('/a.dart', 'part of foo; final v = 0;');
+ serializeLibraryText('library foo; part "a.dart"; final w = 0;');
+ expect(unlinkedUnits[0].variables[0].propagatedTypeSlot, 1);
+ expect(unlinkedUnits[1].variables[0].propagatedTypeSlot, 1);
+ }
+
+ test_type_arguments_explicit() {
+ EntityRef typeRef = serializeTypeText('List<int>');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
+ allowTypeParameters: true, numTypeParameters: 1);
+ expect(typeRef.typeArguments, hasLength(1));
+ checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
+ }
+
+ test_type_arguments_explicit_dynamic() {
+ EntityRef typeRef = serializeTypeText('List<dynamic>');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
+ allowTypeParameters: true, numTypeParameters: 1);
+ expect(typeRef.typeArguments, isEmpty);
+ }
+
+ test_type_arguments_explicit_dynamic_dynamic() {
+ EntityRef typeRef = serializeTypeText('Map<dynamic, dynamic>');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+ allowTypeParameters: true, numTypeParameters: 2);
+ // Trailing type arguments of type `dynamic` are omitted.
+ expect(typeRef.typeArguments, isEmpty);
+ }
+
+ test_type_arguments_explicit_dynamic_int() {
+ EntityRef typeRef = serializeTypeText('Map<dynamic, int>');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+ allowTypeParameters: true, numTypeParameters: 2);
+ // Leading type arguments of type `dynamic` are not omitted.
+ expect(typeRef.typeArguments.length, 2);
+ checkDynamicTypeRef(typeRef.typeArguments[0]);
+ checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'int');
+ }
+
+ test_type_arguments_explicit_dynamic_typedef() {
+ EntityRef typeRef =
+ serializeTypeText('F<dynamic>', otherDeclarations: 'typedef T F<T>();');
+ checkTypeRef(typeRef, null, null, 'F',
+ allowTypeParameters: true,
+ expectedKind: ReferenceKind.typedef,
+ numTypeParameters: 1);
+ expect(typeRef.typeArguments, isEmpty);
+ }
+
+ test_type_arguments_explicit_String_dynamic() {
+ EntityRef typeRef = serializeTypeText('Map<String, dynamic>');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+ allowTypeParameters: true, numTypeParameters: 2);
+ // Trailing type arguments of type `dynamic` are omitted.
+ expect(typeRef.typeArguments.length, 1);
+ checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'String');
+ }
+
+ test_type_arguments_explicit_String_int() {
+ EntityRef typeRef = serializeTypeText('Map<String, int>');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+ allowTypeParameters: true, numTypeParameters: 2);
+ expect(typeRef.typeArguments.length, 2);
+ checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'String');
+ checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'int');
+ }
+
+ test_type_arguments_explicit_typedef() {
+ EntityRef typeRef =
+ serializeTypeText('F<int>', otherDeclarations: 'typedef T F<T>();');
+ checkTypeRef(typeRef, null, null, 'F',
+ allowTypeParameters: true,
+ expectedKind: ReferenceKind.typedef,
+ numTypeParameters: 1);
+ expect(typeRef.typeArguments, hasLength(1));
+ checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
+ }
+
+ test_type_arguments_implicit() {
+ EntityRef typeRef = serializeTypeText('List');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
+ allowTypeParameters: true, numTypeParameters: 1);
+ expect(typeRef.typeArguments, isEmpty);
+ }
+
+ test_type_arguments_implicit_typedef() {
+ EntityRef typeRef =
+ serializeTypeText('F', otherDeclarations: 'typedef T F<T>();');
+ checkTypeRef(typeRef, null, null, 'F',
+ allowTypeParameters: true,
+ expectedKind: ReferenceKind.typedef,
+ numTypeParameters: 1);
+ expect(typeRef.typeArguments, isEmpty);
+ }
+
+ test_type_arguments_order() {
+ EntityRef typeRef = serializeTypeText('Map<int, Object>');
+ checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+ allowTypeParameters: true, numTypeParameters: 2);
+ expect(typeRef.typeArguments, hasLength(2));
+ checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
+ checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'Object');
+ }
+
+ test_type_dynamic() {
+ checkDynamicTypeRef(serializeTypeText('dynamic'));
+ }
+
+ test_type_param_not_shadowed_by_constructor() {
+ UnlinkedClass cls =
+ serializeClassText('class C<D> { D x; C.D(); } class D {}');
+ checkParamTypeRef(cls.fields[0].type, 1);
+ }
+
+ test_type_param_not_shadowed_by_field_in_extends() {
+ UnlinkedClass cls =
+ serializeClassText('class C<T> extends D<T> { T x; } class D<T> {}');
+ checkParamTypeRef(cls.supertype.typeArguments[0], 1);
+ }
+
+ test_type_param_not_shadowed_by_field_in_implements() {
+ UnlinkedClass cls =
+ serializeClassText('class C<T> implements D<T> { T x; } class D<T> {}');
+ checkParamTypeRef(cls.interfaces[0].typeArguments[0], 1);
+ }
+
+ test_type_param_not_shadowed_by_field_in_with() {
+ UnlinkedClass cls = serializeClassText(
+ 'class C<T> extends Object with D<T> { T x; } class D<T> {}');
+ checkParamTypeRef(cls.mixins[0].typeArguments[0], 1);
+ }
+
+ test_type_param_not_shadowed_by_method_parameter() {
+ UnlinkedClass cls = serializeClassText('class C<T> { f(int T, T x) {} }');
+ checkParamTypeRef(cls.executables[0].parameters[1].type, 1);
+ }
+
+ test_type_param_not_shadowed_by_setter() {
+ // The code under test should not produce a compile-time error, but it
+ // does.
+ bool workAroundBug25525 = true;
+ UnlinkedClass cls = serializeClassText(
+ 'class C<D> { D x; void set D(value) {} } class D {}',
+ allowErrors: workAroundBug25525);
+ checkParamTypeRef(cls.fields[0].type, 1);
+ }
+
+ test_type_param_not_shadowed_by_typedef_parameter() {
+ UnlinkedTypedef typedef =
+ serializeTypedefText('typedef void F<T>(int T, T x);');
+ checkParamTypeRef(typedef.parameters[1].type, 1);
+ }
+
+ test_type_param_shadowed_by_field() {
+ UnlinkedClass cls = serializeClassText(
+ 'class C<D> { D x; int D; } class D {}',
+ allowErrors: true);
+ checkDynamicTypeRef(cls.fields[0].type);
+ }
+
+ test_type_param_shadowed_by_getter() {
+ UnlinkedClass cls = serializeClassText(
+ 'class C<D> { D x; int get D => null; } class D {}',
+ allowErrors: true);
+ checkDynamicTypeRef(cls.fields[0].type);
+ }
+
+ test_type_param_shadowed_by_method() {
+ UnlinkedClass cls = serializeClassText(
+ 'class C<D> { D x; void D() {} } class D {}',
+ allowErrors: true);
+ checkDynamicTypeRef(cls.fields[0].type);
+ }
+
+ test_type_param_shadowed_by_type_param() {
+ UnlinkedClass cls =
+ serializeClassText('class C<T> { T f<T>(T x) => null; }');
+ checkParamTypeRef(cls.executables[0].returnType, 1);
+ checkParamTypeRef(cls.executables[0].parameters[0].type, 1);
+ }
+
+ test_type_reference_from_part() {
+ addNamedSource('/a.dart', 'part of foo; C v;');
+ serializeLibraryText('library foo; part "a.dart"; class C {}');
+ checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
+ null, null, 'C',
+ expectedKind: ReferenceKind.classOrEnum,
+ linkedSourceUnit: linked.units[1],
+ unlinkedSourceUnit: unlinkedUnits[1]);
+ }
+
+ test_type_reference_from_part_withPrefix() {
+ addNamedSource('/a.dart', 'class C {}');
+ addNamedSource('/p.dart', 'part of foo; a.C v;');
+ serializeLibraryText(
+ 'library foo; import "a.dart"; import "a.dart" as a; part "p.dart";',
+ allowErrors: true);
+ checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
+ absUri('/a.dart'), 'a.dart', 'C',
+ expectedPrefix: 'a',
+ linkedSourceUnit: linked.units[1],
+ unlinkedSourceUnit: unlinkedUnits[1]);
+ }
+
+ test_type_reference_to_class_argument() {
+ UnlinkedClass cls = serializeClassText('class C<T, U> { T t; U u; }');
+ {
+ EntityRef typeRef =
+ findVariable('t', variables: cls.fields, failIfAbsent: true).type;
+ checkParamTypeRef(typeRef, 2);
+ }
+ {
+ EntityRef typeRef =
+ findVariable('u', variables: cls.fields, failIfAbsent: true).type;
+ checkParamTypeRef(typeRef, 1);
+ }
+ }
+
+ test_type_reference_to_import_of_export() {
+ addNamedSource('/a.dart', 'library a; export "b.dart";');
+ addNamedSource('/b.dart', 'library b; class C {}');
+ checkTypeRef(serializeTypeText('C', otherDeclarations: 'import "a.dart";'),
+ absUri('/b.dart'), 'b.dart', 'C');
+ }
+
+ test_type_reference_to_import_of_export_via_prefix() {
+ addNamedSource('/a.dart', 'library a; export "b.dart";');
+ addNamedSource('/b.dart', 'library b; class C {}');
+ checkTypeRef(
+ serializeTypeText('p.C', otherDeclarations: 'import "a.dart" as p;'),
+ absUri('/b.dart'),
+ 'b.dart',
+ 'C',
+ expectedPrefix: 'p');
+ }
+
+ test_type_reference_to_imported_part() {
+ addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
+ addNamedSource('/b.dart', 'part of my.lib; class C {}');
+ checkTypeRef(
+ serializeTypeText('C',
+ otherDeclarations: 'library my.lib; import "a.dart";'),
+ absUri('/a.dart'),
+ 'a.dart',
+ 'C',
+ expectedTargetUnit: 1);
+ }
+
+ test_type_reference_to_imported_part_with_prefix() {
+ addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
+ addNamedSource('/b.dart', 'part of my.lib; class C {}');
+ checkTypeRef(
+ serializeTypeText('p.C',
+ otherDeclarations: 'library my.lib; import "a.dart" as p;'),
+ absUri('/a.dart'),
+ 'a.dart',
+ 'C',
+ expectedPrefix: 'p',
+ expectedTargetUnit: 1);
+ }
+
+ test_type_reference_to_internal_class() {
+ checkTypeRef(serializeTypeText('C', otherDeclarations: 'class C {}'), null,
+ null, 'C');
+ }
+
+ test_type_reference_to_internal_class_alias() {
+ checkTypeRef(
+ serializeTypeText('C',
+ otherDeclarations: 'class C = D with E; class D {} class E {}'),
+ null,
+ null,
+ 'C');
+ }
+
+ test_type_reference_to_internal_enum() {
+ checkTypeRef(serializeTypeText('E', otherDeclarations: 'enum E { value }'),
+ null, null, 'E');
+ }
+
+ test_type_reference_to_local_part() {
+ addNamedSource('/a.dart', 'part of my.lib; class C {}');
+ checkTypeRef(
+ serializeTypeText('C',
+ otherDeclarations: 'library my.lib; part "a.dart";'),
+ null,
+ null,
+ 'C',
+ expectedTargetUnit: 1);
+ }
+
+ test_type_reference_to_nonexistent_file_via_prefix() {
+ if (!checkAstDerivedData) {
+ // TODO(paulberry): this test currently fails because there is not enough
+ // information in the element model to figure out that the unresolved
+ // reference `p.C` uses the prefix `p`.
+ return;
+ }
+ allowMissingFiles = true;
+ EntityRef typeRef = serializeTypeText('p.C',
+ otherDeclarations: 'import "foo.dart" as p;', allowErrors: true);
+ checkUnresolvedTypeRef(typeRef, 'p', 'C');
+ }
+
+ test_type_reference_to_part() {
+ addNamedSource('/a.dart', 'part of foo; class C { C(); }');
+ serializeLibraryText('library foo; part "a.dart"; C c;');
+ checkTypeRef(unlinkedUnits[0].variables.single.type, null, null, 'C',
+ expectedKind: ReferenceKind.classOrEnum, expectedTargetUnit: 1);
+ }
+
+ test_type_reference_to_type_visible_via_multiple_import_prefixes() {
+ if (!checkAstDerivedData) {
+ // TODO(paulberry): this test currently fails because the element model
+ // doesn't record enough information to track which prefix is used to
+ // refer to a type.
+ return;
+ }
+ addNamedSource('/lib1.dart', 'class C');
+ addNamedSource('/lib2.dart', 'export "lib1.dart";');
+ addNamedSource('/lib3.dart', 'export "lib1.dart";');
+ addNamedSource('/lib4.dart', 'export "lib1.dart";');
+ serializeLibraryText('''
+import 'lib2.dart';
+import 'lib3.dart' as a;
+import 'lib4.dart' as b;
+C c2;
+a.C c3;
+b.C c4;''');
+ // Note: it is important that each reference to class C records the prefix
+ // used to find it; otherwise it's possible that relinking might produce an
+ // incorrect result after a change to lib2.dart, lib3.dart, or lib4.dart.
+ checkTypeRef(
+ findVariable('c2').type, absUri('/lib1.dart'), 'lib1.dart', 'C');
+ checkTypeRef(
+ findVariable('c3').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
+ expectedPrefix: 'a');
+ checkTypeRef(
+ findVariable('c4').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
+ expectedPrefix: 'b');
+ }
+
+ test_type_reference_to_typedef() {
+ checkTypeRef(serializeTypeText('F', otherDeclarations: 'typedef void F();'),
+ null, null, 'F',
+ expectedKind: ReferenceKind.typedef);
+ }
+
+ test_type_unit_counts_unreferenced_units() {
+ addNamedSource('/a.dart', 'library a; part "b.dart"; part "c.dart";');
+ addNamedSource('/b.dart', 'part of a;');
+ addNamedSource('/c.dart', 'part of a; class C {}');
+ EntityRef typeRef =
+ serializeTypeText('C', otherDeclarations: 'import "a.dart";');
+ // The referenced unit should be 2, since unit 0 is a.dart and unit 1 is
+ // b.dart. a.dart and b.dart are counted even though nothing is imported
+ // from them.
+ checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C',
+ expectedTargetUnit: 2);
+ }
+
+ test_type_unresolved() {
+ EntityRef typeRef = serializeTypeText('Foo', allowErrors: true);
+ checkUnresolvedTypeRef(typeRef, null, 'Foo');
+ }
+
+ test_typedef_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+typedef F();''';
+ UnlinkedTypedef typedef = serializeTypedefText(text);
+ expect(typedef.documentationComment, isNotNull);
+ checkDocumentationComment(typedef.documentationComment, text);
+ }
+
+ test_typedef_name() {
+ String text = 'typedef F();';
+ UnlinkedTypedef type = serializeTypedefText(text);
+ expect(type.name, 'F');
+ expect(type.nameOffset, text.indexOf('F'));
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(
+ unlinkedUnits[0].publicNamespace.names[0].kind, ReferenceKind.typedef);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'F');
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+ }
+
+ test_typedef_param_none() {
+ UnlinkedTypedef type = serializeTypedefText('typedef F();');
+ expect(type.parameters, isEmpty);
+ }
+
+ test_typedef_param_order() {
+ UnlinkedTypedef type = serializeTypedefText('typedef F(x, y);');
+ expect(type.parameters, hasLength(2));
+ expect(type.parameters[0].name, 'x');
+ expect(type.parameters[1].name, 'y');
+ }
+
+ test_typedef_private() {
+ serializeTypedefText('typedef _F();', '_F');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_typedef_reference_generic() {
+ EntityRef typeRef =
+ serializeTypeText('F', otherDeclarations: 'typedef void F<A, B>();');
+ checkTypeRef(typeRef, null, null, 'F',
+ numTypeParameters: 2, expectedKind: ReferenceKind.typedef);
+ }
+
+ test_typedef_reference_generic_imported() {
+ addNamedSource('/lib.dart', 'typedef void F<A, B>();');
+ EntityRef typeRef =
+ serializeTypeText('F', otherDeclarations: 'import "lib.dart";');
+ checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'F',
+ numTypeParameters: 2, expectedKind: ReferenceKind.typedef);
+ }
+
+ test_typedef_return_type_explicit() {
+ UnlinkedTypedef type = serializeTypedefText('typedef int F();');
+ checkTypeRef(type.returnType, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_typedef_type_param_in_parameter() {
+ UnlinkedTypedef type = serializeTypedefText('typedef F<T>(T t);');
+ checkParamTypeRef(type.parameters[0].type, 1);
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
+ }
+
+ test_typedef_type_param_in_return_type() {
+ UnlinkedTypedef type = serializeTypedefText('typedef T F<T>();');
+ checkParamTypeRef(type.returnType, 1);
+ }
+
+ test_typedef_type_param_none() {
+ UnlinkedTypedef type = serializeTypedefText('typedef F();');
+ expect(type.typeParameters, isEmpty);
+ }
+
+ test_typedef_type_param_order() {
+ UnlinkedTypedef type = serializeTypedefText('typedef F<T, U>();');
+ expect(type.typeParameters, hasLength(2));
+ expect(type.typeParameters[0].name, 'T');
+ expect(type.typeParameters[1].name, 'U');
+ }
+
+ test_unresolved_reference_in_multiple_parts() {
+ addNamedSource('/a.dart', 'part of foo; int x; Unresolved y;');
+ serializeLibraryText('library foo; part "a.dart"; Unresolved z;',
+ allowErrors: true);
+ // The unresolved types in the defining compilation unit and the part
+ // should both work correctly even though they use different reference
+ // indices.
+ checkUnresolvedTypeRef(
+ unlinkedUnits[0].variables[0].type, null, 'Unresolved');
+ checkUnresolvedTypeRef(
+ unlinkedUnits[1].variables[1].type, null, 'Unresolved',
+ linkedSourceUnit: linked.units[1],
+ unlinkedSourceUnit: unlinkedUnits[1]);
+ }
+
+ test_variable() {
+ String text = 'int i;';
+ UnlinkedVariable v = serializeVariableText(text, variableName: 'i');
+ expect(v.nameOffset, text.indexOf('i;'));
+ expect(findExecutable('i'), isNull);
+ expect(findExecutable('i='), isNull);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
+ expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+ ReferenceKind.topLevelPropertyAccessor);
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'i');
+ expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+ expect(unlinkedUnits[0].publicNamespace.names[1].kind,
+ ReferenceKind.topLevelPropertyAccessor);
+ expect(unlinkedUnits[0].publicNamespace.names[1].name, 'i=');
+ expect(unlinkedUnits[0].publicNamespace.names[1].numTypeParameters, 0);
+ }
+
+ test_variable_const() {
+ UnlinkedVariable variable =
+ serializeVariableText('const int i = 0;', variableName: 'i');
+ expect(variable.isConst, isTrue);
+ }
+
+ test_variable_documented() {
+ String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+var v;''';
+ UnlinkedVariable variable = serializeVariableText(text);
+ expect(variable.documentationComment, isNotNull);
+ checkDocumentationComment(variable.documentationComment, text);
+ }
+
+ test_variable_explicit_dynamic() {
+ UnlinkedVariable variable = serializeVariableText('dynamic v;');
+ checkDynamicTypeRef(variable.type);
+ }
+
+ test_variable_final_top_level() {
+ UnlinkedVariable variable =
+ serializeVariableText('final int i = 0;', variableName: 'i');
+ expect(variable.isFinal, isTrue);
+ }
+
+ test_variable_implicit_dynamic() {
+ UnlinkedVariable variable = serializeVariableText('var v;');
+ expect(variable.type, isNull);
+ }
+
+ test_variable_inferred_type_explicit_initialized() {
+ UnlinkedVariable v = serializeVariableText('int v = 0;');
+ expect(v.inferredTypeSlot, 0);
+ }
+
+ test_variable_inferred_type_implicit_initialized() {
+ UnlinkedVariable v = serializeVariableText('var v = 0;');
+ checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_variable_inferred_type_implicit_uninitialized() {
+ UnlinkedVariable v = serializeVariableText('var v;');
+ expect(v.inferredTypeSlot, 0);
+ }
+
+ test_variable_name() {
+ UnlinkedVariable variable =
+ serializeVariableText('int i;', variableName: 'i');
+ expect(variable.name, 'i');
+ }
+
+ test_variable_no_flags() {
+ UnlinkedVariable variable =
+ serializeVariableText('int i;', variableName: 'i');
+ expect(variable.isStatic, isFalse);
+ expect(variable.isConst, isFalse);
+ expect(variable.isFinal, isFalse);
+ }
+
+ test_variable_non_const() {
+ UnlinkedVariable variable =
+ serializeVariableText('int i = 0;', variableName: 'i');
+ expect(variable.isConst, isFalse);
+ }
+
+ test_variable_non_final() {
+ UnlinkedVariable variable =
+ serializeVariableText('int i;', variableName: 'i');
+ expect(variable.isFinal, isFalse);
+ }
+
+ test_variable_non_static() {
+ UnlinkedVariable variable =
+ serializeClassText('class C { int i; }').fields[0];
+ expect(variable.isStatic, isFalse);
+ }
+
+ test_variable_non_static_top_level() {
+ // Top level variables are considered non-static.
+ UnlinkedVariable variable =
+ serializeVariableText('int i;', variableName: 'i');
+ expect(variable.isStatic, isFalse);
+ }
+
+ test_variable_private() {
+ serializeVariableText('int _i;', variableName: '_i');
+ expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+ }
+
+ test_variable_propagated_type_final_immediate() {
+ UnlinkedVariable v = serializeVariableText('final v = 0;');
+ checkLinkedTypeSlot(v.propagatedTypeSlot, 'dart:core', 'dart:core', 'int');
+ }
+
+ test_variable_propagated_type_new_reference() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedVariable v = serializeVariableText('final v = 0;');
+ // Since the propagated type of `v` is `int`, and there are no references
+ // to `int` elsewhere in the source file, a new linked reference should
+ // have been created for it, with no associated unlinked reference.
+ expect(v.propagatedTypeSlot, isNot(0));
+ EntityRef type = getTypeRefForSlot(v.propagatedTypeSlot);
+ expect(type, isNotNull);
+ expect(type.reference,
+ greaterThanOrEqualTo(unlinkedUnits[0].references.length));
+ }
+
+ test_variable_propagated_type_omit_dynamic() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedVariable v = serializeVariableText('final v = <int, dynamic>{};');
+ EntityRef type = getTypeRefForSlot(v.propagatedTypeSlot);
+ checkLinkedTypeRef(type, 'dart:core', 'dart:core', 'Map',
+ allowTypeParameters: true, numTypeParameters: 2);
+ expect(type.typeArguments, hasLength(1));
+ checkLinkedTypeRef(type.typeArguments[0], 'dart:core', 'dart:core', 'int');
+ }
+
+ test_variable_propagatedTypeSlot_const() {
+ // Const variables are propagable so they have a nonzero
+ // propagatedTypeSlot.
+ UnlinkedVariable variable = serializeVariableText('const v = 0;');
+ expect(variable.propagatedTypeSlot, isNot(0));
+ }
+
+ test_variable_propagatedTypeSlot_final() {
+ // Final variables are propagable so they have a nonzero
+ // propagatedTypeSlot.
+ UnlinkedVariable variable = serializeVariableText('final v = 0;');
+ expect(variable.propagatedTypeSlot, isNot(0));
+ }
+
+ test_variable_propagatedTypeSlot_non_propagable() {
+ // Non-final non-const variables aren't propagable so they don't have a
+ // propagatedTypeSlot.
+ UnlinkedVariable variable = serializeVariableText('var v;');
+ expect(variable.propagatedTypeSlot, 0);
+ }
+
+ test_variable_static() {
+ UnlinkedVariable variable =
+ serializeClassText('class C { static int i; }').fields[0];
+ expect(variable.isStatic, isTrue);
+ }
+
+ test_variable_type() {
+ UnlinkedVariable variable =
+ serializeVariableText('int i;', variableName: 'i');
+ checkTypeRef(variable.type, 'dart:core', 'dart:core', 'int');
+ }
+
+ void _assertUnlinkedConst(UnlinkedConst constExpr,
+ {List<UnlinkedConstOperation> operators,
+ List<int> ints: const <int>[],
+ List<double> doubles: const <double>[],
+ List<String> strings: const <String>[],
+ List<_EntityRefValidator> referenceValidators:
+ const <_EntityRefValidator>[]}) {
+ expect(constExpr, isNotNull);
+ expect(constExpr.operations, operators);
+ expect(constExpr.ints, ints);
+ expect(constExpr.doubles, doubles);
+ expect(constExpr.strings, strings);
+ expect(constExpr.references, hasLength(referenceValidators.length));
+ for (int i = 0; i < referenceValidators.length; i++) {
+ referenceValidators[i](constExpr.references[i]);
+ }
+ }
+}
+
+/**
+ * Description of expectations for a prelinked prefix reference.
+ */
+class _PrefixExpectation {
+ final ReferenceKind kind;
+ final String name;
+ final bool inLibraryDefiningUnit;
+ final String absoluteUri;
+ final String relativeUri;
+ final int numTypeParameters;
+
+ _PrefixExpectation(this.kind, this.name,
+ {this.inLibraryDefiningUnit: false,
+ this.absoluteUri,
+ this.relativeUri,
+ this.numTypeParameters: 0});
+}
diff --git a/pkg/analyzer/test/src/summary/summary_sdk_test.dart b/pkg/analyzer/test/src/summary/summary_sdk_test.dart
deleted file mode 100644
index 5ec807e..0000000
--- a/pkg/analyzer/test/src/summary/summary_sdk_test.dart
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright (c) 2016, 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.src.summary.summary_sdk_test;
-
-import 'dart:io';
-
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/engine.dart'
- show AnalysisContext, CacheState;
-import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
-import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/task/dart.dart';
-import 'package:analyzer/task/model.dart' show AnalysisContextTarget;
-import 'package:analyzer/task/model.dart';
-import 'package:path/path.dart' as pathos;
-import 'package:unittest/unittest.dart';
-
-import '../../generated/test_support.dart';
-import '../../reflective_tests.dart';
-
-main() {
- groupSep = ' | ';
- runReflectiveTests(SummarySdkAnalysisContextTest);
-}
-
-@reflectiveTest
-class SummarySdkAnalysisContextTest {
- static String _analyzerPackagePath;
- static bool _analyzerPackagePathInitialized = false;
-
- static SdkBundle sdkBundle;
-
- SummarySdkAnalysisContext context;
-
- void setUp() {
- _initializeSdkContext();
- }
-
- test_libraryResults() {
- if (context == null) {
- return;
- }
- // verify that there are at least some interesting libraries in the bundle
- expect(sdkBundle.prelinkedLibraryUris, contains('dart:core'));
- expect(sdkBundle.prelinkedLibraryUris, contains('dart:async'));
- expect(sdkBundle.prelinkedLibraryUris, contains('dart:html'));
- // verify every library
- for (String uri in sdkBundle.prelinkedLibraryUris) {
- // TODO(scheglov) breaks at _LibraryResynthesizer.buildImplicitTopLevelVariable
- if (uri == 'dart:io' || uri == 'dart:_isolate_helper') {
- continue;
- }
- _assertLibraryResults(uri);
- }
- }
-
- test_sourceKind() {
- if (context == null) {
- return;
- }
- // libraries
- _assertHasSourceKind('dart:core', SourceKind.LIBRARY);
- _assertHasSourceKind('dart:async', SourceKind.LIBRARY);
- _assertHasSourceKind('dart:math', SourceKind.LIBRARY);
- // parts
- _assertHasSourceKind('dart:core/bool.dart', SourceKind.PART);
- _assertHasSourceKind('dart:async/future.dart', SourceKind.PART);
- // unknown
- _assertHasSourceKind('dart:no_such_library.dart', null);
- _assertHasSourceKind('dart:core/no_such_part.dart', null);
- }
-
- test_typeProvider() {
- if (context == null) {
- return;
- }
- AnalysisContextTarget target = AnalysisContextTarget.request;
- CacheEntry cacheEntry = context.getCacheEntry(target);
- bool hasResult = context.aboutToComputeResult(cacheEntry, TYPE_PROVIDER);
- expect(hasResult, isTrue);
- expect(cacheEntry.getState(TYPE_PROVIDER), CacheState.VALID);
- TypeProvider typeProvider = cacheEntry.getValue(TYPE_PROVIDER);
- expect(typeProvider.objectType, isNotNull);
- expect(typeProvider.boolType, isNotNull);
- expect(typeProvider.intType, isNotNull);
- expect(typeProvider.futureType, isNotNull);
- expect(typeProvider.futureDynamicType, isNotNull);
- expect(typeProvider.streamType, isNotNull);
- expect(typeProvider.streamDynamicType, isNotNull);
- }
-
- void _assertHasLibraryElement(CacheEntry cacheEntry,
- ResultDescriptor<LibraryElement> resultDescriptor) {
- bool hasResult = context.aboutToComputeResult(cacheEntry, resultDescriptor);
- expect(hasResult, isTrue);
- expect(cacheEntry.getState(resultDescriptor), CacheState.VALID);
- LibraryElement library = cacheEntry.getValue(resultDescriptor);
- expect(library, isNotNull);
- }
-
- void _assertHasSourceKind(String uri, SourceKind expectedValue) {
- Source target = context.sourceFactory.forUri(uri);
- CacheEntry cacheEntry = context.getCacheEntry(target);
- ResultDescriptor<SourceKind> resultDescriptor = SOURCE_KIND;
- bool hasResult = context.aboutToComputeResult(cacheEntry, resultDescriptor);
- if (expectedValue == null) {
- expect(hasResult, isFalse);
- expect(cacheEntry.getState(resultDescriptor), CacheState.INVALID);
- } else {
- expect(hasResult, isTrue);
- expect(cacheEntry.getState(resultDescriptor), CacheState.VALID);
- SourceKind value = cacheEntry.getValue(resultDescriptor);
- expect(value, expectedValue);
- }
- }
-
- void _assertIsLibraryElementReady(
- CacheEntry cacheEntry, ResultDescriptor<bool> resultDescriptor) {
- bool hasResult = context.aboutToComputeResult(cacheEntry, resultDescriptor);
- expect(hasResult, isTrue);
- expect(cacheEntry.getState(resultDescriptor), CacheState.VALID);
- bool ready = cacheEntry.getValue(resultDescriptor);
- expect(ready, isTrue);
- }
-
- void _assertLibraryResults(String uri) {
- Source target = context.sourceFactory.forUri(uri);
- CacheEntry cacheEntry = context.getCacheEntry(target);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT1);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT2);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT3);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT4);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT5);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT6);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT7);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT8);
- _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT);
- _assertIsLibraryElementReady(cacheEntry, READY_LIBRARY_ELEMENT2);
- _assertIsLibraryElementReady(cacheEntry, READY_LIBRARY_ELEMENT5);
- _assertIsLibraryElementReady(cacheEntry, READY_LIBRARY_ELEMENT6);
- }
-
- void _initializeSdkBundle() {
- if (sdkBundle != null) {
- return;
- }
- // prepare analyzer path
- String analyzerPath = getAnalyzerPackagePath();
- if (analyzerPath == null) {
- return;
- }
- // prepare summary path
- String sdkSummaryPath = pathos.join(
- analyzerPath, 'test', 'src', 'summary', 'sdk_analysis_summary');
- File file = new File(sdkSummaryPath);
- if (!file.existsSync()) {
- return;
- }
- // load SdkBundle
- List<int> bytes = file.readAsBytesSync();
- sdkBundle = new SdkBundle.fromBuffer(bytes);
- }
-
- void _initializeSdkContext() {
- _initializeSdkBundle();
- if (sdkBundle == null) {
- return;
- }
- context = new _TestSummarySdkAnalysisContext(sdkBundle);
- DartSdk sdk = new _TestSummaryDartSdk();
- context.sourceFactory = new SourceFactory([new DartUriResolver(sdk)]);
- }
-
- static String getAnalyzerPackagePath() {
- if (!_analyzerPackagePathInitialized) {
- _analyzerPackagePathInitialized = true;
- _analyzerPackagePath = _computeAnalyzerPackagePath();
- }
- return _analyzerPackagePath;
- }
-
- /**
- * Return the path to the `analyzer` package root, or `null` if it cannot
- * be determined.
- *
- * This method expects that one of the `analyzer` tests was run, so
- * [Platform.script] is inside of the `analyzer/test` folder.
- */
- static String _computeAnalyzerPackagePath() {
- Uri uri = Platform.script;
- if (uri == null || uri.scheme != 'file') {
- return null;
- }
- String path = pathos.fromUri(uri);
- List<String> segments = pathos.split(path);
- while (segments.length > 2) {
- if (segments[segments.length - 1] == 'test' &&
- segments[segments.length - 2] == 'analyzer') {
- segments.removeLast();
- return pathos.joinAll(segments);
- }
- segments.removeLast();
- }
- return null;
- }
-}
-
-class _TestSummaryDartSdk implements DartSdk {
- @override
- Source mapDartUri(String uriStr) {
- Uri uri = Uri.parse(uriStr);
- List<String> segments = uri.pathSegments;
- if (segments.length == 1) {
- String libraryName = segments.first;
- String path = '/sdk/$libraryName/$libraryName.dart';
- return new _TestSummarySdkSource(path, uri);
- } else {
- String path = '/sdk/' + segments.join('/');
- return new _TestSummarySdkSource(path, uri);
- }
- }
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-/**
- * [SummarySdkAnalysisContext] with simplified cache creation.
- */
-class _TestSummarySdkAnalysisContext extends SummarySdkAnalysisContext {
- _TestSummarySdkAnalysisContext(SdkBundle bundle) : super(bundle);
-
- @override
- AnalysisCache createCacheFromSourceFactory(SourceFactory factory) {
- return new AnalysisCache(<CachePartition>[new SdkCachePartition(this)]);
- }
-}
-
-class _TestSummarySdkSource extends TestSourceWithUri {
- _TestSummarySdkSource(String path, Uri uri) : super(path, uri);
-
- @override
- bool get isInSystemLibrary => true;
-
- @override
- Uri resolveRelativeUri(Uri relativeUri) {
- Uri baseUri = uri;
- if (uri.scheme == 'dart') {
- String libraryName = uri.path;
- baseUri = Uri.parse('dart:$libraryName/$libraryName.dart');
- }
- return baseUri.resolveUri(relativeUri);
- }
-}
diff --git a/pkg/analyzer/test/src/summary/summary_test.dart b/pkg/analyzer/test/src/summary/summary_test.dart
deleted file mode 100644
index 8b25e9d..0000000
--- a/pkg/analyzer/test/src/summary/summary_test.dart
+++ /dev/null
@@ -1,2966 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analyzer.test.src.summary.summary_test;
-
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_engine_io.dart';
-import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/summary/base.dart';
-import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/prelink.dart';
-import 'package:analyzer/src/summary/public_namespace_computer.dart'
- as public_namespace;
-import 'package:analyzer/src/summary/summarize_elements.dart'
- as summarize_elements;
-import 'package:unittest/unittest.dart';
-
-import '../../generated/resolver_test.dart';
-import '../../reflective_tests.dart';
-
-main() {
- groupSep = ' | ';
- runReflectiveTests(SummarizeElementsTest);
- runReflectiveTests(PrelinkerTest);
-}
-
-/**
- * Convert a summary object (or a portion of one) into a canonical form that
- * can be easily compared using [expect]. If [orderByName] is true, and the
- * object is a [List], it is sorted by the `name` field of its elements.
- */
-Object canonicalize(Object obj, {bool orderByName: false}) {
- if (obj is SummaryClass) {
- Map<String, Object> result = <String, Object>{};
- obj.toMap().forEach((String key, Object value) {
- bool orderByName = false;
- if (obj is UnlinkedPublicNamespace && key == 'names') {
- orderByName = true;
- }
- result[key] = canonicalize(value, orderByName: orderByName);
- });
- return result;
- } else if (obj is List) {
- List<Object> result = <Object>[];
- for (Object item in obj) {
- result.add(canonicalize(item));
- }
- if (orderByName) {
- result.sort((Object a, Object b) {
- if (a is Map && b is Map) {
- return Comparable.compare(a['name'], b['name']);
- } else {
- return 0;
- }
- });
- }
- return result;
- } else if (obj is String || obj is num || obj is bool) {
- return obj;
- } else {
- return obj.toString();
- }
-}
-
-UnlinkedPublicNamespace computePublicNamespaceFromText(
- String text, Source source) {
- CharacterReader reader = new CharSequenceReader(text);
- Scanner scanner =
- new Scanner(source, reader, AnalysisErrorListener.NULL_LISTENER);
- Parser parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
- parser.parseGenericMethods = true;
- CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
- UnlinkedPublicNamespace namespace = new UnlinkedPublicNamespace.fromBuffer(
- public_namespace.computePublicNamespace(unit).toBuffer());
- return namespace;
-}
-
-/**
- * Override of [SummaryTest] which verifies the correctness of the prelinker by
- * creating summaries from the element model, discarding their prelinked
- * information, and then recreating it using the prelinker.
- */
-@reflectiveTest
-class PrelinkerTest extends SummarizeElementsTest {
- /**
- * The public namespaces of the sdk are computed once so that we don't bog
- * down the test. Structured as a map from absolute URI to the corresponding
- * public namespace.
- *
- * Note: should an exception occur during computation of this variable, it
- * will silently be set to null to allow other tests to run.
- */
- static final Map<String, UnlinkedPublicNamespace> sdkPublicNamespace = () {
- try {
- AnalysisContext analysisContext =
- AnalysisContextFactory.contextWithCore();
- Map<String, UnlinkedPublicNamespace> uriToNamespace =
- <String, UnlinkedPublicNamespace>{};
- List<LibraryElement> libraries = [
- analysisContext.typeProvider.objectType.element.library,
- analysisContext.typeProvider.futureType.element.library
- ];
- for (LibraryElement library in libraries) {
- summarize_elements.LibrarySerializationResult serializedLibrary =
- summarize_elements.serializeLibrary(
- library, analysisContext.typeProvider);
- for (int i = 0; i < serializedLibrary.unlinkedUnits.length; i++) {
- uriToNamespace[
- serializedLibrary.unitUris[i]] = new UnlinkedUnit.fromBuffer(
- serializedLibrary.unlinkedUnits[i].toBuffer()).publicNamespace;
- }
- }
- return uriToNamespace;
- } catch (_) {
- return null;
- }
- }();
-
- final Map<String, UnlinkedPublicNamespace> uriToPublicNamespace =
- <String, UnlinkedPublicNamespace>{};
-
- @override
- bool get expectAbsoluteUrisInDependencies => false;
-
- @override
- Source addNamedSource(String filePath, String contents) {
- Source source = super.addNamedSource(filePath, contents);
- uriToPublicNamespace[absUri(filePath)] =
- computePublicNamespaceFromText(contents, source);
- return source;
- }
-
- String resolveToAbsoluteUri(LibraryElement library, String relativeUri) {
- Source resolvedSource =
- analysisContext.sourceFactory.resolveUri(library.source, relativeUri);
- if (resolvedSource == null) {
- fail('Failed to resolve relative uri "$relativeUri"');
- }
- return resolvedSource.uri.toString();
- }
-
- @override
- void serializeLibraryElement(LibraryElement library) {
- super.serializeLibraryElement(library);
- Map<String, UnlinkedUnit> uriToUnit = <String, UnlinkedUnit>{};
- expect(unlinkedUnits.length, unitUris.length);
- for (int i = 1; i < unlinkedUnits.length; i++) {
- uriToUnit[unitUris[i]] = unlinkedUnits[i];
- }
- UnlinkedUnit getPart(String relativeUri) {
- String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
- UnlinkedUnit unit = uriToUnit[absoluteUri];
- if (unit == null) {
- fail('Prelinker unexpectedly requested unit for "$relativeUri"'
- ' (resolves to "$absoluteUri").');
- }
- return unit;
- }
- UnlinkedPublicNamespace getImport(String relativeUri) {
- String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
- UnlinkedPublicNamespace namespace = sdkPublicNamespace[absoluteUri];
- if (namespace == null) {
- namespace = uriToPublicNamespace[absoluteUri];
- }
- if (namespace == null && !allowMissingFiles) {
- fail('Prelinker unexpectedly requested namespace for "$relativeUri"'
- ' (resolves to "$absoluteUri").'
- ' Namespaces available: ${uriToPublicNamespace.keys}');
- }
- return namespace;
- }
- prelinked = new PrelinkedLibrary.fromBuffer(
- prelink(unlinkedUnits[0], getPart, getImport).toBuffer());
- }
-}
-
-/**
- * Override of [SummaryTest] which creates summaries from the element model.
- */
-@reflectiveTest
-class SummarizeElementsTest extends ResolverTestCase with SummaryTest {
- /**
- * The list of absolute unit URIs corresponding to the compilation units in
- * [unlinkedUnits].
- */
- List<String> unitUris;
-
- /**
- * Map containing all source files in this test, and their corresponding file
- * contents.
- */
- final Map<Source, String> _fileContents = <Source, String>{};
-
- @override
- bool get checkAstDerivedData => false;
-
- @override
- bool get expectAbsoluteUrisInDependencies => true;
-
- @override
- Source addNamedSource(String filePath, String contents) {
- Source source = super.addNamedSource(filePath, contents);
- _fileContents[source] = contents;
- return source;
- }
-
- /**
- * Serialize the library containing the given class [element], then
- * deserialize it and return the summary of the class.
- */
- UnlinkedClass serializeClassElement(ClassElement element) {
- serializeLibraryElement(element.library);
- return findClass(element.name, failIfAbsent: true);
- }
-
- /**
- * Serialize the given [library] element, then deserialize it and store the
- * resulting summary in [prelinked] and [unlinkedUnits].
- */
- void serializeLibraryElement(LibraryElement library) {
- summarize_elements.LibrarySerializationResult serializedLib =
- summarize_elements.serializeLibrary(library, typeProvider);
- {
- List<int> buffer = serializedLib.prelinked.toBuffer();
- prelinked = new PrelinkedLibrary.fromBuffer(buffer);
- }
- unlinkedUnits = serializedLib.unlinkedUnits.map((UnlinkedUnitBuilder b) {
- List<int> buffer = b.toBuffer();
- return new UnlinkedUnit.fromBuffer(buffer);
- }).toList();
- unitUris = serializedLib.unitUris;
- }
-
- @override
- void serializeLibraryText(String text, {bool allowErrors: false}) {
- Source source = addSource(text);
- _fileContents[source] = text;
- LibraryElement library = resolve2(source);
- if (!allowErrors) {
- assertNoErrors(source);
- }
- serializeLibraryElement(library);
- expect(
- unlinkedUnits[0].imports.length, prelinked.importDependencies.length);
- expect(prelinked.units.length, unlinkedUnits.length);
- for (int i = 0; i < prelinked.units.length; i++) {
- expect(unlinkedUnits[i].references.length,
- prelinked.units[i].references.length);
- }
- verifyPublicNamespace();
- }
-
- @override
- void setUp() {
- super.setUp();
- AnalysisOptionsImpl options = new AnalysisOptionsImpl();
- options.enableGenericMethods = true;
- resetWithOptions(options);
- }
-
- test_class_no_superclass() {
- UnlinkedClass cls = serializeClassElement(typeProvider.objectType.element);
- expect(cls.supertype, isNull);
- expect(cls.hasNoSupertype, isTrue);
- }
-
- /**
- * Verify that [public_namespace.computePublicNamespace] produces data that's
- * equivalent to that produced by [summarize_elements.serializeLibrary].
- */
- void verifyPublicNamespace() {
- for (int i = 0; i < unlinkedUnits.length; i++) {
- Source source = analysisContext.sourceFactory.forUri(unitUris[i]);
- String text = _fileContents[source];
- if (text == null) {
- if (!allowMissingFiles) {
- fail('Could not find file while verifying public namespace: '
- '${unitUris[i]}');
- }
- } else {
- UnlinkedPublicNamespace namespace =
- computePublicNamespaceFromText(text, source);
- expect(canonicalize(namespace),
- canonicalize(unlinkedUnits[i].publicNamespace),
- reason: 'publicNamespace(${unitUris[i]})');
- }
- }
- }
-}
-
-/**
- * Base class containing most summary tests. This allows summary tests to be
- * re-used to exercise all the different ways in which summaries can be
- * generated (e.g. direct from the AST, from the element model, from a
- * "relinking" process, etc.)
- */
-abstract class SummaryTest {
- /**
- * Prelinked summary that results from serializing and then deserializing the
- * library under test.
- */
- PrelinkedLibrary prelinked;
-
- /**
- * Unlinked compilation unit summaries that result from serializing and
- * deserializing the library under test.
- */
- List<UnlinkedUnit> unlinkedUnits;
-
- /**
- * A test will set this to `true` if it contains `import`, `export`, or
- * `part` declarations that deliberately refer to non-existent files.
- */
- bool allowMissingFiles = false;
-
- /**
- * `true` if the summary was created directly from the AST (and hence
- * contains information that is not obtainable from the element model alone).
- * TODO(paulberry): modify the element model so that it contains all the data
- * that summaries need, so that this flag is no longer needed.
- */
- bool get checkAstDerivedData;
-
- /**
- * Get access to the prelinked defining compilation unit.
- */
- PrelinkedUnit get definingUnit => prelinked.units[0];
-
- /**
- * `true` if the prelinked portion of the summary is expected to contain
- * absolute URIs. This happens because the element model doesn't (yet) store
- * enough information to recover relative URIs, TODO(paulberry): fix this.
- */
- bool get expectAbsoluteUrisInDependencies;
-
- /**
- * Convert [path] to a suitably formatted absolute path URI for the current
- * platform.
- */
- String absUri(String path) {
- return FileUtilities2.createFile(path).toURI().toString();
- }
-
- /**
- * Add the given source file so that it may be referenced by the file under
- * test.
- */
- Source addNamedSource(String filePath, String contents);
-
- /**
- * Verify that the [dependency]th element of the dependency table represents
- * a file reachable via the given [absoluteUri] and [relativeUri].
- */
- void checkDependency(int dependency, String absoluteUri, String relativeUri) {
- if (expectAbsoluteUrisInDependencies) {
- // The element model doesn't (yet) store enough information to recover
- // relative URIs, so we have to use the absolute URI.
- // TODO(paulberry): fix this.
- relativeUri = absoluteUri;
- }
- expect(dependency, new isInstanceOf<int>());
- expect(prelinked.dependencies[dependency].uri, relativeUri);
- }
-
- /**
- * Verify that the given [dependency] lists the given [absoluteUris] or
- * [relativeUris] as its parts.
- */
- void checkDependencyParts(PrelinkedDependency dependency,
- List<String> absoluteUris, List<String> relativeUris) {
- if (expectAbsoluteUrisInDependencies) {
- // The element model doesn't (yet) store enough information to recover
- // relative URIs, so we have to use the absolute URI.
- // TODO(paulberry): fix this.
- relativeUris = absoluteUris;
- }
- expect(dependency.parts, relativeUris);
- }
-
- /**
- * Check that the given [documentationComment] matches the first
- * Javadoc-style comment found in [text].
- *
- * Note that the algorithm for finding the Javadoc-style comment in [text] is
- * a simple-minded text search; it is easily confused by corner cases such as
- * strings containing comments, nested comments, etc.
- */
- void checkDocumentationComment(
- UnlinkedDocumentationComment documentationComment, String text) {
- expect(documentationComment, isNotNull);
- int commentStart = text.indexOf('/*');
- expect(commentStart, isNot(-1));
- int commentEnd = text.indexOf('*/');
- expect(commentEnd, isNot(-1));
- commentEnd += 2;
- String expectedCommentText =
- text.substring(commentStart, commentEnd).replaceAll('\r\n', '\n');
- expect(documentationComment.text, expectedCommentText);
- expect(documentationComment.offset, commentStart);
- expect(documentationComment.length, commentEnd - commentStart);
- }
-
- /**
- * Verify that the given [typeRef] represents the type `dynamic`.
- */
- void checkDynamicTypeRef(UnlinkedTypeRef typeRef) {
- checkTypeRef(typeRef, null, null, null);
- }
-
- /**
- * Verify that the dependency table contains an entry for a file reachable
- * via the given [absoluteUri] and [relativeUri].
- *
- * The [PrelinkedDependency] is returned.
- */
- PrelinkedDependency checkHasDependency(
- String absoluteUri, String relativeUri) {
- if (expectAbsoluteUrisInDependencies) {
- // The element model doesn't (yet) store enough information to recover
- // relative URIs, so we have to use the absolute URI.
- // TODO(paulberry): fix this.
- relativeUri = absoluteUri;
- }
- List<String> found = <String>[];
- for (PrelinkedDependency dep in prelinked.dependencies) {
- if (dep.uri == relativeUri) {
- return dep;
- }
- found.add(dep.uri);
- }
- fail('Did not find dependency $relativeUri. Found: $found');
- return null;
- }
-
- /**
- * Verify that the dependency table *does not* contain any entries for a file
- * reachable via the given [absoluteUri] and [relativeUri].
- */
- void checkLacksDependency(String absoluteUri, String relativeUri) {
- if (expectAbsoluteUrisInDependencies) {
- // The element model doesn't (yet) store enough information to recover
- // relative URIs, so we have to use the absolute URI.
- // TODO(paulberry): fix this.
- relativeUri = absoluteUri;
- }
- for (PrelinkedDependency dep in prelinked.dependencies) {
- if (dep.uri == relativeUri) {
- fail('Unexpected dependency found: $relativeUri');
- }
- }
- }
-
- /**
- * Verify that the given [typeRef] represents a reference to a type parameter
- * having the given [deBruijnIndex].
- */
- void checkParamTypeRef(UnlinkedTypeRef typeRef, int deBruijnIndex) {
- expect(typeRef, new isInstanceOf<UnlinkedTypeRef>());
- expect(typeRef.reference, 0);
- expect(typeRef.typeArguments, isEmpty);
- expect(typeRef.paramReference, deBruijnIndex);
- }
-
- /**
- * Verify that [prefixReference] is a valid reference to a prefix having the
- * given [name].
- */
- void checkPrefix(int prefixReference, String name) {
- expect(prefixReference, isNot(0));
- expect(unlinkedUnits[0].references[prefixReference].prefixReference, 0);
- expect(unlinkedUnits[0].references[prefixReference].name, name);
- expect(definingUnit.references[prefixReference].dependency, 0);
- expect(definingUnit.references[prefixReference].kind,
- PrelinkedReferenceKind.prefix);
- expect(definingUnit.references[prefixReference].unit, 0);
- }
-
- /**
- * Verify that the given [typeRef] represents a reference to a type declared
- * in a file reachable via [absoluteUri] and [relativeUri], having name
- * [expectedName]. If [expectedPrefix] is supplied, verify that the type is
- * reached via the given prefix. If [allowTypeParameters] is true, allow the
- * type reference to supply type parameters. [expectedKind] is the kind of
- * object referenced. [prelinkedSourceUnit] and [unlinkedSourceUnit] refer
- * to the compilation unit within which the [typeRef] appears; if not
- * specified they are assumed to refer to the defining compilation unit.
- * [expectedTargetUnit] is the index of the compilation unit in which the
- * target of the [typeRef] is expected to appear; if not specified it is
- * assumed to be the defining compilation unit. [numTypeParameters] is the
- * number of type parameters of the thing being referred to.
- */
- void checkTypeRef(UnlinkedTypeRef typeRef, String absoluteUri,
- String relativeUri, String expectedName,
- {String expectedPrefix,
- bool allowTypeParameters: false,
- PrelinkedReferenceKind expectedKind: PrelinkedReferenceKind.classOrEnum,
- int expectedTargetUnit: 0,
- PrelinkedUnit prelinkedSourceUnit,
- UnlinkedUnit unlinkedSourceUnit,
- int numTypeParameters: 0}) {
- prelinkedSourceUnit ??= definingUnit;
- unlinkedSourceUnit ??= unlinkedUnits[0];
- expect(typeRef, new isInstanceOf<UnlinkedTypeRef>());
- expect(typeRef.paramReference, 0);
- int index = typeRef.reference;
- UnlinkedReference reference = unlinkedSourceUnit.references[index];
- PrelinkedReference referenceResolution =
- prelinkedSourceUnit.references[index];
- if (index == 0) {
- // Index 0 is reserved for "dynamic".
- expect(reference.name, isEmpty);
- expect(reference.prefixReference, 0);
- }
- if (absoluteUri == null) {
- expect(referenceResolution.dependency, 0);
- } else {
- checkDependency(referenceResolution.dependency, absoluteUri, relativeUri);
- }
- if (!allowTypeParameters) {
- expect(typeRef.typeArguments, isEmpty);
- }
- if (expectedKind == PrelinkedReferenceKind.unresolved) {
- // summarize_elements.dart isn't yet able to record the name of
- // unresolved references. TODO(paulberry): fix this.
- expect(reference.name, '*unresolved*');
- } else if (expectedName == null) {
- expect(reference.name, isEmpty);
- } else {
- expect(reference.name, expectedName);
- }
- if (expectedPrefix == null) {
- expect(reference.prefixReference, 0);
- } else {
- checkPrefix(reference.prefixReference, expectedPrefix);
- }
- expect(referenceResolution.kind, expectedKind);
- expect(referenceResolution.unit, expectedTargetUnit);
- expect(referenceResolution.numTypeParameters, numTypeParameters);
- }
-
- /**
- * Verify that the given [typeRef] represents a reference to an unresolved
- * type.
- */
- void checkUnresolvedTypeRef(
- UnlinkedTypeRef typeRef, String expectedPrefix, String expectedName) {
- // When serializing from the element model, unresolved type refs lose their
- // name.
- checkTypeRef(typeRef, null, null, checkAstDerivedData ? expectedName : null,
- expectedPrefix: expectedPrefix,
- expectedKind: PrelinkedReferenceKind.unresolved);
- }
-
- fail_enum_value_documented() {
- // TODO(paulberry): currently broken because of dartbug.com/25385
- String text = '''
-enum E {
- /**
- * Docs
- */
- v
-}''';
- UnlinkedEnumValue value = serializeEnumText(text).values[0];
- expect(value.documentationComment, isNotNull);
- checkDocumentationComment(value.documentationComment, text);
- }
-
- fail_test_import_missing() {
- // TODO(paulberry): At the moment unresolved imports are not included in
- // the element model, so we can't pass this test.
- // Unresolved imports are included since this is necessary for proper
- // dependency tracking.
- allowMissingFiles = true;
- serializeLibraryText('import "foo.dart";', allowErrors: true);
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- checkDependency(
- prelinked.importDependencies[0], absUri('/foo.dart'), 'foo.dart');
- }
-
- fail_type_reference_to_nonexistent_file_via_prefix() {
- // TODO(paulberry): this test currently fails because there is not enough
- // information in the element model to figure out that the unresolved
- // reference `p.C` uses the prefix `p`.
- allowMissingFiles = true;
- UnlinkedTypeRef typeRef = serializeTypeText('p.C',
- otherDeclarations: 'import "foo.dart" as p;', allowErrors: true);
- checkUnresolvedTypeRef(typeRef, 'p', 'C');
- }
-
- fail_type_reference_to_type_visible_via_multiple_import_prefixes() {
- // TODO(paulberry): this test currently fails because the element model
- // doesn't record enough information to track which prefix is used to refer
- // to a type.
- addNamedSource('/lib1.dart', 'class C');
- addNamedSource('/lib2.dart', 'export "lib1.dart";');
- addNamedSource('/lib3.dart', 'export "lib1.dart";');
- addNamedSource('/lib4.dart', 'export "lib1.dart";');
- serializeLibraryText('''
-import 'lib2.dart';
-import 'lib3.dart' as a;
-import 'lib4.dart' as b;
-C c2;
-a.C c3;
-b.C c4;''');
- // Note: it is important that each reference to class C records the prefix
- // used to find it; otherwise it's possible that relinking might produce an
- // incorrect result after a change to lib2.dart, lib3.dart, or lib4.dart.
- checkTypeRef(
- findVariable('c2').type, absUri('/lib1.dart'), 'lib1.dart', 'C');
- checkTypeRef(
- findVariable('c3').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
- expectedPrefix: 'a');
- checkTypeRef(
- findVariable('c4').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
- expectedPrefix: 'b');
- }
-
- /**
- * Find the class with the given [className] in the summary, and return its
- * [UnlinkedClass] data structure. If [unit] is not given, the class is
- * looked for in the defining compilation unit.
- */
- UnlinkedClass findClass(String className,
- {bool failIfAbsent: false, UnlinkedUnit unit}) {
- unit ??= unlinkedUnits[0];
- UnlinkedClass result;
- for (UnlinkedClass cls in unit.classes) {
- if (cls.name == className) {
- if (result != null) {
- fail('Duplicate class $className');
- }
- result = cls;
- }
- }
- if (result == null && failIfAbsent) {
- fail('Class $className not found in serialized output');
- }
- return result;
- }
-
- /**
- * Find the enum with the given [enumName] in the summary, and return its
- * [UnlinkedEnum] data structure. If [unit] is not given, the enum is looked
- * for in the defining compilation unit.
- */
- UnlinkedEnum findEnum(String enumName,
- {bool failIfAbsent: false, UnlinkedUnit unit}) {
- unit ??= unlinkedUnits[0];
- UnlinkedEnum result;
- for (UnlinkedEnum e in unit.enums) {
- if (e.name == enumName) {
- if (result != null) {
- fail('Duplicate enum $enumName');
- }
- result = e;
- }
- }
- if (result == null && failIfAbsent) {
- fail('Enum $enumName not found in serialized output');
- }
- return result;
- }
-
- /**
- * Find the executable with the given [executableName] in the summary, and
- * return its [UnlinkedExecutable] data structure. If [executables] is not
- * given, then the executable is searched for in the defining compilation
- * unit.
- */
- UnlinkedExecutable findExecutable(String executableName,
- {List<UnlinkedExecutable> executables, bool failIfAbsent: false}) {
- executables ??= unlinkedUnits[0].executables;
- UnlinkedExecutable result;
- for (UnlinkedExecutable executable in executables) {
- if (executable.name == executableName) {
- if (result != null) {
- fail('Duplicate executable $executableName');
- }
- result = executable;
- }
- }
- if (result == null && failIfAbsent) {
- fail('Executable $executableName not found in serialized output');
- }
- return result;
- }
-
- /**
- * Find the typedef with the given [typedefName] in the summary, and return
- * its [UnlinkedTypedef] data structure. If [unit] is not given, the typedef
- * is looked for in the defining compilation unit.
- */
- UnlinkedTypedef findTypedef(String typedefName,
- {bool failIfAbsent: false, UnlinkedUnit unit}) {
- unit ??= unlinkedUnits[0];
- UnlinkedTypedef result;
- for (UnlinkedTypedef type in unit.typedefs) {
- if (type.name == typedefName) {
- if (result != null) {
- fail('Duplicate typedef $typedefName');
- }
- result = type;
- }
- }
- if (result == null && failIfAbsent) {
- fail('Typedef $typedefName not found in serialized output');
- }
- return result;
- }
-
- /**
- * Find the top level variable with the given [variableName] in the summary,
- * and return its [UnlinkedVariable] data structure. If [variables] is not
- * specified, the variable is looked for in the defining compilation unit.
- */
- UnlinkedVariable findVariable(String variableName,
- {List<UnlinkedVariable> variables, bool failIfAbsent: false}) {
- variables ??= unlinkedUnits[0].variables;
- UnlinkedVariable result;
- for (UnlinkedVariable variable in variables) {
- if (variable.name == variableName) {
- if (result != null) {
- fail('Duplicate variable $variableName');
- }
- result = variable;
- }
- }
- if (result == null && failIfAbsent) {
- fail('Variable $variableName not found in serialized output');
- }
- return result;
- }
-
- /**
- * Serialize the given library [text] and return the summary of the class
- * with the given [className].
- */
- UnlinkedClass serializeClassText(String text, [String className = 'C']) {
- serializeLibraryText(text);
- return findClass(className, failIfAbsent: true);
- }
-
- /**
- * Serialize the given library [text] and return the summary of the enum with
- * the given [enumName].
- */
- UnlinkedEnum serializeEnumText(String text, [String enumName = 'E']) {
- serializeLibraryText(text);
- return findEnum(enumName, failIfAbsent: true);
- }
-
- /**
- * Serialize the given library [text] and return the summary of the
- * executable with the given [executableName].
- */
- UnlinkedExecutable serializeExecutableText(String text,
- [String executableName = 'f']) {
- serializeLibraryText(text);
- return findExecutable(executableName, failIfAbsent: true);
- }
-
- /**
- * Serialize the given library [text], then deserialize it and store its
- * summary in [lib].
- */
- void serializeLibraryText(String text, {bool allowErrors: false});
-
- /**
- * Serialize the given method [text] and return the summary of the executable
- * with the given [executableName].
- */
- UnlinkedExecutable serializeMethodText(String text,
- [String executableName = 'f']) {
- serializeLibraryText('class C { $text }');
- return findExecutable(executableName,
- executables: findClass('C', failIfAbsent: true).executables,
- failIfAbsent: true);
- }
-
- /**
- * Serialize the given library [text] and return the summary of the typedef
- * with the given [typedefName].
- */
- UnlinkedTypedef serializeTypedefText(String text,
- [String typedefName = 'F']) {
- serializeLibraryText(text);
- return findTypedef(typedefName, failIfAbsent: true);
- }
-
- /**
- * Serialize a type declaration using the given [text] as a type name, and
- * return a summary of the corresponding [UnlinkedTypeRef]. If the type
- * declaration needs to refer to types that are not available in core, those
- * types may be declared in [otherDeclarations].
- */
- UnlinkedTypeRef serializeTypeText(String text,
- {String otherDeclarations: '', bool allowErrors: false}) {
- return serializeVariableText('$otherDeclarations\n$text v;',
- allowErrors: allowErrors).type;
- }
-
- /**
- * Serialize the given library [text] and return the summary of the variable
- * with the given [variableName].
- */
- UnlinkedVariable serializeVariableText(String text,
- {String variableName: 'v', bool allowErrors: false}) {
- serializeLibraryText(text, allowErrors: allowErrors);
- return findVariable(variableName, failIfAbsent: true);
- }
-
- test_cascaded_export_hide_hide() {
- addNamedSource('/lib1.dart', 'export "lib2.dart" hide C hide B, C;');
- addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(
- findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_cascaded_export_hide_show() {
- addNamedSource('/lib1.dart', 'export "lib2.dart" hide C show A, C;');
- addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(
- findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_cascaded_export_show_hide() {
- addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B hide B, C;');
- addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(
- findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_cascaded_export_show_show() {
- addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B show A, C;');
- addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(
- findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_cascaded_import_hide_hide() {
- addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib.dart' hide C hide B, C;
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_cascaded_import_hide_show() {
- addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib.dart' hide C show A, C;
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_cascaded_import_show_hide() {
- addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib.dart' show A, B hide B, C;
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_cascaded_import_show_show() {
- addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
- serializeLibraryText(
- '''
-import 'lib.dart' show A, B show A, C;
-A a;
-B b;
-C c;
- ''',
- allowErrors: true);
- checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
- checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
- checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
- }
-
- test_class_abstract() {
- UnlinkedClass cls = serializeClassText('abstract class C {}');
- expect(cls.isAbstract, true);
- }
-
- test_class_alias_abstract() {
- UnlinkedClass cls = serializeClassText(
- 'abstract class C = D with E; class D {} class E {}');
- expect(cls.isAbstract, true);
- }
-
- test_class_alias_concrete() {
- UnlinkedClass cls =
- serializeClassText('class C = _D with _E; class _D {} class _E {}');
- expect(cls.isAbstract, false);
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.classOrEnum);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
- }
-
- test_class_alias_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-class C = D with E;
-
-class D {}
-class E {}''';
- UnlinkedClass cls = serializeClassText(text);
- expect(cls.documentationComment, isNotNull);
- checkDocumentationComment(cls.documentationComment, text);
- }
-
- test_class_alias_flag() {
- UnlinkedClass cls =
- serializeClassText('class C = D with E; class D {} class E {}');
- expect(cls.isMixinApplication, true);
- }
-
- test_class_alias_generic() {
- serializeClassText('class C<A, B> = _D with _E; class _D {} class _E {}');
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 2);
- }
-
- test_class_alias_mixin_order() {
- UnlinkedClass cls = serializeClassText('''
-class C = D with E, F;
-class D {}
-class E {}
-class F {}
-''');
- expect(cls.mixins, hasLength(2));
- checkTypeRef(cls.mixins[0], null, null, 'E');
- checkTypeRef(cls.mixins[1], null, null, 'F');
- }
-
- test_class_alias_no_implicit_constructors() {
- UnlinkedClass cls = serializeClassText('''
-class C = D with E;
-class D {
- D.foo();
- D.bar();
-}
-class E {}
-''');
- expect(cls.executables, isEmpty);
- }
-
- test_class_alias_private() {
- serializeClassText('class _C = _D with _E; class _D {} class _E {}', '_C');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-
- test_class_alias_reference_generic() {
- UnlinkedTypeRef typeRef = serializeTypeText('C',
- otherDeclarations: 'class C<D, E> = F with G; class F {} class G {}');
- checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
- }
-
- test_class_alias_reference_generic_imported() {
- addNamedSource(
- '/lib.dart', 'class C<D, E> = F with G; class F {} class G {}');
- UnlinkedTypeRef typeRef =
- serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
- checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
- numTypeParameters: 2);
- }
-
- test_class_alias_supertype() {
- UnlinkedClass cls =
- serializeClassText('class C = D with E; class D {} class E {}');
- checkTypeRef(cls.supertype, null, null, 'D');
- expect(cls.hasNoSupertype, isFalse);
- }
-
- test_class_concrete() {
- UnlinkedClass cls = serializeClassText('class C {}');
- expect(cls.isAbstract, false);
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.classOrEnum);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
- }
-
- test_class_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-class C {}''';
- UnlinkedClass cls = serializeClassText(text);
- expect(cls.documentationComment, isNotNull);
- checkDocumentationComment(cls.documentationComment, text);
- }
-
- test_class_documented_with_references() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs referring to [D] and [E]
- */
-class C {}
-
-class D {}
-class E {}''';
- UnlinkedClass cls = serializeClassText(text);
- expect(cls.documentationComment, isNotNull);
- checkDocumentationComment(cls.documentationComment, text);
- }
-
- test_class_documented_with_with_windows_line_endings() {
- String text = '/**\r\n * Docs\r\n */\r\nclass C {}';
- UnlinkedClass cls = serializeClassText(text);
- expect(cls.documentationComment, isNotNull);
- checkDocumentationComment(cls.documentationComment, text);
- }
-
- test_class_interface() {
- UnlinkedClass cls = serializeClassText('''
-class C implements D {}
-class D {}
-''');
- expect(cls.interfaces, hasLength(1));
- checkTypeRef(cls.interfaces[0], null, null, 'D');
- }
-
- test_class_interface_order() {
- UnlinkedClass cls = serializeClassText('''
-class C implements D, E {}
-class D {}
-class E {}
-''');
- expect(cls.interfaces, hasLength(2));
- checkTypeRef(cls.interfaces[0], null, null, 'D');
- checkTypeRef(cls.interfaces[1], null, null, 'E');
- }
-
- test_class_mixin() {
- UnlinkedClass cls = serializeClassText('''
-class C extends Object with D {}
-class D {}
-''');
- expect(cls.mixins, hasLength(1));
- checkTypeRef(cls.mixins[0], null, null, 'D');
- }
-
- test_class_mixin_order() {
- UnlinkedClass cls = serializeClassText('''
-class C extends Object with D, E {}
-class D {}
-class E {}
-''');
- expect(cls.mixins, hasLength(2));
- checkTypeRef(cls.mixins[0], null, null, 'D');
- checkTypeRef(cls.mixins[1], null, null, 'E');
- }
-
- test_class_name() {
- var classText = 'class C {}';
- UnlinkedClass cls = serializeClassText(classText);
- expect(cls.name, 'C');
- expect(cls.nameOffset, classText.indexOf('C'));
- }
-
- test_class_no_flags() {
- UnlinkedClass cls = serializeClassText('class C {}');
- expect(cls.isAbstract, false);
- expect(cls.isMixinApplication, false);
- }
-
- test_class_no_interface() {
- UnlinkedClass cls = serializeClassText('class C {}');
- expect(cls.interfaces, isEmpty);
- }
-
- test_class_no_mixins() {
- UnlinkedClass cls = serializeClassText('class C {}');
- expect(cls.mixins, isEmpty);
- }
-
- test_class_no_type_param() {
- UnlinkedClass cls = serializeClassText('class C {}');
- expect(cls.typeParameters, isEmpty);
- }
-
- test_class_non_alias_flag() {
- UnlinkedClass cls = serializeClassText('class C {}');
- expect(cls.isMixinApplication, false);
- }
-
- test_class_private() {
- serializeClassText('class _C {}', '_C');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-
- test_class_reference_generic() {
- UnlinkedTypeRef typeRef =
- serializeTypeText('C', otherDeclarations: 'class C<D, E> {}');
- checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
- }
-
- test_class_reference_generic_imported() {
- addNamedSource('/lib.dart', 'class C<D, E> {}');
- UnlinkedTypeRef typeRef =
- serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
- checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
- numTypeParameters: 2);
- }
-
- test_class_superclass() {
- UnlinkedClass cls = serializeClassText('class C {}');
- expect(cls.supertype, isNull);
- expect(cls.hasNoSupertype, isFalse);
- }
-
- test_class_superclass_explicit() {
- UnlinkedClass cls = serializeClassText('class C extends D {} class D {}');
- expect(cls.supertype, isNotNull);
- checkTypeRef(cls.supertype, null, null, 'D');
- expect(cls.hasNoSupertype, isFalse);
- }
-
- test_class_type_param_bound() {
- UnlinkedClass cls = serializeClassText('class C<T extends List> {}');
- expect(cls.typeParameters, hasLength(1));
- expect(cls.typeParameters[0].name, 'T');
- expect(cls.typeParameters[0].bound, isNotNull);
- checkTypeRef(cls.typeParameters[0].bound, 'dart:core', 'dart:core', 'List',
- allowTypeParameters: true, numTypeParameters: 1);
- }
-
- test_class_type_param_f_bound() {
- UnlinkedClass cls = serializeClassText('class C<T, U extends List<T>> {}');
- UnlinkedTypeRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
- checkParamTypeRef(typeArgument, 2);
- }
-
- test_class_type_param_f_bound_self_ref() {
- UnlinkedClass cls = serializeClassText('class C<T, U extends List<U>> {}');
- UnlinkedTypeRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
- checkParamTypeRef(typeArgument, 1);
- }
-
- test_class_type_param_no_bound() {
- String text = 'class C<T> {}';
- UnlinkedClass cls = serializeClassText(text);
- expect(cls.typeParameters, hasLength(1));
- expect(cls.typeParameters[0].name, 'T');
- expect(cls.typeParameters[0].nameOffset, text.indexOf('T'));
- expect(cls.typeParameters[0].bound, isNull);
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
- }
-
- test_constructor() {
- String text = 'class C { C(); }';
- UnlinkedExecutable executable =
- findExecutable('', executables: serializeClassText(text).executables);
- expect(executable.kind, UnlinkedExecutableKind.constructor);
- expect(executable.hasImplicitReturnType, isFalse);
- expect(executable.isExternal, isFalse);
- expect(executable.nameOffset, text.indexOf('C();'));
- }
-
- test_constructor_anonymous() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(); }').executables);
- expect(executable.name, isEmpty);
- }
-
- test_constructor_const() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { const C(); }').executables);
- expect(executable.isConst, isTrue);
- expect(executable.isExternal, isFalse);
- }
-
- test_constructor_const_external() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { external const C(); }').executables);
- expect(executable.isConst, isTrue);
- expect(executable.isExternal, isTrue);
- }
-
- test_constructor_documented() {
- String text = '''
-class C {
- /**
- * Docs
- */
- C();
-}''';
- UnlinkedExecutable executable = serializeClassText(text).executables[0];
- expect(executable.documentationComment, isNotNull);
- checkDocumentationComment(executable.documentationComment, text);
- }
-
- test_constructor_external() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { external C(); }').executables);
- expect(executable.isExternal, isTrue);
- }
-
- test_constructor_factory() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { factory C() => null; }').executables);
- expect(executable.isFactory, isTrue);
- }
-
- test_constructor_implicit() {
- // Implicit constructors are not serialized.
- UnlinkedExecutable executable = findExecutable(null,
- executables: serializeClassText('class C { C(); }').executables,
- failIfAbsent: false);
- expect(executable, isNull);
- }
-
- test_constructor_initializing_formal() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { C(this.x); final x; }').executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.isInitializingFormal, isTrue);
- }
-
- test_constructor_initializing_formal_explicit_type() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(int this.x); final x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
- }
-
- test_constructor_initializing_formal_function_typed() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(this.x()); final x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.isFunctionTyped, isTrue);
- }
-
- test_constructor_initializing_formal_function_typed_explicit_return_type() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { C(int this.x()); Function x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
- }
-
- test_constructor_initializing_formal_function_typed_implicit_return_type() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(this.x()); Function x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- // Since the parameter is function-typed it is considered to have an
- // explicit type, even though that explicit type itself has an implicit
- // return type.
- expect(parameter.hasImplicitType, isFalse);
- checkDynamicTypeRef(parameter.type);
- }
-
- test_constructor_initializing_formal_function_typed_no_parameters() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(this.x()); final x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.parameters, isEmpty);
- }
-
- test_constructor_initializing_formal_function_typed_parameter() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(this.x(a)); final x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.parameters, hasLength(1));
- }
-
- test_constructor_initializing_formal_function_typed_parameter_order() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(this.x(a, b)); final x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.parameters, hasLength(2));
- expect(parameter.parameters[0].name, 'a');
- expect(parameter.parameters[1].name, 'b');
- }
-
- test_constructor_initializing_formal_implicit_type() {
- // Note: the implicit type of an initializing formal is the type of the
- // field.
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { C(this.x); int x; }').executables);
- UnlinkedParam parameter = executable.parameters[0];
- checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
- expect(parameter.hasImplicitType, isTrue);
- }
-
- test_constructor_initializing_formal_name() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { C(this.x); final x; }').executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.name, 'x');
- }
-
- test_constructor_initializing_formal_named() {
- // TODO(paulberry): also test default value
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C({this.x}); final x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.kind, UnlinkedParamKind.named);
- }
-
- test_constructor_initializing_formal_non_function_typed() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { C(this.x); final x; }').executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.isFunctionTyped, isFalse);
- }
-
- test_constructor_initializing_formal_positional() {
- // TODO(paulberry): also test default value
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C([this.x]); final x; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.kind, UnlinkedParamKind.positional);
- }
-
- test_constructor_initializing_formal_required() {
- UnlinkedExecutable executable = findExecutable('',
- executables:
- serializeClassText('class C { C(this.x); final x; }').executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.kind, UnlinkedParamKind.required);
- }
-
- test_constructor_initializing_formal_typedef() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText(
- 'typedef F<T>(T x); class C<X> { C(this.f); F<X> f; }')
- .executables);
- UnlinkedParam parameter = executable.parameters[0];
- expect(parameter.parameters, hasLength(1));
- }
-
- test_constructor_named() {
- String text = 'class C { C.foo(); }';
- UnlinkedExecutable executable = findExecutable('foo',
- executables: serializeClassText(text).executables);
- expect(executable.name, 'foo');
- expect(executable.nameOffset, text.indexOf('foo'));
- }
-
- test_constructor_non_const() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(); }').executables);
- expect(executable.isConst, isFalse);
- }
-
- test_constructor_non_factory() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(); }').executables);
- expect(executable.isFactory, isFalse);
- }
-
- test_constructor_return_type() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C { C(); }').executables);
- expect(executable.returnType, isNull);
- }
-
- test_constructor_return_type_parameterized() {
- UnlinkedExecutable executable = findExecutable('',
- executables: serializeClassText('class C<T, U> { C(); }').executables);
- expect(executable.returnType, isNull);
- }
-
- test_dependencies_export_none() {
- // Exports are not listed as dependencies since no change to the exported
- // file can change the summary of the exporting file.
- // TODO(paulberry): this needs to change since the element model for a
- // library includes its export namespace.
- addNamedSource('/a.dart', 'library a; export "b.dart";');
- addNamedSource('/b.dart', 'library b;');
- serializeLibraryText('export "a.dart";');
- checkLacksDependency(absUri('/a.dart'), 'a.dart');
- checkLacksDependency(absUri('/b.dart'), 'b.dart');
- }
-
- test_dependencies_import_to_export() {
- addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
- addNamedSource('/b.dart', 'library b;');
- serializeLibraryText('import "a.dart"; A a;');
- checkHasDependency(absUri('/a.dart'), 'a.dart');
- // The main test library depends on b.dart, because names defined in
- // b.dart are exported by a.dart.
- checkHasDependency(absUri('/b.dart'), 'b.dart');
- }
-
- test_dependencies_import_to_export_in_subdirs_absolute_export() {
- addNamedSource('/a/a.dart',
- 'library a; export "${absUri('/a/b/b.dart')}"; class A {}');
- addNamedSource('/a/b/b.dart', 'library b;');
- serializeLibraryText('import "a/a.dart"; A a;');
- checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
- // The main test library depends on b.dart, because names defined in
- // b.dart are exported by a.dart.
- checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
- }
-
- test_dependencies_import_to_export_in_subdirs_absolute_import() {
- addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
- addNamedSource('/a/b/b.dart', 'library b;');
- serializeLibraryText('import "${absUri('/a/a.dart')}"; A a;');
- checkHasDependency(absUri('/a/a.dart'), absUri('/a/a.dart'));
- // The main test library depends on b.dart, because names defined in
- // b.dart are exported by a.dart.
- checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
- }
-
- test_dependencies_import_to_export_in_subdirs_relative() {
- addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
- addNamedSource('/a/b/b.dart', 'library b;');
- serializeLibraryText('import "a/a.dart"; A a;');
- checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
- // The main test library depends on b.dart, because names defined in
- // b.dart are exported by a.dart.
- checkHasDependency(absUri('/a/b/b.dart'), 'a/b/b.dart');
- }
-
- test_dependencies_import_to_export_loop() {
- addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
- addNamedSource('/b.dart', 'library b; export "a.dart";');
- serializeLibraryText('import "a.dart"; A a;');
- checkHasDependency(absUri('/a.dart'), 'a.dart');
- // Serialization should have been able to walk the transitive export
- // dependencies to b.dart without going into an infinite loop.
- checkHasDependency(absUri('/b.dart'), 'b.dart');
- }
-
- test_dependencies_import_to_export_transitive_closure() {
- addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
- addNamedSource('/b.dart', 'library b; export "c.dart";');
- addNamedSource('/c.dart', 'library c;');
- serializeLibraryText('import "a.dart"; A a;');
- checkHasDependency(absUri('/a.dart'), 'a.dart');
- // The main test library depends on c.dart, because names defined in
- // c.dart are exported by b.dart and then re-exported by a.dart.
- checkHasDependency(absUri('/c.dart'), 'c.dart');
- }
-
- test_dependencies_import_transitive_closure() {
- addNamedSource(
- '/a.dart', 'library a; import "b.dart"; class A extends B {}');
- addNamedSource('/b.dart', 'library b; class B {}');
- serializeLibraryText('import "a.dart"; A a;');
- checkHasDependency(absUri('/a.dart'), 'a.dart');
- // The main test library doesn't depend on b.dart, because no change to
- // b.dart can possibly affect the serialized element model for it.
- checkLacksDependency(absUri('/b.dart'), 'b.dart');
- }
-
- test_dependencies_parts() {
- addNamedSource(
- '/a.dart', 'library a; part "b.dart"; part "c.dart"; class A {}');
- addNamedSource('/b.dart', 'part of a;');
- addNamedSource('/c.dart', 'part of a;');
- serializeLibraryText('import "a.dart"; A a;');
- PrelinkedDependency dep = checkHasDependency(absUri('/a.dart'), 'a.dart');
- checkDependencyParts(
- dep, [absUri('/b.dart'), absUri('/c.dart')], ['b.dart', 'c.dart']);
- }
-
- test_dependencies_parts_relative_to_importing_library() {
- addNamedSource('/a/b.dart', 'export "c/d.dart";');
- addNamedSource('/a/c/d.dart',
- 'library d; part "e/f.dart"; part "g/h.dart"; class D {}');
- addNamedSource('/a/c/e/f.dart', 'part of d;');
- addNamedSource('/a/c/g/h.dart', 'part of d;');
- serializeLibraryText('import "a/b.dart"; D d;');
- PrelinkedDependency dep =
- checkHasDependency(absUri('/a/c/d.dart'), 'a/c/d.dart');
- checkDependencyParts(
- dep,
- [absUri('/a/c/e/f.dart'), absUri('/a/c/g/h.dart')],
- ['a/c/e/f.dart', 'a/c/g/h.dart']);
- }
-
- test_elements_in_part() {
- addNamedSource(
- '/part1.dart',
- '''
-part of my.lib;
-
-class C {}
-enum E { v }
-var v;
-f() {}
-typedef F();
-''');
- serializeLibraryText('library my.lib; part "part1.dart";');
- UnlinkedUnit unit = unlinkedUnits[1];
- expect(findClass('C', unit: unit), isNotNull);
- expect(findEnum('E', unit: unit), isNotNull);
- expect(findVariable('v', variables: unit.variables), isNotNull);
- expect(findExecutable('f', executables: unit.executables), isNotNull);
- expect(findTypedef('F', unit: unit), isNotNull);
- }
-
- test_enum() {
- String text = 'enum E { v1 }';
- UnlinkedEnum e = serializeEnumText(text);
- expect(e.name, 'E');
- expect(e.nameOffset, text.indexOf('E'));
- expect(e.values, hasLength(1));
- expect(e.values[0].name, 'v1');
- expect(e.values[0].nameOffset, text.indexOf('v1'));
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.classOrEnum);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'E');
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
- }
-
- test_enum_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-enum E { v }''';
- UnlinkedEnum enm = serializeEnumText(text);
- expect(enm.documentationComment, isNotNull);
- checkDocumentationComment(enm.documentationComment, text);
- }
-
- test_enum_order() {
- UnlinkedEnum e = serializeEnumText('enum E { v1, v2 }');
- expect(e.values, hasLength(2));
- expect(e.values[0].name, 'v1');
- expect(e.values[1].name, 'v2');
- }
-
- test_enum_private() {
- serializeEnumText('enum _E { v1 }', '_E');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-
- test_executable_abstract() {
- UnlinkedExecutable executable =
- serializeClassText('abstract class C { f(); }').executables[0];
- expect(executable.isAbstract, isTrue);
- }
-
- test_executable_concrete() {
- UnlinkedExecutable executable =
- serializeClassText('abstract class C { f() {} }').executables[0];
- expect(executable.isAbstract, isFalse);
- }
-
- test_executable_function() {
- String text = ' f() {}';
- UnlinkedExecutable executable = serializeExecutableText(text);
- expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
- expect(executable.hasImplicitReturnType, isTrue);
- checkDynamicTypeRef(executable.returnType);
- expect(executable.isExternal, isFalse);
- expect(executable.nameOffset, text.indexOf('f'));
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.other);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
- }
-
- test_executable_function_explicit_return() {
- UnlinkedExecutable executable =
- serializeExecutableText('dynamic f() => null;');
- expect(executable.hasImplicitReturnType, isFalse);
- checkDynamicTypeRef(executable.returnType);
- }
-
- test_executable_function_external() {
- UnlinkedExecutable executable = serializeExecutableText('external f();');
- expect(executable.isExternal, isTrue);
- }
-
- test_executable_function_private() {
- serializeExecutableText('_f() {}', '_f');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-
- test_executable_getter() {
- String text = 'int get f => 1;';
- UnlinkedExecutable executable = serializeExecutableText(text);
- expect(executable.kind, UnlinkedExecutableKind.getter);
- expect(executable.hasImplicitReturnType, isFalse);
- expect(executable.isExternal, isFalse);
- expect(executable.nameOffset, text.indexOf('f'));
- expect(findVariable('f'), isNull);
- expect(findExecutable('f='), isNull);
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.other);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
- }
-
- test_executable_getter_external() {
- UnlinkedExecutable executable =
- serializeExecutableText('external int get f;');
- expect(executable.isExternal, isTrue);
- }
-
- test_executable_getter_private() {
- serializeExecutableText('int get _f => 1;', '_f');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-
- test_executable_getter_type() {
- UnlinkedExecutable executable = serializeExecutableText('int get f => 1;');
- checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
- expect(executable.parameters, isEmpty);
- }
-
- test_executable_getter_type_implicit() {
- UnlinkedExecutable executable = serializeExecutableText('get f => 1;');
- checkDynamicTypeRef(executable.returnType);
- expect(executable.hasImplicitReturnType, isTrue);
- expect(executable.parameters, isEmpty);
- }
-
- test_executable_member_function() {
- UnlinkedExecutable executable = findExecutable('f',
- executables: serializeClassText('class C { f() {} }').executables);
- expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
- expect(executable.hasImplicitReturnType, isTrue);
- expect(executable.isExternal, isFalse);
- }
-
- test_executable_member_function_explicit_return() {
- UnlinkedExecutable executable = findExecutable('f',
- executables:
- serializeClassText('class C { dynamic f() => null; }').executables);
- expect(executable.hasImplicitReturnType, isFalse);
- }
-
- test_executable_member_function_external() {
- UnlinkedExecutable executable = findExecutable('f',
- executables:
- serializeClassText('class C { external f(); }').executables);
- expect(executable.isExternal, isTrue);
- }
-
- test_executable_member_getter() {
- UnlinkedClass cls = serializeClassText('class C { int get f => 1; }');
- UnlinkedExecutable executable =
- findExecutable('f', executables: cls.executables, failIfAbsent: true);
- expect(executable.kind, UnlinkedExecutableKind.getter);
- expect(executable.hasImplicitReturnType, isFalse);
- expect(executable.isExternal, isFalse);
- expect(findVariable('f', variables: cls.fields), isNull);
- expect(findExecutable('f=', executables: cls.executables), isNull);
- }
-
- test_executable_member_getter_external() {
- UnlinkedClass cls = serializeClassText('class C { external int get f; }');
- UnlinkedExecutable executable =
- findExecutable('f', executables: cls.executables, failIfAbsent: true);
- expect(executable.isExternal, isTrue);
- }
-
- test_executable_member_setter() {
- UnlinkedClass cls = serializeClassText('class C { void set f(value) {} }');
- UnlinkedExecutable executable =
- findExecutable('f=', executables: cls.executables, failIfAbsent: true);
- expect(executable.kind, UnlinkedExecutableKind.setter);
- expect(executable.hasImplicitReturnType, isFalse);
- expect(executable.isExternal, isFalse);
- expect(findVariable('f', variables: cls.fields), isNull);
- expect(findExecutable('f', executables: cls.executables), isNull);
- }
-
- test_executable_member_setter_external() {
- UnlinkedClass cls =
- serializeClassText('class C { external void set f(value); }');
- UnlinkedExecutable executable =
- findExecutable('f=', executables: cls.executables, failIfAbsent: true);
- expect(executable.isExternal, isTrue);
- }
-
- test_executable_member_setter_implicit_return() {
- UnlinkedClass cls = serializeClassText('class C { set f(value) {} }');
- UnlinkedExecutable executable =
- findExecutable('f=', executables: cls.executables, failIfAbsent: true);
- expect(executable.hasImplicitReturnType, isTrue);
- checkDynamicTypeRef(executable.returnType);
- }
-
- test_executable_name() {
- UnlinkedExecutable executable = serializeExecutableText('f() {}');
- expect(executable.name, 'f');
- }
-
- test_executable_no_flags() {
- UnlinkedExecutable executable = serializeExecutableText('f() {}');
- expect(executable.isAbstract, isFalse);
- expect(executable.isConst, isFalse);
- expect(executable.isFactory, isFalse);
- expect(executable.isStatic, isFalse);
- }
-
- test_executable_non_static() {
- UnlinkedExecutable executable =
- serializeClassText('class C { f() {} }').executables[0];
- expect(executable.isStatic, isFalse);
- }
-
- test_executable_non_static_top_level() {
- // Top level executables are considered non-static.
- UnlinkedExecutable executable = serializeExecutableText('f() {}');
- expect(executable.isStatic, isFalse);
- }
-
- test_executable_operator() {
- UnlinkedExecutable executable =
- serializeClassText('class C { C operator+(C c) => null; }').executables[
- 0];
- expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
- expect(executable.name, '+');
- expect(executable.hasImplicitReturnType, false);
- expect(executable.isAbstract, false);
- expect(executable.isConst, false);
- expect(executable.isFactory, false);
- expect(executable.isStatic, false);
- expect(executable.parameters, hasLength(1));
- checkTypeRef(executable.returnType, null, null, 'C');
- expect(executable.typeParameters, isEmpty);
- expect(executable.isExternal, false);
- }
-
- test_executable_operator_equal() {
- UnlinkedExecutable executable =
- serializeClassText('class C { bool operator==(C other) => false; }')
- .executables[0];
- expect(executable.name, '==');
- }
-
- test_executable_operator_external() {
- UnlinkedExecutable executable =
- serializeClassText('class C { external C operator+(C c); }')
- .executables[0];
- expect(executable.isExternal, true);
- }
-
- test_executable_operator_greater_equal() {
- UnlinkedExecutable executable =
- serializeClassText('class C { bool operator>=(C other) => false; }')
- .executables[0];
- expect(executable.name, '>=');
- }
-
- test_executable_operator_index() {
- UnlinkedExecutable executable =
- serializeClassText('class C { bool operator[](int i) => null; }')
- .executables[0];
- expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
- expect(executable.name, '[]');
- expect(executable.hasImplicitReturnType, false);
- expect(executable.isAbstract, false);
- expect(executable.isConst, false);
- expect(executable.isFactory, false);
- expect(executable.isStatic, false);
- expect(executable.parameters, hasLength(1));
- checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'bool');
- expect(executable.typeParameters, isEmpty);
- }
-
- test_executable_operator_index_set() {
- UnlinkedExecutable executable = serializeClassText(
- 'class C { void operator[]=(int i, bool v) => null; }').executables[0];
- expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
- expect(executable.name, '[]=');
- expect(executable.hasImplicitReturnType, false);
- expect(executable.isAbstract, false);
- expect(executable.isConst, false);
- expect(executable.isFactory, false);
- expect(executable.isStatic, false);
- expect(executable.parameters, hasLength(2));
- expect(executable.returnType, isNull);
- expect(executable.typeParameters, isEmpty);
- }
-
- test_executable_operator_less_equal() {
- UnlinkedExecutable executable =
- serializeClassText('class C { bool operator<=(C other) => false; }')
- .executables[0];
- expect(executable.name, '<=');
- }
-
- test_executable_param_function_typed() {
- UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
- expect(executable.parameters[0].isFunctionTyped, isTrue);
- // Since the parameter is function-typed it is considered to have an
- // explicit type, even though that explicit type itself has an implicit
- // return type.
- expect(executable.parameters[0].hasImplicitType, isFalse);
- }
-
- test_executable_param_function_typed_explicit_return_type() {
- UnlinkedExecutable executable =
- serializeExecutableText('f(dynamic g()) {}');
- expect(executable.parameters[0].hasImplicitType, isFalse);
- }
-
- test_executable_param_function_typed_param() {
- UnlinkedExecutable executable = serializeExecutableText('f(g(x)) {}');
- expect(executable.parameters[0].parameters, hasLength(1));
- }
-
- test_executable_param_function_typed_param_none() {
- UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
- expect(executable.parameters[0].parameters, isEmpty);
- }
-
- test_executable_param_function_typed_param_order() {
- UnlinkedExecutable executable = serializeExecutableText('f(g(x, y)) {}');
- expect(executable.parameters[0].parameters, hasLength(2));
- expect(executable.parameters[0].parameters[0].name, 'x');
- expect(executable.parameters[0].parameters[1].name, 'y');
- }
-
- test_executable_param_function_typed_return_type() {
- UnlinkedExecutable executable = serializeExecutableText('f(int g()) {}');
- checkTypeRef(
- executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
- }
-
- test_executable_param_function_typed_return_type_implicit() {
- UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
- checkDynamicTypeRef(executable.parameters[0].type);
- }
-
- test_executable_param_function_typed_return_type_void() {
- UnlinkedExecutable executable = serializeExecutableText('f(void g()) {}');
- expect(executable.parameters[0].type, isNull);
- }
-
- test_executable_param_kind_named() {
- UnlinkedExecutable executable = serializeExecutableText('f({x}) {}');
- expect(executable.parameters[0].kind, UnlinkedParamKind.named);
- }
-
- test_executable_param_kind_positional() {
- UnlinkedExecutable executable = serializeExecutableText('f([x]) {}');
- expect(executable.parameters[0].kind, UnlinkedParamKind.positional);
- }
-
- test_executable_param_kind_required() {
- UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
- expect(executable.parameters[0].kind, UnlinkedParamKind.required);
- }
-
- test_executable_param_name() {
- String text = 'f(x) {}';
- UnlinkedExecutable executable = serializeExecutableText(text);
- expect(executable.parameters, hasLength(1));
- expect(executable.parameters[0].name, 'x');
- expect(executable.parameters[0].nameOffset, text.indexOf('x'));
- }
-
- test_executable_param_no_flags() {
- UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
- expect(executable.parameters[0].isFunctionTyped, isFalse);
- expect(executable.parameters[0].isInitializingFormal, isFalse);
- }
-
- test_executable_param_non_function_typed() {
- UnlinkedExecutable executable = serializeExecutableText('f(g) {}');
- expect(executable.parameters[0].isFunctionTyped, isFalse);
- }
-
- test_executable_param_none() {
- UnlinkedExecutable executable = serializeExecutableText('f() {}');
- expect(executable.parameters, isEmpty);
- }
-
- test_executable_param_order() {
- UnlinkedExecutable executable = serializeExecutableText('f(x, y) {}');
- expect(executable.parameters, hasLength(2));
- expect(executable.parameters[0].name, 'x');
- expect(executable.parameters[1].name, 'y');
- }
-
- test_executable_param_type_explicit() {
- UnlinkedExecutable executable = serializeExecutableText('f(dynamic x) {}');
- checkDynamicTypeRef(executable.parameters[0].type);
- expect(executable.parameters[0].hasImplicitType, isFalse);
- }
-
- test_executable_param_type_implicit() {
- UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
- checkDynamicTypeRef(executable.parameters[0].type);
- expect(executable.parameters[0].hasImplicitType, isTrue);
- }
-
- test_executable_return_type() {
- UnlinkedExecutable executable = serializeExecutableText('int f() => 1;');
- checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
- expect(executable.hasImplicitReturnType, isFalse);
- }
-
- test_executable_return_type_implicit() {
- UnlinkedExecutable executable = serializeExecutableText('f() {}');
- checkDynamicTypeRef(executable.returnType);
- expect(executable.hasImplicitReturnType, isTrue);
- }
-
- test_executable_return_type_void() {
- UnlinkedExecutable executable = serializeExecutableText('void f() {}');
- expect(executable.returnType, isNull);
- }
-
- test_executable_setter() {
- String text = 'void set f(value) {}';
- UnlinkedExecutable executable = serializeExecutableText(text, 'f=');
- expect(executable.kind, UnlinkedExecutableKind.setter);
- expect(executable.hasImplicitReturnType, isFalse);
- expect(executable.isExternal, isFalse);
- expect(executable.nameOffset, text.indexOf('f'));
- expect(findVariable('f'), isNull);
- expect(findExecutable('f'), isNull);
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.other);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f=');
- }
-
- test_executable_setter_external() {
- UnlinkedExecutable executable =
- serializeExecutableText('external void set f(value);', 'f=');
- expect(executable.isExternal, isTrue);
- }
-
- test_executable_setter_implicit_return() {
- UnlinkedExecutable executable =
- serializeExecutableText('set f(value) {}', 'f=');
- expect(executable.hasImplicitReturnType, isTrue);
- checkDynamicTypeRef(executable.returnType);
- }
-
- test_executable_setter_private() {
- serializeExecutableText('void set _f(value) {}', '_f=');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-
- test_executable_setter_type() {
- UnlinkedExecutable executable =
- serializeExecutableText('void set f(int value) {}', 'f=');
- expect(executable.returnType, isNull);
- expect(executable.parameters, hasLength(1));
- expect(executable.parameters[0].name, 'value');
- checkTypeRef(
- executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
- }
-
- test_executable_static() {
- UnlinkedExecutable executable =
- serializeClassText('class C { static f() {} }').executables[0];
- expect(executable.isStatic, isTrue);
- }
-
- test_executable_type_param_f_bound_function() {
- UnlinkedExecutable ex =
- serializeExecutableText('void f<T, U extends List<T>>() {}');
- UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
- checkParamTypeRef(typeArgument, 2);
- }
-
- test_executable_type_param_f_bound_method() {
- UnlinkedExecutable ex =
- serializeMethodText('void f<T, U extends List<T>>() {}');
- UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
- checkParamTypeRef(typeArgument, 2);
- }
-
- test_executable_type_param_f_bound_self_ref_function() {
- UnlinkedExecutable ex =
- serializeExecutableText('void f<T, U extends List<U>>() {}');
- UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
- checkParamTypeRef(typeArgument, 1);
- }
-
- test_executable_type_param_f_bound_self_ref_method() {
- UnlinkedExecutable ex =
- serializeMethodText('void f<T, U extends List<U>>() {}');
- UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
- checkParamTypeRef(typeArgument, 1);
- }
-
- test_executable_type_param_in_parameter_function() {
- UnlinkedExecutable ex = serializeExecutableText('void f<T>(T t) {}');
- checkParamTypeRef(ex.parameters[0].type, 1);
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
- }
-
- test_executable_type_param_in_parameter_method() {
- UnlinkedExecutable ex = serializeMethodText('void f<T>(T t) {}');
- checkParamTypeRef(ex.parameters[0].type, 1);
- }
-
- test_executable_type_param_in_return_type_function() {
- UnlinkedExecutable ex = serializeExecutableText('T f<T>() => null;');
- checkParamTypeRef(ex.returnType, 1);
- }
-
- test_executable_type_param_in_return_type_method() {
- UnlinkedExecutable ex = serializeMethodText('T f<T>() => null;');
- checkParamTypeRef(ex.returnType, 1);
- }
-
- test_export_hide_order() {
- serializeLibraryText('export "dart:async" hide Future, Stream;');
- expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
- expect(
- unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
- isEmpty);
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
- hasLength(2));
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[0],
- 'Future');
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[1],
- 'Stream');
- }
-
- test_export_no_combinators() {
- serializeLibraryText('export "dart:async";');
- expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators, isEmpty);
- }
-
- test_export_offset() {
- String libraryText = ' export "dart:async";';
- serializeLibraryText(libraryText);
- expect(unlinkedUnits[0].exports[0].uriOffset,
- libraryText.indexOf('"dart:async"'));
- expect(unlinkedUnits[0].exports[0].uriEnd, libraryText.indexOf(';'));
- expect(unlinkedUnits[0].exports[0].offset, libraryText.indexOf('export'));
- }
-
- test_export_show_order() {
- serializeLibraryText('export "dart:async" show Future, Stream;');
- expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
- expect(
- unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
- hasLength(2));
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
- isEmpty);
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[0],
- 'Future');
- expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[1],
- 'Stream');
- }
-
- test_export_uri() {
- addNamedSource('/a.dart', 'library my.lib;');
- String uriString = '"a.dart"';
- String libraryText = 'export $uriString;';
- serializeLibraryText(libraryText);
- expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.exports[0].uri, 'a.dart');
- }
-
- test_field() {
- UnlinkedClass cls = serializeClassText('class C { int i; }');
- UnlinkedVariable variable = findVariable('i', variables: cls.fields);
- expect(variable, isNotNull);
- expect(variable.isConst, isFalse);
- expect(variable.isStatic, isFalse);
- expect(variable.isFinal, isFalse);
- expect(findExecutable('i', executables: cls.executables), isNull);
- expect(findExecutable('i=', executables: cls.executables), isNull);
- }
-
- test_field_const() {
- UnlinkedVariable variable =
- serializeClassText('class C { static const int i = 0; }').fields[0];
- expect(variable.isConst, isTrue);
- }
-
- test_field_documented() {
- String text = '''
-class C {
- /**
- * Docs
- */
- var v;
-}''';
- UnlinkedVariable variable = serializeClassText(text).fields[0];
- expect(variable.documentationComment, isNotNull);
- checkDocumentationComment(variable.documentationComment, text);
- }
-
- test_field_final() {
- UnlinkedVariable variable =
- serializeClassText('class C { final int i = 0; }').fields[0];
- expect(variable.isFinal, isTrue);
- }
-
- test_field_static() {
- UnlinkedVariable variable =
- serializeClassText('class C { static int i; }').fields[0];
- expect(variable.isStatic, isTrue);
- }
-
- test_function_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-f() {}''';
- UnlinkedExecutable executable = serializeExecutableText(text);
- expect(executable.documentationComment, isNotNull);
- checkDocumentationComment(executable.documentationComment, text);
- }
-
- test_generic_method_in_generic_class() {
- UnlinkedClass cls = serializeClassText(
- 'class C<T, U> { void m<V, W>(T t, U u, V v, W w) {} }');
- List<UnlinkedParam> params = cls.executables[0].parameters;
- checkParamTypeRef(params[0].type, 4);
- checkParamTypeRef(params[1].type, 3);
- checkParamTypeRef(params[2].type, 2);
- checkParamTypeRef(params[3].type, 1);
- }
-
- test_getter_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-get f => null;''';
- UnlinkedExecutable executable = serializeExecutableText(text);
- expect(executable.documentationComment, isNotNull);
- checkDocumentationComment(executable.documentationComment, text);
- }
-
- test_import_deferred() {
- serializeLibraryText(
- 'import "dart:async" deferred as a; main() { print(a.Future); }');
- expect(unlinkedUnits[0].imports[0].isDeferred, isTrue);
- }
-
- test_import_dependency() {
- serializeLibraryText('import "dart:async"; Future x;');
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- checkDependency(
- prelinked.importDependencies[0], 'dart:async', 'dart:async');
- }
-
- test_import_explicit() {
- serializeLibraryText('import "dart:core"; int i;');
- expect(unlinkedUnits[0].imports, hasLength(1));
- expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
- }
-
- test_import_hide_order() {
- serializeLibraryText(
- 'import "dart:async" hide Future, Stream; Completer c;');
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
- expect(unlinkedUnits[0].imports[0].combinators[0].shows, isEmpty);
- expect(unlinkedUnits[0].imports[0].combinators[0].hides, hasLength(2));
- expect(unlinkedUnits[0].imports[0].combinators[0].hides[0], 'Future');
- expect(unlinkedUnits[0].imports[0].combinators[0].hides[1], 'Stream');
- }
-
- test_import_implicit() {
- // The implicit import of dart:core is represented in the model.
- serializeLibraryText('');
- expect(unlinkedUnits[0].imports, hasLength(1));
- checkDependency(prelinked.importDependencies[0], 'dart:core', 'dart:core');
- expect(unlinkedUnits[0].imports[0].uri, isEmpty);
- expect(unlinkedUnits[0].imports[0].uriOffset, 0);
- expect(unlinkedUnits[0].imports[0].uriEnd, 0);
- expect(unlinkedUnits[0].imports[0].prefixReference, 0);
- expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
- expect(unlinkedUnits[0].imports[0].isImplicit, isTrue);
- }
-
- test_import_no_combinators() {
- serializeLibraryText('import "dart:async"; Future x;');
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
- }
-
- test_import_no_flags() {
- serializeLibraryText('import "dart:async"; Future x;');
- expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
- expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
- }
-
- test_import_non_deferred() {
- serializeLibraryText(
- 'import "dart:async" as a; main() { print(a.Future); }');
- expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
- }
-
- test_import_of_file_with_missing_part() {
- // Other references in foo.dart should be resolved even though foo.dart's
- // part declaration for bar.dart refers to a non-existent file.
- allowMissingFiles = true;
- addNamedSource('/foo.dart', 'part "bar.dart"; class C {}');
- serializeLibraryText('import "foo.dart"; C x;');
- checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
- }
-
- test_import_of_missing_export() {
- // Other references in foo.dart should be resolved even though foo.dart's
- // re-export of bar.dart refers to a non-existent file.
- allowMissingFiles = true;
- addNamedSource('/foo.dart', 'export "bar.dart"; class C {}');
- serializeLibraryText('import "foo.dart"; C x;');
- checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
- }
-
- test_import_offset() {
- String libraryText = ' import "dart:async"; Future x;';
- serializeLibraryText(libraryText);
- expect(unlinkedUnits[0].imports[0].offset, libraryText.indexOf('import'));
- expect(unlinkedUnits[0].imports[0].uriOffset,
- libraryText.indexOf('"dart:async"'));
- expect(unlinkedUnits[0].imports[0].uriEnd, libraryText.indexOf('; Future'));
- }
-
- test_import_prefix_name() {
- String libraryText = 'import "dart:async" as a; a.Future x;';
- serializeLibraryText(libraryText);
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- checkPrefix(unlinkedUnits[0].imports[0].prefixReference, 'a');
- expect(unlinkedUnits[0].imports[0].prefixOffset, libraryText.indexOf('a;'));
- }
-
- test_import_prefix_none() {
- serializeLibraryText('import "dart:async"; Future x;');
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- expect(unlinkedUnits[0].imports[0].prefixReference, 0);
- }
-
- test_import_prefix_not_in_public_namespace() {
- serializeLibraryText('import "dart:async" as a; a.Future v;');
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'v');
- expect(unlinkedUnits[0].publicNamespace.names[1].name, 'v=');
- }
-
- test_import_prefix_reference() {
- UnlinkedVariable variable =
- serializeVariableText('import "dart:async" as a; a.Future v;');
- checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
- expectedPrefix: 'a', numTypeParameters: 1);
- }
-
- test_import_prefixes_take_precedence_over_imported_names() {
- addNamedSource('/a.dart', 'class b {} class A');
- addNamedSource('/b.dart', 'class Cls {}');
- addNamedSource('/c.dart', 'class Cls {}');
- addNamedSource('/d.dart', 'class c {} class D');
- serializeLibraryText('''
-import 'a.dart';
-import 'b.dart' as b;
-import 'c.dart' as c;
-import 'd.dart';
-A aCls;
-b.Cls bCls;
-c.Cls cCls;
-D dCls;
-''');
- checkTypeRef(findVariable('aCls').type, absUri('/a.dart'), 'a.dart', 'A');
- checkTypeRef(findVariable('bCls').type, absUri('/b.dart'), 'b.dart', 'Cls',
- expectedPrefix: 'b');
- checkTypeRef(findVariable('cCls').type, absUri('/c.dart'), 'c.dart', 'Cls',
- expectedPrefix: 'c');
- checkTypeRef(findVariable('dCls').type, absUri('/d.dart'), 'd.dart', 'D');
- }
-
- test_import_reference() {
- UnlinkedVariable variable =
- serializeVariableText('import "dart:async"; Future v;');
- checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
- numTypeParameters: 1);
- }
-
- test_import_reference_merged_no_prefix() {
- serializeLibraryText('''
-import "dart:async" show Future;
-import "dart:async" show Stream;
-
-Future f;
-Stream s;
-''');
- checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
- numTypeParameters: 1);
- checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
- numTypeParameters: 1);
- }
-
- test_import_reference_merged_prefixed() {
- serializeLibraryText('''
-import "dart:async" as a show Future;
-import "dart:async" as a show Stream;
-
-a.Future f;
-a.Stream s;
-''');
- checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
- expectedPrefix: 'a', numTypeParameters: 1);
- checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
- expectedPrefix: 'a', numTypeParameters: 1);
- }
-
- test_import_reference_merged_prefixed_separate_libraries() {
- addNamedSource('/a.dart', 'class A {}');
- addNamedSource('/b.dart', 'class B {}');
- serializeLibraryText('''
-import 'a.dart' as p;
-import 'b.dart' as p;
-
-p.A a;
-p.B b;
-''');
- checkTypeRef(findVariable('a').type, absUri('/a.dart'), 'a.dart', 'A',
- expectedPrefix: 'p');
- checkTypeRef(findVariable('b').type, absUri('/b.dart'), 'b.dart', 'B',
- expectedPrefix: 'p');
- }
-
- test_import_show_order() {
- String libraryText =
- 'import "dart:async" show Future, Stream; Future x; Stream y;';
- serializeLibraryText(libraryText);
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
- expect(unlinkedUnits[0].imports[0].combinators[0].shows, hasLength(2));
- expect(unlinkedUnits[0].imports[0].combinators[0].hides, isEmpty);
- expect(unlinkedUnits[0].imports[0].combinators[0].shows[0], 'Future');
- expect(unlinkedUnits[0].imports[0].combinators[0].shows[1], 'Stream');
- }
-
- test_import_uri() {
- String uriString = '"dart:async"';
- String libraryText = 'import $uriString; Future x;';
- serializeLibraryText(libraryText);
- // Second import is the implicit import of dart:core
- expect(unlinkedUnits[0].imports, hasLength(2));
- expect(unlinkedUnits[0].imports[0].uri, 'dart:async');
- }
-
- test_library_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-library foo;''';
- serializeLibraryText(text);
- expect(unlinkedUnits[0].libraryDocumentationComment, isNotNull);
- checkDocumentationComment(
- unlinkedUnits[0].libraryDocumentationComment, text);
- }
-
- test_library_name_with_spaces() {
- String text = 'library foo . bar ;';
- serializeLibraryText(text);
- expect(unlinkedUnits[0].libraryName, 'foo.bar');
- expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo . bar'));
- expect(unlinkedUnits[0].libraryNameLength, 'foo . bar'.length);
- }
-
- test_library_named() {
- String text = 'library foo.bar;';
- serializeLibraryText(text);
- expect(unlinkedUnits[0].libraryName, 'foo.bar');
- expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo.bar'));
- expect(unlinkedUnits[0].libraryNameLength, 'foo.bar'.length);
- }
-
- test_library_unnamed() {
- serializeLibraryText('');
- expect(unlinkedUnits[0].libraryName, isEmpty);
- expect(unlinkedUnits[0].libraryNameOffset, 0);
- expect(unlinkedUnits[0].libraryNameLength, 0);
- }
-
- test_library_with_missing_part() {
- // References to other parts should still be resolved.
- allowMissingFiles = true;
- addNamedSource('/bar.dart', 'part of my.lib; class C {}');
- serializeLibraryText(
- 'library my.lib; part "foo.dart"; part "bar.dart"; C c;',
- allowErrors: true);
- checkTypeRef(findVariable('c').type, null, null, 'C',
- expectedTargetUnit: 2);
- }
-
- test_local_names_take_precedence_over_imported_names() {
- addNamedSource('/a.dart', 'class C {} class D {}');
- serializeLibraryText('''
-import 'a.dart';
-class C {}
-C c;
-D d;''');
- checkTypeRef(findVariable('c').type, null, null, 'C');
- checkTypeRef(findVariable('d').type, absUri('/a.dart'), 'a.dart', 'D');
- }
-
- test_method_documented() {
- String text = '''
-class C {
- /**
- * Docs
- */
- f() {}
-}''';
- UnlinkedExecutable executable = serializeClassText(text).executables[0];
- expect(executable.documentationComment, isNotNull);
- checkDocumentationComment(executable.documentationComment, text);
- }
-
- test_part_declaration() {
- addNamedSource('/a.dart', 'part of my.lib;');
- String text = 'library my.lib; part "a.dart"; // <-part';
- serializeLibraryText(text);
- expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.parts[0], 'a.dart');
- expect(unlinkedUnits[0].parts, hasLength(1));
- expect(unlinkedUnits[0].parts[0].uriOffset, text.indexOf('"a.dart"'));
- expect(unlinkedUnits[0].parts[0].uriEnd, text.indexOf('; // <-part'));
- }
-
- test_parts_defining_compilation_unit() {
- serializeLibraryText('');
- expect(prelinked.units, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.parts, isEmpty);
- }
-
- test_parts_included() {
- addNamedSource('/part1.dart', 'part of my.lib;');
- String partString = '"part1.dart"';
- String libraryText = 'library my.lib; part $partString;';
- serializeLibraryText(libraryText);
- expect(prelinked.units, hasLength(2));
- expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.parts[0], 'part1.dart');
- }
-
- test_public_namespace_of_part() {
- addNamedSource('/a.dart', 'part of foo; class C {}');
- serializeLibraryText('library foo; part "a.dart";');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- expect(unlinkedUnits[1].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[1].publicNamespace.names[0].name, 'C');
- }
-
- test_setter_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-void set f(value) {}''';
- UnlinkedExecutable executable = serializeExecutableText(text, 'f=');
- expect(executable.documentationComment, isNotNull);
- checkDocumentationComment(executable.documentationComment, text);
- }
-
- test_type_arguments_explicit() {
- UnlinkedTypeRef typeRef = serializeTypeText('List<int>');
- checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
- allowTypeParameters: true, numTypeParameters: 1);
- expect(typeRef.typeArguments, hasLength(1));
- checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
- }
-
- test_type_arguments_explicit_dynamic() {
- UnlinkedTypeRef typeRef = serializeTypeText('List<dynamic>');
- checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
- allowTypeParameters: true, numTypeParameters: 1);
- expect(typeRef.typeArguments, isEmpty);
- }
-
- test_type_arguments_explicit_dynamic_typedef() {
- UnlinkedTypeRef typeRef =
- serializeTypeText('F<dynamic>', otherDeclarations: 'typedef T F<T>();');
- checkTypeRef(typeRef, null, null, 'F',
- allowTypeParameters: true,
- expectedKind: PrelinkedReferenceKind.typedef,
- numTypeParameters: 1);
- expect(typeRef.typeArguments, isEmpty);
- }
-
- test_type_arguments_explicit_typedef() {
- UnlinkedTypeRef typeRef =
- serializeTypeText('F<int>', otherDeclarations: 'typedef T F<T>();');
- checkTypeRef(typeRef, null, null, 'F',
- allowTypeParameters: true,
- expectedKind: PrelinkedReferenceKind.typedef,
- numTypeParameters: 1);
- expect(typeRef.typeArguments, hasLength(1));
- checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
- }
-
- test_type_arguments_implicit() {
- UnlinkedTypeRef typeRef = serializeTypeText('List');
- checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
- allowTypeParameters: true, numTypeParameters: 1);
- expect(typeRef.typeArguments, isEmpty);
- }
-
- test_type_arguments_implicit_typedef() {
- UnlinkedTypeRef typeRef =
- serializeTypeText('F', otherDeclarations: 'typedef T F<T>();');
- checkTypeRef(typeRef, null, null, 'F',
- allowTypeParameters: true,
- expectedKind: PrelinkedReferenceKind.typedef,
- numTypeParameters: 1);
- expect(typeRef.typeArguments, isEmpty);
- }
-
- test_type_arguments_order() {
- UnlinkedTypeRef typeRef = serializeTypeText('Map<int, Object>');
- checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
- allowTypeParameters: true, numTypeParameters: 2);
- expect(typeRef.typeArguments, hasLength(2));
- checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
- checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'Object');
- }
-
- test_type_dynamic() {
- checkDynamicTypeRef(serializeTypeText('dynamic'));
- }
-
- test_type_reference_from_part() {
- addNamedSource('/a.dart', 'part of foo; C v;');
- serializeLibraryText('library foo; part "a.dart"; class C {}');
- checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
- null, null, 'C',
- expectedKind: PrelinkedReferenceKind.classOrEnum,
- prelinkedSourceUnit: prelinked.units[1],
- unlinkedSourceUnit: unlinkedUnits[1]);
- }
-
- test_type_reference_from_part_withPrefix() {
- addNamedSource('/a.dart', 'class C {}');
- addNamedSource('/p.dart', 'part of foo; a.C v;');
- serializeLibraryText(
- 'library foo; import "a.dart"; import "a.dart" as a; part "p.dart";',
- allowErrors: true);
- checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
- absUri('/a.dart'), 'a.dart', 'C',
- expectedPrefix: 'a',
- prelinkedSourceUnit: prelinked.units[1],
- unlinkedSourceUnit: unlinkedUnits[1]);
- }
-
- test_type_reference_to_class_argument() {
- UnlinkedClass cls = serializeClassText('class C<T, U> { T t; U u; }');
- {
- UnlinkedTypeRef typeRef =
- findVariable('t', variables: cls.fields, failIfAbsent: true).type;
- checkParamTypeRef(typeRef, 2);
- }
- {
- UnlinkedTypeRef typeRef =
- findVariable('u', variables: cls.fields, failIfAbsent: true).type;
- checkParamTypeRef(typeRef, 1);
- }
- }
-
- test_type_reference_to_import_of_export() {
- addNamedSource('/a.dart', 'library a; export "b.dart";');
- addNamedSource('/b.dart', 'library b; class C {}');
- checkTypeRef(serializeTypeText('C', otherDeclarations: 'import "a.dart";'),
- absUri('/b.dart'), 'b.dart', 'C');
- }
-
- test_type_reference_to_import_of_export_via_prefix() {
- addNamedSource('/a.dart', 'library a; export "b.dart";');
- addNamedSource('/b.dart', 'library b; class C {}');
- checkTypeRef(
- serializeTypeText('p.C', otherDeclarations: 'import "a.dart" as p;'),
- absUri('/b.dart'),
- 'b.dart',
- 'C',
- expectedPrefix: 'p');
- }
-
- test_type_reference_to_imported_part() {
- addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
- addNamedSource('/b.dart', 'part of my.lib; class C {}');
- checkTypeRef(
- serializeTypeText('C',
- otherDeclarations: 'library my.lib; import "a.dart";'),
- absUri('/a.dart'),
- 'a.dart',
- 'C',
- expectedTargetUnit: 1);
- }
-
- test_type_reference_to_imported_part_with_prefix() {
- addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
- addNamedSource('/b.dart', 'part of my.lib; class C {}');
- checkTypeRef(
- serializeTypeText('p.C',
- otherDeclarations: 'library my.lib; import "a.dart" as p;'),
- absUri('/a.dart'),
- 'a.dart',
- 'C',
- expectedPrefix: 'p',
- expectedTargetUnit: 1);
- }
-
- test_type_reference_to_internal_class() {
- checkTypeRef(serializeTypeText('C', otherDeclarations: 'class C {}'), null,
- null, 'C');
- }
-
- test_type_reference_to_internal_class_alias() {
- checkTypeRef(
- serializeTypeText('C',
- otherDeclarations: 'class C = D with E; class D {} class E {}'),
- null,
- null,
- 'C');
- }
-
- test_type_reference_to_internal_enum() {
- checkTypeRef(serializeTypeText('E', otherDeclarations: 'enum E { value }'),
- null, null, 'E');
- }
-
- test_type_reference_to_local_part() {
- addNamedSource('/a.dart', 'part of my.lib; class C {}');
- checkTypeRef(
- serializeTypeText('C',
- otherDeclarations: 'library my.lib; part "a.dart";'),
- null,
- null,
- 'C',
- expectedTargetUnit: 1);
- }
-
- test_type_reference_to_part() {
- addNamedSource('/a.dart', 'part of foo; class C { C(); }');
- serializeLibraryText('library foo; part "a.dart"; C c;');
- checkTypeRef(unlinkedUnits[0].variables.single.type, null, null, 'C',
- expectedKind: PrelinkedReferenceKind.classOrEnum,
- expectedTargetUnit: 1);
- }
-
- test_type_reference_to_typedef() {
- checkTypeRef(serializeTypeText('F', otherDeclarations: 'typedef void F();'),
- null, null, 'F',
- expectedKind: PrelinkedReferenceKind.typedef);
- }
-
- test_type_unit_counts_unreferenced_units() {
- addNamedSource('/a.dart', 'library a; part "b.dart"; part "c.dart";');
- addNamedSource('/b.dart', 'part of a;');
- addNamedSource('/c.dart', 'part of a; class C {}');
- UnlinkedTypeRef typeRef =
- serializeTypeText('C', otherDeclarations: 'import "a.dart";');
- // The referenced unit should be 2, since unit 0 is a.dart and unit 1 is
- // b.dart. a.dart and b.dart are counted even though nothing is imported
- // from them.
- checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C',
- expectedTargetUnit: 2);
- }
-
- test_type_unresolved() {
- UnlinkedTypeRef typeRef = serializeTypeText('Foo', allowErrors: true);
- checkUnresolvedTypeRef(typeRef, null, 'Foo');
- }
-
- test_typedef_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-typedef F();''';
- UnlinkedTypedef typedef = serializeTypedefText(text);
- expect(typedef.documentationComment, isNotNull);
- checkDocumentationComment(typedef.documentationComment, text);
- }
-
- test_typedef_name() {
- String text = 'typedef F();';
- UnlinkedTypedef type = serializeTypedefText(text);
- expect(type.name, 'F');
- expect(type.nameOffset, text.indexOf('F'));
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.typedef);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'F');
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
- }
-
- test_typedef_param_none() {
- UnlinkedTypedef type = serializeTypedefText('typedef F();');
- expect(type.parameters, isEmpty);
- }
-
- test_typedef_param_order() {
- UnlinkedTypedef type = serializeTypedefText('typedef F(x, y);');
- expect(type.parameters, hasLength(2));
- expect(type.parameters[0].name, 'x');
- expect(type.parameters[1].name, 'y');
- }
-
- test_typedef_private() {
- serializeTypedefText('typedef _F();', '_F');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-
- test_typedef_reference_generic() {
- UnlinkedTypeRef typeRef =
- serializeTypeText('F', otherDeclarations: 'typedef void F<A, B>();');
- checkTypeRef(typeRef, null, null, 'F',
- numTypeParameters: 2, expectedKind: PrelinkedReferenceKind.typedef);
- }
-
- test_typedef_reference_generic_imported() {
- addNamedSource('/lib.dart', 'typedef void F<A, B>();');
- UnlinkedTypeRef typeRef =
- serializeTypeText('F', otherDeclarations: 'import "lib.dart";');
- checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'F',
- numTypeParameters: 2, expectedKind: PrelinkedReferenceKind.typedef);
- }
-
- test_typedef_return_type_explicit() {
- UnlinkedTypedef type = serializeTypedefText('typedef int F();');
- checkTypeRef(type.returnType, 'dart:core', 'dart:core', 'int');
- }
-
- test_typedef_type_param_in_parameter() {
- UnlinkedTypedef type = serializeTypedefText('typedef F<T>(T t);');
- checkParamTypeRef(type.parameters[0].type, 1);
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
- }
-
- test_typedef_type_param_in_return_type() {
- UnlinkedTypedef type = serializeTypedefText('typedef T F<T>();');
- checkParamTypeRef(type.returnType, 1);
- }
-
- test_typedef_type_param_none() {
- UnlinkedTypedef type = serializeTypedefText('typedef F();');
- expect(type.typeParameters, isEmpty);
- }
-
- test_typedef_type_param_order() {
- UnlinkedTypedef type = serializeTypedefText('typedef F<T, U>();');
- expect(type.typeParameters, hasLength(2));
- expect(type.typeParameters[0].name, 'T');
- expect(type.typeParameters[1].name, 'U');
- }
-
- test_variable() {
- String text = 'int i;';
- UnlinkedVariable v = serializeVariableText(text, variableName: 'i');
- expect(v.nameOffset, text.indexOf('i;'));
- expect(findExecutable('i'), isNull);
- expect(findExecutable('i='), isNull);
- expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
- expect(unlinkedUnits[0].publicNamespace.names[0].kind,
- PrelinkedReferenceKind.other);
- expect(unlinkedUnits[0].publicNamespace.names[0].name, 'i');
- expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
- expect(unlinkedUnits[0].publicNamespace.names[1].kind,
- PrelinkedReferenceKind.other);
- expect(unlinkedUnits[0].publicNamespace.names[1].name, 'i=');
- expect(unlinkedUnits[0].publicNamespace.names[1].numTypeParameters, 0);
- }
-
- test_variable_const() {
- UnlinkedVariable variable =
- serializeVariableText('const int i = 0;', variableName: 'i');
- expect(variable.isConst, isTrue);
- }
-
- test_variable_documented() {
- String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-var v;''';
- UnlinkedVariable variable = serializeVariableText(text);
- expect(variable.documentationComment, isNotNull);
- checkDocumentationComment(variable.documentationComment, text);
- }
-
- test_variable_explicit_dynamic() {
- UnlinkedVariable variable = serializeVariableText('dynamic v;');
- checkDynamicTypeRef(variable.type);
- expect(variable.hasImplicitType, isFalse);
- }
-
- test_variable_final_top_level() {
- UnlinkedVariable variable =
- serializeVariableText('final int i = 0;', variableName: 'i');
- expect(variable.isFinal, isTrue);
- }
-
- test_variable_implicit_dynamic() {
- UnlinkedVariable variable = serializeVariableText('var v;');
- checkDynamicTypeRef(variable.type);
- expect(variable.hasImplicitType, isTrue);
- }
-
- test_variable_name() {
- UnlinkedVariable variable =
- serializeVariableText('int i;', variableName: 'i');
- expect(variable.name, 'i');
- }
-
- test_variable_no_flags() {
- UnlinkedVariable variable =
- serializeVariableText('int i;', variableName: 'i');
- expect(variable.isStatic, isFalse);
- expect(variable.isConst, isFalse);
- expect(variable.isFinal, isFalse);
- }
-
- test_variable_non_const() {
- UnlinkedVariable variable =
- serializeVariableText('int i = 0;', variableName: 'i');
- expect(variable.isConst, isFalse);
- }
-
- test_variable_non_final() {
- UnlinkedVariable variable =
- serializeVariableText('int i;', variableName: 'i');
- expect(variable.isFinal, isFalse);
- }
-
- test_variable_non_static() {
- UnlinkedVariable variable =
- serializeClassText('class C { int i; }').fields[0];
- expect(variable.isStatic, isFalse);
- }
-
- test_variable_non_static_top_level() {
- // Top level variables are considered non-static.
- UnlinkedVariable variable =
- serializeVariableText('int i;', variableName: 'i');
- expect(variable.isStatic, isFalse);
- }
-
- test_variable_static() {
- UnlinkedVariable variable =
- serializeClassText('class C { static int i; }').fields[0];
- expect(variable.isStatic, isTrue);
- }
-
- test_variable_type() {
- UnlinkedVariable variable =
- serializeVariableText('int i;', variableName: 'i');
- checkTypeRef(variable.type, 'dart:core', 'dart:core', 'int');
- }
-
- test_varible_private() {
- serializeVariableText('int _i;', variableName: '_i');
- expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
- }
-}
diff --git a/pkg/analyzer/test/src/summary/test_all.dart b/pkg/analyzer/test/src/summary/test_all.dart
index 252c95f..d24342f 100644
--- a/pkg/analyzer/test/src/summary/test_all.dart
+++ b/pkg/analyzer/test/src/summary/test_all.dart
@@ -9,9 +9,12 @@
import '../../utils.dart';
import 'flat_buffers_test.dart' as flat_buffers_test;
import 'name_filter_test.dart' as name_filter_test;
+import 'prelinker_test.dart' as prelinker_test;
+import 'resynthesize_strong_test.dart' as resynthesize_strong_test;
import 'resynthesize_test.dart' as resynthesize_test;
-import 'summary_sdk_test.dart' as summary_sdk_test;
-import 'summary_test.dart' as summary_test;
+import 'summarize_ast_test.dart' as summarize_ast_test;
+import 'summarize_elements_strong_test.dart' as summarize_elements_strong_test;
+import 'summarize_elements_test.dart' as summarize_elements_test;
/// Utility for manually running all tests.
main() {
@@ -19,8 +22,11 @@
group('summary tests', () {
flat_buffers_test.main();
name_filter_test.main();
+ prelinker_test.main();
+ resynthesize_strong_test.main();
resynthesize_test.main();
- summary_sdk_test.main();
- summary_test.main();
+ summarize_ast_test.main();
+ summarize_elements_strong_test.main();
+ summarize_elements_test.main();
});
}
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 23930d8..e351c39 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -4,14 +4,15 @@
library analyzer.test.src.task.dart_test;
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart'
- show AnalysisOptionsImpl, CacheState;
+ show AnalysisOptions, AnalysisOptionsImpl, CacheState;
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart';
@@ -31,6 +32,7 @@
import '../../reflective_tests.dart';
import '../../utils.dart';
import '../context/abstract_context.dart';
+import '../mock_sdk.dart';
main() {
initializeTestEnvironment();
@@ -42,6 +44,7 @@
runReflectiveTests(BuildPublicNamespaceTaskTest);
runReflectiveTests(BuildSourceExportClosureTaskTest);
runReflectiveTests(BuildTypeProviderTaskTest);
+ runReflectiveTests(BuildTypeProviderTaskTest_noAsync);
runReflectiveTests(ComputeConstantDependenciesTaskTest);
runReflectiveTests(ComputeConstantValueTaskTest);
runReflectiveTests(ComputeInferableStaticVariableDependenciesTaskTest);
@@ -1005,6 +1008,32 @@
}
@reflectiveTest
+class BuildTypeProviderTaskTest_noAsync extends _AbstractDartTaskTest {
+ void prepareAnalysisContext([AnalysisOptions options]) {
+ AnalysisOptionsImpl newOptions = new AnalysisOptionsImpl();
+ newOptions.enableAsync = false;
+ super.prepareAnalysisContext(newOptions);
+ }
+
+ void setUp() {
+ sdk = new MockSdk(dartAsync: false);
+ super.setUp();
+ }
+
+ test_perform_noAsync() {
+ expect(context, isNotNull);
+ computeResult(AnalysisContextTarget.request, TYPE_PROVIDER,
+ matcher: isBuildTypeProviderTask);
+ // validate
+ TypeProvider typeProvider = outputs[TYPE_PROVIDER];
+ expect(typeProvider, isNotNull);
+ expect(typeProvider.boolType, isNotNull);
+ expect(typeProvider.intType, isNotNull);
+ expect(typeProvider.futureType, isNotNull);
+ }
+}
+
+@reflectiveTest
class ComputeConstantDependenciesTaskTest extends _AbstractDartTaskTest {
Annotation findClassAnnotation(CompilationUnit unit, String className) {
for (CompilationUnitMember member in unit.declarations) {
@@ -2993,6 +3022,40 @@
expect(outputs[UNITS], hasLength(1));
}
+ test_perform_computeSourceKind_noDirectives_hasContainingLibrary() {
+ // Parse "lib.dart" to let the context know that "test.dart" is included.
+ computeResult(
+ newSource(
+ '/lib.dart',
+ r'''
+library lib;
+part 'test.dart';
+'''),
+ PARSED_UNIT);
+ // If there are no the "part of" directive, then it is not a part.
+ _performParseTask('');
+ expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
+ }
+
+ test_perform_computeSourceKind_noDirectives_noContainingLibrary() {
+ _performParseTask('');
+ expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
+ }
+
+ test_perform_doesNotExist() {
+ _performParseTask(null);
+ expect(outputs, hasLength(9));
+ expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
+ expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
+ _assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
+ expect(outputs[INCLUDED_PARTS], hasLength(0));
+ expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
+ expect(outputs[PARSE_ERRORS], hasLength(0));
+ expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
+ expect(outputs[UNITS], hasLength(1));
+ }
+
test_perform_enableAsync_false() {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableAsync = false;
@@ -3028,40 +3091,6 @@
expect(outputs[UNITS], hasLength(1));
}
- test_perform_computeSourceKind_noDirectives_hasContainingLibrary() {
- // Parse "lib.dart" to let the context know that "test.dart" is included.
- computeResult(
- newSource(
- '/lib.dart',
- r'''
-library lib;
-part 'test.dart';
-'''),
- PARSED_UNIT);
- // If there are no the "part of" directive, then it is not a part.
- _performParseTask('');
- expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
- }
-
- test_perform_computeSourceKind_noDirectives_noContainingLibrary() {
- _performParseTask('');
- expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
- }
-
- test_perform_doesNotExist() {
- _performParseTask(null);
- expect(outputs, hasLength(9));
- expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
- expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
- _assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
- expect(outputs[INCLUDED_PARTS], hasLength(0));
- expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
- expect(outputs[PARSE_ERRORS], hasLength(0));
- expect(outputs[PARSED_UNIT], isNotNull);
- expect(outputs[SOURCE_KIND], SourceKind.UNKNOWN);
- expect(outputs[UNITS], hasLength(1));
- }
-
test_perform_flushTokenStream() {
_performParseTask(r'''
class Test {}
@@ -3133,7 +3162,11 @@
}
void _performParseTask(String content) {
- source = newSource('/test.dart', content);
+ if (content == null) {
+ source = resourceProvider.getFile('/test.dart').createSource();
+ } else {
+ source = newSource('/test.dart', content);
+ }
computeResult(source, PARSED_UNIT, matcher: isParseDartTask);
}
diff --git a/pkg/analyzer/test/src/task/dart_work_manager_test.dart b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
index 7938cc9..315e061 100644
--- a/pkg/analyzer/test/src/task/dart_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
@@ -4,8 +4,8 @@
library analyzer.test.src.task.dart_work_manager_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart'
show
AnalysisErrorInfo,
diff --git a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
index 114a452..8ef225a 100644
--- a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
+++ b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
@@ -4,8 +4,8 @@
library analyzer.test.src.task.incremental_element_builder_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/task/incremental_element_builder.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analyzer/test/src/task/model_test.dart b/pkg/analyzer/test/src/task/model_test.dart
index 4db1ee2..a798472 100644
--- a/pkg/analyzer/test/src/task/model_test.dart
+++ b/pkg/analyzer/test/src/task/model_test.dart
@@ -103,7 +103,7 @@
@reflectiveTest
class TaskDescriptorImplTest extends EngineTestCase {
- test_create() {
+ test_create_noOptionalArgs() {
String name = 'name';
BuildTask buildTask = (context, target) {};
CreateTaskInputs createTaskInputs = (target) {};
@@ -114,12 +114,30 @@
expect(descriptor.name, name);
expect(descriptor.buildTask, equals(buildTask));
expect(descriptor.createTaskInputs, equals(createTaskInputs));
+ expect(descriptor.suitabilityFor(null), TaskSuitability.LOWEST);
+ expect(descriptor.results, results);
+ }
+
+ test_create_withIsAppropriateFor() {
+ String name = 'name';
+ BuildTask buildTask = (context, target) {};
+ CreateTaskInputs createTaskInputs = (target) {};
+ List<ResultDescriptor> results = <ResultDescriptor>[];
+ SuitabilityFor suitabilityFor = (target) => TaskSuitability.NONE;
+ TaskDescriptorImpl descriptor = new TaskDescriptorImpl(
+ name, buildTask, createTaskInputs, results,
+ suitabilityFor: suitabilityFor);
+ expect(descriptor, isNotNull);
+ expect(descriptor.name, name);
+ expect(descriptor.buildTask, equals(buildTask));
+ expect(descriptor.createTaskInputs, equals(createTaskInputs));
+ expect(descriptor.suitabilityFor(null), TaskSuitability.NONE);
expect(descriptor.results, results);
}
test_createTask() {
- BuildTask buildTask = (context, target) =>
- new TestAnalysisTask(context, target);
+ BuildTask buildTask =
+ (context, target) => new TestAnalysisTask(context, target);
CreateTaskInputs createTaskInputs = (target) {};
List<ResultDescriptor> results = <ResultDescriptor>[];
TaskDescriptorImpl descriptor =
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 55b73a8..bb8216a 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -964,6 +964,16 @@
'''
});
+ testChecker('Function subtyping: uninferred closure', {
+ '/main.dart': '''
+ typedef num Num2Num(num x);
+ void main() {
+ Num2Num g = /*info:INFERRED_TYPE_CLOSURE,severe:STATIC_TYPE_ERROR*/(int x) { return x; };
+ print(g(42));
+ }
+ '''
+ });
+
testChecker('Relaxed casts', {
'/main.dart': '''
@@ -1141,6 +1151,21 @@
'''
});
+ testChecker('factory constructor downcast', {
+ '/main.dart': r'''
+ class Animal {
+ Animal();
+ factory Animal.cat() => return new Cat();
+ }
+
+ class Cat extends Animal {}
+
+ void main() {
+ Cat c = /*info:ASSIGNMENT_CAST*/new Animal.cat();
+ c = /*severe:STATIC_TYPE_ERROR*/new Animal();
+ }'''
+ });
+
testChecker('field/field override', {
'/main.dart': '''
class A {}
@@ -1389,7 +1414,51 @@
class DerivedFuture4<A> extends Future<A> {
/*=B*/ then/*<B>*/(Object onValue(A a)) => null;
}
- '''
+ '''
+ });
+
+ testChecker('generic function wrong number of arguments', {
+ '/main.dart': r'''
+ /*=T*/ foo/*<T>*/(/*=T*/ x, /*=T*/ y) => x;
+ /*=T*/ bar/*<T>*/({/*=T*/ x, /*=T*/ y}) => x;
+
+ main() {
+ // resolving thses shouldn't crash.
+ foo(1, 2, 3);
+ String x = foo('1', '2', '3');
+ foo(1);
+ String x = foo('1');
+ x = /*severe:STATIC_TYPE_ERROR*/foo(1, 2, 3);
+ x = /*severe:STATIC_TYPE_ERROR*/foo(1);
+
+ // named arguments
+ bar(y: 1, x: 2, z: 3);
+ String x = bar(z: '1', x: '2', y: '3');
+ bar(y: 1);
+ x = bar(x: '1', z: 42);
+ x = /*severe:STATIC_TYPE_ERROR*/bar(y: 1, x: 2, z: 3);
+ x = /*severe:STATIC_TYPE_ERROR*/bar(x: 1);
+ }
+ '''
+ });
+
+ testChecker('type promotion from dynamic', {
+ '/main.dart': r'''
+ f() {
+ dynamic x;
+ if (x is int) {
+ int y = x;
+ String z = /*severe:STATIC_TYPE_ERROR*/x;
+ }
+ }
+ g() {
+ Object x;
+ if (x is int) {
+ int y = x;
+ String z = /*severe:STATIC_TYPE_ERROR*/x;
+ }
+ }
+ '''
});
testChecker('unary operators', {
@@ -1642,6 +1711,15 @@
'''
});
+ testChecker('loadLibrary', {
+ '/lib1.dart': '''library lib1;''',
+ '/main.dart': r'''
+ import 'lib1.dart' deferred as lib1;
+ main() {
+ Future f = lib1.loadLibrary();
+ }'''
+ });
+
group('invalid overrides', () {
testChecker('child override', {
'/main.dart': '''
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index 0141e38..f386377 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -6,11 +6,12 @@
// package:dev_compiler's tests
library analyzer.test.src.task.strong.strong_test_helper;
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/context/context.dart' show SdkAnalysisContext;
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/sdk.dart';
@@ -95,6 +96,7 @@
}
''',
'dart:async': '''
+ library dart.async;
class Future<T> {
Future(computation()) {}
Future.value(T t) {}
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index 6859d48..097d5d4 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -4,9 +4,9 @@
library analyzer.test.src.task.strong_mode_test;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/task/strong_mode.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analyzer/test/src/task/test_all.dart b/pkg/analyzer/test/src/task/test_all.dart
index 41e568e..956a8e5 100644
--- a/pkg/analyzer/test/src/task/test_all.dart
+++ b/pkg/analyzer/test/src/task/test_all.dart
@@ -21,6 +21,7 @@
import 'options_test.dart' as options_test;
import 'options_work_manager_test.dart' as options_work_manager_test;
import 'strong_mode_test.dart' as strong_mode_test;
+import 'yaml_test.dart' as yaml_test;
/// Utility for manually running all tests.
main() {
@@ -39,5 +40,6 @@
options_test.main();
options_work_manager_test.main();
strong_mode_test.main();
+ yaml_test.main();
});
}
diff --git a/pkg/analyzer/test/src/task/yaml_test.dart b/pkg/analyzer/test/src/task/yaml_test.dart
new file mode 100644
index 0000000..5deb5f5
--- /dev/null
+++ b/pkg/analyzer/test/src/task/yaml_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2016, 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 analyzer.test.src.task.yaml_test;
+
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/yaml.dart';
+import 'package:analyzer/task/general.dart';
+import 'package:analyzer/task/yaml.dart';
+import 'package:unittest/unittest.dart';
+import 'package:yaml/yaml.dart';
+
+import '../../reflective_tests.dart';
+import '../../utils.dart';
+import '../context/abstract_context.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(ParseYamlTaskTest);
+}
+
+isInstanceOf isParseYamlTask = new isInstanceOf<ParseYamlTask>();
+
+@reflectiveTest
+class ParseYamlTaskTest extends AbstractContextTest {
+ Source source;
+
+ test_perform() {
+ _performParseTask(r'''
+rules:
+ style_guide:
+ camel_case_types: false
+''');
+ expect(outputs, hasLength(3));
+ YamlDocument document = outputs[YAML_DOCUMENT];
+ expect(document, isNotNull);
+ var value = document.contents.value;
+ expect(value, new isInstanceOf<Map>());
+ expect(value['rules']['style_guide']['camel_case_types'], isFalse);
+ expect(outputs[YAML_ERRORS], hasLength(0));
+ LineInfo lineInfo = outputs[LINE_INFO];
+ expect(lineInfo, isNotNull);
+ expect(lineInfo.getOffsetOfLine(0), 0);
+ expect(lineInfo.getOffsetOfLine(1), 7);
+ expect(lineInfo.getOffsetOfLine(2), 22);
+ expect(lineInfo.getOffsetOfLine(3), 50);
+ }
+
+ test_perform_doesNotExist() {
+ _performParseTask(null);
+ expect(outputs, hasLength(3));
+ YamlDocument document = outputs[YAML_DOCUMENT];
+ expect(document, isNotNull);
+ expect(document.contents.value, isNull);
+ expect(outputs[YAML_ERRORS], hasLength(1));
+ LineInfo lineInfo = outputs[LINE_INFO];
+ expect(lineInfo, isNotNull);
+ expect(lineInfo.getOffsetOfLine(0), 0);
+ }
+
+ void _performParseTask(String content) {
+ if (content == null) {
+ source = resourceProvider.getFile('/test.yaml').createSource();
+ } else {
+ source = newSource('/test.yaml', content);
+ }
+ computeResult(source, YAML_DOCUMENT, matcher: isParseYamlTask);
+ }
+}
diff --git a/pkg/analyzer/test/utils.dart b/pkg/analyzer/test/utils.dart
index e162219..a8c39a5 100644
--- a/pkg/analyzer/test/utils.dart
+++ b/pkg/analyzer/test/utils.dart
@@ -4,9 +4,9 @@
library analyzer.test.utils;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:path/path.dart' as path;
diff --git a/pkg/analyzer/tool/summary/build_sdk_summary.dart b/pkg/analyzer/tool/summary/build_sdk_summary.dart
index db17c57..738e0a1 100644
--- a/pkg/analyzer/tool/summary/build_sdk_summary.dart
+++ b/pkg/analyzer/tool/summary/build_sdk_summary.dart
@@ -45,9 +45,8 @@
//
// Serialize each SDK library.
//
- List<String> prelinkedLibraryUris = <String>[];
- List<PrelinkedLibraryBuilder> prelinkedLibraries =
- <PrelinkedLibraryBuilder>[];
+ List<String> linkedLibraryUris = <String>[];
+ List<LinkedLibraryBuilder> linkedLibraries = <LinkedLibraryBuilder>[];
List<String> unlinkedUnitUris = <String>[];
List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
for (SdkLibrary lib in sdk.sdkLibraries) {
@@ -55,19 +54,20 @@
Source librarySource = sdk.mapDartUri(lib.shortName);
LibraryElement libraryElement =
context.computeLibraryElement(librarySource);
+ // TODO(paulberry): also build a summary of the SDK in strong mode.
LibrarySerializationResult libraryResult =
- serializeLibrary(libraryElement, context.typeProvider);
- prelinkedLibraryUris.add(lib.shortName);
- prelinkedLibraries.add(libraryResult.prelinked);
+ serializeLibrary(libraryElement, context.typeProvider, false);
+ linkedLibraryUris.add(lib.shortName);
+ linkedLibraries.add(libraryResult.linked);
unlinkedUnitUris.addAll(libraryResult.unitUris);
unlinkedUnits.addAll(libraryResult.unlinkedUnits);
}
//
// Write the whole SDK bundle.
//
- SdkBundleBuilder sdkBundle = encodeSdkBundle(
- prelinkedLibraryUris: prelinkedLibraryUris,
- prelinkedLibraries: prelinkedLibraries,
+ SdkBundleBuilder sdkBundle = new SdkBundleBuilder(
+ linkedLibraryUris: linkedLibraryUris,
+ linkedLibraries: linkedLibraries,
unlinkedUnitUris: unlinkedUnitUris,
unlinkedUnits: unlinkedUnits);
File file = new File(outputFilePath);
diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart
index 1918074..afd790d 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -88,8 +88,12 @@
if (type.isList) {
if (_idl.classes.containsKey(type.typeName)) {
// List of classes is ok
+ } else if (_idl.enums.containsKey(type.typeName)) {
+ // List of enums is ok
} else if (type.typeName == 'int') {
// List of ints is ok
+ } else if (type.typeName == 'double') {
+ // List of doubles is ok
} else if (type.typeName == 'String') {
// List of strings is ok
} else {
@@ -116,12 +120,21 @@
/**
* Generate a Dart expression representing the default value for a field
* having the given [type], or `null` if there is no default value.
+ *
+ * If [builder] is `true`, the returned type should be appropriate for use in
+ * a builder class.
*/
- String defaultValue(idlModel.FieldType type) {
+ String defaultValue(idlModel.FieldType type, bool builder) {
if (type.isList) {
- return 'const <${type.typeName}>[]';
+ if (builder) {
+ idlModel.FieldType elementType =
+ new idlModel.FieldType(type.typeName, false);
+ return '<${encodedType(elementType)}>[]';
+ } else {
+ return 'const <${type.typeName}>[]';
+ }
} else if (_idl.enums.containsKey(type.typeName)) {
- return '${type.typeName}.${_idl.enums[type.typeName].values[0]}';
+ return '${type.typeName}.${_idl.enums[type.typeName].values[0].name}';
} else if (type.typeName == 'int') {
return '0';
} else if (type.typeName == 'String') {
@@ -200,7 +213,9 @@
new idlModel.EnumDeclaration(doc, decl.name.name);
_idl.enums[enm.name] = enm;
for (EnumConstantDeclaration constDecl in decl.constants) {
- enm.values.add(constDecl.name.name);
+ String doc = _getNodeDoc(lineInfo, constDecl);
+ enm.values
+ .add(new idlModel.EnumValueDeclaration(doc, constDecl.name.name));
}
} else if (decl is TopLevelVariableDeclaration) {
// Ignore top level variable declarations; they are present just to make
@@ -261,21 +276,14 @@
out("import 'base.dart' as base;");
out("import 'flat_buffers.dart' as fb;");
out();
- _idl.enums.forEach((String name, idlModel.EnumDeclaration enm) {
- outDoc(enm.documentation);
- out('enum $name {');
- indent(() {
- for (String value in enm.values) {
- out('$value,');
- }
- });
- out('}');
+ for (idlModel.EnumDeclaration enm in _idl.enums.values) {
+ _generateEnum(enm);
out();
- });
- for (var cls in _idl.classes.values) {
- List<String> builderParams = _generateBuilder(cls);
+ _generateEnumReader(enm);
out();
- _generateEncodeFunction(cls, builderParams);
+ }
+ for (idlModel.ClassDeclaration cls in _idl.classes.values) {
+ _generateBuilder(cls);
out();
_generateInterface(cls);
out();
@@ -283,6 +291,8 @@
out();
_generateImpl(cls);
out();
+ _generateMixin(cls);
+ out();
}
}
@@ -293,10 +303,13 @@
return JSON.encode(s);
}
- List<String> _generateBuilder(idlModel.ClassDeclaration cls) {
- String builderName = cls.name + 'Builder';
- List<String> builderParams = <String>[];
- out('class $builderName {');
+ void _generateBuilder(idlModel.ClassDeclaration cls) {
+ String name = cls.name;
+ String builderName = name + 'Builder';
+ String mixinName = '_${name}Mixin';
+ List<String> constructorParams = <String>[];
+ out('class $builderName extends Object with $mixinName '
+ 'implements $name {');
indent(() {
out('bool _finished = false;');
// Generate fields.
@@ -307,24 +320,45 @@
String typeStr = encodedType(type);
out('$typeStr _$fieldName;');
}
- // Generate constructor.
- out();
- out('$builderName();');
- // Generate setters.
+ // Generate getters and setters.
for (idlModel.FieldDeclaration field in cls.fields) {
String fieldName = field.name;
- String typeStr = encodedType(field.type);
+ idlModel.FieldType fieldType = field.type;
+ String typeStr = encodedType(fieldType);
+ String def = defaultValue(fieldType, true);
+ String defSuffix = def == null ? '' : ' ??= $def';
+ out();
+ out('@override');
+ out('$typeStr get $fieldName => _$fieldName$defSuffix;');
out();
outDoc(field.documentation);
- builderParams.add('$typeStr $fieldName');
+ constructorParams.add('$typeStr $fieldName');
out('void set $fieldName($typeStr _value) {');
indent(() {
String stateFieldName = '_' + fieldName;
out('assert(!_finished);');
+ // Validate that int(s) are non-negative.
+ if (fieldType.typeName == 'int') {
+ if (!fieldType.isList) {
+ out('assert(_value == null || _value >= 0);');
+ } else {
+ out('assert(_value == null || _value.every((e) => e >= 0));');
+ }
+ }
+ // Set the value.
out('$stateFieldName = _value;');
});
out('}');
}
+ // Generate constructor.
+ out();
+ out('$builderName({${constructorParams.join(', ')}})');
+ for (int i = 0; i < cls.fields.length; i++) {
+ idlModel.FieldDeclaration field = cls.fields[i];
+ String prefix = i == 0 ? ' : ' : ' ';
+ String suffix = i == cls.fields.length - 1 ? ';' : ',';
+ out('${prefix}_${field.name} = ${field.name}$suffix');
+ }
// Generate finish.
if (cls.isTopLevel) {
out();
@@ -362,8 +396,16 @@
String itemCode = 'b.finish(fbBuilder)';
String listCode = '$valueName.map((b) => $itemCode).toList()';
writeCode = '$offsetName = fbBuilder.writeList($listCode);';
+ } else if (_idl.enums.containsKey(fieldType.typeName)) {
+ String itemCode = 'b.index';
+ String listCode = '$valueName.map((b) => $itemCode).toList()';
+ writeCode = '$offsetName = fbBuilder.writeListUint32($listCode);';
} else if (fieldType.typeName == 'int') {
- writeCode = '$offsetName = fbBuilder.writeListInt32($valueName);';
+ writeCode =
+ '$offsetName = fbBuilder.writeListUint32($valueName);';
+ } else if (fieldType.typeName == 'double') {
+ writeCode =
+ '$offsetName = fbBuilder.writeListFloat64($valueName);';
} else {
assert(fieldType.typeName == 'String');
String itemCode = 'fbBuilder.writeString(b)';
@@ -404,11 +446,11 @@
condition = '$valueName == true';
writeCode = 'fbBuilder.addBool($index, true);';
} else if (fieldType.typeName == 'int') {
- condition += ' && $valueName != ${defaultValue(fieldType)}';
- writeCode = 'fbBuilder.addInt32($index, $valueName);';
+ condition += ' && $valueName != ${defaultValue(fieldType, true)}';
+ writeCode = 'fbBuilder.addUint32($index, $valueName);';
} else if (_idl.enums.containsKey(fieldType.typeName)) {
- condition += ' && $valueName != ${defaultValue(fieldType)}';
- writeCode = 'fbBuilder.addInt32($index, $valueName.index);';
+ condition += ' && $valueName != ${defaultValue(fieldType, true)}';
+ writeCode = 'fbBuilder.addUint32($index, $valueName.index);';
}
if (writeCode == null) {
throw new UnimplementedError('Writing type ${fieldType.typeName}');
@@ -424,21 +466,43 @@
out('}');
});
out('}');
- return builderParams;
}
- void _generateEncodeFunction(
- idlModel.ClassDeclaration cls, List<String> builderParams) {
- String className = cls.name;
- String builderName = className + 'Builder';
- out('$builderName encode$className({${builderParams.join(', ')}}) {');
+ void _generateEnum(idlModel.EnumDeclaration enm) {
+ String name = enm.name;
+ outDoc(enm.documentation);
+ out('enum $name {');
indent(() {
- out('$builderName builder = new $builderName();');
- for (idlModel.FieldDeclaration field in cls.fields) {
- String fieldName = field.name;
- out('builder.$fieldName = $fieldName;');
+ for (idlModel.EnumValueDeclaration value in enm.values) {
+ outDoc(value.documentation);
+ if (enm.values.last == value) {
+ out('${value.name}');
+ } else {
+ out('${value.name},');
+ out();
+ }
}
- out('return builder;');
+ });
+ out('}');
+ }
+
+ void _generateEnumReader(idlModel.EnumDeclaration enm) {
+ String name = enm.name;
+ String readerName = '_${name}Reader';
+ out('class $readerName extends fb.Reader<$name> {');
+ indent(() {
+ out('const $readerName() : super();');
+ out();
+ out('@override');
+ out('int get size => 4;');
+ out();
+ out('@override');
+ out('$name read(fb.BufferPointer bp) {');
+ indent(() {
+ out('int index = const fb.Uint32Reader().read(bp);');
+ out('return $name.values[index];');
+ });
+ out('}');
});
out('}');
}
@@ -446,7 +510,8 @@
void _generateImpl(idlModel.ClassDeclaration cls) {
String name = cls.name;
String implName = '_${name}Impl';
- out('class $implName implements $name {');
+ String mixinName = '_${name}Mixin';
+ out('class $implName extends Object with $mixinName implements $name {');
indent(() {
out('final fb.BufferPointer _bp;');
out();
@@ -458,59 +523,50 @@
String fieldName = field.name;
out('$returnType _$fieldName;');
}
- out();
- // Write toMap().
- out('@override');
- out('Map<String, Object> toMap() => {');
- indent(() {
- for (idlModel.FieldDeclaration field in cls.fields) {
- String fieldName = field.name;
- out('${quoted(fieldName)}: $fieldName,');
- }
- });
- out('};');
// Write getters.
cls.fields.asMap().forEach((index, field) {
String fieldName = field.name;
idlModel.FieldType type = field.type;
String typeName = type.typeName;
- // Prepare "readExpr" or "readCode" + "def"
- String readExpr;
+ // Prepare "readCode" + "def"
String readCode;
- String def = defaultValue(type);
+ String def = defaultValue(type, false);
if (type.isList) {
if (typeName == 'int') {
- String itemCode = 'const fb.Int32Reader()';
+ String itemCode = 'const fb.Uint32Reader()';
readCode = 'const fb.ListReader<int>($itemCode)';
+ } else if (typeName == 'double') {
+ readCode = 'const fb.Float64ListReader()';
} else if (typeName == 'String') {
String itemCode = 'const fb.StringReader()';
readCode = 'const fb.ListReader<String>($itemCode)';
- } else {
+ } else if (_idl.classes.containsKey(typeName)) {
String itemCode = '$typeName>(const _${typeName}Reader()';
readCode = 'const fb.ListReader<$itemCode)';
+ } else {
+ assert(_idl.enums.containsKey(typeName));
+ String itemCode = 'const _${typeName}Reader()';
+ readCode = 'const fb.ListReader<$typeName>($itemCode)';
}
} else if (typeName == 'bool') {
readCode = 'const fb.BoolReader()';
} else if (typeName == 'int') {
- readCode = 'const fb.Int32Reader()';
+ readCode = 'const fb.Uint32Reader()';
} else if (typeName == 'String') {
readCode = 'const fb.StringReader()';
} else if (_idl.enums.containsKey(typeName)) {
- readExpr =
- '$typeName.values[const fb.Int32Reader().vTableGet(_bp, $index, 0)]';
+ readCode = 'const _${typeName}Reader()';
} else if (_idl.classes.containsKey(typeName)) {
readCode = 'const _${typeName}Reader()';
}
- if (readExpr == null) {
- assert(readCode != null);
- readExpr = '$readCode.vTableGet(_bp, $index, $def)';
- }
+ assert(readCode != null);
// Write the getter implementation.
out();
out('@override');
String returnType = dartType(type);
out('$returnType get $fieldName {');
indent(() {
+ String readExpr = '$readCode.vTableGet(_bp, $index, $def)';
out('_$fieldName ??= $readExpr;');
out('return _$fieldName;');
});
@@ -544,6 +600,25 @@
out('}');
}
+ void _generateMixin(idlModel.ClassDeclaration cls) {
+ String name = cls.name;
+ String mixinName = '_${name}Mixin';
+ out('abstract class $mixinName implements $name {');
+ indent(() {
+ // Write toMap().
+ out('@override');
+ out('Map<String, Object> toMap() => {');
+ indent(() {
+ for (idlModel.FieldDeclaration field in cls.fields) {
+ String fieldName = field.name;
+ out('${quoted(fieldName)}: $fieldName,');
+ }
+ });
+ out('};');
+ });
+ out('}');
+ }
+
void _generateReader(idlModel.ClassDeclaration cls) {
String name = cls.name;
String readerName = '_${name}Reader';
diff --git a/pkg/analyzer/tool/summary/idl.dart b/pkg/analyzer/tool/summary/idl.dart
index 39e7a4a..cb2ee1d 100644
--- a/pkg/analyzer/tool/summary/idl.dart
+++ b/pkg/analyzer/tool/summary/idl.dart
@@ -10,26 +10,30 @@
* The code generation process introduces the following non-typical semantics:
* - Fields of type List are never null, and have a default value of the empty
* list.
- * - Fields of type int are never null, and have a default value of zero.
+ * - Fields of type int are unsigned 32-bit integers, never null, and have a
+ * default value of zero.
* - Fields of type String are never null, and have a default value of ''.
* - Fields of type bool are never null, and have a default value of false.
* - Fields whose type is an enum are never null, and have a default value of
* the first value declared in the enum.
*
* Terminology used in this document:
- * - "Unlinked" refers to information that can be determined from reading the
- * .dart file for the library itself (including all parts) and no other
- * files.
- * - "Prelinked" refers to information that can be determined from reading the
- * unlinked information for the library itself and the unlinked information
- * for all direct imports (plus the transitive closure of exports reachable
- * from those direct imports).
- * - "Linked" refers to information that can be determined only from reading
- * the unlinked and prelinked information for the library itself and the
- * transitive closure of its imports.
+ * - "Unlinked" refers to information that can be determined from reading a
+ * single .dart file in isolation.
+ * - "Prelinked" refers to information that can be determined from the defining
+ * compilation unit of a library, plus direct imports, plus the transitive
+ * closure of exports reachable from those libraries, plus all part files
+ * constituting those libraries.
+ * - "Linked" refers to all other information; in theory, this information may
+ * depend on all files in the transitive import/export closure. However, in
+ * practice we expect that the number of additional dependencies will usually
+ * be small, since the additional dependencies only need to be consulted for
+ * type propagation, type inference, and constant evaluation, which typically
+ * have short dependency chains.
*
- * TODO(paulberry): currently the summary format only contains unlinked and
- * prelinked information.
+ * Since we expect "linked" and "prelinked" dependencies to be similar, we only
+ * rarely distinguish between them; most information is that is not "unlinked"
+ * is typically considered "linked" for simplicity.
*
* Except as otherwise noted, synthetic elements are not stored in the summary;
* they are re-synthesized at the time the summary is read.
@@ -63,10 +67,59 @@
const topLevel = null;
/**
+ * Summary information about a reference to a an entity such as a type, top
+ * level executable, or executable within a class.
+ */
+class EntityRef {
+ /**
+ * If this [EntityRef] is contained within [LinkedUnit.types], slot id (which
+ * is unique within the compilation unit) identifying the target of type
+ * propagation or type inference with which this [EntityRef] is associated.
+ *
+ * Otherwise zero.
+ */
+ int slot;
+
+ /**
+ * Index into [UnlinkedUnit.references] for the entity being referred to, or
+ * zero if this is a reference to a type parameter.
+ */
+ int reference;
+
+ /**
+ * If this is a reference to a type parameter, one-based index into the list
+ * of [UnlinkedTypeParam]s currently in effect. Indexing is done using De
+ * Bruijn index conventions; that is, innermost parameters come first, and
+ * if a class or method has multiple parameters, they are indexed from right
+ * to left. So for instance, if the enclosing declaration is
+ *
+ * class C<T,U> {
+ * m<V,W> {
+ * ...
+ * }
+ * }
+ *
+ * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
+ * respectively.
+ *
+ * If the type being referred to is not a type parameter, [paramReference] is
+ * zero.
+ */
+ int paramReference;
+
+ /**
+ * If this is an instantiation of a generic type or generic executable, the
+ * type arguments used to instantiate it. Trailing type arguments of type
+ * `dynamic` are omitted.
+ */
+ List<EntityRef> typeArguments;
+}
+
+/**
* Information about a dependency that exists between one library and another
* due to an "import" declaration.
*/
-class PrelinkedDependency {
+class LinkedDependency {
/**
* The relative URI of the dependent library. This URI is relative to the
* importing library, even if there are intervening `export` declarations.
@@ -84,58 +137,109 @@
}
/**
- * Pre-linked summary of a library.
+ * Information about a single name in the export namespace of the library that
+ * is not in the public namespace.
+ */
+class LinkedExportName {
+ /**
+ * Name of the exported entity. TODO(paulberry): do we include the trailing
+ * '=' for a setter?
+ */
+ String name;
+
+ /**
+ * Index into [LinkedLibrary.dependencies] for the library in which the
+ * entity is defined.
+ */
+ int dependency;
+
+ /**
+ * Integer index indicating which unit in the exported library contains the
+ * definition of the entity. As with indices into [LinkedLibrary.units],
+ * zero represents the defining compilation unit, and nonzero values
+ * represent parts in the order of the corresponding `part` declarations.
+ */
+ int unit;
+
+ /**
+ * The kind of the entity being referred to.
+ */
+ ReferenceKind kind;
+}
+
+/**
+ * Linked summary of a library.
*/
@topLevel
-class PrelinkedLibrary {
+class LinkedLibrary {
/**
- * The pre-linked summary of all the compilation units constituting the
+ * The linked summary of all the compilation units constituting the
* library. The summary of the defining compilation unit is listed first,
* followed by the summary of each part, in the order of the `part`
* declarations in the defining compilation unit.
*/
- List<PrelinkedUnit> units;
+ List<LinkedUnit> units;
/**
* The libraries that this library depends on (either via an explicit import
* statement or via the implicit dependencies on `dart:core` and
* `dart:async`). The first element of this array is a pseudo-dependency
- * representing the library itself (it is also used for "dynamic").
+ * representing the library itself (it is also used for `dynamic` and
+ * `void`). This is followed by elements representing "prelinked"
+ * dependencies (direct imports and the transitive closure of exports).
+ * After the prelinked dependencies are elements representing "linked"
+ * dependencies.
*
- * TODO(paulberry): consider removing this entirely and just using
- * [UnlinkedLibrary.imports].
+ * A library is only included as a "linked" dependency if it is a true
+ * dependency (e.g. a propagated or inferred type or constant value
+ * implicitly refers to an element declared in the library) or
+ * anti-dependency (e.g. the result of type propagation or type inference
+ * depends on the lack of a certain declaration in the library).
*/
- List<PrelinkedDependency> dependencies;
+ List<LinkedDependency> dependencies;
/**
* For each import in [UnlinkedUnit.imports], an index into [dependencies]
* of the library being imported.
- *
- * TODO(paulberry): if [dependencies] is removed, this can be removed as
- * well, since there will effectively be a one-to-one mapping.
*/
List<int> importDependencies;
+
+ /**
+ * Information about entities in the export namespace of the library that are
+ * not in the public namespace of the library (that is, entities that are
+ * brought into the namespace via `export` directives).
+ *
+ * Sorted by name.
+ */
+ List<LinkedExportName> exportNames;
+
+ /**
+ * The number of elements in [dependencies] which are not "linked"
+ * dependencies (that is, the number of libraries in the direct imports plus
+ * the transitive closure of exports, plus the library itself).
+ */
+ int numPrelinkedDependencies;
}
/**
* Information about the resolution of an [UnlinkedReference].
*/
-class PrelinkedReference {
+class LinkedReference {
/**
- * Index into [PrelinkedLibrary.dependencies] indicating which imported library
+ * Index into [LinkedLibrary.dependencies] indicating which imported library
* declares the entity being referred to.
*/
int dependency;
/**
- * The kind of the entity being referred to. For the pseudo-type `dynamic`,
- * the kind is [PrelinkedReferenceKind.classOrEnum].
+ * The kind of the entity being referred to. For the pseudo-types `dynamic`
+ * and `void`, the kind is [ReferenceKind.classOrEnum].
*/
- PrelinkedReferenceKind kind;
+ ReferenceKind kind;
/**
* Integer index indicating which unit in the imported library contains the
- * definition of the entity. As with indices into [PrelinkedLibrary.units],
+ * definition of the entity. As with indices into [LinkedLibrary.units],
* zero represents the defining compilation unit, and nonzero values
* represent parts in the order of the corresponding `part` declarations.
*/
@@ -146,27 +250,80 @@
* it accepts. Otherwise zero.
*/
int numTypeParameters;
+
+ /**
+ * If this [LinkedReference] doesn't have an associated [UnlinkedReference],
+ * name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
+ */
+ String name;
+}
+
+/**
+ * Linked summary of a compilation unit.
+ */
+class LinkedUnit {
+ /**
+ * Information about the resolution of references within the compilation
+ * unit. Each element of [UnlinkedUnit.references] has a corresponding
+ * element in this list (at the same index). If this list has additional
+ * elements beyond the number of elements in [UnlinkedUnit.references], those
+ * additional elements are references that are only referred to implicitly
+ * (e.g. elements involved in inferred or propagated types).
+ */
+ List<LinkedReference> references;
+
+ /**
+ * List associating slot ids found inside the unlinked summary for the
+ * compilation unit with propagated and inferred types.
+ */
+ List<EntityRef> types;
}
/**
* Enum used to indicate the kind of entity referred to by a
- * [PrelinkedReference].
+ * [LinkedReference].
*/
-enum PrelinkedReferenceKind {
+enum ReferenceKind {
/**
* The entity is a class or enum.
*/
classOrEnum,
/**
+ * The entity is a constructor.
+ */
+ constructor,
+
+ /**
+ * The entity is a static const field.
+ */
+ constField,
+
+ /**
+ * The entity is a static method.
+ */
+ staticMethod,
+
+ /**
+ * The `length` property access.
+ */
+ length,
+
+ /**
* The entity is a typedef.
*/
typedef,
/**
- * The entity is a variable or executable.
+ * The entity is a top level function.
*/
- other,
+ topLevelFunction,
+
+ /**
+ * The entity is a top level getter or setter.
+ */
+ topLevelPropertyAccessor,
/**
* The entity is a prefix.
@@ -180,30 +337,19 @@
}
/**
- * Pre-linked summary of a compilation unit.
- */
-class PrelinkedUnit {
- /**
- * For each reference in [UnlinkedUnit.references], information about how
- * that reference is resolved.
- */
- List<PrelinkedReference> references;
-}
-
-/**
* Information about SDK.
*/
@topLevel
class SdkBundle {
/**
- * The list of URIs of items in [prelinkedLibraries], e.g. `dart:core`.
+ * The list of URIs of items in [linkedLibraries], e.g. `dart:core`.
*/
- List<String> prelinkedLibraryUris;
+ List<String> linkedLibraryUris;
/**
- * Pre-linked libraries.
+ * Linked libraries.
*/
- List<PrelinkedLibrary> prelinkedLibraries;
+ List<LinkedLibrary> linkedLibraries;
/**
* The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
@@ -248,17 +394,17 @@
* explicitly declare a supertype (and hence has supertype `Object`), or (b)
* the class *is* `Object` (and hence has no supertype).
*/
- UnlinkedTypeRef supertype;
+ EntityRef supertype;
/**
* Mixins appearing in a `with` clause, if any.
*/
- List<UnlinkedTypeRef> mixins;
+ List<EntityRef> mixins;
/**
* Interfaces appearing in an `implements` clause, if any.
*/
- List<UnlinkedTypeRef> interfaces;
+ List<EntityRef> interfaces;
/**
* Field declarations contained in the class.
@@ -304,6 +450,336 @@
}
/**
+ * Unlinked summary information about a compile-time constant expression, or a
+ * potentially constant expression.
+ *
+ * Constant expressions are represented using a simple stack-based language
+ * where [operations] is a sequence of operations to execute starting with an
+ * empty stack. Once all operations have been executed, the stack should
+ * contain a single value which is the value of the constant. Note that some
+ * operations consume additional data from the other fields of this class.
+ */
+class UnlinkedConst {
+ /**
+ * Sequence of operations to execute (starting with an empty stack) to form
+ * the constant value.
+ */
+ List<UnlinkedConstOperation> operations;
+
+ /**
+ * Sequence of unsigned 32-bit integers consumed by the operations
+ * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+ * `makeList`, and `makeMap`.
+ */
+ List<int> ints;
+
+ /**
+ * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+ */
+ List<double> doubles;
+
+ /**
+ * Sequence of strings consumed by the operations `pushString` and
+ * `invokeConstructor`.
+ */
+ List<String> strings;
+
+ /**
+ * Sequence of language constructs consumed by the operations
+ * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`. Note
+ * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+ * actual entity being referred to may be something other than a type.
+ */
+ List<EntityRef> references;
+}
+
+/**
+ * Enum representing the various kinds of operations which may be performed to
+ * produce a constant value. These options are assumed to execute in the
+ * context of a stack which is initially empty.
+ */
+enum UnlinkedConstOperation {
+ /**
+ * Push the value of the n-th constructor argument (where n is obtained from
+ * [UnlinkedConst.ints]) onto the stack.
+ */
+ pushArgument,
+
+ /**
+ * Push the next value from [UnlinkedConst.ints] (a 32-bit unsigned integer)
+ * onto the stack.
+ *
+ * Note that Dart supports integers larger than 32 bits; these are
+ * represented by composing 32 bit values using the [shiftOr] operation.
+ */
+ pushInt,
+
+ /**
+ * Pop the top value off the stack, which should be an integer. Multiply it
+ * by 2^32, "or" in the next value from [UnlinkedConst.ints] (which is
+ * interpreted as a 32-bit unsigned integer), and push the result back onto
+ * the stack.
+ */
+ shiftOr,
+
+ /**
+ * Push the next value from [UnlinkedConst.doubles] (a double precision
+ * floating point value) onto the stack.
+ */
+ pushDouble,
+
+ /**
+ * Push the constant `true` onto the stack.
+ */
+ pushTrue,
+
+ /**
+ * Push the constant `false` onto the stack.
+ */
+ pushFalse,
+
+ /**
+ * Push the next value from [UnlinkedConst.strings] onto the stack.
+ */
+ pushString,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), convert them to strings (if they aren't already),
+ * concatenate them into a single string, and push it back onto the stack.
+ *
+ * This operation is used to represent constants whose value is a literal
+ * string containing string interpolations.
+ */
+ concatenate,
+
+ /**
+ * Pop the top value from the stack which should be string, convert it to
+ * a symbol, and push it back onto the stack.
+ */
+ makeSymbol,
+
+ /**
+ * Push the constant `null` onto the stack.
+ */
+ pushNull,
+
+ /**
+ * Evaluate a (potentially qualified) identifier expression and push the
+ * resulting value onto the stack. The identifier to be evaluated is
+ * obtained from [UnlinkedConst.references].
+ *
+ * This operation is used to represent the following kinds of constants
+ * (which are indistinguishable from an unresolved AST alone):
+ *
+ * - A qualified reference to a static constant variable (e.g. `C.v`, where
+ * C is a class and `v` is a constant static variable in `C`).
+ * - An identifier expression referring to a constant variable.
+ * - A simple or qualified identifier denoting a class or type alias.
+ * - A simple or qualified identifier denoting a top-level function or a
+ * static method.
+ */
+ pushReference,
+
+ /**
+ * Pop the top `n` values from the stack (where `n` is obtained from
+ * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
+ * `n` values from [UnlinkedConst.strings] and use the lists of names and
+ * values to create named arguments. Then pop the top `m` values from the
+ * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
+ * from the end) and use them as positional arguments. Use the lists of
+ * positional and names arguments to invoke a constant constructor obtained
+ * from [UnlinkedConst.references], and push the resulting value back onto the
+ * stack.
+ *
+ * Note that for an invocation of the form `const a.b(...)` (where no type
+ * arguments are specified), it is impossible to tell from the unresolved AST
+ * alone whether `a` is a class name and `b` is a constructor name, or `a` is
+ * a prefix name and `b` is a class name. For consistency between AST based
+ * and elements based summaries, references to default constructors are always
+ * recorded as references to corresponding classes.
+ */
+ invokeConstructor,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), place them in a [List], and push the result back
+ * onto the stack. The type parameter for the [List] is implicitly `dynamic`.
+ */
+ makeUntypedList,
+
+ /**
+ * Pop the top 2*n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+ * [Map], and push the result back onto the stack. The two type parameters
+ * for the [Map] are implicitly `dynamic`.
+ */
+ makeUntypedMap,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), place them in a [List], and push the result back
+ * onto the stack. The type parameter for the [List] is obtained from
+ * [UnlinkedConst.references].
+ */
+ makeTypedList,
+
+ /**
+ * Pop the top 2*n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+ * [Map], and push the result back onto the stack. The two type parameters for
+ * the [Map] are obtained from [UnlinkedConst.references].
+ */
+ makeTypedMap,
+
+ /**
+ * Pop the top 2 values from the stack, pass them to the predefined Dart
+ * function `identical`, and push the result back onto the stack.
+ */
+ identical,
+
+ /**
+ * Pop the top 2 values from the stack, evaluate `v1 == v2`, and push the
+ * result back onto the stack.
+ *
+ * This is also used to represent `v1 != v2`, by composition with [not].
+ */
+ equal,
+
+ /**
+ * Pop the top value from the stack, compute its boolean negation, and push
+ * the result back onto the stack.
+ */
+ not,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 && v2`, and push the
+ * result back onto the stack.
+ */
+ and,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 || v2`, and push the
+ * result back onto the stack.
+ */
+ or,
+
+ /**
+ * Pop the top value from the stack, compute its integer complement, and push
+ * the result back onto the stack.
+ */
+ complement,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 ^ v2`, and push the
+ * result back onto the stack.
+ */
+ bitXor,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 & v2`, and push the
+ * result back onto the stack.
+ */
+ bitAnd,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 | v2`, and push the
+ * result back onto the stack.
+ */
+ bitOr,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 >> v2`, and push the
+ * result back onto the stack.
+ */
+ bitShiftRight,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 << v2`, and push the
+ * result back onto the stack.
+ */
+ bitShiftLeft,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 + v2`, and push the
+ * result back onto the stack.
+ */
+ add,
+
+ /**
+ * Pop the top value from the stack, compute its integer negation, and push
+ * the result back onto the stack.
+ */
+ negate,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 - v2`, and push the
+ * result back onto the stack.
+ */
+ subtract,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 * v2`, and push the
+ * result back onto the stack.
+ */
+ multiply,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 / v2`, and push the
+ * result back onto the stack.
+ */
+ divide,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 ~/ v2`, and push the
+ * result back onto the stack.
+ */
+ floorDivide,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 > v2`, and push the
+ * result back onto the stack.
+ */
+ greater,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 < v2`, and push the
+ * result back onto the stack.
+ */
+ less,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 >= v2`, and push the
+ * result back onto the stack.
+ */
+ greaterEqual,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 <= v2`, and push the
+ * result back onto the stack.
+ */
+ lessEqual,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 % v2`, and push the
+ * result back onto the stack.
+ */
+ modulo,
+
+ /**
+ * Pop the top 3 values from the stack, compute `v1 ? v2 : v3`, and push the
+ * result back onto the stack.
+ */
+ conditional,
+
+ /**
+ * Pop the top value from the stack, evaluate `v.length`, and push the result
+ * back onto the stack.
+ */
+ length,
+}
+
+/**
* Unlinked summary information about a documentation comment.
*/
class UnlinkedDocumentationComment {
@@ -414,11 +890,10 @@
List<UnlinkedTypeParam> typeParameters;
/**
- * Declared return type of the executable. Absent if the return type is
- * `void` or the executable is a constructor. Note that when strong mode is
- * enabled, the actual return type may be different due to type inference.
+ * Declared return type of the executable. Absent if the executable is a
+ * constructor or the return type is implicit.
*/
- UnlinkedTypeRef returnType;
+ EntityRef returnType;
/**
* Parameters of the executable, if any. Note that getters have no
@@ -458,15 +933,18 @@
bool isFactory;
/**
- * Indicates whether the executable lacks an explicit return type
- * declaration. False for constructors and setters.
- */
- bool hasImplicitReturnType;
-
- /**
* Indicates whether the executable is declared using the `external` keyword.
*/
bool isExternal;
+
+ /**
+ * If this executable's return type is inferrable, nonzero slot id
+ * identifying which entry in [LinkedLibrary.types] contains the inferred
+ * return type. If there is no matching entry in [LinkedLibrary.types], then
+ * no return type was inferred for this variable, so its static type is
+ * `dynamic`.
+ */
+ int inferredReturnTypeSlot;
}
/**
@@ -614,12 +1092,10 @@
/**
* If [isFunctionTyped] is `true`, the declared return type. If
- * [isFunctionTyped] is `false`, the declared type. Absent if
- * [isFunctionTyped] is `true` and the declared return type is `void`. Note
- * that when strong mode is enabled, the actual type may be different due to
- * type inference.
+ * [isFunctionTyped] is `false`, the declared type. Absent if the type is
+ * implicit.
*/
- UnlinkedTypeRef type;
+ EntityRef type;
/**
* If [isFunctionTyped] is `true`, the parameters of the function type.
@@ -643,10 +1119,17 @@
bool isInitializingFormal;
/**
- * Indicates whether this parameter lacks an explicit type declaration.
- * Always false for a function-typed parameter.
+ * If this parameter's type is inferrable, nonzero slot id identifying which
+ * entry in [LinkedLibrary.types] contains the inferred type. If there is no
+ * matching entry in [LinkedLibrary.types], then no type was inferred for
+ * this variable, so its static type is `dynamic`.
+ *
+ * Note that although strong mode considers initializing formals to be
+ * inferrable, they are not marked as such in the summary; if their type is
+ * not specified, they always inherit the static type of the corresponding
+ * field.
*/
- bool hasImplicitType;
+ int inferredTypeSlot;
}
/**
@@ -692,12 +1175,6 @@
* Unlinked summary information about a specific name contributed by a
* compilation unit to a library's public namespace.
*
- * TODO(paulberry): add a count of generic parameters, so that resynthesis
- * doesn't have to peek into the library to obtain this info.
- *
- * TODO(paulberry): for classes, add info about static members and
- * constructors, since this will be needed to prelink info about constants.
- *
* TODO(paulberry): some of this information is redundant with information
* elsewhere in the summary. Consider reducing the redundancy to reduce
* summary size.
@@ -711,13 +1188,20 @@
/**
* The kind of object referred to by the name.
*/
- PrelinkedReferenceKind kind;
+ ReferenceKind kind;
/**
* If the entity being referred to is generic, the number of type parameters
* it accepts. Otherwise zero.
*/
int numTypeParameters;
+
+ /**
+ * If this [UnlinkedPublicName] is a class, the list of members which can be
+ * referenced from constants - static constant fields, static methods, and
+ * constructors. Otherwise empty.
+ */
+ List<UnlinkedPublicName> constMembers;
}
/**
@@ -752,8 +1236,8 @@
*/
class UnlinkedReference {
/**
- * Name of the entity being referred to. The empty string refers to the
- * pseudo-type `dynamic`.
+ * Name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
*/
String name;
@@ -796,9 +1280,9 @@
List<UnlinkedTypeParam> typeParameters;
/**
- * Return type of the typedef. Absent if the return type is `void`.
+ * Return type of the typedef.
*/
- UnlinkedTypeRef returnType;
+ EntityRef returnType;
/**
* Parameters of the executable, if any.
@@ -825,51 +1309,7 @@
* Bound of the type parameter, if a bound is explicitly declared. Otherwise
* null.
*/
- UnlinkedTypeRef bound;
-}
-
-/**
- * Unlinked summary information about a reference to a type.
- */
-class UnlinkedTypeRef {
- /**
- * Index into [UnlinkedUnit.references] for the type being referred to, or
- * zero if this is a reference to a type parameter.
- *
- * Note that since zero is also a valid index into
- * [UnlinkedUnit.references], we cannot distinguish between references to
- * type parameters and references to types by checking [reference] against
- * zero. To distinguish between references to type parameters and references
- * to types, check whether [paramReference] is zero.
- */
- int reference;
-
- /**
- * If this is a reference to a type parameter, one-based index into the list
- * of [UnlinkedTypeParam]s currently in effect. Indexing is done using De
- * Bruijn index conventions; that is, innermost parameters come first, and
- * if a class or method has multiple parameters, they are indexed from right
- * to left. So for instance, if the enclosing declaration is
- *
- * class C<T,U> {
- * m<V,W> {
- * ...
- * }
- * }
- *
- * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
- * respectively.
- *
- * If the type being referred to is not a type parameter, [paramReference] is
- * zero.
- */
- int paramReference;
-
- /**
- * If this is an instantiation of a generic type, the type arguments used to
- * instantiate it. Trailing type arguments of type `dynamic` are omitted.
- */
- List<UnlinkedTypeRef> typeArguments;
+ EntityRef bound;
}
/**
@@ -910,8 +1350,10 @@
/**
* Top level and prefixed names referred to by this compilation unit. The
- * zeroth element of this array is always populated and always represents a
- * reference to the pseudo-type "dynamic".
+ * zeroth element of this array is always populated and is used to represent
+ * the absence of a reference in places where a reference is optional (for
+ * example [UnlinkedReference.prefixReference or
+ * UnlinkedImport.prefixReference]).
*/
List<UnlinkedReference> references;
@@ -981,10 +1423,15 @@
UnlinkedDocumentationComment documentationComment;
/**
- * Declared type of the variable. Note that when strong mode is enabled, the
- * actual type of the variable may be different due to type inference.
+ * Declared type of the variable. Absent if the type is implicit.
*/
- UnlinkedTypeRef type;
+ EntityRef type;
+
+ /**
+ * If [isConst] is true, and the variable has an initializer, the constant
+ * expression in the initializer.
+ */
+ UnlinkedConst constExpr;
/**
* Indicates whether the variable is declared using the `static` keyword.
@@ -1006,7 +1453,20 @@
bool isConst;
/**
- * Indicates whether this variable lacks an explicit type declaration.
+ * If this variable is propagable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the propagated type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then this variable's
+ * propagated type is the same as its declared type.
+ *
+ * Non-propagable variables have a [propagatedTypeSlot] of zero.
*/
- bool hasImplicitType;
+ int propagatedTypeSlot;
+
+ /**
+ * If this variable is inferrable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the inferred type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then no type was
+ * inferred for this variable, so its static type is `dynamic`.
+ */
+ int inferredTypeSlot;
}
diff --git a/pkg/analyzer/tool/summary/idl_model.dart b/pkg/analyzer/tool/summary/idl_model.dart
index 07be039..9317215 100644
--- a/pkg/analyzer/tool/summary/idl_model.dart
+++ b/pkg/analyzer/tool/summary/idl_model.dart
@@ -51,13 +51,21 @@
/**
* List of enumerated values.
*/
- final List<String> values = <String>[];
+ final List<EnumValueDeclaration> values = <EnumValueDeclaration>[];
EnumDeclaration(String documentation, String name)
: super(documentation, name);
}
/**
+ * Information about a single enum value defined in the IDL.
+ */
+class EnumValueDeclaration extends Declaration {
+ EnumValueDeclaration(String documentation, String name)
+ : super(documentation, name);
+}
+
+/**
* Information about a single class field defined in the IDL.
*/
class FieldDeclaration extends Declaration {
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 0b6ae40..19b7af4 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/plugin/options.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/source/embedder.dart';
import 'package:analyzer/source/package_map_provider.dart';
import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/source/pub_package_map_provider.dart';
@@ -302,7 +303,8 @@
/// Decide on the appropriate method for resolving URIs based on the given
/// [options] and [customUrlMappings] settings, and return a
/// [SourceFactory] that has been configured accordingly.
- SourceFactory _chooseUriResolutionPolicy(CommandLineOptions options) {
+ SourceFactory _chooseUriResolutionPolicy(
+ CommandLineOptions options, EmbedderYamlLocator yamlLocator) {
Packages packages;
Map<String, List<fileSystem.Folder>> packageMap;
UriResolver packageUriResolver;
@@ -356,9 +358,24 @@
}
// Now, build our resolver list.
+ List<UriResolver> resolvers = [];
// 'dart:' URIs come first.
- List<UriResolver> resolvers = [new DartUriResolver(sdk)];
+
+ // Setup embedding.
+ yamlLocator.refresh(packageMap);
+
+ EmbedderUriResolver embedderUriResolver =
+ new EmbedderUriResolver(yamlLocator.embedderYamls);
+ if (embedderUriResolver.length == 0) {
+ // The embedder uri resolver has no mappings. Use the default Dart SDK
+ // uri resolver.
+ resolvers.add(new DartUriResolver(sdk));
+ } else {
+ // The embedder uri resolver has mappings, use it instead of the default
+ // Dart SDK uri resolver.
+ resolvers.add(embedderUriResolver);
+ }
// Next SdkExts.
if (packageMap != null) {
@@ -401,13 +418,16 @@
return;
}
_previousOptions = options;
+
+ // Create a context.
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+
// Choose a package resolution policy and a diet parsing policy based on
// the command-line options.
- SourceFactory sourceFactory = _chooseUriResolutionPolicy(options);
+ SourceFactory sourceFactory = _chooseUriResolutionPolicy(
+ options, (context as InternalAnalysisContext).embedderYamlLocator);
AnalyzeFunctionBodiesPredicate dietParsingPolicy =
_chooseDietParsingPolicy(options);
- // Create a context using these policies.
- AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
context.sourceFactory = sourceFactory;
diff --git a/pkg/analyzer_cli/test/data/embedder_client/_packages b/pkg/analyzer_cli/test/data/embedder_client/_packages
new file mode 100644
index 0000000..03ed0f7
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/embedder_client/_packages
@@ -0,0 +1 @@
+package_with_embedder_yaml:../package_with_embedder_yaml/lib/
diff --git a/pkg/analyzer_cli/test/data/embedder_client/embedder_yaml_user.dart b/pkg/analyzer_cli/test/data/embedder_client/embedder_yaml_user.dart
new file mode 100644
index 0000000..2d88a2a
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/embedder_client/embedder_yaml_user.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:bear'; // Defined in package_with_embedder_yaml/lib/_embedder.yaml
+
+main() {
+ print(new Bear()); // Defined in 'dart:bear'
+}
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/_embedder.yaml b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/_embedder.yaml
new file mode 100644
index 0000000..5253771
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/_embedder.yaml
@@ -0,0 +1,4 @@
+embedder_libs:
+ "dart:bear": "grizzly.dart"
+ "dart:core": "core.dart"
+ "dart:async": "async.dart"
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart
new file mode 100644
index 0000000..3b69a2a
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, 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 dart.async;
+
+abstract class Future<T> {}
+
+abstract class Stream<T> {}
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/core.dart b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/core.dart
new file mode 100644
index 0000000..a7fa657
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/core.dart
@@ -0,0 +1,106 @@
+// Copyright (c) 2016, 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 dart.core;
+
+class Object {
+ bool operator ==(other) => identical(this, other);
+ String toString() => 'a string';
+ int get hashCode => 0;
+}
+
+class Function {}
+
+class StackTrace {}
+
+class Symbol {}
+
+class Type {}
+
+abstract class Comparable<T> {
+ int compareTo(T other);
+}
+
+abstract class String implements Comparable<String> {
+ external factory String.fromCharCodes(Iterable<int> charCodes,
+ [int start = 0, int end]);
+ bool get isEmpty => false;
+ bool get isNotEmpty => false;
+ int get length => 0;
+ String toUpperCase();
+ List<int> get codeUnits;
+}
+
+class bool extends Object {}
+
+abstract class num implements Comparable<num> {
+ bool operator <(num other);
+ bool operator <=(num other);
+ bool operator >(num other);
+ bool operator >=(num other);
+ num operator +(num other);
+ num operator -(num other);
+ num operator *(num other);
+ num operator %(num other);
+ num operator /(num other);
+ int toInt();
+ num abs();
+ int round();
+}
+
+abstract class int extends num {
+ bool get isEven => false;
+ int operator -();
+ external static int parse(String source,
+ {int radix, int onError(String source)});
+}
+
+class double extends num {}
+
+class DateTime extends Object {}
+
+class Null extends Object {}
+
+class Deprecated extends Object {
+ final String expires;
+ const Deprecated(this.expires);
+}
+
+const Object deprecated = const Deprecated("next release");
+
+class Iterator<E> {
+ bool moveNext();
+ E get current;
+}
+
+abstract class Iterable<E> {
+ Iterator<E> get iterator;
+ bool get isEmpty;
+}
+
+abstract class List<E> implements Iterable<E> {
+ void add(E value);
+ E operator [](int index);
+ void operator []=(int index, E value);
+ Iterator<E> get iterator => null;
+ void clear();
+}
+
+abstract class Map<K, V> extends Object {
+ bool containsKey(Object key);
+ Iterable<K> get keys;
+}
+
+external bool identical(Object a, Object b);
+
+void print(Object object) {}
+
+class Uri {
+ static List<int> parseIPv6Address(String host, [int start = 0, int end]) {
+ int parseHex(int start, int end) {
+ return 0;
+ }
+ return null;
+ }
+}
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/grizzly.dart b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/grizzly.dart
new file mode 100644
index 0000000..d575643
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/grizzly.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, 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 grizzly;
+
+class Bear {}
diff --git a/pkg/analyzer_cli/test/embedder_test.dart b/pkg/analyzer_cli/test/embedder_test.dart
new file mode 100644
index 0000000..ded83fd
--- /dev/null
+++ b/pkg/analyzer_cli/test/embedder_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+main() {
+ initializeTestEnvironment();
+
+ group('_embedder.yaml', () {
+ StringSink savedOutSink, savedErrorSink;
+ int savedExitCode;
+
+ setUp(() {
+ savedOutSink = outSink;
+ savedErrorSink = errorSink;
+ savedExitCode = exitCode;
+ outSink = new StringBuffer();
+ errorSink = new StringBuffer();
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ errorSink = savedErrorSink;
+ exitCode = savedExitCode;
+ });
+
+ test('resolution', wrap(() {
+ var testDir = path.join(testDirectory, 'data', 'embedder_client');
+ new Driver().start([
+ '--packages',
+ path.join(testDir, '_packages'),
+ path.join(testDir, 'embedder_yaml_user.dart')
+ ]);
+
+ expect(exitCode, 0);
+ expect(outSink.toString(), contains('No issues found'));
+ }));
+ });
+}
+
+/// Wrap a function call to dump stdout and stderr in case of an exception.
+Function wrap(Function f) {
+ return () {
+ try {
+ f();
+ } catch (e) {
+ if (outSink.toString().isNotEmpty) {
+ print('stdout:');
+ print(outSink);
+ }
+ if (errorSink.toString().isNotEmpty) {
+ print('stderr:');
+ print(errorSink);
+ }
+ throw e;
+ }
+ };
+}
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 8f81d15..e84777f 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -33,6 +33,14 @@
const bool forceIncrementalSupport =
const bool.fromEnvironment('DART2JS_EXPERIMENTAL_INCREMENTAL_SUPPORT');
+/// For every 'dart:' library, a corresponding environment variable is set
+/// to "true". The environment variable's name is the concatenation of
+/// this prefix and the name (without the 'dart:'.
+///
+/// For example 'dart:html' has the environment variable 'dart.library.html' set
+/// to "true".
+const String dartLibraryEnvironmentPrefix = 'dart.library.';
+
/// Locations of the platform descriptor files relative to the library root.
const String _clientPlatform = "lib/dart_client.platform";
const String _serverPlatform = "lib/dart_server.platform";
@@ -580,7 +588,26 @@
}
}
- fromEnvironment(String name) => environment[name];
+ fromEnvironment(String name) {
+ assert(invariant(NO_LOCATION_SPANNABLE,
+ sdkLibraries != null, message: "setupSdk() has not been run"));
+
+ var result = environment[name];
+ if (result != null || environment.containsKey(name)) return result;
+ if (!name.startsWith(dartLibraryEnvironmentPrefix)) return null;
+
+ String libraryName = name.substring(dartLibraryEnvironmentPrefix.length);
+ if (sdkLibraries.containsKey(libraryName)) {
+ // Dart2js always "supports" importing 'dart:mirrors' but will abort
+ // the compilation at a later point if the backend doesn't support
+ // mirrors. In this case 'mirrors' should not be in the environment.
+ if (name == dartLibraryEnvironmentPrefix + 'mirrors') {
+ return backend.supportsReflection ? "true" : null;
+ }
+ return "true";
+ }
+ return null;
+ }
Uri lookupLibraryUri(String libraryName) {
assert(invariant(NO_LOCATION_SPANNABLE,
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 53be699..4b37788 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -1073,6 +1073,8 @@
dumpInfoTask.dumpInfo();
}
+ backend.sourceInformationStrategy.onComplete();
+
checkQueues();
}
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 945aaba..fde5cde 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -64,6 +64,8 @@
bool get isMinusZero => false;
bool get isZero => false;
bool get isOne => false;
+ bool get isPositiveInfinity => false;
+ bool get isNegativeInfinity => false;
// TODO(johnniwinther): Replace with a 'type' getter.
DartType getType(CoreTypes types);
@@ -279,6 +281,10 @@
bool get isOne => primitiveValue == 1.0;
+ bool get isPositiveInfinity => primitiveValue == double.INFINITY;
+
+ bool get isNegativeInfinity => primitiveValue == -double.INFINITY;
+
DartType getType(CoreTypes types) => types.doubleType;
bool operator ==(var other) {
diff --git a/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart b/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
index 422aaa3..b55a433 100644
--- a/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
+++ b/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
@@ -77,7 +77,7 @@
prim..replaceUsesWith(value)..destroy();
let.remove();
} else if (prim is GetLength || prim is GetField || prim is GetIndex) {
- if (prim.hasNoEffectiveUses) {
+ if (prim.hasNoRefinedUses) {
destroyRefinementsOfDeadPrimitive(prim);
LetPrim let = prim.parent;
prim..destroy();
diff --git a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
index 44cbbb0..798875f 100644
--- a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
+++ b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
@@ -614,6 +614,16 @@
@override
void visitInvokeMethod(InvokeMethod node) {
+ if (node.selector.isGetter && node.selector.name == 'length') {
+ // If the receiver type is not known to be indexable, the length call
+ // was not rewritten to GetLength. But if we can prove that the call only
+ // succeeds for indexables, we can trust that it returns the length.
+ TypeMask successType =
+ types.receiverTypeFor(node.selector, node.dartReceiver.type);
+ if (types.isDefinitelyIndexable(successType)) {
+ valueOf[node] = getLength(node.dartReceiver, currentEffectNumber);
+ }
+ }
// TODO(asgerf): What we really need is a "changes length" side effect flag.
if (world
.getSideEffectsOfSelector(node.selector, node.mask)
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index 0a80f33..470a96d 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -21,7 +21,8 @@
import '../js/js.dart' as js show
js,
LiteralStatement,
- Template;
+ Template,
+ isIdentityTemplate;
import '../native/native.dart' show
NativeBehavior;
import '../tree/tree.dart' as ast;
@@ -166,6 +167,11 @@
JumpCollector.retrn(this._continuation)
: _continuationEnvironment = null, target = null;
+ /// Construct a collector for collecting goto jumps.
+ ///
+ /// There is no continuation or environment at the destination.
+ JumpCollector.goto(this.target) : _continuationEnvironment = null;
+
/// True if the collector has not recorded any jumps to its continuation.
bool get isEmpty;
@@ -421,6 +427,31 @@
}
}
+/// Collect 'goto' jumps, continue to a labeled case from within a switch.
+///
+/// These jumps are unrestricted within the switch. They can be forward or
+/// backward. They are implemented by assigning to a state variable.
+class GotoJumpCollector extends JumpCollector {
+ bool isEmpty = true;
+ final ir.Continuation continuation = null;
+ final Environment environment = null;
+
+ int _stateVariableIndex;
+ int _stateValue;
+ JumpCollector _breakJoin;
+
+ GotoJumpCollector(JumpTarget target, this._stateVariableIndex,
+ this._stateValue, this._breakJoin) : super.goto(target);
+
+ void addJump(IrBuilder builder,
+ [ir.Primitive value, SourceInformation sourceInformation]) {
+ isEmpty = false;
+ ir.Primitive constant = builder.buildIntegerConstant(_stateValue);
+ builder.environment.index2value[_stateVariableIndex] = constant;
+ builder.jumpTo(_breakJoin);
+ }
+}
+
/// Function for building a node in the context of the current builder.
typedef ir.Node BuildFunction(node);
@@ -532,7 +563,7 @@
///
/// The IR fragment is an expression with a hole in it. The hole represents
/// the focus where new expressions can be added. The fragment is implemented
-/// by [_root] which is the root of the expression and [_current] which is the
+/// by [root] which is the root of the expression and [_current] which is the
/// expression that immediately contains the hole. Not all expressions have a
/// hole (e.g., invocations, which always occur in tail position, do not have a
/// hole). Expressions with a hole have a plug method.
@@ -559,7 +590,7 @@
/// side effects.
Map<Local, ir.MutableVariable> mutableVariables;
- ir.Expression _root = null;
+ ir.Expression root = null;
ir.Expression _current = null;
GlobalProgramInformation get program => state.program;
@@ -613,7 +644,7 @@
return mutableVariables[local];
}
- bool get isOpen => _root == null || _current != null;
+ bool get isOpen => root == null || _current != null;
List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters,
{ClosureScope closureScope,
@@ -640,8 +671,8 @@
/// new value of current.
void add(ir.Expression expr) {
assert(isOpen);
- if (_root == null) {
- _root = _current = expr;
+ if (root == null) {
+ root = _current = expr;
} else {
_current = _current.plug(expr);
}
@@ -789,8 +820,8 @@
// if condition (then, else)
ir.Continuation thenContinuation = new ir.Continuation([]);
ir.Continuation elseContinuation = new ir.Continuation([]);
- thenContinuation.body = thenBuilder._root;
- elseContinuation.body = elseBuilder._root;
+ thenContinuation.body = thenBuilder.root;
+ elseContinuation.body = elseBuilder.root;
add(new ir.LetCont(join.continuation,
new ir.LetCont.two(thenContinuation, elseContinuation,
new ir.Branch.strict(condition,
@@ -812,7 +843,7 @@
_current = null;
}
- /// Create a [ir.FunctionDefinition] using [_root] as the body.
+ /// Create a [ir.FunctionDefinition] using [root] as the body.
///
/// The protocol for building a function is:
/// 1. Call [buildFunctionHeader].
@@ -825,7 +856,7 @@
state.thisParameter,
state.functionParameters,
state.returnContinuation,
- _root);
+ root);
}
/// Create a invocation of the [method] on the super class where the call
@@ -1107,17 +1138,17 @@
// case that one of them is null, it must be the only one that is open
// and thus contains the new hole in the context. This case is handled
// after the branch is plugged into the current hole.
- thenContinuation.body = thenBuilder._root;
- elseContinuation.body = elseBuilder._root;
+ thenContinuation.body = thenBuilder.root;
+ elseContinuation.body = elseBuilder.root;
add(result);
if (join == null) {
// At least one subexpression is closed.
if (thenBuilder.isOpen) {
- if (thenBuilder._root != null) _current = thenBuilder._current;
+ if (thenBuilder.root != null) _current = thenBuilder._current;
environment = thenBuilder.environment;
} else if (elseBuilder.isOpen) {
- if (elseBuilder._root != null) _current = elseBuilder._current;
+ if (elseBuilder.root != null) _current = elseBuilder._current;
environment = elseBuilder.environment;
} else {
_current = null;
@@ -1243,16 +1274,16 @@
// it is guaranteed that the updateBuilder has a non-empty term.
if (hasContinues) {
outerBodyBuilder.add(new ir.LetCont(continueCollector.continuation,
- innerBodyBuilder._root));
- continueCollector.continuation.body = updateBuilder._root;
+ innerBodyBuilder.root));
+ continueCollector.continuation.body = updateBuilder.root;
} else {
- outerBodyBuilder.add(innerBodyBuilder._root);
+ outerBodyBuilder.add(innerBodyBuilder.root);
}
// Create loop exit and body entry continuations and a branch to them.
ir.Continuation exitContinuation = new ir.Continuation([]);
ir.Continuation bodyContinuation = new ir.Continuation([]);
- bodyContinuation.body = outerBodyBuilder._root;
+ bodyContinuation.body = outerBodyBuilder.root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1268,7 +1299,7 @@
if (hasBreaks) {
IrBuilder exitBuilder = makeDelimitedBuilder();
exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder._root;
+ exitContinuation.body = exitBuilder.root;
letBreak = new ir.LetCont(breakCollector.continuation, branch);
add(letBreak);
environment = breakCollector.environment;
@@ -1411,7 +1442,7 @@
// in branch condition (body, exit)
ir.Continuation exitContinuation = new ir.Continuation([]);
ir.Continuation bodyContinuation = new ir.Continuation([]);
- bodyContinuation.body = bodyBuilder._root;
+ bodyContinuation.body = bodyBuilder.root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1427,7 +1458,7 @@
if (hasBreaks) {
IrBuilder exitBuilder = makeDelimitedBuilder();
exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder._root;
+ exitContinuation.body = exitBuilder.root;
letBreak = new ir.LetCont(breakCollector.continuation, branch);
add(letBreak);
environment = breakCollector.environment;
@@ -1486,7 +1517,7 @@
// Create body entry and loop exit continuations and a branch to them.
ir.Continuation exitContinuation = new ir.Continuation([]);
ir.Continuation bodyContinuation = new ir.Continuation([]);
- bodyContinuation.body = bodyBuilder._root;
+ bodyContinuation.body = bodyBuilder.root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1502,7 +1533,7 @@
if (hasBreaks) {
IrBuilder exitBuilder = makeDelimitedBuilder();
exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder._root;
+ exitContinuation.body = exitBuilder.root;
letBreak = new ir.LetCont(breakCollector.continuation, branch);
add(letBreak);
environment = breakCollector.environment;
@@ -1569,18 +1600,18 @@
ir.Continuation exitContinuation = new ir.Continuation([]);
IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder();
exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder._root;
+ exitContinuation.body = exitBuilder.root;
ir.Continuation repeatContinuation = new ir.Continuation([]);
IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder();
repeatBuilder.jumpTo(loop);
- repeatContinuation.body = repeatBuilder._root;
+ repeatContinuation.body = repeatBuilder.root;
continueBuilder.add(
new ir.LetCont.two(exitContinuation, repeatContinuation,
new ir.Branch.strict(condition,
repeatContinuation,
exitContinuation)));
- continueCollector.continuation.body = continueBuilder._root;
+ continueCollector.continuation.body = continueBuilder.root;
// Construct the loop continuation (i.e., the body and condition).
// <Loop> =
@@ -1589,56 +1620,25 @@
// in [[body]]; continue(v, ...)
loopBuilder.add(
new ir.LetCont(continueCollector.continuation,
- bodyBuilder._root));
+ bodyBuilder.root));
// And tie it all together.
- add(new ir.LetCont(breakCollector.continuation, loopBuilder._root));
+ add(new ir.LetCont(breakCollector.continuation, loopBuilder.root));
environment = breakCollector.environment;
}
- void buildSimpleSwitch(JumpTarget target,
- ir.Primitive value,
+ void buildSimpleSwitch(JumpCollector join,
List<SwitchCaseInfo> cases,
- SwitchCaseInfo defaultCase,
- Element error,
- SourceInformation sourceInformation) {
- assert(isOpen);
- JumpCollector join = new ForwardJumpCollector(environment, target: target);
-
+ SubbuildFunction buildDefaultBody) {
IrBuilder casesBuilder = makeDelimitedBuilder();
- casesBuilder.state.breakCollectors.add(join);
for (SwitchCaseInfo caseInfo in cases) {
- buildConditionsFrom(int index) => (IrBuilder builder) {
- ir.Primitive comparison = builder.buildIdentical(
- value, caseInfo.constants[index]);
- return (index == caseInfo.constants.length - 1)
- ? comparison
- : builder.buildLogicalOperator(
- comparison, buildConditionsFrom(index + 1), isLazyOr: true);
- };
-
- ir.Primitive condition = buildConditionsFrom(0)(casesBuilder);
+ ir.Primitive condition = caseInfo.buildCondition(casesBuilder);
IrBuilder thenBuilder = makeDelimitedBuilder();
caseInfo.buildBody(thenBuilder);
- if (thenBuilder.isOpen) {
- // It is a runtime error to reach the end of a switch case, unless
- // it is the last case.
- if (caseInfo == cases.last && defaultCase == null) {
- thenBuilder.jumpTo(join);
- } else {
- ir.Primitive exception = thenBuilder.buildInvokeStatic(
- error,
- new Selector.fromElement(error),
- <ir.Primitive>[],
- sourceInformation);
- thenBuilder.buildThrow(exception);
- }
- }
-
ir.Continuation thenContinuation = new ir.Continuation([]);
- thenContinuation.body = thenBuilder._root;
+ thenContinuation.body = thenBuilder.root;
ir.Continuation elseContinuation = new ir.Continuation([]);
- // A LetCont.many term has a hole as the body of the first listed
+ // A LetCont.two term has a hole as the body of the first listed
// continuation, to be plugged by the translation. Therefore put the
// else continuation first.
casesBuilder.add(
@@ -1648,18 +1648,17 @@
elseContinuation)));
}
- if (defaultCase != null) {
- defaultCase.buildBody(casesBuilder);
+ if (buildDefaultBody == null) {
+ casesBuilder.jumpTo(join);
+ } else {
+ buildDefaultBody(casesBuilder);
}
- if (casesBuilder.isOpen) casesBuilder.jumpTo(join);
-
- casesBuilder.state.breakCollectors.removeLast();
if (!join.isEmpty) {
- add(new ir.LetCont(join.continuation, casesBuilder._root));
+ add(new ir.LetCont(join.continuation, casesBuilder.root));
environment = join.environment;
- } else if (casesBuilder._root != null) {
- add(casesBuilder._root);
+ } else if (casesBuilder.root != null) {
+ add(casesBuilder.root);
_current = casesBuilder._current;
environment = casesBuilder.environment;
} else {
@@ -1721,11 +1720,11 @@
List<ir.Parameter> catchParameters = buildCatch(catchBuilder, join);
ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
- catchContinuation.body = catchBuilder._root;
+ catchContinuation.body = catchBuilder.root;
tryCatchBuilder.add(
- new ir.LetHandler(catchContinuation, tryBuilder._root));
+ new ir.LetHandler(catchContinuation, tryBuilder.root));
- leaveTryCatch(this, join, tryCatchBuilder._root);
+ leaveTryCatch(this, join, tryCatchBuilder.root);
}
/// Translates a try/catch.
@@ -1829,7 +1828,7 @@
}
clause.buildCatchBlock(clauseBuilder);
if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
- return clauseBuilder._root;
+ return clauseBuilder.root;
}
// Expand multiple catch clauses into an explicit if/then/else. Iterate
@@ -1855,7 +1854,7 @@
new ir.Branch.strict(typeMatches,
thenContinuation,
elseContinuation)));
- catchBody = checkBuilder._root;
+ catchBody = checkBuilder.root;
}
builder.add(catchBody);
@@ -1960,7 +1959,7 @@
IrBuilder builder = makeDelimitedBuilder(newCollector.environment);
buildFinallyBlock(builder);
if (builder.isOpen) builder.jumpTo(originalCollector);
- newCollector.continuation.body = builder._root;
+ newCollector.continuation.body = builder.root;
exits.add(newCollector.continuation);
}
for (int i = 0; i < newBreaks.length; ++i) {
@@ -1974,7 +1973,7 @@
ir.Primitive value = builder.environment.discard(1);
buildFinallyBlock(builder);
if (builder.isOpen) builder.buildReturn(value: value);
- newReturn.continuation.body = builder._root;
+ newReturn.continuation.body = builder.root;
exits.add(newReturn.continuation);
}
builder.add(new ir.LetCont.many(exits, body));
@@ -2062,7 +2061,8 @@
ir.Primitive value = buildForeignCode(
js.js.uncachedExpressionTemplate(code),
arguments,
- behavior);
+ behavior,
+ type: program.getTypeMaskForNativeFunction(function));
buildReturn(value: value, sourceInformation: source);
}
@@ -2100,10 +2100,10 @@
bool hasBreaks = !join.isEmpty;
if (hasBreaks) {
if (innerBuilder.isOpen) innerBuilder.jumpTo(join);
- add(new ir.LetCont(join.continuation, innerBuilder._root));
+ add(new ir.LetCont(join.continuation, innerBuilder.root));
environment = join.environment;
- } else if (innerBuilder._root != null) {
- add(innerBuilder._root);
+ } else if (innerBuilder.root != null) {
+ add(innerBuilder.root);
_current = innerBuilder._current;
environment = innerBuilder.environment;
} else {
@@ -2239,8 +2239,8 @@
ir.Continuation leftFalseContinuation = new ir.Continuation([]);
ir.Continuation rightTrueContinuation = new ir.Continuation([]);
ir.Continuation rightFalseContinuation = new ir.Continuation([]);
- rightTrueContinuation.body = rightTrueBuilder._root;
- rightFalseContinuation.body = rightFalseBuilder._root;
+ rightTrueContinuation.body = rightTrueBuilder.root;
+ rightFalseContinuation.body = rightFalseBuilder.root;
// The right subexpression has two continuations.
rightBuilder.add(
new ir.LetCont.two(rightTrueContinuation, rightFalseContinuation,
@@ -2251,11 +2251,11 @@
// either the right subexpression or an invocation of the join-point
// continuation.
if (isLazyOr) {
- leftTrueContinuation.body = emptyBuilder._root;
- leftFalseContinuation.body = rightBuilder._root;
+ leftTrueContinuation.body = emptyBuilder.root;
+ leftFalseContinuation.body = rightBuilder.root;
} else {
- leftTrueContinuation.body = rightBuilder._root;
- leftFalseContinuation.body = emptyBuilder._root;
+ leftTrueContinuation.body = rightBuilder.root;
+ leftFalseContinuation.body = emptyBuilder.root;
}
add(new ir.LetCont(join.continuation,
@@ -2411,7 +2411,7 @@
arguments.add(value);
}
return addPrimitive(new ir.CreateInstance(
- classElement, arguments, const <ir.Primitive>[], sourceInformation));
+ classElement, arguments, null, sourceInformation));
}
/// Create a read access of [local] function, variable, or parameter.
@@ -2577,7 +2577,8 @@
ir.Primitive value = buildTypeVariableAccess(variable);
arguments.add(value);
});
- return addPrimitive(new ir.TypeExpression(type, arguments));
+ return addPrimitive(new ir.TypeExpression(ir.TypeExpressionKind.COMPLETE,
+ type, arguments));
} else if (type.treatAsDynamic) {
return buildNullConstant();
} else {
@@ -2634,9 +2635,19 @@
ir.Primitive buildForeignCode(js.Template codeTemplate,
List<ir.Primitive> arguments,
NativeBehavior behavior,
- {Element dependency}) {
+ {Element dependency,
+ TypeMask type}) {
assert(behavior != null);
- TypeMask type = program.getTypeMaskForForeign(behavior);
+ if (type == null) {
+ type = program.getTypeMaskForForeign(behavior);
+ }
+ if (js.isIdentityTemplate(codeTemplate) && !program.isArrayType(type)) {
+ // JS expression is just a refinement.
+ // Do not do this for arrays - those are special because array types can
+ // change after creation. The input and output must therefore be modeled
+ // as distinct values.
+ return addPrimitive(new ir.Refinement(arguments.single, type));
+ }
ir.Primitive result = addPrimitive(new ir.ForeignCode(
codeTemplate,
type,
@@ -2834,10 +2845,8 @@
}
class SwitchCaseInfo {
- final List<ir.Primitive> constants = <ir.Primitive>[];
+ final SubbuildFunction buildCondition;
final SubbuildFunction buildBody;
- SwitchCaseInfo(this.buildBody);
-
- void addConstant(ir.Primitive constant) => constants.add(constant);
+ SwitchCaseInfo(this.buildCondition, this.buildBody);
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index 5c55f63..f98c9dd 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -382,7 +382,7 @@
IrBuilder builder = getBuilderFor(constructor);
final bool requiresTypeInformation =
- builder.program.requiresRuntimeTypesFor(classElement);
+ builder.program.requiresRuntimeTypesFor(classElement);
return withBuilder(builder, () {
// Setup parameters and create a box if anything is captured.
@@ -410,11 +410,15 @@
closureScope: getClosureScopeForFunction(constructor));
// Create a list of the values of all type argument parameters, if any.
- List<ir.Primitive> typeInformation;
+ ir.Primitive typeInformation;
if (requiresTypeInformation) {
- typeInformation = irParameters.sublist(firstTypeArgumentParameterIndex);
+ typeInformation = new ir.TypeExpression(
+ ir.TypeExpressionKind.INSTANCE,
+ classElement.thisType,
+ irParameters.sublist(firstTypeArgumentParameterIndex));
+ irBuilder.add(new ir.LetPrim(typeInformation));
} else {
- typeInformation = const <ir.Primitive>[];
+ typeInformation = null;
}
// -- Load values for type variables declared on super classes --
@@ -753,7 +757,8 @@
TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
tryStatements = variables.tryStatements;
IrBuilder builder = getBuilderFor(element);
- return withBuilder(builder, () => _makeFunctionBody(element, node));
+ return withBuilder(builder,
+ () => _makeFunctionBody(builder, element, node));
}
ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) {
@@ -875,17 +880,24 @@
}
}
- ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
- ast.FunctionExpression node) {
+ ir.FunctionDefinition _makeFunctionBody(
+ IrBuilder builder,
+ FunctionElement element,
+ ast.FunctionExpression node) {
FunctionSignature signature = element.functionSignature;
List<Local> parameters = <Local>[];
signature.orderedForEachParameter(
(LocalParameterElement e) => parameters.add(e));
+ bool requiresRuntimeTypes = false;
if (element.isFactoryConstructor) {
- // Type arguments are passed in as extra parameters.
- for (DartType typeVariable in element.enclosingClass.typeVariables) {
- parameters.add(new closure.TypeVariableLocal(typeVariable, element));
+ requiresRuntimeTypes =
+ builder.program.requiresRuntimeTypesFor(element.enclosingElement);
+ if (requiresRuntimeTypes) {
+ // Type arguments are passed in as extra parameters.
+ for (DartType typeVariable in element.enclosingClass.typeVariables) {
+ parameters.add(new closure.TypeVariableLocal(typeVariable, element));
+ }
}
}
@@ -893,7 +905,45 @@
closureScope: getClosureScopeForNode(node),
env: getClosureEnvironment());
- visit(node.body);
+ if (element == helpers.jsArrayTypedConstructor) {
+ // Generate a body for JSArray<E>.typed(allocation):
+ //
+ // t1 = setRuntimeTypeInfo(allocation, TypeExpression($E));
+ // return Refinement(t1, <JSArray>);
+ //
+ assert(parameters.length == 1 || parameters.length == 2);
+ ir.Primitive allocation = irBuilder.buildLocalGet(parameters[0]);
+ ClassElement classElement = element.enclosingElement;
+
+ // Only call setRuntimeTypeInfo if JSArray requires the type parameter.
+ if (requiresRuntimeTypes) {
+ assert(parameters.length == 2);
+ closure.TypeVariableLocal typeParameter = parameters[1];
+ ir.Primitive typeArgument =
+ irBuilder.buildTypeVariableAccess(typeParameter.typeVariable);
+
+ ir.Primitive typeInformation = irBuilder.addPrimitive(
+ new ir.TypeExpression(ir.TypeExpressionKind.INSTANCE,
+ element.enclosingClass.thisType,
+ <ir.Primitive>[typeArgument]));
+
+ MethodElement helper = helpers.setRuntimeTypeInfo;
+ CallStructure callStructure = CallStructure.TWO_ARGS;
+ Selector selector = new Selector.call(helper.memberName, callStructure);
+ allocation = irBuilder.buildInvokeStatic(
+ helper, selector, <ir.Primitive>[allocation, typeInformation],
+ sourceInformationBuilder.buildGeneric(node));
+ }
+
+ ir.Primitive refinement = irBuilder.addPrimitive(
+ new ir.Refinement(allocation, typeMaskSystem.arrayType));
+
+ irBuilder.buildReturn(value: refinement,
+ sourceInformation:
+ sourceInformationBuilder.buildImplicitReturn(element));
+ } else {
+ visit(node.body);
+ }
return irBuilder.makeFunctionDefinition();
}
@@ -1172,44 +1222,270 @@
}
visitSwitchStatement(ast.SwitchStatement node) {
+ // Dart switch cases can be labeled and be the target of continue from
+ // within the switch. Such cases are 'recursive'. If there are any
+ // recursive cases, we implement the switch using a pair of switches with
+ // the second one switching over a state variable in a loop. The first
+ // switch contains the non-recursive cases, and the second switch contains
+ // the recursive ones.
+ //
+ // For example, for the Dart switch:
+ //
+ // switch (E) {
+ // case 0:
+ // BODY0;
+ // break;
+ // LABEL0: case 1:
+ // BODY1;
+ // break;
+ // case 2:
+ // BODY2;
+ // continue LABEL1;
+ // LABEL1: case 3:
+ // BODY3;
+ // continue LABEL0;
+ // default:
+ // BODY4;
+ // }
+ //
+ // We translate it as if it were the JavaScript:
+ //
+ // var state = -1;
+ // switch (E) {
+ // case 0:
+ // BODY0;
+ // break;
+ // case 1:
+ // state = 0; // Recursive, label ID = 0.
+ // break;
+ // case 2:
+ // BODY2;
+ // state = 1; // Continue to label ID = 1.
+ // break;
+ // case 3:
+ // state = 1; // Recursive, label ID = 1.
+ // break;
+ // default:
+ // BODY4;
+ // }
+ // L: while (state != -1) {
+ // case 0:
+ // BODY1;
+ // break L; // Break from switch becomes break from loop.
+ // case 1:
+ // BODY2;
+ // state = 0; // Continue to label ID = 0.
+ // break;
+ // }
assert(irBuilder.isOpen);
- // We do not handle switch statements with continue to labeled cases.
- for (ast.SwitchCase switchCase in node.cases) {
+ // Preprocess: compute a list of cases that are the target of continue.
+ // These are the so-called 'recursive' cases.
+ List<JumpTarget> continueTargets = <JumpTarget>[];
+ List<ast.Node> switchCases = node.cases.nodes.toList();
+ for (ast.SwitchCase switchCase in switchCases) {
for (ast.Node labelOrCase in switchCase.labelsAndCases) {
if (labelOrCase is ast.Label) {
LabelDefinition definition = elements.getLabelDefinition(labelOrCase);
if (definition != null && definition.isContinueTarget) {
- return giveup(node, "continue to a labeled switch case");
+ continueTargets.add(definition.target);
}
}
}
}
- // Each switch case contains a list of interleaved labels and expressions
- // and a non-empty body. We can ignore the labels because they are not
- // jump targets.
- List<SwitchCaseInfo> cases = <SwitchCaseInfo>[];
- SwitchCaseInfo defaultCase;
- for (ast.SwitchCase switchCase in node.cases) {
- SwitchCaseInfo caseInfo =
- new SwitchCaseInfo(subbuildSequence(switchCase.statements));
- if (switchCase.isDefaultCase) {
- defaultCase = caseInfo;
- } else {
- cases.add(caseInfo);
- for (ast.Node labelOrCase in switchCase.labelsAndCases) {
- if (labelOrCase is ast.CaseMatch) {
- ir.Primitive constant = translateConstant(labelOrCase.expression);
- caseInfo.addConstant(constant);
- }
- }
- }
+ // If any cases are continue targets, use an anonymous local value to
+ // implement a state machine. The initial value is -1.
+ ir.Primitive initial;
+ int stateIndex;
+ if (continueTargets.isNotEmpty) {
+ initial = irBuilder.buildIntegerConstant(-1);
+ stateIndex = irBuilder.environment.length;
+ irBuilder.environment.extend(null, initial);
}
+
+ // Use a simple switch for the non-recursive cases. A break will go to the
+ // join-point after the switch. A continue to a labeled case will assign
+ // to the state variable and go to the join-point.
ir.Primitive value = visit(node.expression);
- JumpTarget target = elements.getTargetDefinition(node);
- Element error = helpers.fallThroughError;
- irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error,
- sourceInformationBuilder.buildGeneric(node));
+ JumpCollector join = new ForwardJumpCollector(irBuilder.environment,
+ target: elements.getTargetDefinition(node));
+ irBuilder.state.breakCollectors.add(join);
+ for (int i = 0; i < continueTargets.length; ++i) {
+ // The state value is i, the case's position in the list of recursive
+ // cases.
+ irBuilder.state.continueCollectors.add(new GotoJumpCollector(
+ continueTargets[i], stateIndex, i, join));
+ }
+
+ // For each non-default case use a pair of functions, one to translate the
+ // condition and one to translate the body. For the default case use a
+ // function to translate the body. Use continueTargetIterator as a pointer
+ // to the next recursive case.
+ Iterator<JumpTarget> continueTargetIterator = continueTargets.iterator;
+ continueTargetIterator.moveNext();
+ List<SwitchCaseInfo> cases = <SwitchCaseInfo>[];
+ SubbuildFunction buildDefaultBody;
+ for (ast.SwitchCase switchCase in switchCases) {
+ JumpTarget nextContinueTarget = continueTargetIterator.current;
+ if (switchCase.isDefaultCase) {
+ if (nextContinueTarget != null &&
+ switchCase == nextContinueTarget.statement) {
+ // In this simple switch, recursive cases are as if they immediately
+ // continued to themselves.
+ buildDefaultBody = nested(() {
+ irBuilder.buildContinue(nextContinueTarget);
+ });
+ continueTargetIterator.moveNext();
+ } else {
+ // Non-recursive cases consist of the translation of the body.
+ // For the default case, there is implicitly a break if control
+ // flow reaches the end.
+ buildDefaultBody = nested(() {
+ irBuilder.buildSequence(switchCase.statements, visit);
+ if (irBuilder.isOpen) irBuilder.jumpTo(join);
+ });
+ }
+ continue;
+ }
+
+ ir.Primitive buildCondition(IrBuilder builder) {
+ // There can be multiple cases sharing the same body, because empty
+ // cases are allowed to fall through to the next one. Each case is
+ // a comparison, build a short-circuited disjunction of all of them.
+ return withBuilder(builder, () {
+ ir.Primitive condition;
+ for (ast.Node labelOrCase in switchCase.labelsAndCases) {
+ if (labelOrCase is ast.CaseMatch) {
+ ir.Primitive buildComparison() {
+ ir.Primitive constant =
+ translateConstant(labelOrCase.expression);
+ return irBuilder.buildIdentical(value, constant);
+ }
+
+ if (condition == null) {
+ condition = buildComparison();
+ } else {
+ condition = irBuilder.buildLogicalOperator(condition,
+ nested(buildComparison), isLazyOr: true);
+ }
+ }
+ }
+ return condition;
+ });
+ }
+
+ SubbuildFunction buildBody;
+ if (nextContinueTarget != null &&
+ switchCase == nextContinueTarget.statement) {
+ // Recursive cases are as if they immediately continued to themselves.
+ buildBody = nested(() {
+ irBuilder.buildContinue(nextContinueTarget);
+ });
+ continueTargetIterator.moveNext();
+ } else {
+ // Non-recursive cases consist of the translation of the body. It is a
+ // runtime error if control-flow reaches the end of the body of any but
+ // the last case.
+ buildBody = (IrBuilder builder) {
+ withBuilder(builder, () {
+ irBuilder.buildSequence(switchCase.statements, visit);
+ if (irBuilder.isOpen) {
+ if (switchCase == switchCases.last) {
+ irBuilder.jumpTo(join);
+ } else {
+ Element error = helpers.fallThroughError;
+ ir.Primitive exception = irBuilder.buildInvokeStatic(
+ error,
+ new Selector.fromElement(error),
+ <ir.Primitive>[],
+ sourceInformationBuilder.buildGeneric(node));
+ irBuilder.buildThrow(exception);
+ }
+ }
+ });
+ return null;
+ };
+ }
+
+ cases.add(new SwitchCaseInfo(buildCondition, buildBody));
+ }
+
+ irBuilder.buildSimpleSwitch(join, cases, buildDefaultBody);
+ irBuilder.state.breakCollectors.removeLast();
+ irBuilder.state.continueCollectors.length -= continueTargets.length;
+ if (continueTargets.isEmpty) return;
+
+ // If there were recursive cases build a while loop whose body is a
+ // switch containing (only) the recursive cases. The condition is
+ // 'state != initialValue' so the loop is not taken when the state variable
+ // has not been assigned.
+ //
+ // 'loop' is the join-point of the exits from the inner switch which will
+ // perform another iteration of the loop. 'exit' is the join-point of the
+ // breaks from the switch, outside the loop.
+ JumpCollector loop = new ForwardJumpCollector(irBuilder.environment);
+ JumpCollector exit = new ForwardJumpCollector(irBuilder.environment,
+ target: elements.getTargetDefinition(node));
+ irBuilder.state.breakCollectors.add(exit);
+ for (int i = 0; i < continueTargets.length; ++i) {
+ irBuilder.state.continueCollectors.add(new GotoJumpCollector(
+ continueTargets[i], stateIndex, i, loop));
+ }
+ cases.clear();
+ for (int i = 0; i < continueTargets.length; ++i) {
+ // The conditions compare to the recursive case index.
+ ir.Primitive buildCondition(IrBuilder builder) {
+ ir.Primitive constant = builder.buildIntegerConstant(i);
+ return builder.buildIdentical(
+ builder.environment.index2value[stateIndex], constant);
+ }
+
+ ir.Primitive buildBody(IrBuilder builder) {
+ withBuilder(builder, () {
+ ast.SwitchCase switchCase = continueTargets[i].statement;
+ irBuilder.buildSequence(switchCase.statements, visit);
+ if (irBuilder.isOpen) {
+ if (switchCase == switchCases.last) {
+ irBuilder.jumpTo(exit);
+ } else {
+ Element error = helpers.fallThroughError;
+ ir.Primitive exception = irBuilder.buildInvokeStatic(
+ error,
+ new Selector.fromElement(error),
+ <ir.Primitive>[],
+ sourceInformationBuilder.buildGeneric(node));
+ irBuilder.buildThrow(exception);
+ }
+ }
+ });
+ return null;
+ }
+
+ cases.add(new SwitchCaseInfo(buildCondition, buildBody));
+ }
+
+ // A loop with a simple switch in the body.
+ IrBuilder whileBuilder = irBuilder.makeDelimitedBuilder();
+ whileBuilder.buildWhile(
+ buildCondition: (IrBuilder builder) {
+ ir.Primitive condition = builder.buildIdentical(
+ builder.environment.index2value[stateIndex], initial);
+ return builder.buildNegation(condition);
+ },
+ buildBody: (IrBuilder builder) {
+ builder.buildSimpleSwitch(loop, cases, null);
+ });
+ // Jump to the exit continuation. This jump is the body of the loop exit
+ // continuation, so the loop exit continuation can be eta-reduced. The
+ // jump is here for simplicity because `buildWhile` does not expose the
+ // loop's exit continuation directly and has already emitted all jumps
+ // to it anyway.
+ whileBuilder.jumpTo(exit);
+ irBuilder.add(new ir.LetCont(exit.continuation, whileBuilder.root));
+ irBuilder.environment = exit.environment;
+ irBuilder.environment.discard(1); // Discard the state variable.
+ irBuilder.state.breakCollectors.removeLast();
+ irBuilder.state.continueCollectors.length -= continueTargets.length;
}
visitTryStatement(ast.TryStatement node) {
@@ -1325,8 +1601,25 @@
}
List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
InterfaceType type = elements.getType(node);
- return irBuilder.buildListLiteral(type, values,
- allocationSiteType: getAllocationSiteType(node));
+ TypeMask allocationSiteType = getAllocationSiteType(node);
+ // TODO(sra): In checked mode, the elements must be checked as though
+ // operator[]= is called.
+ ir.Primitive list = irBuilder.buildListLiteral(type, values,
+ allocationSiteType: allocationSiteType);
+ if (type.treatAsRaw) return list;
+ // Call JSArray<E>.typed(allocation) to install the reified type.
+ ConstructorElement constructor = helpers.jsArrayTypedConstructor;
+ ir.Primitive tagged = irBuilder.buildConstructorInvocation(
+ constructor.effectiveTarget,
+ CallStructure.ONE_ARG,
+ constructor.computeEffectiveTargetType(type),
+ <ir.Primitive>[list],
+ sourceInformationBuilder.buildNew(node));
+
+ if (allocationSiteType == null) return tagged;
+
+ return irBuilder.addPrimitive(
+ new ir.Refinement(tagged, allocationSiteType));
}
ir.Primitive visitLiteralMap(ast.LiteralMap node) {
@@ -1334,12 +1627,48 @@
if (node.isConst) {
return translateConstant(node);
}
+
InterfaceType type = elements.getType(node);
- List<ir.LiteralMapEntry> entries =
- node.entries.nodes.mapToList((ast.LiteralMapEntry e) {
- return new ir.LiteralMapEntry(visit(e.key), visit(e.value));
- });
- return irBuilder.addPrimitive(new ir.LiteralMap(type, entries));
+
+ if (node.entries.nodes.isEmpty) {
+ if (type.treatAsRaw) {
+ return irBuilder.buildStaticFunctionInvocation(
+ helpers.mapLiteralUntypedEmptyMaker,
+ <ir.Primitive>[],
+ sourceInformation: sourceInformationBuilder.buildNew(node));
+ } else {
+ ConstructorElement constructor = helpers.mapLiteralConstructorEmpty;
+ return irBuilder.buildConstructorInvocation(
+ constructor.effectiveTarget,
+ CallStructure.NO_ARGS,
+ constructor.computeEffectiveTargetType(type),
+ <ir.Primitive>[],
+ sourceInformationBuilder.buildNew(node));
+ }
+ }
+
+ List<ir.Primitive> keysAndValues = <ir.Primitive>[];
+ for (ast.LiteralMapEntry entry in node.entries.nodes.toList()) {
+ keysAndValues.add(visit(entry.key));
+ keysAndValues.add(visit(entry.value));
+ }
+ ir.Primitive keysAndValuesList =
+ irBuilder.buildListLiteral(null, keysAndValues);
+
+ if (type.treatAsRaw) {
+ return irBuilder.buildStaticFunctionInvocation(
+ helpers.mapLiteralUntypedMaker,
+ <ir.Primitive>[keysAndValuesList],
+ sourceInformation: sourceInformationBuilder.buildNew(node));
+ } else {
+ ConstructorElement constructor = helpers.mapLiteralConstructor;
+ return irBuilder.buildConstructorInvocation(
+ constructor.effectiveTarget,
+ CallStructure.ONE_ARG,
+ constructor.computeEffectiveTargetType(type),
+ <ir.Primitive>[keysAndValuesList],
+ sourceInformationBuilder.buildNew(node));
+ }
}
ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) {
@@ -1869,7 +2198,10 @@
List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
// Use default values from the effective target, not the immediate target.
- ConstructorElement target = constructor.effectiveTarget;
+ ConstructorElement target = constructor.implementation;
+ while (target.isRedirectingFactory && !target.isCyclicRedirection) {
+ target = target.effectiveTarget.implementation;
+ }
callStructure = normalizeStaticArguments(callStructure, target, arguments);
TypeMask allocationSiteType;
@@ -1880,10 +2212,11 @@
Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
allocationSiteType = getAllocationSiteType(send);
}
+ ConstructorElement constructorImplementation = constructor.implementation;
return irBuilder.buildConstructorInvocation(
target,
callStructure,
- constructor.computeEffectiveTargetType(type),
+ constructorImplementation.computeEffectiveTargetType(type),
arguments,
sourceInformationBuilder.buildNew(node),
allocationSiteType: allocationSiteType);
@@ -2900,7 +3233,7 @@
return irBuilder.buildForeignCode(
js.js.parseForeignJS(backend.namer.staticStateHolder),
const <ir.Primitive>[],
- NativeBehavior.PURE);
+ NativeBehavior.DEPENDS_OTHER);
case 'JS_SET_STATIC_STATE':
validateArgumentCount(exactly: 1);
@@ -2910,7 +3243,7 @@
return irBuilder.buildForeignCode(
js.js.parseForeignJS("$isolateName = #"),
<ir.Primitive>[value],
- NativeBehavior.PURE);
+ NativeBehavior.CHANGES_OTHER);
case 'JS_CALL_IN_ISOLATE':
validateArgumentCount(exactly: 2);
@@ -3544,6 +3877,14 @@
return TypeMaskFactory.fromNativeBehavior(behavior, _compiler);
}
+ bool isArrayType(TypeMask type) {
+ return type.satisfies(_backend.helpers.jsArrayClass, _compiler.world);
+ }
+
+ TypeMask getTypeMaskForNativeFunction(FunctionElement function) {
+ return _compiler.typesTask.getGuaranteedReturnTypeOfElement(function);
+ }
+
FieldElement locateSingleField(Selector selector, TypeMask type) {
return _compiler.world.locateSingleField(selector, type);
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 49c8a6b..e73dd84 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -5,6 +5,7 @@
import 'dart:collection';
import 'cps_fragment.dart' show CpsFragment;
+import 'cps_ir_nodes_sexpr.dart';
import '../constants/values.dart' as values;
import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
import '../elements/elements.dart';
@@ -39,6 +40,37 @@
///
/// All constructors call this method to initialize parent pointers.
void setParentPointers();
+
+ /// Returns the SExpression for the subtree rooted at this node.
+ ///
+ /// [annotations] maps strings to nodes and/or nodes to values that will be
+ /// converted to strings. Each binding causes the annotation to appear on the
+ /// given node.
+ ///
+ /// For example, the following could be used to diagnose a problem with nodes
+ /// not appearing in an environment map:
+ ///
+ /// if (environment[node] == null)
+ /// root.debugPrint({
+ /// 'currentNode': node,
+ /// 'caller': someContinuation
+ /// });
+ /// throw 'Node was not in environment';
+ /// }
+ ///
+ /// If two strings map to the same node, it will be given both annotations.
+ ///
+ /// Avoid using nodes as keys if there is a chance that two keys are the
+ /// same node.
+ String debugString([Map annotations]) {
+ return new SExpressionStringifier()
+ .withAnnotations(annotations).visit(this);
+ }
+
+ /// Prints the result of [debugString].
+ void debugPrint([Map annotations]) {
+ print(debugString(annotations));
+ }
}
/// Expressions can be evaluated, and may diverge, throw, and/or have
@@ -195,9 +227,9 @@
}
}
-class EffectiveUseIterable extends IterableBase<Reference<Primitive>> {
+class RefinedUseIterable extends IterableBase<Reference<Primitive>> {
Primitive primitive;
- EffectiveUseIterable(this.primitive);
+ RefinedUseIterable(this.primitive);
EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive);
}
@@ -238,6 +270,9 @@
// TODO(asgerf): Also do this for [TypeCast]?
Primitive get effectiveDefinition => this;
+ /// Like [effectiveDefinition] but only unfolds [Refinement] nodes.
+ Primitive get unrefined => this;
+
/// True if the two primitives are (refinements of) the same value.
bool sameValue(Primitive other) {
return effectiveDefinition == other.effectiveDefinition;
@@ -252,15 +287,15 @@
/// - References to this primitive created during iteration will not be seen.
/// - References to a refinement of this primitive may not be created during
/// iteration.
- EffectiveUseIterable get effectiveUses => new EffectiveUseIterable(this);
+ RefinedUseIterable get refinedUses => new RefinedUseIterable(this);
- bool get hasMultipleEffectiveUses {
- Iterator it = effectiveUses.iterator;
+ bool get hasMultipleRefinedUses {
+ Iterator it = refinedUses.iterator;
return it.moveNext() && it.moveNext();
}
- bool get hasNoEffectiveUses {
- return effectiveUses.isEmpty;
+ bool get hasNoRefinedUses {
+ return refinedUses.isEmpty;
}
/// Unlinks all references contained in this node.
@@ -734,6 +769,8 @@
Primitive get effectiveDefinition => value.definition.effectiveDefinition;
+ Primitive get unrefined => value.definition.unrefined;
+
void setParentPointers() {
value.parent = this;
}
@@ -1446,15 +1483,17 @@
/// May be `null` to indicate that no type information is needed because the
/// compiler determined that the type information for instances of this class
/// is not needed at runtime.
- final List<Reference<Primitive>> typeInformation;
+ final Reference<Primitive> typeInformation;
final SourceInformation sourceInformation;
CreateInstance(this.classElement, List<Primitive> arguments,
- List<Primitive> typeInformation,
+ Primitive typeInformation,
this.sourceInformation)
: this.arguments = _referenceList(arguments),
- this.typeInformation = _referenceList(typeInformation);
+ this.typeInformation = typeInformation == null
+ ? null
+ : new Reference<Primitive>(typeInformation);
accept(Visitor visitor) => visitor.visitCreateInstance(this);
@@ -1466,7 +1505,7 @@
void setParentPointers() {
_setParentsOnList(arguments, this);
- if (typeInformation != null) _setParentsOnList(typeInformation, this);
+ if (typeInformation != null) typeInformation.parent = this;
}
}
@@ -1529,12 +1568,12 @@
class ForeignCode extends UnsafePrimitive {
final js.Template codeTemplate;
- final TypeMask type;
+ final TypeMask storedType;
final List<Reference<Primitive>> arguments;
final native.NativeBehavior nativeBehavior;
final FunctionElement dependency;
- ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments,
+ ForeignCode(this.codeTemplate, this.storedType, List<Primitive> arguments,
this.nativeBehavior, {this.dependency})
: this.arguments = _referenceList(arguments);
@@ -1596,35 +1635,6 @@
}
}
-class LiteralMapEntry {
- final Reference<Primitive> key;
- final Reference<Primitive> value;
-
- LiteralMapEntry(Primitive key, Primitive value)
- : this.key = new Reference<Primitive>(key),
- this.value = new Reference<Primitive>(value);
-}
-
-class LiteralMap extends Primitive {
- final InterfaceType dartType;
- final List<LiteralMapEntry> entries;
-
- LiteralMap(this.dartType, this.entries);
-
- accept(Visitor visitor) => visitor.visitLiteralMap(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- for (LiteralMapEntry entry in entries) {
- entry.key.parent = this;
- entry.value.parent = this;
- }
- }
-}
-
class Parameter extends Primitive {
Parameter(Entity hint) {
super.hint = hint;
@@ -1651,8 +1661,25 @@
// A continuation is recursive if it has any recursive invocations.
bool isRecursive;
+ /// True if this is the return continuation. The return continuation is bound
+ /// by [FunctionDefinition].
bool get isReturnContinuation => body == null;
+ /// True if this is a branch continuation. Branch continuations are bound
+ /// by [LetCont] and can only have one use.
+ bool get isBranchContinuation => firstRef?.parent is Branch;
+
+ /// True if this is the exception handler bound by a [LetHandler].
+ bool get isHandlerContinuation => parent is LetHandler;
+
+ /// True if this is a non-return continuation that can be targeted by
+ /// [InvokeContinuation].
+ bool get isJoinContinuation {
+ return body != null &&
+ parent is! LetHandler &&
+ (firstRef == null || firstRef.parent is InvokeContinuation);
+ }
+
Continuation(this.parameters, {this.isRecursive: false});
Continuation.retrn()
@@ -1773,21 +1800,74 @@
}
}
-/// Representation of a closed type (that is, a type without type variables).
+enum TypeExpressionKind {
+ COMPLETE,
+ INSTANCE
+}
+
+/// Constructs a representation of a closed or ground-term type (that is, a type
+/// without type variables).
///
-/// The resulting value is constructed from [dartType] by replacing the type
+/// There are two forms:
+///
+/// - COMPLETE: A complete form that is self contained, used for the values of
+/// type parameters and non-raw is-checks.
+///
+/// - INSTANCE: A headless flat form for representing the sequence of values of
+/// the type parameters of an instance of a generic type.
+///
+/// The COMPLETE form value is constructed from [dartType] by replacing the type
/// variables with consecutive values from [arguments], in the order generated
/// by [DartType.forEachTypeVariable]. The type variables in [dartType] are
/// treated as 'holes' in the term, which means that it must be ensured at
/// construction, that duplicate occurences of a type variable in [dartType]
/// are assigned the same value.
+///
+/// The INSTANCE form is constructed as a list of [arguments]. This is the same
+/// as the COMPLETE form for the 'thisType', except the root term's type is
+/// missing; this is implicit as the raw type of instance. The [dartType] of
+/// the INSTANCE form must be the thisType of some class.
+///
+/// While we would like to remove the constrains on the INSTANCE form, we can
+/// get by with a tree of TypeExpressions. Consider:
+///
+/// class Foo<T> {
+/// ... new Set<List<T>>()
+/// }
+/// class Set<E1> {
+/// factory Set() => new _LinkedHashSet<E1>();
+/// }
+/// class List<E2> { ... }
+/// class _LinkedHashSet<E3> { ... }
+///
+/// After inlining the factory constructor for `Set<E1>`, the CreateInstance
+/// should have type `_LinkedHashSet<List<T>>` and the TypeExpression should be
+/// a tree:
+///
+/// CreateInstance(dartType: _LinkedHashSet<List<T>>,
+/// [], // No arguments
+/// TypeExpression(INSTANCE,
+/// dartType: _LinkedHashSet<E3>, // _LinkedHashSet's thisType
+/// TypeExpression(COMPLETE, // E3 = List<T>
+/// dartType: List<E2>,
+/// ReadTypeVariable(this, T)))) // E2 = T
+//
+// TODO(sra): The INSTANCE form requires the actual instance for full
+// interpretation. I want to move to a representation where the INSTANCE form is
+// also a complete form (possibly the same).
class TypeExpression extends Primitive {
+ final TypeExpressionKind kind;
final DartType dartType;
final List<Reference<Primitive>> arguments;
- TypeExpression(this.dartType,
- [List<Primitive> arguments = const <Primitive>[]])
- : this.arguments = _referenceList(arguments);
+ TypeExpression(this.kind,
+ this.dartType,
+ List<Primitive> arguments)
+ : this.arguments = _referenceList(arguments) {
+ assert(kind == TypeExpressionKind.INSTANCE
+ ? dartType == (dartType.element as ClassElement).thisType
+ : true);
+ }
@override
accept(Visitor visitor) {
@@ -1801,6 +1881,13 @@
void setParentPointers() {
_setParentsOnList(arguments, this);
}
+
+ String get kindAsString {
+ switch (kind) {
+ case TypeExpressionKind.COMPLETE: return 'COMPLETE';
+ case TypeExpressionKind.INSTANCE: return 'INSTANCE';
+ }
+ }
}
class Await extends UnsafePrimitive {
@@ -1965,7 +2052,6 @@
T visitAwait(Await node);
T visitYield(Yield node);
T visitLiteralList(LiteralList node);
- T visitLiteralMap(LiteralMap node);
T visitConstant(Constant node);
T visitGetMutable(GetMutable node);
T visitParameter(Parameter node);
@@ -2016,7 +2102,6 @@
processFunctionDefinition(node);
if (node.thisParameter != null) visit(node.thisParameter);
node.parameters.forEach(visit);
- visit(node.returnContinuation);
visit(node.body);
}
@@ -2147,15 +2232,6 @@
node.values.forEach(processReference);
}
- processLiteralMap(LiteralMap node) {}
- visitLiteralMap(LiteralMap node) {
- processLiteralMap(node);
- for (LiteralMapEntry entry in node.entries) {
- processReference(entry.key);
- processReference(entry.value);
- }
- }
-
processConstant(Constant node) {}
visitConstant(Constant node) {
processConstant(node);
@@ -2187,7 +2263,7 @@
visitCreateInstance(CreateInstance node) {
processCreateInstance(node);
node.arguments.forEach(processReference);
- node.typeInformation.forEach(processReference);
+ if (node.typeInformation != null) processReference(node.typeInformation);
}
processSetField(SetField node) {}
@@ -2377,7 +2453,6 @@
processFunctionDefinition(node);
if (node.thisParameter != null) visit(node.thisParameter);
node.parameters.forEach(visit);
- visit(node.returnContinuation);
visit(node.body);
}
@@ -2574,13 +2649,6 @@
..allocationSiteType = node.allocationSiteType;
}
- Definition visitLiteralMap(LiteralMap node) {
- List<LiteralMapEntry> entries = node.entries.map((LiteralMapEntry entry) {
- return new LiteralMapEntry(getCopy(entry.key), getCopy(entry.value));
- }).toList();
- return new LiteralMap(node.dartType, entries);
- }
-
Definition visitConstant(Constant node) {
return new Constant(node.value, sourceInformation: node.sourceInformation);
}
@@ -2607,8 +2675,10 @@
}
Definition visitCreateInstance(CreateInstance node) {
- return new CreateInstance(node.classElement, getList(node.arguments),
- getList(node.typeInformation),
+ return new CreateInstance(
+ node.classElement,
+ getList(node.arguments),
+ node.typeInformation == null ? null : getCopy(node.typeInformation),
node.sourceInformation);
}
@@ -2630,7 +2700,8 @@
}
Definition visitTypeExpression(TypeExpression node) {
- return new TypeExpression(node.dartType, getList(node.arguments));
+ return new TypeExpression(
+ node.kind, node.dartType, getList(node.arguments));
}
Definition visitCreateInvocationMirror(CreateInvocationMirror node) {
@@ -2695,7 +2766,7 @@
}
Definition visitForeignCode(ForeignCode node) {
- return new ForeignCode(node.codeTemplate, node.type,
+ return new ForeignCode(node.codeTemplate, node.storedType,
getList(node.arguments),
node.nativeBehavior,
dependency: node.dependency);
@@ -2723,6 +2794,7 @@
assert(_current != null);
InteriorExpression interior = _current;
interior.body = body;
+ body.parent = interior;
}
_current = body;
}
@@ -2740,7 +2812,9 @@
Expression savedFirst = _first;
_first = _current = null;
_processBlock(cont.body);
- _copies[cont].body = _first;
+ Continuation contCopy = _copies[cont];
+ contCopy.body = _first;
+ _first.parent = contCopy;
_first = savedFirst;
_current = null;
});
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index bde9b0e..37836bf 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -29,7 +29,52 @@
}
}
+ /// Create a stringifier with an extra layer of decoration.
+ SExpressionStringifier withDecorator(Decorator subDecorator) {
+ return new SExpressionStringifier((node, String s) {
+ return subDecorator(node, decorator(node, s));
+ });
+ }
+
+ /// Create a stringifier that displays type information.
+ SExpressionStringifier withTypes() => withDecorator(typeDecorator);
+
+ /// Creates a stringifier that adds annotations from a map;
+ /// see [Node.debugString].
+ SExpressionStringifier withAnnotations(Map annotations) {
+ return withDecorator(decoratorFromMap(annotations));
+ }
+
+ static Decorator decoratorFromMap(Map annotations) {
+ Map<Node, String> nodeMap = {};
+ for (var key in annotations.keys) {
+ if (key is Node) {
+ nodeMap[key] = '${annotations[key]}';
+ } else {
+ String text = key;
+ Node node = annotations[key];
+ if (nodeMap.containsKey(node)) {
+ // In case two annotations belong to the same node,
+ // put both annotations on that node.
+ nodeMap[node] += ' $text';
+ } else {
+ nodeMap[node] = text;
+ }
+ }
+ }
+ return (node, string) {
+ String text = nodeMap[node];
+ if (text != null) return '***$string*** $text';
+ return string;
+ };
+ }
+
+ static String typeDecorator(node, String string) {
+ return node is Variable ? '$string:${node.type}' : string;
+ }
+
String access(Reference<Definition> r) {
+ if (r == null) return '**** NULL ****';
return decorator(r, namer.getName(r.definition));
}
@@ -71,24 +116,42 @@
String visitLetPrim(LetPrim node) {
String name = newValueName(node.primitive);
String value = visit(node.primitive);
+ String bindings = '($name $value)';
+ String skip = ' ' * '(LetPrim ('.length;
+ while (node.body is LetPrim) {
+ node = node.body;
+ name = newValueName(node.primitive);
+ value = visit(node.primitive);
+ String binding = decorator(node, '($name $value)');
+ bindings += '\n${indentation}$skip$binding';
+ }
String body = indentBlock(() => visit(node.body));
- return '$indentation(LetPrim ($name $value)\n$body)';
+ return '$indentation(LetPrim ($bindings)\n$body)';
+ }
+
+ bool isBranchTarget(Continuation cont) {
+ return cont.hasExactlyOneUse && cont.firstRef.parent is Branch;
}
String visitLetCont(LetCont node) {
String conts;
bool first = true;
+ String skip = ' ' * '(LetCont ('.length;
for (Continuation continuation in node.continuations) {
+ // Branch continuations will be printed at their use site.
+ if (isBranchTarget(continuation)) continue;
if (first) {
first = false;
conts = visit(continuation);
} else {
// Each subsequent line is indented additional spaces to align it
// with the previous continuation.
- String indent = '$indentation${' ' * '(LetCont ('.length}';
- conts = '$conts\n$indent${visit(continuation)}';
+ conts += '\n${indentation}$skip${visit(continuation)}';
}
}
+ // If there were no continuations printed, just print the body.
+ if (first) return visit(node.body);
+
String body = indentBlock(() => visit(node.body));
return '$indentation(LetCont ($conts)\n$body)';
}
@@ -175,7 +238,9 @@
String visitInvokeContinuation(InvokeContinuation node) {
String name = access(node.continuation);
if (node.isRecursive) name = 'rec $name';
- String args = node.arguments.map(access).join(' ');
+ String args = node.arguments == null
+ ? '**** NULL ****'
+ : node.arguments.map(access).join(' ');
String escaping = node.isEscapingTry ? ' escape' : '';
return '$indentation(InvokeContinuation $name ($args)$escaping)';
}
@@ -191,10 +256,14 @@
String visitBranch(Branch node) {
String condition = access(node.condition);
- String trueCont = access(node.trueContinuation);
- String falseCont = access(node.falseContinuation);
+ assert(isBranchTarget(node.trueContinuation.definition));
+ assert(isBranchTarget(node.falseContinuation.definition));
+ String trueCont =
+ indentBlock(() => visit(node.trueContinuation.definition));
+ String falseCont =
+ indentBlock(() => visit(node.falseContinuation.definition));
String strict = node.isStrictCheck ? 'Strict' : 'NonStrict';
- return '$indentation(Branch $condition $trueCont $falseCont $strict)';
+ return '$indentation(Branch $strict $condition\n$trueCont\n$falseCont)';
}
String visitUnreachable(Unreachable node) {
@@ -207,11 +276,17 @@
}
String visitContinuation(Continuation node) {
+ if (isBranchTarget(node)) {
+ assert(node.parameters.isEmpty);
+ assert(!node.isRecursive);
+ return indentBlock(() => visit(node.body));
+ }
String name = newContinuationName(node);
if (node.isRecursive) name = 'rec $name';
- // TODO(karlklose): this should be changed to `.map(visit).join(' ')` and
- // should recurse to [visit]. Currently we can't do that, because the
- // unstringifier_test produces [LetConts] with dummy arguments on them.
+ // TODO(karlklose): this should be changed to `.map(visit).join(' ')`
+ // and should recurse to [visit]. Currently we can't do that, because
+ // the unstringifier_test produces [LetConts] with dummy arguments on
+ // them.
String parameters = node.parameters
.map((p) => '${decorator(p, newValueName(p))}')
.join(' ');
@@ -250,12 +325,6 @@
return '(LiteralList ($values))';
}
- String visitLiteralMap(LiteralMap node) {
- String keys = node.entries.map((e) => access(e.key)).join(' ');
- String values = node.entries.map((e) => access(e.value)).join(' ');
- return '(LiteralMap ($keys) ($values))';
- }
-
String visitSetField(SetField node) {
String object = access(node.object);
String field = node.field.name;
@@ -292,7 +361,7 @@
String visitCreateInstance(CreateInstance node) {
String className = node.classElement.name;
String arguments = node.arguments.map(access).join(' ');
- String typeInformation = node.typeInformation.map(access).join(' ');
+ String typeInformation = optionalAccess(node.typeInformation);
return '(CreateInstance $className ($arguments) ($typeInformation))';
}
@@ -310,7 +379,7 @@
String visitTypeExpression(TypeExpression node) {
String args = node.arguments.map(access).join(' ');
- return '(TypeExpression ${node.dartType} ($args))';
+ return '(TypeExpression ${node.kindAsString} ${node.dartType} ($args))';
}
String visitCreateInvocationMirror(CreateInvocationMirror node) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index e732f3d..db1592d 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -29,7 +29,7 @@
builder.visit(node);
for (Block block in builder.entries) {
- printBlock(block, entryPointParameters: node.parameters);
+ printBlock(block, entryPoint: node);
}
for (Block block in builder.cont2block.values) {
printBlock(block);
@@ -63,9 +63,8 @@
return count;
}
- /// If [entryPointParameters] is given, this block is an entry point
- /// and [entryPointParameters] is the list of function parameters.
- printBlock(Block block, {List<cps_ir.Definition> entryPointParameters}) {
+ /// If [entryPoint] is given, this block is an entry point.
+ printBlock(Block block, {cps_ir.FunctionDefinition entryPoint}) {
tag("block", () {
printProperty("name", block.name);
printProperty("from_bci", -1);
@@ -84,9 +83,12 @@
String formatParameter(cps_ir.Parameter param) {
return '${names.name(param)} ${param.type}';
}
- if (entryPointParameters != null) {
- String params = entryPointParameters.map(formatParameter).join(', ');
- printStmt('x0', 'Entry ($params)');
+ if (entryPoint != null) {
+ String thisParam = entryPoint.thisParameter != null
+ ? formatParameter(entryPoint.thisParameter)
+ : 'no receiver';
+ String params = entryPoint.parameters.map(formatParameter).join(', ');
+ printStmt('x0', 'Entry ($thisParam) ($params)');
}
String params = block.parameters.map(formatParameter).join(', ');
printStmt('x0', 'Parameters ($params)');
@@ -192,16 +194,6 @@
return "LiteralList ($values)";
}
- visitLiteralMap(cps_ir.LiteralMap node) {
- List<String> entries = new List<String>();
- for (cps_ir.LiteralMapEntry entry in node.entries) {
- String key = formatReference(entry.key);
- String value = formatReference(entry.value);
- entries.add("$key: $value");
- }
- return "LiteralMap (${entries.join(', ')})";
- }
-
visitTypeCast(cps_ir.TypeCast node) {
String value = formatReference(node.value);
String args = node.typeArguments.map(formatReference).join(', ');
@@ -303,8 +295,7 @@
visitCreateInstance(cps_ir.CreateInstance node) {
String className = node.classElement.name;
String arguments = node.arguments.map(formatReference).join(', ');
- String typeInformation =
- node.typeInformation.map(formatReference).join(', ');
+ String typeInformation = formatReference(node.typeInformation);
return 'CreateInstance $className ($arguments) <$typeInformation>';
}
@@ -328,7 +319,7 @@
}
visitTypeExpression(cps_ir.TypeExpression node) {
- return "TypeExpression ${node.dartType} "
+ return "TypeExpression ${node.kindAsString} ${node.dartType}"
"${node.arguments.map(formatReference).join(', ')}";
}
@@ -578,10 +569,6 @@
unexpectedNode(node);
}
- visitLiteralMap(cps_ir.LiteralMap node) {
- unexpectedNode(node);
- }
-
visitConstant(cps_ir.Constant node) {
unexpectedNode(node);
}
diff --git a/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart b/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
new file mode 100644
index 0000000..7b1d294
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library dart2js.cps_ir.duplicate_branch;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart';
+import 'cps_fragment.dart';
+
+/// Removes branches that branch on the same value as a previously seen branch.
+/// For example:
+///
+/// if (x == y) {
+/// if (x == y) TRUE else FALSE
+/// }
+///
+/// ==> ([GVN] pass merges identical expressions)
+///
+/// var b = (x == y)
+/// if (b) {
+/// if (b) TRUE else FALSE
+/// }
+///
+/// ==> (this pass removes the duplicate branch)
+///
+/// var b = (x == y)
+/// if (b) {
+/// TRUE
+/// }
+//
+// TODO(asgerf): A kind of redundant join can arise where a branching condition
+// is known to be true/false on all but one predecessor for a branch. We could
+// try to reduce those.
+//
+// TODO(asgerf): Could be more precise if GVN shared expressions that are not
+// in direct scope of one another, e.g. by using phis pass the shared value.
+//
+class DuplicateBranchEliminator extends TrampolineRecursiveVisitor
+ implements Pass {
+ String get passName => 'Duplicate branch elimination';
+
+ static const int TRUE = 1 << 0;
+ static const int OTHER_TRUTHY = 1 << 1;
+ static const int FALSE = 1 << 2;
+ static const int OTHER_FALSY = 1 << 3;
+
+ static const int TRUTHY = TRUE | OTHER_TRUTHY;
+ static const int FALSY = FALSE | OTHER_FALSY;
+ static const int ANY = TRUTHY | FALSY;
+
+ /// The possible values of the given primitive (or ANY if absent) at the
+ /// current traversal position.
+ Map<Primitive, int> valueOf = <Primitive, int>{};
+
+ /// The possible values of each primitive at the entry to a continuation.
+ ///
+ /// Unreachable continuations are absent from the map.
+ final Map<Continuation, Map<Primitive, int>> valuesAt =
+ <Continuation, Map<Primitive, int>>{};
+
+ void rewrite(FunctionDefinition node) {
+ visit(node);
+ }
+
+ Map<Primitive, int> copy(Map<Primitive, int> map) {
+ return new Map<Primitive, int>.from(map);
+ }
+
+ Expression traverseLetHandler(LetHandler node) {
+ valuesAt[node.handler] = copy(valueOf);
+ push(node.handler);
+ return node.body;
+ }
+
+ Expression traverseContinuation(Continuation cont) {
+ valueOf = valuesAt[cont];
+ if (valueOf == null) {
+ // Do not go into unreachable code.
+ destroyAndReplace(cont.body, new Unreachable());
+ }
+ return cont.body;
+ }
+
+ void visitInvokeContinuation(InvokeContinuation node) {
+ Continuation cont = node.continuation.definition;
+ if (cont.isReturnContinuation) return;
+ if (node.isRecursive) return;
+ Map<Primitive, int> target = valuesAt[cont];
+ if (target == null) {
+ valuesAt[cont] = valueOf;
+ } else {
+ for (Primitive prim in target.keys) {
+ target[prim] |= valueOf[prim] ?? ANY;
+ }
+ }
+ }
+
+ visitBranch(Branch node) {
+ Primitive condition = node.condition.definition.effectiveDefinition;
+ Continuation trueCont = node.trueContinuation.definition;
+ Continuation falseCont = node.falseContinuation.definition;
+ if (condition.hasExactlyOneUse) {
+ // Handle common case specially. Do not add [condition] to the map if
+ // there are no other uses.
+ valuesAt[trueCont] = copy(valueOf);
+ valuesAt[falseCont] = valueOf;
+ return;
+ }
+ int values = valueOf[condition] ?? ANY;
+ int positiveValues = node.isStrictCheck ? TRUE : TRUTHY;
+ int negativeValues = (~positiveValues) & ANY;
+ if (values & positiveValues == 0) {
+ destroyAndReplace(node, new InvokeContinuation(falseCont, []));
+ valuesAt[falseCont] = valueOf;
+ } else if (values & negativeValues == 0) {
+ destroyAndReplace(node, new InvokeContinuation(trueCont, []));
+ valuesAt[trueCont] = valueOf;
+ } else {
+ valuesAt[trueCont] = copy(valueOf)..[condition] = values & positiveValues;
+ valuesAt[falseCont] = valueOf..[condition] = values & negativeValues;
+ }
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/finalize.dart b/pkg/compiler/lib/src/cps_ir/finalize.dart
index 1406a58..7e3b6e1 100644
--- a/pkg/compiler/lib/src/cps_ir/finalize.dart
+++ b/pkg/compiler/lib/src/cps_ir/finalize.dart
@@ -5,6 +5,7 @@
import 'optimizers.dart' show Pass;
import '../js_backend/js_backend.dart' show JavaScriptBackend;
import '../js_backend/backend_helpers.dart';
+import '../js/js.dart' as js;
/// A transformation pass that must run immediately before the tree IR builder.
///
@@ -78,4 +79,18 @@
node..witness.unlink()..witness = null;
}
}
+
+ void visitForeignCode(ForeignCode node) {
+ if (js.isIdentityTemplate(node.codeTemplate)) {
+ // The CPS builder replaces identity templates with refinements, except
+ // when the refined type is an array type. Some optimizations assume the
+ // type of an object is immutable, but the type of an array can change
+ // after allocation. After the finalize pass, this assumption is no
+ // longer needed, so we can replace the remaining idenitity templates.
+ Refinement refinement = new Refinement(
+ node.arguments.single.definition,
+ node.type)..type = node.type;
+ node.replaceWith(refinement);
+ }
+ }
}
diff --git a/pkg/compiler/lib/src/cps_ir/inline.dart b/pkg/compiler/lib/src/cps_ir/inline.dart
index cc046ee..554e93e 100644
--- a/pkg/compiler/lib/src/cps_ir/inline.dart
+++ b/pkg/compiler/lib/src/cps_ir/inline.dart
@@ -86,6 +86,9 @@
static const int ABSENT = -1;
static const int NO_INLINE = 0;
+ final Map<ExecutableElement, FunctionDefinition> unoptimized =
+ <ExecutableElement, FunctionDefinition>{};
+
final Map<ExecutableElement, List<CacheEntry>> map =
<ExecutableElement, List<CacheEntry>>{};
@@ -144,6 +147,29 @@
}
return ABSENT;
}
+
+ /// Cache the unoptimized CPS term for a function.
+ ///
+ /// The unoptimized term should not have any inlining-context-specific
+ /// optimizations applied to it. It will be used to compile the
+ /// non-specialized version of the function.
+ void putUnoptimized(ExecutableElement element, FunctionDefinition function) {
+ unoptimized.putIfAbsent(element, () => copier.copy(function));
+ }
+
+ /// Look up the unoptimized CPS term for a function.
+ ///
+ /// The unoptimized term will not have any inlining-context-specific
+ /// optimizations applied to it. It can be used to compile the
+ /// non-specialized version of the function.
+ FunctionDefinition getUnoptimized(ExecutableElement element) {
+ FunctionDefinition function = unoptimized[element];
+ if (function != null) {
+ function = copier.copy(function);
+ ParentVisitor.setParents(function);
+ }
+ return function;
+ }
}
class Inliner implements Pass {
@@ -323,7 +349,7 @@
outgoingNames.add(formal.name);
});
newCallStructure =
- new CallStructure(signature.parameterCount, outgoingNames);
+ new CallStructure(signature.parameterCount, outgoingNames);
} else {
signature.forEachOptionalParameter((ParameterElement formal) {
if (parameterIndex < parameters.length) {
@@ -372,6 +398,13 @@
return null;
}
+ // Don't inline methods that never return. They are usually helper functions
+ // that throw an exception.
+ if (invoke.type.isEmpty && !invoke.type.isNullable) {
+ // TODO(sra): It would be ok to inline if doing so was shrinking.
+ return null;
+ }
+
Reference<Primitive> dartReceiver = invoke.dartReceiverReference;
TypeMask abstractReceiver =
dartReceiver == null ? null : abstractType(dartReceiver);
@@ -434,9 +467,14 @@
// The argument count at the call site does not match the target's
// formal parameter count. Build the IR term for an adapter function
// body.
- function = buildAdapter(invoke, target);
+ if (backend.isNative(target)) {
+ // TODO(25548): Generate correct adaptor for native methods.
+ return doNotInline();
+ } else {
+ function = buildAdapter(invoke, target);
+ }
} else {
- function = _inliner.functionCompiler.compileToCpsIr(target);
+ function = compileToCpsIr(target);
void setValue(Variable variable, Reference<Primitive> value) {
variable.type = value.definition.type;
}
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index 812b204..599476f 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -25,6 +25,7 @@
export 'inline.dart' show Inliner;
export 'eagerly_load_statics.dart' show EagerlyLoadStatics;
export 'loop_invariant_branch.dart' show LoopInvariantBranchMotion;
+export 'duplicate_branch.dart' show DuplicateBranchEliminator;
export 'parent_visitor.dart' show ParentVisitor;
/// An optimization pass over the CPS IR.
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
index 92f64ae..808c1c7 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -8,15 +8,15 @@
import 'optimizers.dart';
/// Eliminates redundant join points.
-///
+///
/// A redundant join point is a continuation that immediately branches
/// based on one of its parameters, and that parameter is a constant value
/// at every invocation. Each invocation is redirected to jump directly
/// to the branch target.
-///
+///
/// Internally in this pass, parameters are treated as names with lexical
/// scoping, and a given parameter "name" may be declared by more than
-/// one continuation. The reference chains for parameters are therefore
+/// one continuation. The reference chains for parameters are therefore
/// meaningless during this pass, until repaired by [AlphaRenamer] at
/// the end.
class RedundantJoinEliminator extends TrampolineRecursiveVisitor implements Pass {
@@ -113,11 +113,11 @@
return;
}
- // Lift any continuations bound inside branchCont so they are in scope at
+ // Lift any continuations bound inside branchCont so they are in scope at
// the call sites. When lifting, the parameters of branchCont fall out of
// scope, so they are added as parameters on each lifted continuation.
// Schematically:
- //
+ //
// (LetCont (branchCont (x1, x2, x3) =
// (LetCont (innerCont (y) = ...) in
// [... innerCont(y') ...]))
@@ -127,8 +127,8 @@
// (LetCont (innerCont (y, x1, x2, x3) = ...) in
// (LetCont (branchCont (x1, x2, x3) =
// [... innerCont(y', x1, x2, x3) ...])
- //
- // Parameter objects become shared between branchCont and the lifted
+ //
+ // Parameter objects become shared between branchCont and the lifted
// continuations. [AlphaRenamer] will clean up at the end of this pass.
LetCont outerLetCont = branchCont.parent;
while (branchCont.body is LetCont) {
@@ -202,13 +202,13 @@
/// Ensures parameter objects are not shared between different continuations,
/// akin to alpha-renaming variables so every variable is named uniquely.
/// For example:
-///
+///
/// LetCont (k1 x = (return x)) in
/// LetCont (k2 x = (InvokeContinuation k3 x)) in ...
-/// =>
+/// =>
/// LetCont (k1 x = (return x)) in
/// LetCont (k2 x' = (InvokeContinuation k3 x')) in ...
-///
+///
/// After lifting LetConts in the main pass above, parameter objects can have
/// multiple bindings. Each reference implicitly refers to the binding that
/// is currently in scope.
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index 7f16af9..f5d5423 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
@@ -61,10 +61,10 @@
/// Returns the unique definition of parameter i if it exists and null
/// otherwise. A definition is unique if it is the only value used to
/// invoke the continuation, excluding feedback.
- Definition uniqueDefinitionOf(int i) {
- Definition value = null;
+ Primitive uniqueDefinitionOf(int i) {
+ Primitive value = null;
for (InvokeContinuation invoke in invokes) {
- Definition def = invoke.arguments[i].definition;
+ Primitive def = invoke.arguments[i].definition.effectiveDefinition;
if (cont.parameters[i] == def) {
// Invocation param == param in LetCont (i.e. a recursive call).
@@ -104,7 +104,7 @@
int dst = 0;
for (int src = 0; src < cont.parameters.length; src++) {
// Is the current phi redundant?
- Definition uniqueDefinition = uniqueDefinitionOf(src);
+ Primitive uniqueDefinition = uniqueDefinitionOf(src);
if (uniqueDefinition == null || !safeForHandlers(uniqueDefinition)) {
// Reorganize parameters and arguments in case of deletions.
if (src != dst) {
@@ -117,7 +117,7 @@
continue;
}
- Definition oldDefinition = cont.parameters[src];
+ Primitive oldDefinition = cont.parameters[src];
// Add continuations of about-to-be modified invokes to worklist since
// we might introduce new optimization opportunities.
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index 16a1d15..42ae6cd 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -6,7 +6,6 @@
import 'cps_ir_nodes.dart';
import 'optimizers.dart';
-import 'cps_fragment.dart';
/**
* [ShrinkingReducer] applies shrinking reductions to CPS terms as described
@@ -15,26 +14,68 @@
class ShrinkingReducer extends Pass {
String get passName => 'Shrinking reductions';
- List<_ReductionTask> _worklist;
-
- static final _DeletedNode _DELETED = new _DeletedNode();
+ final List<_ReductionTask> _worklist = new List<_ReductionTask>();
/// Applies shrinking reductions to root, mutating root in the process.
@override
void rewrite(FunctionDefinition root) {
- _worklist = new List<_ReductionTask>();
_RedexVisitor redexVisitor = new _RedexVisitor(_worklist);
// Sweep over the term, collecting redexes into the worklist.
redexVisitor.visit(root);
- // Process the worklist.
+ _iterateWorklist();
+ }
+
+ void _iterateWorklist() {
while (_worklist.isNotEmpty) {
_ReductionTask task = _worklist.removeLast();
_processTask(task);
}
}
+ /// Call instead of [_iterateWorklist] to check at every step that no
+ /// redex was missed.
+ void _debugWorklist(FunctionDefinition root) {
+ while (_worklist.isNotEmpty) {
+ _ReductionTask task = _worklist.removeLast();
+ String irBefore = root.debugString({
+ task.node: '${task.kind} applied here'
+ });
+ _processTask(task);
+ Set seenRedexes = _worklist.where(isValidTask).toSet();
+ Set actualRedexes = (new _RedexVisitor([])..visit(root)).worklist.toSet();
+ if (!seenRedexes.containsAll(actualRedexes)) {
+ _ReductionTask missedTask =
+ actualRedexes.firstWhere((x) => !seenRedexes.contains(x));
+ print('\nBEFORE $task:\n');
+ print(irBefore);
+ print('\nAFTER $task:\n');
+ root.debugPrint({
+ missedTask.node: 'MISSED ${missedTask.kind}'
+ });
+ throw 'Missed $missedTask after processing $task';
+ }
+ }
+ }
+
+ bool isValidTask(_ReductionTask task) {
+ switch (task.kind) {
+ case _ReductionKind.DEAD_VAL:
+ return _isDeadVal(task.node);
+ case _ReductionKind.DEAD_CONT:
+ return _isDeadCont(task.node);
+ case _ReductionKind.BETA_CONT_LIN:
+ return _isBetaContLin(task.node);
+ case _ReductionKind.ETA_CONT:
+ return _isEtaCont(task.node);
+ case _ReductionKind.DEAD_PARAMETER:
+ return _isDeadParameter(task.node);
+ case _ReductionKind.BRANCH:
+ return _isBranchRedex(task.node);
+ }
+ }
+
/// Removes the given node from the CPS graph, replacing it with its body
/// and marking it as deleted. The node's parent must be a [[InteriorNode]].
void _removeNode(InteriorNode node) {
@@ -44,7 +85,14 @@
body.parent = parent;
parent.body = body;
- node.parent = _DELETED;
+ node.parent = null;
+
+ // The removed node could be the last node between a continuation and
+ // an InvokeContinuation in the body.
+ if (parent is Continuation) {
+ _checkEtaCont(parent);
+ _checkUselessBranchTarget(parent);
+ }
}
/// Remove a given continuation from the CPS graph. The LetCont itself is
@@ -56,12 +104,12 @@
} else {
parent.continuations.remove(cont);
}
- cont.parent = _DELETED;
+ cont.parent = null;
}
void _processTask(_ReductionTask task) {
// Skip tasks for deleted nodes.
- if (task.node.parent == _DELETED) {
+ if (task.node.parent == null) {
return;
}
@@ -81,6 +129,9 @@
case _ReductionKind.DEAD_PARAMETER:
_reduceDeadParameter(task);
break;
+ case _ReductionKind.BRANCH:
+ _reduceBranch(task);
+ break;
default:
assert(false);
}
@@ -89,15 +140,31 @@
/// Applies the dead-val reduction:
/// letprim x = V in E -> E (x not free in E).
void _reduceDeadVal(_ReductionTask task) {
+ if (_isRemoved(task.node)) return;
assert(_isDeadVal(task.node));
- // Remove dead primitive.
- LetPrim letPrim = task.node;
- destroyRefinementsOfDeadPrimitive(letPrim.primitive);
- _removeNode(letPrim);
+ LetPrim deadLet = task.node;
+ Primitive deadPrim = deadLet.primitive;
+ assert(deadPrim.hasNoRefinedUses);
+ // The node has no effective uses but can have refinement uses, which
+ // themselves can have more refinements uses (but only refinement uses).
+ // We must remove the entire refinement tree while looking for redexes
+ // whenever we remove one.
+ List<Primitive> deadlist = <Primitive>[deadPrim];
+ while (deadlist.isNotEmpty) {
+ Primitive node = deadlist.removeLast();
+ while (node.firstRef != null) {
+ Reference ref = node.firstRef;
+ Refinement use = ref.parent;
+ deadlist.add(use);
+ ref.unlink();
+ }
+ LetPrim binding = node.parent;
+ _removeNode(binding); // Remove the binding and check for eta redexes.
+ }
// Perform bookkeeping on removed body and scan for new redexes.
- new _RemovalVisitor(_worklist).visit(letPrim.primitive);
+ new _RemovalVisitor(_worklist).visit(deadPrim);
}
/// Applies the dead-cont reduction:
@@ -127,25 +194,36 @@
return;
}
- // Remove the continuation.
Continuation cont = task.node;
- _removeContinuation(cont);
-
- // Replace its invocation with the continuation body.
InvokeContinuation invoke = cont.firstRef.parent;
InteriorNode invokeParent = invoke.parent;
+ Expression body = cont.body;
- cont.body.parent = invokeParent;
- invokeParent.body = cont.body;
+ // Replace the invocation with the continuation body.
+ invokeParent.body = body;
+ body.parent = invokeParent;
+ cont.body = null;
// Substitute the invocation argument for the continuation parameter.
for (int i = 0; i < invoke.arguments.length; i++) {
- cont.parameters[i].replaceUsesWith(invoke.arguments[i].definition);
- invoke.arguments[i].definition.useElementAsHint(cont.parameters[i].hint);
+ Parameter param = cont.parameters[i];
+ Primitive argument = invoke.arguments[i].definition;
+ param.replaceUsesWith(argument);
+ argument.useElementAsHint(param.hint);
+ _checkConstantBranchCondition(argument);
}
+ // Remove the continuation after inlining it so we can check for eta redexes
+ // which may arise after removing the LetCont.
+ _removeContinuation(cont);
+
// Perform bookkeeping on substituted body and scan for new redexes.
new _RemovalVisitor(_worklist).visit(invoke);
+
+ if (invokeParent is Continuation) {
+ _checkEtaCont(invokeParent);
+ _checkUselessBranchTarget(invokeParent);
+ }
}
/// Applies the eta-cont reduction:
@@ -184,13 +262,48 @@
}
}
- // Replace all occurrences with the wrapped continuation.
- cont.replaceUsesWith(wrappedCont);
+ // Replace all occurrences with the wrapped continuation and find redexes.
+ while (cont.firstRef != null) {
+ Reference ref = cont.firstRef;
+ ref.changeTo(wrappedCont);
+ Node use = ref.parent;
+ if (use is InvokeContinuation && use.parent is Continuation) {
+ _checkUselessBranchTarget(use.parent);
+ }
+ }
// Perform bookkeeping on removed body and scan for new redexes.
new _RemovalVisitor(_worklist).visit(cont);
}
+ void _reduceBranch(_ReductionTask task) {
+ Branch branch = task.node;
+ // Replace Branch with InvokeContinuation of one of the targets. When the
+ // branch is deleted the other target becomes unreferenced and the chosen
+ // target becomes available for eta-cont and further reductions.
+ Continuation target;
+ Primitive condition = branch.condition.definition;
+ if (condition is Constant) {
+ target = isTruthyConstant(condition.value, strict: branch.isStrictCheck)
+ ? branch.trueContinuation.definition
+ : branch.falseContinuation.definition;
+ } else if (_isBranchTargetOfUselessIf(branch.trueContinuation.definition)) {
+ target = branch.trueContinuation.definition;
+ } else {
+ return;
+ }
+
+ InvokeContinuation invoke = new InvokeContinuation(
+ target, <Primitive>[]
+ // TODO(sra): Add sourceInformation.
+ /*, sourceInformation: branch.sourceInformation*/);
+ branch.parent.body = invoke;
+ invoke.parent = branch.parent;
+ branch.parent = null;
+
+ new _RemovalVisitor(_worklist).visit(branch);
+ }
+
void _reduceDeadParameter(_ReductionTask task) {
// Continuation eta-reduction can destroy a dead parameter redex. For
// example, in the term:
@@ -207,61 +320,105 @@
// Where the dead parameter reduction is no longer valid because we do not
// allow removing the paramter of call continuations. We disallow such eta
// reductions in [_isEtaCont].
- assert(_isDeadParameter(task.node));
-
Parameter parameter = task.node;
+ if (_isParameterRemoved(parameter)) return;
+ assert(_isDeadParameter(parameter));
+
Continuation continuation = parameter.parent;
int index = continuation.parameters.indexOf(parameter);
assert(index != -1);
+ continuation.parameters.removeAt(index);
+ parameter.parent = null; // Mark as removed.
// Remove the index'th argument from each invocation.
- Reference<Continuation> current = continuation.firstRef;
- while (current != null) {
- InvokeContinuation invoke = current.parent;
+ for (Reference ref = continuation.firstRef; ref != null; ref = ref.next) {
+ InvokeContinuation invoke = ref.parent;
Reference<Primitive> argument = invoke.arguments[index];
argument.unlink();
- // Removing an argument can create a dead parameter or dead value redex.
- if (argument.definition is Parameter) {
- if (_isDeadParameter(argument.definition)) {
- _worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER,
- argument.definition));
- }
- } else {
- Node parent = argument.definition.parent;
- if (parent is LetPrim) {
- if (_isDeadVal(parent)) {
- _worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
- }
- }
- }
invoke.arguments.removeAt(index);
- current = current.next;
+ // Removing an argument can create a dead primitive or an eta-redex
+ // in case the parent is a continuation that now has matching parameters.
+ _checkDeadPrimitive(argument.definition);
+ if (invoke.parent is Continuation) {
+ _checkEtaCont(invoke.parent);
+ _checkUselessBranchTarget(invoke.parent);
+ }
}
- continuation.parameters.removeAt(index);
- // Removing an unused parameter can create an eta-redex.
+ // Removing an unused parameter can create an eta-redex, in case the
+ // body is an InvokeContinuation that now has matching arguments.
+ _checkEtaCont(continuation);
+ }
+
+ void _checkEtaCont(Continuation continuation) {
if (_isEtaCont(continuation)) {
_worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, continuation));
}
}
+
+ void _checkUselessBranchTarget(Continuation continuation) {
+ if (_isBranchTargetOfUselessIf(continuation)) {
+ _worklist.add(new _ReductionTask(_ReductionKind.BRANCH,
+ continuation.firstRef.parent));
+ }
+ }
+
+ void _checkConstantBranchCondition(Primitive primitive) {
+ if (primitive is! Constant) return;
+ for (Reference ref = primitive.firstRef; ref != null; ref = ref.next) {
+ Node use = ref.parent;
+ if (use is Branch) {
+ _worklist.add(new _ReductionTask(_ReductionKind.BRANCH, use));
+ }
+ }
+ }
+
+ void _checkDeadPrimitive(Primitive primitive) {
+ primitive = primitive.unrefined;
+ if (primitive is Parameter) {
+ if (_isDeadParameter(primitive)) {
+ _worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER,
+ primitive));
+ }
+ } else if (primitive.parent is LetPrim) {
+ LetPrim letPrim = primitive.parent;
+ if (_isDeadVal(letPrim)) {
+ _worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, letPrim));
+ }
+ }
+ }
+}
+
+bool _isRemoved(InteriorNode node) {
+ return node.parent == null;
+}
+
+bool _isParameterRemoved(Parameter parameter) {
+ // A parameter can be removed directly or because its continuation is removed.
+ return parameter.parent == null || _isRemoved(parameter.parent);
}
/// Returns true iff the bound primitive is unused, and has no effects
/// preventing it from being eliminated.
bool _isDeadVal(LetPrim node) {
- return node.primitive.hasNoEffectiveUses &&
+ return !_isRemoved(node) &&
+ node.primitive.hasNoRefinedUses &&
node.primitive.isSafeForElimination;
}
/// Returns true iff the continuation is unused.
bool _isDeadCont(Continuation cont) {
- return !cont.isReturnContinuation && !cont.hasAtLeastOneUse;
+ return !_isRemoved(cont) &&
+ !cont.isReturnContinuation &&
+ !cont.hasAtLeastOneUse;
}
/// Returns true iff the continuation has a body (i.e., it is not the return
/// continuation), it is used exactly once, and that use is as the continuation
/// of a continuation invocation.
bool _isBetaContLin(Continuation cont) {
+ if (_isRemoved(cont)) return false;
+
// There is a restriction on continuation eta-redexes that the body is not an
// invocation of the return continuation, because that leads to worse code
// when translating back to direct style (it duplicates returns). There is no
@@ -275,26 +432,21 @@
if (cont.firstRef.parent is! InvokeContinuation) return false;
InvokeContinuation invoke = cont.firstRef.parent;
- if (cont != invoke.continuation.definition) return false;
// Beta-reduction will move the continuation's body to its unique invocation
// site. This is not safe if the body is moved into an exception handler
- // binding. Search from the invocation to the continuation binding to
- // make sure that there is no binding for a handler.
- Node current = invoke.parent;
- while (current != cont.parent) {
- // There is no need to reduce a beta-redex inside a deleted subterm.
- if (current == ShrinkingReducer._DELETED) return false;
- if (current is LetHandler) return false;
- current = current.parent;
- }
+ // binding.
+ if (invoke.isEscapingTry) return false;
+
return true;
}
/// Returns true iff the continuation consists of a continuation
/// invocation, passing on all parameters. Special cases exist (see below).
bool _isEtaCont(Continuation cont) {
- if (cont.isReturnContinuation || cont.body is! InvokeContinuation) {
+ if (_isRemoved(cont)) return false;
+
+ if (!cont.isJoinContinuation || cont.body is! InvokeContinuation) {
return false;
}
@@ -307,25 +459,6 @@
return false;
}
- // Do not perform reductions replace a function call continuation with a
- // non-call continuation. The invoked continuation is definitely not a call
- // continuation, because it has a direct invocation in this continuation's
- // body.
- bool isCallContinuation(Continuation continuation) {
- Reference<Continuation> current = cont.firstRef;
- while (current != null) {
- if (current.parent is InvokeContinuation) {
- InvokeContinuation invoke = current.parent;
- if (invoke.continuation.definition == continuation) return false;
- }
- current = current.next;
- }
- return true;
- }
- if (isCallContinuation(cont)) {
- return false;
- }
-
// Translation to direct style generates different statements for recursive
// and non-recursive invokes. It should still be possible to apply eta-cont if
// this is not a self-invocation.
@@ -371,15 +504,61 @@
return true;
}
-bool _isDeadParameter(Parameter parameter) {
- // We cannot remove function parameters as an intraprocedural optimization.
- if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) {
+Expression _unfoldDeadRefinements(Expression node) {
+ while (node is LetPrim) {
+ LetPrim let = node;
+ Primitive prim = let.primitive;
+ if (prim.hasAtLeastOneUse || prim is! Refinement) return node;
+ node = node.next;
+ }
+ return node;
+}
+
+bool _isBranchRedex(Branch branch) {
+ return _isUselessIf(branch) || branch.condition.definition is Constant;
+}
+
+bool _isBranchTargetOfUselessIf(Continuation cont) {
+ // A useless-if has an empty then and else branch, e.g. `if (cond);`.
+ //
+ // Detect T or F in
+ //
+ // let cont Join() = ...
+ // in let cont T() = Join()
+ // F() = Join()
+ // in branch condition T F
+ //
+ if (!cont.hasExactlyOneUse) return false;
+ Node use = cont.firstRef.parent;
+ if (use is! Branch) return false;
+ return _isUselessIf(use);
+}
+
+bool _isUselessIf(Branch branch) {
+ Continuation trueCont = branch.trueContinuation.definition;
+ Expression trueBody = _unfoldDeadRefinements(trueCont.body);
+ if (trueBody is! InvokeContinuation) return false;
+ Continuation falseCont = branch.falseContinuation.definition;
+ Expression falseBody = _unfoldDeadRefinements(falseCont.body);
+ if (falseBody is! InvokeContinuation) return false;
+ InvokeContinuation trueInvoke = trueBody;
+ InvokeContinuation falseInvoke = falseBody;
+ if (trueInvoke.continuation.definition !=
+ falseInvoke.continuation.definition) {
return false;
}
+ assert(trueInvoke.arguments.length == falseInvoke.arguments.length);
+ // Matching zero arguments should be adequate, since isomorphic true and false
+ // invocations should result in redundant phis which are removed elsewhere.
+ if (trueInvoke.arguments.isNotEmpty) return false;
+ return true;
+}
- // We cannot remove exception handler parameters, they have a fixed arity
- // of two.
- if (parameter.parent.parent is LetHandler) {
+bool _isDeadParameter(Parameter parameter) {
+ if (_isParameterRemoved(parameter)) return false;
+
+ // We cannot remove function parameters as an intraprocedural optimization.
+ if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) {
return false;
}
@@ -388,14 +567,8 @@
// exactly one argument). The return continuation is a call continuation, so
// we cannot remove its dummy parameter.
Continuation continuation = parameter.parent;
- if (continuation.isReturnContinuation) return false;
- Reference<Continuation> current = continuation.firstRef;
- while (current != null) {
- if (current.parent is! InvokeContinuation) return false;
- InvokeContinuation invoke = current.parent;
- if (invoke.continuation.definition != continuation) return false;
- current = current.next;
- }
+ if (!continuation.isJoinContinuation) return false;
+
return true;
}
@@ -411,6 +584,12 @@
}
}
+ void processBranch(Branch node) {
+ if (_isBranchRedex(node)) {
+ worklist.add(new _ReductionTask(_ReductionKind.BRANCH, node));
+ }
+ }
+
void processContinuation(Continuation node) {
// While it would be nice to remove exception handlers that are provably
// unnecessary (e.g., the body cannot throw), that takes more sophisticated
@@ -452,23 +631,26 @@
_RemovalVisitor(this.worklist);
void processLetPrim(LetPrim node) {
- node.parent = ShrinkingReducer._DELETED;
+ node.parent = null;
}
void processContinuation(Continuation node) {
- node.parent = ShrinkingReducer._DELETED;
+ node.parent = null;
}
void processReference(Reference reference) {
reference.unlink();
if (reference.definition is Primitive) {
- Primitive primitive = reference.definition;
+ Primitive primitive = reference.definition.unrefined;
Node parent = primitive.parent;
// The parent might be the deleted sentinel, or it might be a
// Continuation or FunctionDefinition if the primitive is an argument.
if (parent is LetPrim && _isDeadVal(parent)) {
worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
+ } else if (primitive is Parameter && _isDeadParameter(primitive)) {
+ worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER,
+ primitive));
}
} else if (reference.definition is Continuation) {
Continuation cont = reference.definition;
@@ -486,29 +668,22 @@
worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont));
} else if (_isBetaContLin(cont)) {
worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont));
+ } else if (_isBranchTargetOfUselessIf(cont)) {
+ worklist.add(
+ new _ReductionTask(_ReductionKind.BRANCH, cont.firstRef.parent));
}
}
}
}
}
-
-
-class _ReductionKind {
- final String name;
- final int hashCode;
-
- const _ReductionKind(this.name, this.hashCode);
-
- static const _ReductionKind DEAD_VAL = const _ReductionKind('dead-val', 0);
- static const _ReductionKind DEAD_CONT = const _ReductionKind('dead-cont', 1);
- static const _ReductionKind BETA_CONT_LIN =
- const _ReductionKind('beta-cont-lin', 2);
- static const _ReductionKind ETA_CONT = const _ReductionKind('eta-cont', 3);
- static const _ReductionKind DEAD_PARAMETER =
- const _ReductionKind('dead-parameter', 4);
-
- String toString() => name;
+enum _ReductionKind {
+ DEAD_VAL,
+ DEAD_CONT,
+ BETA_CONT_LIN,
+ ETA_CONT,
+ DEAD_PARAMETER,
+ BRANCH
}
/// Represents a reduction task on the worklist. Implements both hashCode and
@@ -518,12 +693,12 @@
final Node node;
int get hashCode {
- assert(kind.hashCode < (1 << 3));
- return (node.hashCode << 3) | kind.hashCode;
+ return (node.hashCode << 3) | kind.index;
}
_ReductionTask(this.kind, this.node) {
- assert(node is Continuation || node is LetPrim || node is Parameter);
+ assert(node is Continuation || node is LetPrim || node is Parameter ||
+ node is Branch);
}
bool operator==(_ReductionTask that) {
@@ -532,10 +707,3 @@
String toString() => "$kind: $node";
}
-
-/// A dummy class used solely to mark nodes as deleted once they are removed
-/// from a term.
-class _DeletedNode extends Node {
- accept(_) {}
- setParentPointers() {}
-}
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index 25fb1c9..0a21c3f 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -448,10 +448,8 @@
}
@override
- bool areDisjoint(TypeMask leftType, TypeMask rightType) {
- TypeMask intersected = intersection(leftType, rightType);
- return intersected.isEmpty && !intersected.isNullable;
- }
+ bool areDisjoint(TypeMask leftType, TypeMask rightType) =>
+ leftType.isDisjoint(rightType, classWorld);
@override
bool isMorePreciseOrEqual(TypeMask t1, TypeMask t2) {
@@ -468,8 +466,8 @@
}
if (type is types.InterfaceType) {
TypeMask typeAsMask = allowNull
- ? new TypeMask.subtype(type.element, classWorld)
- : new TypeMask.nonNullSubtype(type.element, classWorld);
+ ? new TypeMask.subtype(type.element, classWorld)
+ : new TypeMask.nonNullSubtype(type.element, classWorld);
if (areDisjoint(value, typeAsMask)) {
// Disprove the subtype relation based on the class alone.
return AbstractBool.False;
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index aa26e31..6277667 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -714,8 +714,10 @@
final CpsFunctionCompiler _functionCompiler;
final Map<Variable, ConstantValue> _values= <Variable, ConstantValue>{};
final ConstantPropagationLattice _lattice;
+ final bool recomputeAll;
- TypePropagator(CpsFunctionCompiler functionCompiler)
+ TypePropagator(CpsFunctionCompiler functionCompiler,
+ {this.recomputeAll: false})
: _functionCompiler = functionCompiler,
_lattice = new ConstantPropagationLattice(functionCompiler);
@@ -731,7 +733,7 @@
_values,
_internalError);
- analyzer.analyze(root);
+ analyzer.analyze(root, recomputeAll);
// Transform. Uses the data acquired in the previous analysis phase to
// replace branches with fixed targets and side-effect-free expressions
@@ -1047,6 +1049,16 @@
push(invoke);
return;
}
+
+ // Shortcut negation to help simplify control flow. The tree IR will insert
+ // a negation again if that's useful.
+ if (condition is ApplyBuiltinOperator &&
+ condition.operator == BuiltinOperator.IsFalsy) {
+ node.condition.changeTo(condition.arguments.single.definition);
+ node.trueContinuation.changeTo(falseCont);
+ node.falseContinuation.changeTo(trueCont);
+ return;
+ }
}
void visitInvokeContinuation(InvokeContinuation node) {
@@ -1142,7 +1154,7 @@
return cps;
}
- if (node.selector.isOperator && node.arguments.length == 2) {
+ if (node.selector.isOperator && node.dartArgumentsLength == 1) {
Primitive leftArg = node.dartReceiver;
Primitive rightArg = node.dartArgument(0);
AbstractConstantValue left = getValue(leftArg);
@@ -1223,7 +1235,7 @@
}
}
}
- if (node.selector.isOperator && node.arguments.length == 1) {
+ if (node.selector.isOperator && node.dartArgumentsLength == 0) {
Primitive argument = node.dartReceiver;
AbstractConstantValue value = getValue(argument);
@@ -1244,7 +1256,7 @@
Primitive receiver = node.dartReceiver;
AbstractConstantValue receiverValue = getValue(receiver);
if (name == 'remainder') {
- if (node.arguments.length == 2) {
+ if (node.dartArgumentsLength == 1) {
Primitive arg = node.dartArgument(0);
AbstractConstantValue argValue = getValue(arg);
if (lattice.isDefinitelyInt(receiverValue, allowNull: true) &&
@@ -1255,7 +1267,7 @@
}
}
} else if (name == 'codeUnitAt') {
- if (node.arguments.length == 2) {
+ if (node.dartArgumentsLength == 1) {
Primitive index = node.dartArgument(0);
if (lattice.isDefinitelyString(receiverValue) &&
lattice.isDefinitelyInt(getValue(index))) {
@@ -1534,7 +1546,7 @@
// Check that all uses of the iterator are 'moveNext' and 'current'.
assert(!isInterceptedSelector(Selectors.moveNext));
assert(!isInterceptedSelector(Selectors.current));
- for (Reference ref in iterator.effectiveUses) {
+ for (Reference ref in iterator.refinedUses) {
if (ref.parent is! InvokeMethod) return null;
InvokeMethod use = ref.parent;
if (ref != use.receiver) return null;
@@ -1551,7 +1563,7 @@
MutableVariable current = new MutableVariable(new LoopItemEntity());
// Rewrite all uses of the iterator.
- for (Reference ref in iterator.effectiveUses) {
+ for (Reference ref in iterator.refinedUses) {
InvokeMethod use = ref.parent;
if (use.selector == Selectors.current) {
// Rewrite iterator.current to a use of the 'current' variable.
@@ -1760,7 +1772,7 @@
// If there are multiple uses, we cannot eliminate the getter call and
// therefore risk duplicating its side effects.
- if (!isPure && tearOff.hasMultipleEffectiveUses) return null;
+ if (!isPure && tearOff.hasMultipleRefinedUses) return null;
// If the getter call is impure, we risk reordering side effects,
// unless it is immediately prior to the closure call.
@@ -1776,7 +1788,7 @@
sourceInformation: node.sourceInformation);
node.receiver.changeTo(new Parameter(null)); // Remove the tear off use.
- if (tearOff.hasNoEffectiveUses) {
+ if (tearOff.hasNoRefinedUses) {
// Eliminate the getter call if it has no more uses.
// This cannot be delegated to other optimizations because we need to
// avoid duplication of side effects.
@@ -1991,7 +2003,7 @@
// Nothing happens. The primitive remains as it is.
//
- void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
+ visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
ast.DartString getString(AbstractConstantValue value) {
StringConstantValue constant = value.constant;
return constant.primitiveValue;
@@ -2051,42 +2063,70 @@
Primitive rightArg = node.arguments[1].definition;
AbstractConstantValue left = getValue(leftArg);
AbstractConstantValue right = getValue(rightArg);
- if (lattice.isDefinitelyBool(left) &&
- right.isConstant &&
- right.constant.isTrue) {
- // Replace identical(x, true) by x when x is known to be a boolean.
- // Note that this is not safe if x is null, because the value might
- // not be used as a condition.
- node.replaceUsesWith(leftArg);
- } else if (lattice.isDefinitelyBool(right) &&
- left.isConstant &&
- left.constant.isTrue) {
- node.replaceUsesWith(rightArg);
- } else if (left.isNullConstant || right.isNullConstant) {
+ BuiltinOperator newOperator;
+ if (left.isNullConstant || right.isNullConstant) {
// Use `==` for comparing against null, so JS undefined and JS null
// are considered equal.
- node.operator = BuiltinOperator.LooseEq;
+ newOperator = BuiltinOperator.LooseEq;
} else if (!left.isNullable || !right.isNullable) {
// If at most one operand can be Dart null, we can use `===`.
// This is not safe when we might compare JS null and JS undefined.
- node.operator = BuiltinOperator.StrictEq;
+ newOperator = BuiltinOperator.StrictEq;
} else if (lattice.isDefinitelyNum(left, allowNull: true) &&
lattice.isDefinitelyNum(right, allowNull: true)) {
// If both operands can be null, but otherwise are of the same type,
// we can use `==` for comparison.
// This is not safe e.g. for comparing strings against numbers.
- node.operator = BuiltinOperator.LooseEq;
+ newOperator = BuiltinOperator.LooseEq;
} else if (lattice.isDefinitelyString(left, allowNull: true) &&
lattice.isDefinitelyString(right, allowNull: true)) {
- node.operator = BuiltinOperator.LooseEq;
+ newOperator = BuiltinOperator.LooseEq;
} else if (lattice.isDefinitelyBool(left, allowNull: true) &&
lattice.isDefinitelyBool(right, allowNull: true)) {
- node.operator = BuiltinOperator.LooseEq;
+ newOperator = BuiltinOperator.LooseEq;
+ }
+ if (newOperator != null) {
+ return new ApplyBuiltinOperator(newOperator,
+ node.arguments.map((ref) => ref.definition).toList(),
+ node.sourceInformation);
+ }
+ break;
+
+ case BuiltinOperator.StrictEq:
+ case BuiltinOperator.LooseEq:
+ case BuiltinOperator.StrictNeq:
+ case BuiltinOperator.LooseNeq:
+ bool negated =
+ node.operator == BuiltinOperator.StrictNeq ||
+ node.operator == BuiltinOperator.LooseNeq;
+ for (int firstIndex in [0, 1]) {
+ int secondIndex = 1 - firstIndex;
+ Primitive firstArg = node.arguments[firstIndex].definition;
+ Primitive secondArg = node.arguments[secondIndex].definition;
+ AbstractConstantValue first = getValue(firstArg);
+ if (!lattice.isDefinitelyBool(first)) continue;
+ AbstractConstantValue second = getValue(secondArg);
+ if (!second.isConstant || !second.constant.isBool) continue;
+ bool isTrueConstant = second.constant.isTrue;
+ if (isTrueConstant == !negated) {
+ // (x === true) ==> x
+ // (x !== false) ==> x
+ node.replaceUsesWith(firstArg);
+ return null;
+ } else {
+ // (x === false) ==> !x
+ // (x !== true) ==> !x
+ return new ApplyBuiltinOperator(
+ BuiltinOperator.IsFalsy,
+ [firstArg],
+ node.sourceInformation);
+ }
}
break;
default:
}
+ return null;
}
void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
@@ -2288,8 +2328,11 @@
this.values,
this.internalError);
- void analyze(FunctionDefinition root) {
+ void analyze(FunctionDefinition root, bool recomputeAll) {
reachableContinuations.clear();
+ if (recomputeAll) {
+ new ResetAnalysisInfo(reachableContinuations, values).visit(root);
+ }
// Initially, only the root node is reachable.
push(root);
@@ -2532,7 +2575,7 @@
// Calculate the resulting constant if possible.
String opname = node.selector.name;
- if (node.arguments.length == 1) {
+ if (node.dartArgumentsLength == 0) {
// Unary operator.
if (opname == "unary-") {
opname = "-";
@@ -2540,7 +2583,7 @@
UnaryOperator operator = UnaryOperator.parse(opname);
AbstractConstantValue result = lattice.unaryOp(operator, receiver);
return finish(result, canReplace: !receiver.isNullable);
- } else if (node.arguments.length == 2) {
+ } else if (node.dartArgumentsLength == 1) {
// Binary operator.
AbstractConstantValue right = getValue(node.dartArgument(0));
BinaryOperator operator = BinaryOperator.parse(opname);
@@ -2619,37 +2662,34 @@
case BuiltinOperator.Identical:
case BuiltinOperator.StrictEq:
+ case BuiltinOperator.StrictNeq:
case BuiltinOperator.LooseEq:
- AbstractConstantValue leftConst =
- getValue(node.arguments[0].definition);
- AbstractConstantValue rightConst =
- getValue(node.arguments[1].definition);
- ConstantValue leftValue = leftConst.constant;
- ConstantValue rightValue = rightConst.constant;
- if (leftConst.isNothing || rightConst.isNothing) {
+ case BuiltinOperator.LooseNeq:
+ bool negated =
+ node.operator == BuiltinOperator.StrictNeq ||
+ node.operator == BuiltinOperator.LooseNeq;
+ AbstractConstantValue left = getValue(node.arguments[0].definition);
+ AbstractConstantValue right = getValue(node.arguments[1].definition);
+ if (left.isNothing || right.isNothing) {
setValue(node, lattice.nothing);
- return; // And come back later.
- } else if (!leftConst.isConstant || !rightConst.isConstant) {
- TypeMask leftType = leftConst.type;
- TypeMask rightType = rightConst.type;
- if (typeSystem.areDisjoint(leftType, rightType)) {
- setValue(node,
- constantValue(new FalseConstantValue(), typeSystem.boolType));
- } else {
- setValue(node, nonConstant(typeSystem.boolType));
- }
return;
- } else if (leftValue.isPrimitive && rightValue.isPrimitive) {
- assert(leftConst.isConstant && rightConst.isConstant);
- PrimitiveConstantValue left = leftValue;
- PrimitiveConstantValue right = rightValue;
- // Should this be constantSystem.identity.fold(left, right)?
- ConstantValue result =
- new BoolConstantValue(left.primitiveValue == right.primitiveValue);
- setValue(node, constantValue(result, typeSystem.boolType));
- } else {
- setValue(node, nonConstant(typeSystem.boolType));
}
+ if (left.isConstant && right.isConstant) {
+ ConstantValue equal = lattice.constantSystem.identity.fold(
+ left.constant, right.constant);
+ if (equal != null && equal.isBool) {
+ ConstantValue result =
+ new BoolConstantValue(equal.isTrue == !negated);
+ setValue(node, constantValue(result, typeSystem.boolType));
+ return;
+ }
+ }
+ if (typeSystem.areDisjoint(left.type, right.type)) {
+ ConstantValue result = new BoolConstantValue(negated);
+ setValue(node, constantValue(result, typeSystem.boolType));
+ return;
+ }
+ setValue(node, nonConstant(typeSystem.boolType));
break;
case BuiltinOperator.NumAdd:
@@ -2862,12 +2902,6 @@
}
}
- void visitLiteralMap(LiteralMap node) {
- // Constant maps are translated into (Constant MapConstant(...)) IR nodes,
- // and thus LiteralMap nodes are NonConst.
- setValue(node, nonConstant(typeSystem.mapType));
- }
-
void visitConstant(Constant node) {
ConstantValue value = node.value;
if (value.isDummy || !value.isConstant) {
@@ -2980,7 +3014,21 @@
@override
void visitForeignCode(ForeignCode node) {
- setValue(node, nonConstant(node.type));
+ bool firstArgumentIsNullable = false;
+ if (node.arguments.length > 0) {
+ AbstractConstantValue first = getValue(node.arguments.first.definition);
+ if (first.isNothing) {
+ setValue(node, nothing);
+ return;
+ }
+ firstArgumentIsNullable = first.isNullable;
+ }
+ setValue(node, nonConstant(node.storedType));
+ node.isSafeForElimination =
+ !node.nativeBehavior.sideEffects.hasSideEffects() &&
+ (!node.nativeBehavior.throwBehavior.canThrow ||
+ (!firstArgumentIsNullable &&
+ node.nativeBehavior.throwBehavior.isOnlyNullNSMGuard));
}
@override
diff --git a/pkg/compiler/lib/src/cps_ir/update_refinements.dart b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
index d93e747..48e3242 100644
--- a/pkg/compiler/lib/src/cps_ir/update_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
@@ -20,7 +20,7 @@
final TypeMaskSystem typeSystem;
- Map<Primitive, Refinement> refinementFor = <Primitive, Refinement>{};
+ Map<Primitive, Primitive> refinementFor = <Primitive, Primitive>{};
UpdateRefinements(this.typeSystem);
@@ -29,11 +29,33 @@
}
Expression traverseLetPrim(LetPrim node) {
+ Expression next = node.body;
visit(node.primitive);
- return node.body;
+ return next;
}
- @override
+ visitNullCheck(NullCheck node) {
+ if (refine(node.value)) {
+ Primitive value = node.value.definition;
+ if (value.type.isNullable) {
+ // Update the type if the input has changed.
+ node.type = value.type.nonNullable();
+ } else {
+ node..replaceUsesWith(value)..destroy();
+ LetPrim letPrim = node.parent;
+ letPrim.remove();
+ return;
+ }
+ }
+ // Use the NullCheck as a refinement.
+ Primitive value = node.effectiveDefinition;
+ Primitive old = refinementFor[value];
+ refinementFor[value] = node;
+ pushAction(() {
+ refinementFor[value] = old;
+ });
+ }
+
visitRefinement(Refinement node) {
if (refine(node.value)) {
// Update the type if the input has changed.
@@ -41,14 +63,13 @@
node.refineType);
}
Primitive value = node.effectiveDefinition;
- Refinement old = refinementFor[value];
+ Primitive old = refinementFor[value];
refinementFor[value] = node;
pushAction(() {
refinementFor[value] = old;
});
}
- @override
processReference(Reference ref) {
refine(ref);
}
@@ -56,7 +77,7 @@
bool refine(Reference ref) {
Definition def = ref.definition;
if (def is Primitive) {
- Refinement refinement = refinementFor[def.effectiveDefinition];
+ Primitive refinement = refinementFor[def.effectiveDefinition];
if (refinement != null && refinement != ref.definition) {
ref.changeTo(refinement);
return true;
diff --git a/pkg/compiler/lib/src/diagnostics/dart2js_messages.dart b/pkg/compiler/lib/src/diagnostics/dart2js_messages.dart
deleted file mode 100644
index 90d4ecf..0000000
--- a/pkg/compiler/lib/src/diagnostics/dart2js_messages.dart
+++ /dev/null
@@ -1,3732 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// The messages in this file should meet the following guide lines:
-//
-// 1. The message should be a complete sentence starting with an uppercase
-// letter, and ending with a period.
-//
-// 2. Reserved words and embedded identifiers should be in single quotes, so
-// prefer double quotes for the complete message. For example, "The
-// class '#{className}' can't use 'super'." Notice that the word 'class' in the
-// preceding message is not quoted as it refers to the concept 'class', not the
-// reserved word. On the other hand, 'super' refers to the reserved word. Do
-// not quote 'null' and numeric literals.
-//
-// 3. Do not try to compose messages, as it can make translating them hard.
-//
-// 4. Try to keep the error messages short, but informative.
-//
-// 5. Use simple words and terminology, assume the reader of the message
-// doesn't have an advanced degree in math, and that English is not the
-// reader's native language. Do not assume any formal computer science
-// training. For example, do not use Latin abbreviations (prefer "that is" over
-// "i.e.", and "for example" over "e.g."). Also avoid phrases such as "if and
-// only if" and "iff", that level of precision is unnecessary.
-//
-// 6. Prefer contractions when they are in common use, for example, prefer
-// "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
-// off-putting to people new to programming.
-//
-// 7. Use common terminology, preferably from the Dart Language
-// Specification. This increases the user's chance of finding a good
-// explanation on the web.
-//
-// 8. Do not try to be cute or funny. It is extremely frustrating to work on a
-// product that crashes with a "tongue-in-cheek" message, especially if you did
-// not want to use this product to begin with.
-//
-// 9. Do not lie, that is, do not write error messages containing phrases like
-// "can't happen". If the user ever saw this message, it would be a
-// lie. Prefer messages like: "Internal error: This function should not be
-// called when 'x' is null.".
-//
-// 10. Prefer to not use imperative tone. That is, the message should not sound
-// accusing or like it is ordering the user around. The computer should
-// describe the problem, not criticize for violating the specification.
-//
-// Other things to keep in mind:
-//
-// An INFO message should always be preceded by a non-INFO message, and the
-// INFO messages are additional details about the preceding non-INFO
-// message. For example, consider duplicated elements. First report a WARNING
-// or ERROR about the duplicated element, and then report an INFO about the
-// location of the existing element.
-//
-// Generally, we want to provide messages that consists of three sentences:
-// 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we
-// combine the first two in [template] and the last in [howToFix].
-
-/// Padding used before and between import chains in the message for
-/// [MessageKind.IMPORT_EXPERIMENTAL_MIRRORS].
-const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n* ';
-
-/// Padding used before and between import chains in the message for
-/// [MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND].
-const String MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING = '\n ';
-
-/// Padding used before and between import chains in the message for
-/// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
-const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n ';
-
-const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
-
-final Map<String, Map> MESSAGES = {
- /// Do not use this. It is here for legacy and debugging. It violates item
- /// 4 of the guide lines for error messages in the beginning of the file.
- 'GENERIC': {'id': 'SOWPSL', 'template': "#{text}",},
-
- 'NOT_ASSIGNABLE': {
- 'id': 'VYNMAP',
- 'template': "'#{fromType}' is not assignable to '#{toType}'.",
- },
-
- 'FORIN_NOT_ASSIGNABLE': {
- 'id': 'XQSRXO',
- 'template': "The element type '#{currentType}' of '#{expressionType}' "
- "is not assignable to '#{elementType}'.",
- },
-
- 'VOID_EXPRESSION': {
- 'id': 'QHEVSC',
- 'template': "Expression does not yield a value.",
- },
-
- 'VOID_VARIABLE': {
- 'id': 'RFEURK',
- 'template': "Variable cannot be of type void.",
- },
-
- 'RETURN_VALUE_IN_VOID': {
- 'id': 'FUNYDS',
- 'template': "Cannot return value from void function.",
- },
-
- 'RETURN_NOTHING': {
- 'id': 'HPPODJ',
- 'template': "Value of type '#{returnType}' expected.",
- },
-
- 'MISSING_ARGUMENT': {
- 'id': 'LHMCIK',
- 'template': "Missing argument of type '#{argumentType}'.",
- },
-
- 'ADDITIONAL_ARGUMENT': {'id': 'GMITMA', 'template': "Additional argument.",},
-
- 'NAMED_ARGUMENT_NOT_FOUND': {
- 'id': 'UCEARQ',
- 'template': "No named argument '#{argumentName}' found on method.",
- },
-
- 'MEMBER_NOT_FOUND': {
- 'id': 'MMQODC',
- 'template': "No member named '#{memberName}' in class '#{className}'.",
- },
-
- 'AWAIT_MEMBER_NOT_FOUND': {
- 'id': 'XIDLIP',
- 'template': "No member named 'await' in class '#{className}'.",
- 'howToFix': "Did you mean to add the 'async' marker "
- "to '#{functionName}'?",
- 'examples': [
- """
-class A {
-m() => await -3;
-}
-main() => new A().m();
-"""
- ],
- },
-
- 'AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE': {
- 'id': 'HBIYGN',
- 'template': "No member named 'await' in class '#{className}'.",
- 'howToFix': "Did you mean to add the 'async' marker "
- "to the enclosing function?",
- 'examples': [
- """
-class A {
-m() => () => await -3;
-}
-main() => new A().m();
-"""
- ],
- },
-
- 'METHOD_NOT_FOUND': {
- 'id': 'QYYHBU',
- 'template': "No method named '#{memberName}' in class '#{className}'.",
- },
-
- 'OPERATOR_NOT_FOUND': {
- 'id': 'SXGOYS',
- 'template': "No operator '#{memberName}' in class '#{className}'.",
- },
-
- 'SETTER_NOT_FOUND': {
- 'id': 'ADFRVF',
- 'template': "No setter named '#{memberName}' in class '#{className}'.",
- },
-
- 'SETTER_NOT_FOUND_IN_SUPER': {
- 'id': 'OCVRNJ',
- 'template': "No setter named '#{name}' in superclass of '#{className}'.",
- },
-
- 'GETTER_NOT_FOUND': {
- 'id': 'PBNXAC',
- 'template': "No getter named '#{memberName}' in class '#{className}'.",
- },
-
- 'NOT_CALLABLE': {
- 'id': 'SEMKJO',
- 'template': "'#{elementName}' is not callable.",
- },
-
- 'MEMBER_NOT_STATIC': {
- 'id': 'QIOISX',
- 'template': "'#{className}.#{memberName}' is not static.",
- },
-
- 'NO_INSTANCE_AVAILABLE': {
- 'id': 'FQPYLR',
- 'template': "'#{name}' is only available in instance methods.",
- },
-
- 'NO_THIS_AVAILABLE': {
- 'id': 'LXPXKG',
- 'template': "'this' is only available in instance methods.",
- },
-
- 'PRIVATE_ACCESS': {
- 'id': 'DIMHCR',
- 'template': "'#{name}' is declared private within library "
- "'#{libraryName}'.",
- },
-
- 'THIS_IS_THE_DECLARATION': {
- 'id': 'YIJWTO',
- 'template': "This is the declaration of '#{name}'.",
- },
-
- 'THIS_IS_THE_METHOD': {
- 'id': 'PYXWLF',
- 'template': "This is the method declaration.",
- },
-
- 'CANNOT_RESOLVE': {'id': 'SPVJYO', 'template': "Cannot resolve '#{name}'.",},
-
- 'CANNOT_RESOLVE_AWAIT': {
- 'id': 'YQYLRS',
- 'template': "Cannot resolve '#{name}'.",
- 'howToFix': "Did you mean to add the 'async' marker "
- "to '#{functionName}'?",
- 'examples': ["main() => await -3;", "foo() => await -3; main() => foo();"],
- },
-
- 'CANNOT_RESOLVE_AWAIT_IN_CLOSURE': {
- 'id': 'SIXRAA',
- 'template': "Cannot resolve '#{name}'.",
- 'howToFix': "Did you mean to add the 'async' marker "
- "to the enclosing function?",
- 'examples': ["main() { (() => await -3)(); }",],
- },
-
- 'CANNOT_RESOLVE_IN_INITIALIZER': {
- 'id': 'VVEQFD',
- 'template':
- "Cannot resolve '#{name}'. It would be implicitly looked up on this "
- "instance, but instances are not available in initializers.",
- 'howToFix': "Try correcting the unresolved reference or move the "
- "initialization to a constructor body.",
- 'examples': [
- """
-class A {
-var test = unresolvedName;
-}
-main() => new A();
-"""
- ],
- },
-
- 'CANNOT_RESOLVE_CONSTRUCTOR': {
- 'id': 'QRPATN',
- 'template': "Cannot resolve constructor '#{constructorName}'.",
- },
-
- 'CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT': {
- 'id': 'IFKCHF',
- 'template': "cannot resolve constructor '#{constructorName}' "
- "for implicit super call.",
- 'howToFix': "Try explicitly invoking a constructor of the super class",
- 'examples': [
- """
-class A {
-A.foo() {}
-}
-class B extends A {
-B();
-}
-main() => new B();
-"""
- ],
- },
-
- 'INVALID_UNNAMED_CONSTRUCTOR_NAME': {
- 'id': 'VPJLVI',
- 'template': "Unnamed constructor name must be '#{name}'.",
- },
-
- 'INVALID_CONSTRUCTOR_NAME': {
- 'id': 'LMDCAS',
- 'template': "Constructor name must start with '#{name}'.",
- },
-
- 'CANNOT_RESOLVE_TYPE': {
- 'id': 'PQIAPG',
- 'template': "Cannot resolve type '#{typeName}'.",
- },
-
- 'DUPLICATE_DEFINITION': {
- 'id': 'LVTYNW',
- 'template': "Duplicate definition of '#{name}'.",
- 'howToFix': "Try to rename or remove this definition.",
- 'examples': [
- """
-class C {
-void f() {}
-int get f => 1;
-}
-
-main() {
-new C();
-}
-
-"""
- ],
- },
-
- 'EXISTING_DEFINITION': {
- 'id': 'DAUYKK',
- 'template': "Existing definition of '#{name}'.",
- },
-
- 'DUPLICATE_IMPORT': {
- 'id': 'KYJFJN',
- 'template': "Duplicate import of '#{name}'.",
- },
-
- 'HIDDEN_IMPORT': {
- 'id': 'ACRDPR',
- 'template': "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
- "from library '#{hidingUri}'.",
- 'howToFix': "Try adding 'hide #{name}' to the import of '#{hiddenUri}'.",
- 'examples': [
- {
- 'main.dart': """
-import 'dart:async'; // This imports a class Future.
-import 'future.dart';
-
-void main() => new Future();""",
- 'future.dart': """
-library future;
-
-class Future {}"""
- },
- {
- 'main.dart': """
-import 'future.dart';
-import 'dart:async'; // This imports a class Future.
-
-void main() => new Future();""",
- 'future.dart': """
-library future;
-
-class Future {}"""
- },
- {
- 'main.dart': """
-import 'export.dart';
-import 'dart:async'; // This imports a class Future.
-
-void main() => new Future();""",
- 'future.dart': """
-library future;
-
-class Future {}""",
- 'export.dart': """
-library export;
-
-export 'future.dart';"""
- },
- {
- 'main.dart': """
-import 'future.dart' as prefix;
-import 'dart:async' as prefix; // This imports a class Future.
-
-void main() => new prefix.Future();""",
- 'future.dart': """
-library future;
-
-class Future {}"""
- }
- ],
- },
-
- 'HIDDEN_IMPLICIT_IMPORT': {
- 'id': 'WDNFSI',
- 'template': "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
- "from library '#{hidingUri}'.",
- 'howToFix': "Try adding an explicit "
- "'import \"#{hiddenUri}\" hide #{name}'.",
- 'examples': [
- {
- 'main.dart': """
-// This hides the implicit import of class Type from dart:core.
-import 'type.dart';
-
-void main() => new Type();""",
- 'type.dart': """
-library type;
-
-class Type {}"""
- },
- {
- 'conflictsWithDart.dart': """
-library conflictsWithDart;
-
-class Duration {
-static var x = 100;
-}
-""",
- 'conflictsWithDartAsWell.dart': """
-library conflictsWithDartAsWell;
-
-class Duration {
-static var x = 100;
-}
-""",
- 'main.dart': r"""
-library testDartConflicts;
-
-import 'conflictsWithDart.dart';
-import 'conflictsWithDartAsWell.dart';
-
-main() {
-print("Hail Caesar ${Duration.x}");
-}
-"""
- }
- ],
- },
-
- 'DUPLICATE_EXPORT': {
- 'id': 'XGNOCL',
- 'template': "Duplicate export of '#{name}'.",
- 'howToFix': "Try adding 'hide #{name}' to one of the exports.",
- 'examples': [
- {
- 'main.dart': """
-export 'decl1.dart';
-export 'decl2.dart';
-
-main() {}""",
- 'decl1.dart': "class Class {}",
- 'decl2.dart': "class Class {}"
- }
- ],
- },
-
- 'DUPLICATE_EXPORT_CONT': {
- 'id': 'BDROED',
- 'template': "This is another export of '#{name}'.",
- },
-
- 'DUPLICATE_EXPORT_DECL': {
- 'id': 'GFFLMA',
- 'template':
- "The exported '#{name}' from export #{uriString} is defined here.",
- },
-
- 'EMPTY_HIDE': {
- 'id': 'ODFAOC',
- 'template': "Library '#{uri}' doesn't export a '#{name}' declaration.",
- 'howToFix': "Try removing '#{name}' the 'hide' clause.",
- 'examples': [
- {
- 'main.dart': """
-import 'dart:core' hide Foo;
-
-main() {}"""
- },
- {
- 'main.dart': """
-export 'dart:core' hide Foo;
-
-main() {}"""
- },
- ],
- },
-
- 'EMPTY_SHOW': {
- 'id': 'EXONIK',
- 'template': "Library '#{uri}' doesn't export a '#{name}' declaration.",
- 'howToFix': "Try removing '#{name}' from the 'show' clause.",
- 'examples': [
- {
- 'main.dart': """
-import 'dart:core' show Foo;
-
-main() {}"""
- },
- {
- 'main.dart': """
-export 'dart:core' show Foo;
-
-main() {}"""
- },
- ],
- },
-
- 'NOT_A_TYPE': {'id': 'CTTAXD', 'template': "'#{node}' is not a type.",},
-
- 'NOT_A_PREFIX': {'id': 'LKEUMI', 'template': "'#{node}' is not a prefix.",},
-
- 'PREFIX_AS_EXPRESSION': {
- 'id': 'CYIMBJ',
- 'template': "Library prefix '#{prefix}' is not a valid expression.",
- },
-
- 'CANNOT_FIND_CONSTRUCTOR': {
- 'id': 'DROVNH',
- 'template': "Cannot find constructor '#{constructorName}' in class "
- "'#{className}'.",
- },
-
- 'CANNOT_FIND_UNNAMED_CONSTRUCTOR': {
- 'id': 'GDCTGB',
- 'template': "Cannot find unnamed constructor in class "
- "'#{className}'.",
- },
-
- 'CYCLIC_CLASS_HIERARCHY': {
- 'id': 'HKFYOA',
- 'template': "'#{className}' creates a cycle in the class hierarchy.",
- },
-
- 'CYCLIC_REDIRECTING_FACTORY': {
- 'id': 'QGETJC',
- 'template': "Redirecting factory leads to a cyclic redirection.",
- },
-
- 'INVALID_RECEIVER_IN_INITIALIZER': {
- 'id': 'SYUTHA',
- 'template': "Field initializer expected.",
- },
-
- 'NO_SUPER_IN_STATIC': {
- 'id': 'HSCESG',
- 'template': "'super' is only available in instance methods.",
- },
-
- 'DUPLICATE_INITIALIZER': {
- 'id': 'GKVFEP',
- 'template': "Field '#{fieldName}' is initialized more than once.",
- },
-
- 'ALREADY_INITIALIZED': {
- 'id': 'NCRMVD',
- 'template': "'#{fieldName}' was already initialized here.",
- },
-
- 'INIT_STATIC_FIELD': {
- 'id': 'DBSRHA',
- 'template': "Cannot initialize static field '#{fieldName}'.",
- },
-
- 'NOT_A_FIELD': {
- 'id': 'FYEPLC',
- 'template': "'#{fieldName}' is not a field.",
- },
-
- 'CONSTRUCTOR_CALL_EXPECTED': {
- 'id': 'GEJCDX',
- 'template': "only call to 'this' or 'super' constructor allowed.",
- },
-
- 'INVALID_FOR_IN': {
- 'id': 'AUQJBG',
- 'template': "Invalid for-in variable declaration.",
- },
-
- 'INVALID_INITIALIZER': {'id': 'JKUKSA', 'template': "Invalid initializer.",},
-
- 'FUNCTION_WITH_INITIALIZER': {
- 'id': 'BNRDDK',
- 'template': "Only constructors can have initializers.",
- },
-
- 'REDIRECTING_CONSTRUCTOR_CYCLE': {
- 'id': 'CQTMEP',
- 'template': "Cyclic constructor redirection.",
- },
-
- 'REDIRECTING_CONSTRUCTOR_HAS_BODY': {
- 'id': 'WXJQNE',
- 'template': "Redirecting constructor can't have a body.",
- },
-
- 'CONST_CONSTRUCTOR_HAS_BODY': {
- 'id': 'GNEFQG',
- 'template': "Const constructor or factory can't have a body.",
- 'howToFix': "Remove the 'const' keyword or the body",
- 'examples': [
- """
-class C {
-const C() {}
-}
-
-main() => new C();"""
- ],
- },
-
- 'REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER': {
- 'id': 'NUIDSF',
- 'template': "Redirecting constructor cannot have other initializers.",
- },
-
- 'SUPER_INITIALIZER_IN_OBJECT': {
- 'id': 'DXYGND',
- 'template': "'Object' cannot have a super initializer.",
- },
-
- 'DUPLICATE_SUPER_INITIALIZER': {
- 'id': 'FFKOWP',
- 'template': "Cannot have more than one super initializer.",
- },
-
- 'SUPER_CALL_TO_FACTORY': {
- 'id': 'YTOWGV',
- 'template': "The target of the superinitializer must be a generative "
- "constructor.",
- 'howToFix': "Try calling another constructor on the superclass.",
- 'examples': [
- """
-class Super {
-factory Super() => null;
-}
-class Class extends Super {}
-main() => new Class();
-""",
- """
-class Super {
-factory Super() => null;
-}
-class Class extends Super {
-Class();
-}
-main() => new Class();
-""",
- """
-class Super {
-factory Super() => null;
-}
-class Class extends Super {
-Class() : super();
-}
-main() => new Class();
-""",
- """
-class Super {
-factory Super.foo() => null;
-}
-class Class extends Super {
-Class() : super.foo();
-}
-main() => new Class();
-"""
- ],
- },
-
- 'THIS_CALL_TO_FACTORY': {
- 'id': 'JLATDB',
- 'template': "The target of the redirection clause must be a generative "
- "constructor",
- 'howToFix': "Try redirecting to another constructor.",
- 'examples': [
- """
-class Class {
-factory Class() => null;
-Class.foo() : this();
-}
-main() => new Class.foo();
-""",
- """
-class Class {
-factory Class.foo() => null;
-Class() : this.foo();
-}
-main() => new Class();
-"""
- ],
- },
-
- 'INVALID_CONSTRUCTOR_ARGUMENTS': {
- 'id': 'WVPLKL',
- 'template': "Arguments do not match the expected parameters of constructor "
- "'#{constructorName}'.",
- },
-
- 'NO_MATCHING_CONSTRUCTOR': {
- 'id': 'OJQQLE',
- 'template':
- "'super' call arguments and constructor parameters do not match.",
- },
-
- 'NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT': {
- 'id': 'WHCVID',
- 'template': "Implicit 'super' call arguments and constructor parameters "
- "do not match.",
- },
-
- 'CONST_CALLS_NON_CONST': {
- 'id': 'CQFHXC',
- 'template': "'const' constructor cannot call a non-const constructor.",
- },
-
- 'CONST_CALLS_NON_CONST_FOR_IMPLICIT': {
- 'id': 'SFCEXS',
- 'template': "'const' constructor cannot call a non-const constructor. "
- "This constructor has an implicit call to a "
- "super non-const constructor.",
- 'howToFix': "Try making the super constructor const.",
- 'examples': [
- """
-class C {
-C(); // missing const
-}
-class D extends C {
-final d;
-const D(this.d);
-}
-main() => new D(0);"""
- ],
- },
-
- 'CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS': {
- 'id': 'XBHUDL',
- 'template': "Can't declare constructor 'const' on class #{className} "
- "because the class contains non-final instance fields.",
- 'howToFix': "Try making all fields final.",
- 'examples': [
- """
-class C {
-// 'a' must be declared final to allow for the const constructor.
-var a;
-const C(this.a);
-}
-
-main() => new C(0);"""
- ],
- },
-
- 'CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD': {
- 'id': 'YYAHVD',
- 'template': "This non-final field prevents using const constructors.",
- },
-
- 'CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR': {
- 'id': 'FROWJB',
- 'template': "This const constructor is not allowed due to "
- "non-final fields.",
- },
-
- 'INITIALIZING_FORMAL_NOT_ALLOWED': {
- 'id': 'YIPXYP',
- 'template': "Initializing formal parameter only allowed in generative "
- "constructor.",
- },
-
- 'INVALID_PARAMETER': {
- 'id': 'OWWLIX',
- 'template': "Cannot resolve parameter.",
- },
-
- 'NOT_INSTANCE_FIELD': {
- 'id': 'VSPKMU',
- 'template': "'#{fieldName}' is not an instance field.",
- },
-
- 'THIS_PROPERTY': {'id': 'MWFIGH', 'template': "Expected an identifier.",},
-
- 'NO_CATCH_NOR_FINALLY': {
- 'id': 'OPJXPP',
- 'template': "Expected 'catch' or 'finally'.",
- },
-
- 'EMPTY_CATCH_DECLARATION': {
- 'id': 'UNHCPY',
- 'template': "Expected an identifier in catch declaration.",
- },
-
- 'EXTRA_CATCH_DECLARATION': {
- 'id': 'YGGRAK',
- 'template': "Extra parameter in catch declaration.",
- },
-
- 'PARAMETER_WITH_TYPE_IN_CATCH': {
- 'id': 'EXQVDU',
- 'template': "Cannot use type annotations in catch.",
- },
-
- 'PARAMETER_WITH_MODIFIER_IN_CATCH': {
- 'id': 'BQLKRF',
- 'template': "Cannot use modifiers in catch.",
- },
-
- 'OPTIONAL_PARAMETER_IN_CATCH': {
- 'id': 'DAICPP',
- 'template': "Cannot use optional parameters in catch.",
- },
-
- 'THROW_WITHOUT_EXPRESSION': {
- 'id': 'YHACYV',
- 'template': "Cannot use re-throw outside of catch block "
- "(expression expected after 'throw').",
- },
-
- 'UNBOUND_LABEL': {
- 'id': 'GLDXHY',
- 'template': "Cannot resolve label '#{labelName}'.",
- },
-
- 'NO_BREAK_TARGET': {
- 'id': 'VBXXBE',
- 'template': "'break' statement not inside switch or loop.",
- },
-
- 'NO_CONTINUE_TARGET': {
- 'id': 'JTTHHM',
- 'template': "'continue' statement not inside loop.",
- },
-
- 'EXISTING_LABEL': {
- 'id': 'AHCSXF',
- 'template': "Original declaration of duplicate label '#{labelName}'.",
- },
-
- 'DUPLICATE_LABEL': {
- 'id': 'HPULLI',
- 'template': "Duplicate declaration of label '#{labelName}'.",
- },
-
- 'UNUSED_LABEL': {'id': 'KFREJO', 'template': "Unused label '#{labelName}'.",},
-
- 'INVALID_CONTINUE': {
- 'id': 'DSKTPX',
- 'template': "Target of continue is not a loop or switch case.",
- },
-
- 'INVALID_BREAK': {
- 'id': 'MFCCWX',
- 'template': "Target of break is not a statement.",
- },
-
- 'DUPLICATE_TYPE_VARIABLE_NAME': {
- 'id': 'BAYCCM',
- 'template': "Type variable '#{typeVariableName}' already declared.",
- },
-
- 'TYPE_VARIABLE_WITHIN_STATIC_MEMBER': {
- 'id': 'XQLXRL',
- 'template': "Cannot refer to type variable '#{typeVariableName}' "
- "within a static member.",
- },
-
- 'TYPE_VARIABLE_IN_CONSTANT': {
- 'id': 'ANDEVG',
- 'template': "Constant expressions can't refer to type variables.",
- 'howToFix': "Try removing the type variable or replacing it with a "
- "concrete type.",
- 'examples': [
- """
-class C<T> {
-const C();
-
-m(T t) => const C<T>();
-}
-
-void main() => new C().m(null);
-"""
- ],
- },
-
- 'INVALID_TYPE_VARIABLE_BOUND': {
- 'id': 'WQAEDK',
- 'template': "'#{typeArgument}' is not a subtype of bound '#{bound}' for "
- "type variable '#{typeVariable}' of type '#{thisType}'.",
- 'howToFix': "Try to change or remove the type argument.",
- 'examples': [
- """
-class C<T extends num> {}
-
-// 'String' is not a valid instantiation of T with bound num.'.
-main() => new C<String>();
-"""
- ],
- },
-
- 'INVALID_USE_OF_SUPER': {
- 'id': 'JKYYSN',
- 'template': "'super' not allowed here.",
- },
-
- 'INVALID_CASE_DEFAULT': {
- 'id': 'ABSPBM',
- 'template': "'default' only allowed on last case of a switch.",
- },
-
- 'SWITCH_CASE_TYPES_NOT_EQUAL': {
- 'id': 'UFQPBC',
- 'template': "'case' expressions do not all have type '#{type}'.",
- },
-
- 'SWITCH_CASE_TYPES_NOT_EQUAL_CASE': {
- 'id': 'RDMVAC',
- 'template': "'case' expression of type '#{type}'.",
- },
-
- 'SWITCH_CASE_FORBIDDEN': {
- 'id': 'UHSCSU',
- 'template': "'case' expression may not be of type '#{type}'.",
- },
-
- 'SWITCH_CASE_VALUE_OVERRIDES_EQUALS': {
- 'id': 'NRTWXL',
- 'template': "'case' expression type '#{type}' overrides 'operator =='.",
- },
-
- 'INVALID_ARGUMENT_AFTER_NAMED': {
- 'id': 'WAJURC',
- 'template': "Unnamed argument after named argument.",
- },
-
- 'NOT_A_COMPILE_TIME_CONSTANT': {
- 'id': 'SBCHWL',
- 'template': "Not a compile-time constant.",
- },
-
- 'DEFERRED_COMPILE_TIME_CONSTANT': {
- 'id': 'FHXTCK',
- 'template': "A deferred value cannot be used as a compile-time constant.",
- },
-
- 'DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION': {
- 'id': 'TSBXLG',
- 'template': "A deferred class cannot be used to create a "
- "compile-time constant.",
- },
-
- 'CYCLIC_COMPILE_TIME_CONSTANTS': {
- 'id': 'JJWJYE',
- 'template': "Cycle in the compile-time constant computation.",
- },
-
- 'CONSTRUCTOR_IS_NOT_CONST': {
- 'id': 'DOJCUX',
- 'template': "Constructor is not a 'const' constructor.",
- },
-
- 'CONST_MAP_KEY_OVERRIDES_EQUALS': {
- 'id': 'VJNWEL',
- 'template': "Const-map key type '#{type}' overrides 'operator =='.",
- },
-
- 'NO_SUCH_LIBRARY_MEMBER': {
- 'id': 'IOXVBA',
- 'template': "'#{libraryName}' has no member named '#{memberName}'.",
- },
-
- 'CANNOT_INSTANTIATE_TYPEDEF': {
- 'id': 'KOYNMU',
- 'template': "Cannot instantiate typedef '#{typedefName}'.",
- },
-
- 'REQUIRED_PARAMETER_WITH_DEFAULT': {
- 'id': 'CJWECI',
- 'template': "Non-optional parameters can't have a default value.",
- 'howToFix':
- "Try removing the default value or making the parameter optional.",
- 'examples': [
- """
-main() {
-foo(a: 1) => print(a);
-foo(2);
-}""",
- """
-main() {
-foo(a = 1) => print(a);
-foo(2);
-}"""
- ],
- },
-
- 'NAMED_PARAMETER_WITH_EQUALS': {
- 'id': 'RPJDXD',
- 'template': "Named optional parameters can't use '=' to specify a default "
- "value.",
- 'howToFix': "Try replacing '=' with ':'.",
- 'examples': [
- """
-main() {
-foo({a = 1}) => print(a);
-foo(a: 2);
-}"""
- ],
- },
-
- 'POSITIONAL_PARAMETER_WITH_EQUALS': {
- 'id': 'JMSSDX',
- 'template': "Positional optional parameters can't use ':' to specify a "
- "default value.",
- 'howToFix': "Try replacing ':' with '='.",
- 'examples': [
- """
-main() {
-foo([a: 1]) => print(a);
-foo(2);
-}"""
- ],
- },
-
- 'TYPEDEF_FORMAL_WITH_DEFAULT': {
- 'id': 'NABHHS',
- 'template': "A parameter of a typedef can't specify a default value.",
- 'howToFix': "Try removing the default value.",
- 'examples': [
- """
-typedef void F([int arg = 0]);
-
-main() {
-F f;
-}""",
- """
-typedef void F({int arg: 0});
-
-main() {
-F f;
-}"""
- ],
- },
-
- 'FUNCTION_TYPE_FORMAL_WITH_DEFAULT': {
- 'id': 'APKYLU',
- 'template': "A function type parameter can't specify a default value.",
- 'howToFix': "Try removing the default value.",
- 'examples': [
- """
-foo(f(int i, [a = 1])) {}
-
-main() {
-foo(1, 2);
-}""",
- """
-foo(f(int i, {a: 1})) {}
-
-main() {
-foo(1, a: 2);
-}"""
- ],
- },
-
- 'REDIRECTING_FACTORY_WITH_DEFAULT': {
- 'id': 'AWSSEY',
- 'template':
- "A parameter of a redirecting factory constructor can't specify a "
- "default value.",
- 'howToFix': "Try removing the default value.",
- 'examples': [
- """
-class A {
-A([a]);
-factory A.foo([a = 1]) = A;
-}
-
-main() {
-new A.foo(1);
-}""",
- """
-class A {
-A({a});
-factory A.foo({a: 1}) = A;
-}
-
-main() {
-new A.foo(a: 1);
-}"""
- ],
- },
-
- 'FORMAL_DECLARED_CONST': {
- 'id': 'AVPRDK',
- 'template': "A formal parameter can't be declared const.",
- 'howToFix': "Try removing 'const'.",
- 'examples': [
- """
-foo(const x) {}
-main() => foo(42);
-""",
- """
-foo({const x}) {}
-main() => foo(42);
-""",
- """
-foo([const x]) {}
-main() => foo(42);
-"""
- ],
- },
-
- 'FORMAL_DECLARED_STATIC': {
- 'id': 'PJKDMX',
- 'template': "A formal parameter can't be declared static.",
- 'howToFix': "Try removing 'static'.",
- 'examples': [
- """
-foo(static x) {}
-main() => foo(42);
-""",
- """
-foo({static x}) {}
-main() => foo(42);
-""",
- """
-foo([static x]) {}
-main() => foo(42);
-"""
- ],
- },
-
- 'FINAL_FUNCTION_TYPE_PARAMETER': {
- 'id': 'JIOPIQ',
- 'template': "A function type parameter can't be declared final.",
- 'howToFix': "Try removing 'final'.",
- 'examples': [
- """
-foo(final int x(int a)) {}
-main() => foo((y) => 42);
-""",
- """
-foo({final int x(int a)}) {}
-main() => foo((y) => 42);
-""",
- """
-foo([final int x(int a)]) {}
-main() => foo((y) => 42);
-"""
- ],
- },
-
- 'VAR_FUNCTION_TYPE_PARAMETER': {
- 'id': 'FOQOHK',
- 'template': "A function type parameter can't be declared with 'var'.",
- 'howToFix': "Try removing 'var'.",
- 'examples': [
- """
-foo(var int x(int a)) {}
-main() => foo((y) => 42);
-""",
- """
-foo({var int x(int a)}) {}
-main() => foo((y) => 42);
-""",
- """
-foo([var int x(int a)]) {}
-main() => foo((y) => 42);
-"""
- ],
- },
-
- 'CANNOT_INSTANTIATE_TYPE_VARIABLE': {
- 'id': 'JAYHCH',
- 'template': "Cannot instantiate type variable '#{typeVariableName}'.",
- },
-
- 'CYCLIC_TYPE_VARIABLE': {
- 'id': 'RQMPSO',
- 'template': "Type variable '#{typeVariableName}' is a supertype of itself.",
- },
-
- 'CYCLIC_TYPEDEF': {
- 'id': 'VFERCQ',
- 'template': "A typedef can't refer to itself.",
- 'howToFix': "Try removing all references to '#{typedefName}' "
- "in the definition of '#{typedefName}'.",
- 'examples': [
- """
-typedef F F(); // The return type 'F' is a self-reference.
-main() { F f = null; }"""
- ],
- },
-
- 'CYCLIC_TYPEDEF_ONE': {
- 'id': 'ASWLWR',
- 'template': "A typedef can't refer to itself through another typedef.",
- 'howToFix': "Try removing all references to "
- "'#{otherTypedefName}' in the definition of '#{typedefName}'.",
- 'examples': [
- """
-typedef G F(); // The return type 'G' is a self-reference through typedef 'G'.
-typedef F G(); // The return type 'F' is a self-reference through typedef 'F'.
-main() { F f = null; }""",
- """
-typedef G F(); // The return type 'G' creates a self-reference.
-typedef H G(); // The return type 'H' creates a self-reference.
-typedef H(F f); // The argument type 'F' creates a self-reference.
-main() { F f = null; }"""
- ],
- },
-
- 'CLASS_NAME_EXPECTED': {'id': 'DPKNHY', 'template': "Class name expected.",},
-
- 'CANNOT_EXTEND': {
- 'id': 'GCIQXD',
- 'template': "'#{type}' cannot be extended.",
- },
-
- 'CANNOT_IMPLEMENT': {
- 'id': 'IBOQKV',
- 'template': "'#{type}' cannot be implemented.",
- },
-
- // TODO(johnnwinther): Split messages into reasons for malformedness.
- 'CANNOT_EXTEND_MALFORMED': {
- 'id': 'YPFJBD',
- 'template': "Class '#{className}' can't extend the type '#{malformedType}' "
- "because it is malformed.",
- 'howToFix': "Try correcting the malformed type annotation or removing the "
- "'extends' clause.",
- 'examples': [
- """
-class A extends Malformed {}
-main() => new A();"""
- ],
- },
-
- 'CANNOT_IMPLEMENT_MALFORMED': {
- 'id': 'XJUIAQ',
- 'template':
- "Class '#{className}' can't implement the type '#{malformedType}' "
- "because it is malformed.",
- 'howToFix': "Try correcting the malformed type annotation or removing the "
- "type from the 'implements' clause.",
- 'examples': [
- """
-class A implements Malformed {}
-main() => new A();"""
- ],
- },
-
- 'CANNOT_MIXIN_MALFORMED': {
- 'id': 'SSMNXN',
- 'template': "Class '#{className}' can't mixin the type '#{malformedType}' "
- "because it is malformed.",
- 'howToFix': "Try correcting the malformed type annotation or removing the "
- "type from the 'with' clause.",
- 'examples': [
- """
-class A extends Object with Malformed {}
-main() => new A();"""
- ],
- },
-
- 'CANNOT_MIXIN': {
- 'id': 'KLSXDQ',
- 'template': "The type '#{type}' can't be mixed in.",
- 'howToFix': "Try removing '#{type}' from the 'with' clause.",
- 'examples': [
- """
-class C extends Object with String {}
-
-main() => new C();
-""",
- """
-typedef C = Object with String;
-
-main() => new C();
-"""
- ],
- },
-
- 'CANNOT_EXTEND_ENUM': {
- 'id': 'JEPRST',
- 'template':
- "Class '#{className}' can't extend the type '#{enumType}' because "
- "it is declared by an enum.",
- 'howToFix': "Try making '#{enumType}' a normal class or removing the "
- "'extends' clause.",
- 'examples': [
- """
-enum Enum { A }
-class B extends Enum {}
-main() => new B();"""
- ],
- },
-
- 'CANNOT_IMPLEMENT_ENUM': {
- 'id': 'JMJMSH',
- 'template': "Class '#{className}' can't implement the type '#{enumType}' "
- "because it is declared by an enum.",
- 'howToFix': "Try making '#{enumType}' a normal class or removing the "
- "type from the 'implements' clause.",
- 'examples': [
- """
-enum Enum { A }
-class B implements Enum {}
-main() => new B();"""
- ],
- },
-
- 'CANNOT_MIXIN_ENUM': {
- 'id': 'YSYDIM',
- 'template':
- "Class '#{className}' can't mixin the type '#{enumType}' because it "
- "is declared by an enum.",
- 'howToFix': "Try making '#{enumType}' a normal class or removing the "
- "type from the 'with' clause.",
- 'examples': [
- """
-enum Enum { A }
-class B extends Object with Enum {}
-main() => new B();"""
- ],
- },
-
- 'CANNOT_INSTANTIATE_ENUM': {
- 'id': 'CQYIFU',
- 'template': "Enum type '#{enumName}' cannot be instantiated.",
- 'howToFix': "Try making '#{enumType}' a normal class or use an enum "
- "constant.",
- 'examples': [
- """
-enum Enum { A }
-main() => new Enum(0);""",
- """
-enum Enum { A }
-main() => const Enum(0);"""
- ],
- },
-
- 'EMPTY_ENUM_DECLARATION': {
- 'id': 'JFPDOH',
- 'template': "Enum '#{enumName}' must contain at least one value.",
- 'howToFix': "Try adding an enum constant or making #{enumName} a "
- "normal class.",
- 'examples': [
- """
-enum Enum {}
-main() { Enum e; }"""
- ],
- },
-
- 'MISSING_ENUM_CASES': {
- 'id': 'HHEOIW',
- 'template': "Missing enum constants in switch statement: #{enumValues}.",
- 'howToFix': "Try adding the missing constants or a default case.",
- 'examples': [
- """
-enum Enum { A, B }
-main() {
-switch (Enum.A) {
-case Enum.B: break;
-}
-}""",
- """
-enum Enum { A, B, C }
-main() {
-switch (Enum.A) {
-case Enum.B: break;
-}
-}"""
- ],
- },
-
- 'DUPLICATE_EXTENDS_IMPLEMENTS': {
- 'id': 'BKRKEO',
- 'template': "'#{type}' can not be both extended and implemented.",
- },
-
- 'DUPLICATE_IMPLEMENTS': {
- 'id': 'IWJFTU',
- 'template': "'#{type}' must not occur more than once "
- "in the implements clause.",
- },
-
- 'MULTI_INHERITANCE': {
- 'id': 'NWXGOI',
- 'template':
- "Dart2js does not currently support inheritance of the same class "
- "with different type arguments: Both #{firstType} and #{secondType} "
- "are supertypes of #{thisType}.",
- },
-
- 'ILLEGAL_SUPER_SEND': {
- 'id': 'LDRGIU',
- 'template': "'#{name}' cannot be called on super.",
- },
-
- 'NO_SUCH_SUPER_MEMBER': {
- 'id': 'HIJJVG',
- 'template':
- "Cannot resolve '#{memberName}' in a superclass of '#{className}'.",
- },
-
- 'ADDITIONAL_TYPE_ARGUMENT': {
- 'id': 'HWYHWH',
- 'template': "Additional type argument.",
- },
-
- 'MISSING_TYPE_ARGUMENT': {
- 'id': 'KYTQWA',
- 'template': "Missing type argument.",
- },
-
- // TODO(johnniwinther): Use ADDITIONAL_TYPE_ARGUMENT or
- // MISSING_TYPE_ARGUMENT instead.
- 'TYPE_ARGUMENT_COUNT_MISMATCH': {
- 'id': 'ECXGRM',
- 'template': "Incorrect number of type arguments on '#{type}'.",
- },
-
- 'GETTER_MISMATCH': {
- 'id': 'MNODFW',
- 'template': "Setter disagrees on: '#{modifiers}'.",
- },
-
- 'SETTER_MISMATCH': {
- 'id': 'FMNHPL',
- 'template': "Getter disagrees on: '#{modifiers}'.",
- },
-
- 'ILLEGAL_SETTER_FORMALS': {
- 'id': 'COTPVN',
- 'template': "A setter must have exactly one argument.",
- },
-
- 'NO_STATIC_OVERRIDE': {
- 'id': 'EHINXB',
- 'template':
- "Static member cannot override instance member '#{memberName}' of "
- "'#{className}'.",
- },
-
- 'NO_STATIC_OVERRIDE_CONT': {
- 'id': 'TEVJMA',
- 'template': "This is the instance member that cannot be overridden "
- "by a static member.",
- },
-
- 'INSTANCE_STATIC_SAME_NAME': {
- 'id': 'LTBFBO',
- 'template': "Instance member '#{memberName}' and static member of "
- "superclass '#{className}' have the same name.",
- },
-
- 'INSTANCE_STATIC_SAME_NAME_CONT': {
- 'id': 'CHSUCQ',
- 'template': "This is the static member with the same name.",
- },
-
- 'INVALID_OVERRIDE_METHOD': {
- 'id': 'NINKPI',
- 'template': "The type '#{declaredType}' of method '#{name}' declared in "
- "'#{class}' is not a subtype of the overridden method type "
- "'#{inheritedType}' inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDDEN_METHOD': {
- 'id': 'BQHUPY',
- 'template': "This is the overridden method '#{name}' declared in class "
- "'#{class}'.",
- },
-
- 'INVALID_OVERRIDE_GETTER': {
- 'id': 'KLMPWO',
- 'template': "The type '#{declaredType}' of getter '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden getter inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDDEN_GETTER': {
- 'id': 'ASSKCT',
- 'template': "This is the overridden getter '#{name}' declared in class "
- "'#{class}'.",
- },
-
- 'INVALID_OVERRIDE_GETTER_WITH_FIELD': {
- 'id': 'TCCGXU',
- 'template': "The type '#{declaredType}' of field '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden getter inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDE_FIELD_WITH_GETTER': {
- 'id': 'UMMEXO',
- 'template': "The type '#{declaredType}' of getter '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden field inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDE_SETTER': {
- 'id': 'BWRGEC',
- 'template': "The type '#{declaredType}' of setter '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden setter inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDDEN_SETTER': {
- 'id': 'XQUOLL',
- 'template': "This is the overridden setter '#{name}' declared in class "
- "'#{class}'.",
- },
-
- 'INVALID_OVERRIDE_SETTER_WITH_FIELD': {
- 'id': 'GKGOFA',
- 'template': "The type '#{declaredType}' of field '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden setter inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDE_FIELD_WITH_SETTER': {
- 'id': 'OOXKHQ',
- 'template': "The type '#{declaredType}' of setter '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden field inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDE_FIELD': {
- 'id': 'LDPKOL',
- 'template': "The type '#{declaredType}' of field '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden field inherited from '#{inheritedClass}'.",
- },
-
- 'INVALID_OVERRIDDEN_FIELD': {
- 'id': 'UNQFWX',
- 'template': "This is the overridden field '#{name}' declared in class "
- "'#{class}'.",
- },
-
- 'CANNOT_OVERRIDE_FIELD_WITH_METHOD': {
- 'id': 'SYKCSK',
- 'template': "Method '#{name}' in '#{class}' can't override field from "
- "'#{inheritedClass}'.",
- },
-
- 'CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT': {
- 'id': 'HYHQSO',
- 'template': "This is the field that cannot be overridden by a method.",
- },
-
- 'CANNOT_OVERRIDE_METHOD_WITH_FIELD': {
- 'id': 'UROMAS',
- 'template': "Field '#{name}' in '#{class}' can't override method from "
- "'#{inheritedClass}'.",
- },
-
- 'CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT': {
- 'id': 'NSORYS',
- 'template': "This is the method that cannot be overridden by a field.",
- },
-
- 'CANNOT_OVERRIDE_GETTER_WITH_METHOD': {
- 'id': 'MMFIOH',
- 'template': "Method '#{name}' in '#{class}' can't override getter from "
- "'#{inheritedClass}'.",
- },
-
- 'CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT': {
- 'id': 'YGWPDH',
- 'template': "This is the getter that cannot be overridden by a method.",
- },
-
- 'CANNOT_OVERRIDE_METHOD_WITH_GETTER': {
- 'id': 'BNKNXO',
- 'template': "Getter '#{name}' in '#{class}' can't override method from "
- "'#{inheritedClass}'.",
- },
-
- 'CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT': {
- 'id': 'KFBCYX',
- 'template': "This is the method that cannot be overridden by a getter.",
- },
-
- 'MISSING_FORMALS': {
- 'id': 'BOERAF',
- 'template': "Formal parameters are missing.",
- },
-
- 'EXTRA_FORMALS': {
- 'id': 'UTWRIU',
- 'template': "Formal parameters are not allowed here.",
- },
-
- 'UNARY_OPERATOR_BAD_ARITY': {
- 'id': 'TNHLAL',
- 'template': "Operator '#{operatorName}' must have no parameters.",
- },
-
- 'MINUS_OPERATOR_BAD_ARITY': {
- 'id': 'SXDRRU',
- 'template': "Operator '-' must have 0 or 1 parameters.",
- },
-
- 'BINARY_OPERATOR_BAD_ARITY': {
- 'id': 'QKWAUM',
- 'template': "Operator '#{operatorName}' must have exactly 1 parameter.",
- },
-
- 'TERNARY_OPERATOR_BAD_ARITY': {
- 'id': 'LSMQGF',
- 'template': "Operator '#{operatorName}' must have exactly 2 parameters.",
- },
-
- 'OPERATOR_OPTIONAL_PARAMETERS': {
- 'id': 'HSGRBV',
- 'template': "Operator '#{operatorName}' cannot have optional parameters.",
- },
-
- 'OPERATOR_NAMED_PARAMETERS': {
- 'id': 'EACWGS',
- 'template': "Operator '#{operatorName}' cannot have named parameters.",
- },
-
- 'CONSTRUCTOR_WITH_RETURN_TYPE': {
- 'id': 'OPMBHF',
- 'template': "Cannot have return type for constructor.",
- },
-
- 'CANNOT_RETURN_FROM_CONSTRUCTOR': {
- 'id': 'NFUGNH',
- 'template': "Constructors can't return values.",
- 'howToFix': "Remove the return statement or use a factory constructor.",
- 'examples': [
- """
-class C {
-C() {
- return 1;
-}
-}
-
-main() => new C();"""
- ],
- },
-
- 'ILLEGAL_FINAL_METHOD_MODIFIER': {
- 'id': 'YUKCVU',
- 'template': "Cannot have final modifier on method.",
- },
-
- 'ILLEGAL_CONST_FIELD_MODIFIER': {
- 'id': 'JGFAGV',
- 'template': "Cannot have const modifier on non-static field.",
- 'howToFix': "Try adding a static modifier, or removing the const modifier.",
- 'examples': [
- """
-class C {
-const int a = 1;
-}
-
-main() => new C();"""
- ],
- },
-
- 'ILLEGAL_CONSTRUCTOR_MODIFIERS': {
- 'id': 'WODRHN',
- 'template': "Illegal constructor modifiers: '#{modifiers}'.",
- },
-
- 'ILLEGAL_MIXIN_APPLICATION_MODIFIERS': {
- 'id': 'OFLFHN',
- 'template': "Illegal mixin application modifiers: '#{modifiers}'.",
- },
-
- 'ILLEGAL_MIXIN_SUPERCLASS': {
- 'id': 'TPVVYN',
- 'template': "Class used as mixin must have Object as superclass.",
- },
-
- 'ILLEGAL_MIXIN_OBJECT': {
- 'id': 'CMVTLF',
- 'template': "Cannot use Object as mixin.",
- },
-
- 'ILLEGAL_MIXIN_CONSTRUCTOR': {
- 'id': 'HXBUIB',
- 'template': "Class used as mixin cannot have non-factory constructor.",
- },
-
- 'ILLEGAL_MIXIN_CYCLE': {
- 'id': 'ANXAMU',
- 'template': "Class used as mixin introduces mixin cycle: "
- "'#{mixinName1}' <-> '#{mixinName2}'.",
- },
-
- 'ILLEGAL_MIXIN_WITH_SUPER': {
- 'id': 'KIEUGK',
- 'template': "Cannot use class '#{className}' as a mixin because it uses "
- "'super'.",
- },
-
- 'ILLEGAL_MIXIN_SUPER_USE': {
- 'id': 'QKUPLH',
- 'template': "Use of 'super' in class used as mixin.",
- },
-
- 'PARAMETER_NAME_EXPECTED': {
- 'id': 'JOUOBT',
- 'template': "parameter name expected.",
- },
-
- 'CANNOT_RESOLVE_GETTER': {
- 'id': 'TDHKSW',
- 'template': "Cannot resolve getter.",
- },
-
- 'CANNOT_RESOLVE_SETTER': {
- 'id': 'QQFANP',
- 'template': "Cannot resolve setter.",
- },
-
- 'ASSIGNING_FINAL_FIELD_IN_SUPER': {
- 'id': 'LXUPCC',
- 'template': "Cannot assign a value to final field '#{name}' "
- "in superclass '#{superclassName}'.",
- },
-
- 'ASSIGNING_METHOD': {
- 'id': 'JUVMYC',
- 'template': "Cannot assign a value to a method.",
- },
-
- 'ASSIGNING_METHOD_IN_SUPER': {
- 'id': 'AGMAXN',
- 'template': "Cannot assign a value to method '#{name}' "
- "in superclass '#{superclassName}'.",
- },
-
- 'ASSIGNING_TYPE': {
- 'id': 'VXTPWE',
- 'template': "Cannot assign a value to a type.",
- },
-
- 'IF_NULL_ASSIGNING_TYPE': {
- 'id': 'XBRHGK',
- 'template':
- "Cannot assign a value to a type. Note that types are never null, "
- "so this ??= assignment has no effect.",
- 'howToFix': "Try removing the '??=' assignment.",
- 'examples': ["class A {} main() { print(A ??= 3);}",],
- },
-
- 'VOID_NOT_ALLOWED': {
- 'id': 'DMMDXT',
- 'template':
- "Type 'void' can't be used here because it isn't a return type.",
- 'howToFix':
- "Try removing 'void' keyword or replace it with 'var', 'final', "
- "or a type.",
- 'examples': ["void x; main() {}", "foo(void x) {} main() { foo(null); }",],
- },
-
- 'NULL_NOT_ALLOWED': {
- 'id': 'STYNSK',
- 'template': "`null` can't be used here.",
- },
-
- 'BEFORE_TOP_LEVEL': {
- 'id': 'GRCXQF',
- 'template': "Part header must come before top-level definitions.",
- },
-
- 'IMPORT_PART_OF': {
- 'id': 'VANCWE',
- 'template': "The imported library must not have a 'part-of' directive.",
- 'howToFix': "Try removing the 'part-of' directive or replacing the "
- "import of the library with a 'part' directive.",
- 'examples': [
- {
- 'main.dart': """
-library library;
-
-import 'part.dart';
-
-main() {}
-""",
- 'part.dart': """
-part of library;
-"""
- }
- ],
- },
-
- 'IMPORT_PART_OF_HERE': {
- 'id': 'TRSZOJ',
- 'template': 'The library is imported here.',
- },
-
- 'MAIN_HAS_PART_OF': {
- 'id': 'MFMRRL',
- 'template': "The main application file must not have a 'part-of' "
- "directive.",
- 'howToFix': "Try removing the 'part-of' directive or starting compilation "
- "from another file.",
- 'examples': [
- {
- 'main.dart': """
-part of library;
-
-main() {}
-"""
- }
- ],
- },
-
- 'LIBRARY_NAME_MISMATCH': {
- 'id': 'AXGYPQ',
- 'template': "Expected part of library name '#{libraryName}'.",
- 'howToFix': "Try changing the directive to 'part of #{libraryName};'.",
- 'examples': [
- {
- 'main.dart': """
-library lib.foo;
-
-part 'part.dart';
-
-main() {}
-""",
- 'part.dart': """
-part of lib.bar;
-"""
- }
- ],
- },
-
- 'MISSING_LIBRARY_NAME': {
- 'id': 'NYQNCA',
- 'template': "Library has no name. Part directive expected library name "
- "to be '#{libraryName}'.",
- 'howToFix': "Try adding 'library #{libraryName};' to the library.",
- 'examples': [
- {
- 'main.dart': """
-part 'part.dart';
-
-main() {}
-""",
- 'part.dart': """
-part of lib.foo;
-"""
- }
- ],
- },
-
- 'THIS_IS_THE_PART_OF_TAG': {
- 'id': 'RPSJRS',
- 'template': "This is the part of directive.",
- },
-
- 'MISSING_PART_OF_TAG': {
- 'id': 'QNYCMV',
- 'template': "This file has no part-of tag, but it is being used as a part.",
- },
-
- 'DUPLICATED_PART_OF': {
- 'id': 'UJDYHF',
- 'template': "Duplicated part-of directive.",
- },
-
- 'DUPLICATED_LIBRARY_NAME': {
- 'id': 'OSEHXI',
- 'template': "Duplicated library name '#{libraryName}'.",
- },
-
- 'DUPLICATED_RESOURCE': {
- 'id': 'UFWKBY',
- 'template': "The resource '#{resourceUri}' is loaded through both "
- "'#{canonicalUri1}' and '#{canonicalUri2}'.",
- },
-
- 'DUPLICATED_LIBRARY_RESOURCE': {
- 'id': 'KYGYTT',
- 'template':
- "The library '#{libraryName}' in '#{resourceUri}' is loaded through "
- "both '#{canonicalUri1}' and '#{canonicalUri2}'.",
- },
-
- // This is used as an exception.
- 'INVALID_SOURCE_FILE_LOCATION': {
- 'id': 'WIGJFG',
- 'template': """
-Invalid offset (#{offset}) in source map.
-File: #{fileName}
-Length: #{length}""",
- },
-
- 'TOP_LEVEL_VARIABLE_DECLARED_STATIC': {
- 'id': 'IVNDML',
- 'template': "Top-level variable cannot be declared static.",
- },
-
- 'REFERENCE_IN_INITIALIZATION': {
- 'id': 'OVWTEU',
- 'template': "Variable '#{variableName}' is referenced during its "
- "initialization.",
- 'howToFix': "If you are trying to reference a shadowed variable, rename "
- "one of the variables.",
- 'examples': [
- """
-foo(t) {
-var t = t;
-return t;
-}
-
-main() => foo(1);
-"""
- ],
- },
-
- 'CONST_WITHOUT_INITIALIZER': {
- 'id': 'UDWCNH',
- 'template': "A constant variable must be initialized.",
- 'howToFix': "Try adding an initializer or "
- "removing the 'const' modifier.",
- 'examples': [
- """
-void main() {
-const c; // This constant variable must be initialized.
-}"""
- ],
- },
-
- 'FINAL_WITHOUT_INITIALIZER': {
- 'id': 'YMESFI',
- 'template': "A final variable must be initialized.",
- 'howToFix': "Try adding an initializer or "
- "removing the 'final' modifier.",
- 'examples': ["class C { static final field; } main() => C.field;"],
- },
-
- 'CONST_LOOP_VARIABLE': {
- 'id': 'WUSKMG',
- 'template': "A loop variable cannot be constant.",
- 'howToFix': "Try remove the 'const' modifier or "
- "replacing it with a 'final' modifier.",
- 'examples': [
- """
-void main() {
- for (const c in []) {}
-}"""
- ],
- },
-
- 'MEMBER_USES_CLASS_NAME': {
- 'id': 'TVFYRK',
- 'template': "Member variable can't have the same name as the class it is "
- "declared in.",
- 'howToFix': "Try renaming the variable.",
- 'examples': [
- """
-class A { var A; }
-main() {
-var a = new A();
-a.A = 1;
-}
-""",
- """
-class A { static var A; }
-main() => A.A = 1;
-"""
- ],
- },
-
- 'WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT': {
- 'id': 'IXYNUF',
- 'template': "Wrong number of arguments to assert. Should be 1, but given "
- "#{argumentCount}.",
- },
-
- 'ASSERT_IS_GIVEN_NAMED_ARGUMENTS': {
- 'id': 'EJFDTO',
- 'template':
- "'assert' takes no named arguments, but given #{argumentCount}.",
- },
-
- 'FACTORY_REDIRECTION_IN_NON_FACTORY': {
- 'id': 'DTBWEX',
- 'template': "Factory redirection only allowed in factories.",
- },
-
- 'MISSING_FACTORY_KEYWORD': {
- 'id': 'HOQYYA',
- 'template': "Did you forget a factory keyword here?",
- },
-
- 'NO_SUCH_METHOD_IN_NATIVE': {
- 'id': 'MSDDBX',
- 'template':
- "'NoSuchMethod' is not supported for classes that extend native "
- "classes.",
- },
-
- 'DEFERRED_LIBRARY_DART_2_DART': {
- 'id': 'RIRQAH',
- 'template': "Deferred loading is not supported by the dart backend yet. "
- "The output will not be split.",
- },
-
- 'DEFERRED_LIBRARY_WITHOUT_PREFIX': {
- 'id': 'CARRII',
- 'template': "This import is deferred but there is no prefix keyword.",
- 'howToFix': "Try adding a prefix to the import."
- },
-
- 'DEFERRED_OLD_SYNTAX': {
- 'id': 'QCBRAE',
- 'template': "The DeferredLibrary annotation is obsolete.",
- 'howToFix':
- "Use the \"import 'lib.dart' deferred as prefix\" syntax instead.",
- },
-
- 'DEFERRED_LIBRARY_DUPLICATE_PREFIX': {
- 'id': 'BBMJTD',
- 'template': "The prefix of this deferred import is not unique.",
- 'howToFix': "Try changing the import prefix."
- },
-
- 'DEFERRED_TYPE_ANNOTATION': {
- 'id': 'JOUEFD',
- 'template': "The type #{node} is deferred. "
- "Deferred types are not valid as type annotations.",
- 'howToFix': "Try using a non-deferred abstract class as an interface.",
- },
-
- 'ILLEGAL_STATIC': {
- 'id': 'HFBHVE',
- 'template': "Modifier static is only allowed on functions declared in "
- "a class.",
- },
-
- 'STATIC_FUNCTION_BLOAT': {
- 'id': 'SJHTKF',
- 'template': "Using '#{class}.#{name}' may lead to unnecessarily large "
- "generated code.",
- 'howToFix': "Try adding '@MirrorsUsed(...)' as described at "
- "https://goo.gl/Akrrog.",
- },
-
- 'NON_CONST_BLOAT': {
- 'id': 'RDRSHO',
- 'template': "Using 'new #{name}' may lead to unnecessarily large generated "
- "code.",
- 'howToFix': "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
- "described at https://goo.gl/Akrrog.",
- },
-
- 'STRING_EXPECTED': {
- 'id': 'OEJOOI',
- 'template': "Expected a 'String', but got an instance of '#{type}'.",
- },
-
- 'PRIVATE_IDENTIFIER': {
- 'id': 'XAHVWI',
- 'template': "'#{value}' is not a valid Symbol name because it starts with "
- "'_'.",
- },
-
- 'PRIVATE_NAMED_PARAMETER': {
- 'id': 'VFGCLK',
- 'template': "Named optional parameter can't have a library private name.",
- 'howToFix': "Try removing the '_' or making the parameter positional or "
- "required.",
- 'examples': ["""foo({int _p}) {} main() => foo();"""],
- },
-
- 'UNSUPPORTED_LITERAL_SYMBOL': {
- 'id': 'OYCDII',
- 'template':
- "Symbol literal '##{value}' is currently unsupported by dart2js.",
- },
-
- 'INVALID_SYMBOL': {
- 'id': 'RUXMBL',
- 'template': '''
-'#{value}' is not a valid Symbol name because is not:
-* an empty String,
-* a user defined operator,
-* a qualified non-private identifier optionally followed by '=', or
-* a qualified non-private identifier followed by '.' and a user-defined '''
- "operator.",
- },
-
- 'AMBIGUOUS_REEXPORT': {
- 'id': 'YNTOND',
- 'template': "'#{name}' is (re)exported by multiple libraries.",
- },
-
- 'AMBIGUOUS_LOCATION': {
- 'id': 'SKLTYA',
- 'template': "'#{name}' is defined here.",
- },
-
- 'IMPORTED_HERE': {'id': 'IMUXAE', 'template': "'#{name}' is imported here.",},
-
- 'OVERRIDE_EQUALS_NOT_HASH_CODE': {
- 'id': 'MUHYXI',
- 'template': "The class '#{class}' overrides 'operator==', "
- "but not 'get hashCode'.",
- },
-
- 'INTERNAL_LIBRARY_FROM': {
- 'id': 'RXOCLX',
- 'template': "Internal library '#{resolvedUri}' is not accessible from "
- "'#{importingUri}'.",
- },
-
- 'INTERNAL_LIBRARY': {
- 'id': 'SYLJAV',
- 'template': "Internal library '#{resolvedUri}' is not accessible.",
- },
-
- 'JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS': {
- 'id': 'LSHKJK',
- 'template':
- "Js-interop class '#{cls}' cannot extend from the non js-interop "
- "class '#{superclass}'.",
- 'howToFix': "Annotate the superclass with @JS.",
- 'examples': [
- """
- import 'package:js/js.dart';
-
- class Foo { }
-
- @JS()
- class Bar extends Foo { }
-
- main() {
- new Bar();
- }
- """
- ],
- },
-
- 'JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER': {
- 'id': 'QLLLEE',
- 'template':
- "Member '#{member}' in js-interop class '#{cls}' is not external.",
- 'howToFix': "Mark all interop methods external",
- 'examples': [
- """
- import 'package:js/js.dart';
-
- @JS()
- class Foo {
- bar() {}
- }
-
- main() {
- new Foo().bar();
- }
- """
- ],
- },
-
- 'JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS': {
- 'id': 'TDQHRY',
- 'template': "Js-interop method '#{method}' has named arguments but is not "
- "a factory constructor of an @anonymous @JS class.",
- 'howToFix': "Remove all named arguments from js-interop method or "
- "in the case of a factory constructor annotate the class "
- "as @anonymous.",
- 'examples': [
- """
- import 'package:js/js.dart';
-
- @JS()
- class Foo {
- external bar(foo, {baz});
- }
-
- main() {
- new Foo().bar(4, baz: 5);
- }
- """
- ],
- },
-
- 'JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS': {
- 'id': 'EHEKUY',
- 'template':
- "Parameter '#{parameter}' in anonymous js-interop class '#{cls}' "
- "object literal constructor is positional instead of named."
- ".",
- 'howToFix': "Make all arguments in external factory object literal "
- "constructors named.",
- 'examples': [
- """
- import 'package:js/js.dart';
-
- @anonymous
- @JS()
- class Foo {
- external factory Foo(foo, {baz});
- }
-
- main() {
- new Foo(5, baz: 5);
- }
- """
- ],
- },
-
- 'LIBRARY_NOT_FOUND': {
- 'id': 'BARPSL',
- 'template': "Library not found '#{resolvedUri}'.",
- },
-
- 'LIBRARY_NOT_SUPPORTED': {
- 'id': 'GDXUNS',
- 'template': "Library not supported '#{resolvedUri}'.",
- 'howToFix': "Try removing the dependency or enabling support using "
- "the '--categories' option.",
- 'examples': [
-// """
-// import 'dart:io';
-// main() {}
-// """
- ],
- // TODO(johnniwinther): Enable example when message_kind_test.dart
- // supports library loader callbacks.
- },
-
- 'UNSUPPORTED_EQ_EQ_EQ': {
- 'id': 'GPOVNO',
- 'template': "'===' is not an operator. "
- "Did you mean '#{lhs} == #{rhs}' or 'identical(#{lhs}, #{rhs})'?",
- },
-
- 'UNSUPPORTED_BANG_EQ_EQ': {
- 'id': 'HDYKMV',
- 'template': "'!==' is not an operator. "
- "Did you mean '#{lhs} != #{rhs}' or '!identical(#{lhs}, #{rhs})'?",
- },
-
- 'UNSUPPORTED_PREFIX_PLUS': {
- 'id': 'LSQTHP',
- 'template': "'+' is not a prefix operator. ",
- 'howToFix': "Try removing '+'.",
- 'examples': ["main() => +2; // No longer a valid way to write '2'"],
- },
-
- 'UNSUPPORTED_THROW_WITHOUT_EXP': {
- 'id': 'QOAKGE',
- 'template': "No expression after 'throw'. "
- "Did you mean 'rethrow'?",
- },
-
- 'DEPRECATED_TYPEDEF_MIXIN_SYNTAX': {
- 'id': 'BBGGFE',
- 'template': "'typedef' not allowed here. ",
- 'howToFix': "Try replacing 'typedef' with 'class'.",
- 'examples': [
- """
-class B { }
-class M1 { }
-typedef C = B with M1; // Need to replace 'typedef' with 'class'.
-main() { new C(); }
-"""
- ],
- },
-
- 'MIRRORS_EXPECTED_STRING': {
- 'id': 'XSKTIB',
- 'template':
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "and a 'String' value is expected.",
- 'howToFix': "Did you forget to add quotes?",
- 'examples': [
- """
-// 'Foo' is a type literal, not a string.
-@MirrorsUsed(symbols: const [Foo])
-import 'dart:mirrors';
-
-class Foo {}
-
-main() {}
-"""
- ],
- },
-
- 'MIRRORS_EXPECTED_STRING_OR_TYPE': {
- 'id': 'JQDJPL',
- 'template':
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "and a 'String' or 'Type' value is expected.",
- 'howToFix': "Did you forget to add quotes?",
- 'examples': [
- """
-// 'main' is a method, not a class.
-@MirrorsUsed(targets: const [main])
-import 'dart:mirrors';
-
-main() {}
-"""
- ],
- },
-
- 'MIRRORS_EXPECTED_STRING_OR_LIST': {
- 'id': 'UVYCOE',
- 'template':
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "and a 'String' or 'List' value is expected.",
- 'howToFix': "Did you forget to add quotes?",
- 'examples': [
- """
-// 'Foo' is not a string.
-@MirrorsUsed(symbols: Foo)
-import 'dart:mirrors';
-
-class Foo {}
-
-main() {}
-"""
- ],
- },
-
- 'MIRRORS_EXPECTED_STRING_TYPE_OR_LIST': {
- 'id': 'WSYDFL',
- 'template':
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "but a 'String', 'Type', or 'List' value is expected.",
- 'howToFix': "Did you forget to add quotes?",
- 'examples': [
- """
-// '1' is not a string.
-@MirrorsUsed(targets: 1)
-import 'dart:mirrors';
-
-main() {}
-"""
- ],
- },
-
- 'MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY': {
- 'id': 'VDBBNE',
- 'template': "Can't find '#{name}' in the current library.",
- // TODO(ahe): The closest identifiers in edit distance would be nice.
- 'howToFix': "Did you forget to add an import?",
- 'examples': [
- """
-// 'window' is not in scope because dart:html isn't imported.
-@MirrorsUsed(targets: 'window')
-import 'dart:mirrors';
-
-main() {}
-"""
- ],
- },
-
- 'MIRRORS_CANNOT_RESOLVE_IN_LIBRARY': {
- 'id': 'RUEKXE',
- 'template': "Can't find '#{name}' in the library '#{library}'.",
- // TODO(ahe): The closest identifiers in edit distance would be nice.
- 'howToFix': "Is '#{name}' spelled right?",
- 'examples': [
- """
-// 'List' is misspelled.
-@MirrorsUsed(targets: 'dart.core.Lsit')
-import 'dart:mirrors';
-
-main() {}
-"""
- ],
- },
-
- 'MIRRORS_CANNOT_FIND_IN_ELEMENT': {
- 'id': 'ACPDCS',
- 'template': "Can't find '#{name}' in '#{element}'.",
- // TODO(ahe): The closest identifiers in edit distance would be nice.
- 'howToFix': "Is '#{name}' spelled right?",
- 'examples': [
- """
-// 'addAll' is misspelled.
-@MirrorsUsed(targets: 'dart.core.List.addAl')
-import 'dart:mirrors';
-
-main() {}
-"""
- ],
- },
-
- 'INVALID_URI': {
- 'id': 'QQEQMK',
- 'template': "'#{uri}' is not a valid URI.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- """
-// can't have a '[' in a URI
-import '../../Udyn[mic ils/expect.dart';
-
-main() {}
-"""
- ],
- },
-
- 'INVALID_PACKAGE_CONFIG': {
- 'id': 'XKFAJO',
- 'template': """Package config file '#{uri}' is invalid.
-#{exception}""",
- 'howToFix': DONT_KNOW_HOW_TO_FIX
- },
-
- 'INVALID_PACKAGE_URI': {
- 'id': 'MFVNNJ',
- 'template': "'#{uri}' is not a valid package URI (#{exception}).",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- """
-// can't have a 'top level' package URI
-import 'package:foo.dart';
-
-main() {}
-""",
- """
-// can't have 2 slashes
-import 'package://foo/foo.dart';
-
-main() {}
-""",
- """
-// package name must be valid
-import 'package:not\valid/foo.dart';
-
-main() {}
-"""
- ],
- },
-
- 'READ_SCRIPT_ERROR': {
- 'id': 'JDDYLH',
- 'template': "Can't read '#{uri}' (#{exception}).",
- // Don't know how to fix since the underlying error is unknown.
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- """
-// 'foo.dart' does not exist.
-import 'foo.dart';
-
-main() {}
-"""
- ],
- },
-
- 'READ_SELF_ERROR': {
- 'id': 'CRJUAV',
- 'template': "#{exception}",
- // Don't know how to fix since the underlying error is unknown.
- 'howToFix': DONT_KNOW_HOW_TO_FIX
- },
-
- 'EXTRANEOUS_MODIFIER': {
- 'id': 'DPLVJG',
- 'template': "Can't have modifier '#{modifier}' here.",
- 'howToFix': "Try removing '#{modifier}'.",
- 'examples': [
- "var String foo; main(){}",
- // "var get foo; main(){}",
- "var set foo; main(){}",
- "var final foo; main(){}",
- "var var foo; main(){}",
- "var const foo; main(){}",
- "var abstract foo; main(){}",
- "var static foo; main(){}",
- "var external foo; main(){}",
- "get var foo; main(){}",
- "set var foo; main(){}",
- "final var foo; main(){}",
- "var var foo; main(){}",
- "const var foo; main(){}",
- "abstract var foo; main(){}",
- "static var foo; main(){}",
- "external var foo; main(){}"
- ],
- },
-
- 'EXTRANEOUS_MODIFIER_REPLACE': {
- 'id': 'SSXDLN',
- 'template': "Can't have modifier '#{modifier}' here.",
- 'howToFix': "Try replacing modifier '#{modifier}' with 'var', 'final', "
- "or a type.",
- 'examples': [
- // "get foo; main(){}",
- "set foo; main(){}",
- "abstract foo; main(){}",
- "static foo; main(){}",
- "external foo; main(){}"
- ],
- },
-
- 'ABSTRACT_CLASS_INSTANTIATION': {
- 'id': 'KOBCRO',
- 'template': "Can't instantiate abstract class.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': ["abstract class A {} main() { new A(); }"],
- },
-
- 'BODY_EXPECTED': {
- 'id': 'YXCAHO',
- 'template': "Expected a function body or '=>'.",
- // TODO(ahe): In some scenarios, we can suggest removing the 'static'
- // keyword.
- 'howToFix': "Try adding {}.",
- 'examples': ["main();"],
- },
-
- 'MIRROR_BLOAT': {
- 'id': 'BSEAIT',
- 'template':
- "#{count} methods retained for use by dart:mirrors out of #{total}"
- " total methods (#{percentage}%).",
- },
-
- 'MIRROR_IMPORT': {'id': 'BDAETE', 'template': "Import of 'dart:mirrors'.",},
-
- 'MIRROR_IMPORT_NO_USAGE': {
- 'id': 'OJOHTR',
- 'template':
- "This import is not annotated with @MirrorsUsed, which may lead to "
- "unnecessarily large generated code.",
- 'howToFix': "Try adding '@MirrorsUsed(...)' as described at "
- "https://goo.gl/Akrrog.",
- },
-
- 'JS_PLACEHOLDER_CAPTURE': {
- 'id': 'EJXEGQ',
- 'template': "JS code must not use '#' placeholders inside functions.",
- 'howToFix': "Use an immediately called JavaScript function to capture the"
- " the placeholder values as JavaScript function parameters.",
- },
-
- 'WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT': {
- 'id': 'JHRISO',
- 'template':
- "Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant.",
- },
-
- 'EXPECTED_IDENTIFIER_NOT_RESERVED_WORD': {
- 'id': 'FEJXJF',
- 'template': "'#{keyword}' is a reserved word and can't be used here.",
- 'howToFix': "Try using a different name.",
- 'examples': ["do() {} main() {}"],
- },
-
- 'NAMED_FUNCTION_EXPRESSION': {
- 'id': 'CTHFPI',
- 'template': "Function expression '#{name}' cannot be named.",
- 'howToFix': "Try removing the name.",
- 'examples': ["main() { var f = func() {}; }"],
- },
-
- 'UNUSED_METHOD': {
- 'id': 'PKLRQL',
- 'template': "The method '#{name}' is never called.",
- 'howToFix': "Consider deleting it.",
- 'examples': ["deadCode() {} main() {}"],
- },
-
- 'UNUSED_CLASS': {
- 'id': 'TBIECC',
- 'template': "The class '#{name}' is never used.",
- 'howToFix': "Consider deleting it.",
- 'examples': ["class DeadCode {} main() {}"],
- },
-
- 'UNUSED_TYPEDEF': {
- 'id': 'JBIPCN',
- 'template': "The typedef '#{name}' is never used.",
- 'howToFix': "Consider deleting it.",
- 'examples': ["typedef DeadCode(); main() {}"],
- },
-
- 'ABSTRACT_METHOD': {
- 'id': 'HOKOBG',
- 'template': "The method '#{name}' has no implementation in "
- "class '#{class}'.",
- 'howToFix': "Try adding a body to '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-class Class {
-method();
-}
-main() => new Class().method();
-"""
- ],
- },
-
- 'ABSTRACT_GETTER': {
- 'id': 'VKTRNK',
- 'template': "The getter '#{name}' has no implementation in "
- "class '#{class}'.",
- 'howToFix': "Try adding a body to '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-class Class {
-get getter;
-}
-main() => new Class();
-"""
- ],
- },
-
- 'ABSTRACT_SETTER': {
- 'id': 'XGDGKK',
- 'template': "The setter '#{name}' has no implementation in "
- "class '#{class}'.",
- 'howToFix': "Try adding a body to '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-class Class {
-set setter(_);
-}
-main() => new Class();
-"""
- ],
- },
-
- 'INHERIT_GETTER_AND_METHOD': {
- 'id': 'UMEUEG',
- 'template': "The class '#{class}' can't inherit both getters and methods "
- "by the named '#{name}'.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- """
-class A {
-get member => null;
-}
-class B {
-member() {}
-}
-class Class implements A, B {
-}
-main() => new Class();
-"""
- ],
- },
-
- 'INHERITED_METHOD': {
- 'id': 'GMSVBM',
- 'template': "The inherited method '#{name}' is declared here in class "
- "'#{class}'.",
- },
-
- 'INHERITED_EXPLICIT_GETTER': {
- 'id': 'KKAVRS',
- 'template': "The inherited getter '#{name}' is declared here in class "
- "'#{class}'.",
- },
-
- 'INHERITED_IMPLICIT_GETTER': {
- 'id': 'JBAMEJ',
- 'template': "The inherited getter '#{name}' is implicitly declared by this "
- "field in class '#{class}'.",
- },
-
- 'UNIMPLEMENTED_METHOD_ONE': {
- 'id': 'CMCLWO',
- 'template': "'#{class}' doesn't implement '#{method}' "
- "declared in '#{declarer}'.",
- 'howToFix': "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-abstract class I {
-m();
-}
-class C implements I {}
-main() => new C();
-""",
- """
-abstract class I {
-m();
-}
-class C extends I {}
-main() => new C();
-"""
- ],
- },
-
- 'UNIMPLEMENTED_METHOD': {
- 'id': 'IJSNQB',
- 'template': "'#{class}' doesn't implement '#{method}'.",
- 'howToFix': "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-abstract class I {
-m();
-}
-
-abstract class J {
-m();
-}
-
-class C implements I, J {}
-
-main() {
-new C();
-}
-""",
- """
-abstract class I {
-m();
-}
-
-abstract class J {
-m();
-}
-
-class C extends I implements J {}
-
-main() {
-new C();
-}
-"""
- ],
- },
-
- 'UNIMPLEMENTED_METHOD_CONT': {
- 'id': 'KFBKPO',
- 'template': "The method '#{name}' is declared here in class '#{class}'.",
- },
-
- 'UNIMPLEMENTED_SETTER_ONE': {
- 'id': 'QGKTEA',
- 'template': "'#{class}' doesn't implement the setter '#{name}' "
- "declared in '#{declarer}'.",
- 'howToFix': "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-abstract class I {
-set m(_);
-}
-class C implements I {}
-class D implements I {
-set m(_) {}
-}
-main() {
-new D().m = 0;
-new C();
-}
-"""
- ],
- },
-
- 'UNIMPLEMENTED_SETTER': {
- 'id': 'VEEGJQ',
- 'template': "'#{class}' doesn't implement the setter '#{name}'.",
- 'howToFix': "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-abstract class I {
-set m(_);
-}
-abstract class J {
-set m(_);
-}
-class C implements I, J {}
-main() => new C();
-""",
- """
-abstract class I {
-set m(_);
-}
-abstract class J {
-set m(_);
-}
-class C extends I implements J {}
-main() => new C();
-"""
- ],
- },
-
- 'UNIMPLEMENTED_EXPLICIT_SETTER': {
- 'id': 'SABABA',
- 'template': "The setter '#{name}' is declared here in class '#{class}'.",
- },
-
- 'UNIMPLEMENTED_IMPLICIT_SETTER': {
- 'id': 'SWESAQ',
- 'template': "The setter '#{name}' is implicitly declared by this field "
- "in class '#{class}'.",
- },
-
- 'UNIMPLEMENTED_GETTER_ONE': {
- 'id': 'ODEPFW',
- 'template': "'#{class}' doesn't implement the getter '#{name}' "
- "declared in '#{declarer}'.",
- 'howToFix': "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-abstract class I {
-get m;
-}
-class C implements I {}
-main() => new C();
-""",
- """
-abstract class I {
-get m;
-}
-class C extends I {}
-main() => new C();
-"""
- ],
- },
-
- 'UNIMPLEMENTED_GETTER': {
- 'id': 'VHSECG',
- 'template': "'#{class}' doesn't implement the getter '#{name}'.",
- 'howToFix': "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- 'examples': [
- """
-abstract class I {
-get m;
-}
-abstract class J {
-get m;
-}
-class C implements I, J {}
-main() => new C();
-""",
- """
-abstract class I {
-get m;
-}
-abstract class J {
-get m;
-}
-class C extends I implements J {}
-main() => new C();
-"""
- ],
- },
-
- 'UNIMPLEMENTED_EXPLICIT_GETTER': {
- 'id': 'HFDJPP',
- 'template': "The getter '#{name}' is declared here in class '#{class}'.",
- },
-
- 'UNIMPLEMENTED_IMPLICIT_GETTER': {
- 'id': 'BSCQNO',
- 'template': "The getter '#{name}' is implicitly declared by this field "
- "in class '#{class}'.",
- },
-
- 'INVALID_METADATA': {
- 'id': 'RKJGDE',
- 'template':
- "A metadata annotation must be either a reference to a compile-time "
- "constant variable or a call to a constant constructor.",
- 'howToFix':
- "Try using a different constant value or referencing it through a "
- "constant variable.",
- 'examples': [
-'@Object main() {}',
-'@print main() {}']
- },
-
- 'INVALID_METADATA_GENERIC': {
- 'id': 'WEEDQD',
- 'template':
- "A metadata annotation using a constant constructor cannot use type "
- "arguments.",
- 'howToFix':
- "Try removing the type arguments or referencing the constant "
- "through a constant variable.",
- 'examples': [
- '''
-class C<T> {
- const C();
-}
-@C<int>() main() {}
-'''],
- },
-
- 'EQUAL_MAP_ENTRY_KEY': {
- 'id': 'KIDLPM',
- 'template': "An entry with the same key already exists in the map.",
- 'howToFix': "Try removing the previous entry or changing the key in one "
- "of the entries.",
- 'examples': [
- """
-main() {
-var m = const {'foo': 1, 'foo': 2};
-}"""
- ],
- },
-
- 'BAD_INPUT_CHARACTER': {
- 'id': 'SHQWJY',
- 'template': "Character U+#{characterHex} isn't allowed here.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- """
-main() {
-String x = ç;
-}
-"""
- ],
- },
-
- 'UNTERMINATED_STRING': {
- 'id': 'TRLTHK',
- 'template': "String must end with #{quote}.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- """
-main() {
-return '
-;
-}
-""",
- """
-main() {
-return \"
-;
-}
-""",
- """
-main() {
-return r'
-;
-}
-""",
- """
-main() {
-return r\"
-;
-}
-""",
- """
-main() => '''
-""",
- """
-main() => \"\"\"
-""",
- """
-main() => r'''
-""",
- """
-main() => r\"\"\"
-"""
- ],
- },
-
- 'UNMATCHED_TOKEN': {
- 'id': 'AGJKMQ',
- 'template': "Can't find '#{end}' to match '#{begin}'.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': ["main(", "main(){", "main(){]}",],
- },
-
- 'UNTERMINATED_TOKEN': {
- 'id': 'VIIXHQ',
- 'template':
- // This is a fall-back message that shouldn't happen.
- "Incomplete token.",
- },
-
- 'EXPONENT_MISSING': {
- 'id': 'CXPLCR',
- 'template':
- "Numbers in exponential notation should always contain an exponent"
- " (an integer number with an optional sign).",
- 'howToFix': "Make sure there is an exponent, and remove any whitespace "
- "before it.",
- 'examples': [
- """
-main() {
-var i = 1e;
-}
-"""
- ],
- },
-
- 'HEX_DIGIT_EXPECTED': {
- 'id': 'GKCAGV',
- 'template': "A hex digit (0-9 or A-F) must follow '0x'.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX, // Seems obvious from the error message.
- 'examples': [
- """
-main() {
-var i = 0x;
-}
-"""
- ],
- },
-
- 'MALFORMED_STRING_LITERAL': {
- 'id': 'DULNSD',
- 'template':
- r"A '$' has special meaning inside a string, and must be followed by "
- "an identifier or an expression in curly braces ({}).",
- 'howToFix': r"Try adding a backslash (\) to escape the '$'.",
- 'examples': [
- r"""
-main() {
-return '$';
-}
-""",
- r'''
-main() {
-return "$";
-}
-''',
- r"""
-main() {
-return '''$''';
-}
-""",
- r'''
-main() {
-return """$""";
-}
-'''
- ],
- },
-
- 'UNTERMINATED_COMMENT': {
- 'id': 'NECJNM',
- 'template': "Comment starting with '/*' must end with '*/'.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- r"""
-main() {
-}
-/*"""
- ],
- },
-
- 'MISSING_TOKEN_BEFORE_THIS': {
- 'id': 'AFKXGU',
- 'template': "Expected '#{token}' before this.",
- // Consider the second example below: the parser expects a ')' before
- // 'y', but a ',' would also have worked. We don't have enough
- // information to give a good suggestion.
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': ["main() => true ? 1;", "main() => foo(x: 1 y: 2);",],
- },
-
- 'MISSING_TOKEN_AFTER_THIS': {
- 'id': 'FMUFJL',
- 'template': "Expected '#{token}' after this.",
- // See [MISSING_TOKEN_BEFORE_THIS], we don't have enough information
- // to give a good suggestion.
- 'howToFix': DONT_KNOW_HOW_TO_FIX,
- 'examples': [
- "main(x) {x}",
- """
-class S1 {}
-class S2 {}
-class S3 {}
-class A = S1 with S2, S3
-main() => new A();
-"""
- ],
- },
-
- 'CONSIDER_ANALYZE_ALL': {
- 'id': 'HHILSH',
- 'template': "Could not find '#{main}'. Nothing will be analyzed.",
- 'howToFix': "Try using '--analyze-all' to analyze everything.",
- 'examples': [''],
- },
-
- 'MISSING_MAIN': {
- 'id': 'HNAOPV',
- 'template': "Could not find '#{main}'.",
- // No example, test uses '--analyze-only' which will produce the above
- // message [CONSIDER_ANALYZE_ALL]. An example for a human operator
- // would be an empty file.
- 'howToFix': "Try adding a method named '#{main}' to your program."
- },
-
- 'MAIN_NOT_A_FUNCTION': {
- 'id': 'PIURPA',
- 'template': "'#{main}' is not a function.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX, // Don't state the obvious.
- 'examples': ['var main;'],
- },
-
- 'MAIN_WITH_EXTRA_PARAMETER': {
- 'id': 'ONOGQB',
- 'template': "'#{main}' cannot have more than two parameters.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX, // Don't state the obvious.
- 'examples': ['main(a, b, c) {}'],
- },
-
- 'COMPILER_CRASHED': {
- 'id': 'MHDWAV',
- 'template': "The compiler crashed when compiling this element.",
- },
-
- 'PLEASE_REPORT_THE_CRASH': {
- 'id': 'UUTHXX',
- 'template': '''
-The compiler is broken.
-
-When compiling the above element, the compiler crashed. It is not
-possible to tell if this is caused by a problem in your program or
-not. Regardless, the compiler should not crash.
-
-The Dart team would greatly appreciate if you would take a moment to
-report this problem at http://dartbug.com/new.
-
-Please include the following information:
-
-* the name and version of your operating system,
-
-* the Dart SDK build number (#{buildId}), and
-
-* the entire message you see here (including the full stack trace
-below as well as the source location above).
-''',
- },
-
- 'POTENTIAL_MUTATION': {
- 'id': 'YGNLLB',
- 'template': "Variable '#{variableName}' is not known to be of type "
- "'#{shownType}' because it is potentially mutated in the scope for "
- "promotion.",
- },
-
- 'POTENTIAL_MUTATION_HERE': {
- 'id': 'ATMSVX',
- 'template': "Variable '#{variableName}' is potentially mutated here.",
- },
-
- 'POTENTIAL_MUTATION_IN_CLOSURE': {
- 'id': 'XUAHTW',
- 'template': "Variable '#{variableName}' is not known to be of type "
- "'#{shownType}' because it is potentially mutated within a closure.",
- },
-
- 'POTENTIAL_MUTATION_IN_CLOSURE_HERE': {
- 'id': 'UHFXLG',
- 'template': "Variable '#{variableName}' is potentially mutated in a "
- "closure here.",
- },
-
- 'ACCESSED_IN_CLOSURE': {
- 'id': 'JJHKSF',
- 'template': "Variable '#{variableName}' is not known to be of type "
- "'#{shownType}' because it is accessed by a closure in the scope for "
- "promotion and potentially mutated in the scope of "
- "'#{variableName}'.",
- },
-
- 'ACCESSED_IN_CLOSURE_HERE': {
- 'id': 'KMJVEA',
- 'template': "Variable '#{variableName}' is accessed in a closure here.",
- },
-
- 'NOT_MORE_SPECIFIC': {
- 'id': 'EJHQAG',
- 'template': "Variable '#{variableName}' is not shown to have type "
- "'#{shownType}' because '#{shownType}' is not more specific than the "
- "known type '#{knownType}' of '#{variableName}'.",
- },
-
- 'NOT_MORE_SPECIFIC_SUBTYPE': {
- 'id': 'APICDL',
- 'template': "Variable '#{variableName}' is not shown to have type "
- "'#{shownType}' because '#{shownType}' is not a subtype of the "
- "known type '#{knownType}' of '#{variableName}'.",
- },
-
- 'NOT_MORE_SPECIFIC_SUGGESTION': {
- 'id': 'FFNCJX',
- 'template': "Variable '#{variableName}' is not shown to have type "
- "'#{shownType}' because '#{shownType}' is not more specific than the "
- "known type '#{knownType}' of '#{variableName}'.",
- 'howToFix': "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'.",
- },
-
- 'NO_COMMON_SUBTYPES': {
- 'id': 'XKJOEC',
- 'template': "Types '#{left}' and '#{right}' have no common subtypes.",
- },
-
- 'HIDDEN_WARNINGS_HINTS': {
- 'id': 'JBAWEK',
- 'template':
- "#{warnings} warning(s) and #{hints} hint(s) suppressed in #{uri}.",
- },
-
- 'HIDDEN_WARNINGS': {
- 'id': 'JIYWDC',
- 'template': "#{warnings} warning(s) suppressed in #{uri}.",
- },
-
- 'HIDDEN_HINTS': {
- 'id': 'RHNXQT',
- 'template': "#{hints} hint(s) suppressed in #{uri}.",
- },
-
- 'PREAMBLE': {
- 'id': 'GXGWIF',
- 'template': "When run on the command-line, the compiled output might"
- " require a preamble file located in:\n"
- " <sdk>/lib/_internal/js_runtime/lib/preambles.",
- },
-
- 'INVALID_SYNC_MODIFIER': {
- 'id': 'FNYUYU',
- 'template': "Invalid modifier 'sync'.",
- 'howToFix': "Try replacing 'sync' with 'sync*'.",
- 'examples': ["main() sync {}"],
- },
-
- 'INVALID_AWAIT_FOR': {
- 'id': 'IEYGCY',
- 'template': "'await' is only supported on for-in loops.",
- 'howToFix': "Try rewriting the loop as a for-in loop or removing the "
- "'await' keyword.",
- 'examples': [
- """
-main() async* {
-await for (int i = 0; i < 10; i++) {}
-}
-"""
- ],
- },
-
- 'INVALID_AWAIT_FOR_IN': {
- 'id': 'FIEYGC',
- 'template': "'await' is only supported in methods with an 'async' or "
- "'async*' body modifier.",
- 'howToFix': "Try adding 'async' or 'async*' to the method body or "
- "removing the 'await' keyword.",
- 'examples': [
- """
-main(o) sync* {
- await for (var e in o) {}
-}
-"""
- ],
- },
-
- 'INVALID_AWAIT': {
- 'id': 'IEYHYD',
- 'template': "'await' is only supported in methods with an 'async' or "
- "'async*' body modifier.",
- 'howToFix': "Try adding 'async' or 'async*' to the method body.",
- 'examples': [
- """
-main() sync* {
- await null;
-}
-"""
- ],
- },
-
- 'INVALID_YIELD': {
- 'id': 'IPGGCY',
- 'template': "'yield' is only supported in methods with a 'sync*' or "
- "'async*' body modifier.",
- 'howToFix': "Try adding 'sync*' or 'async*' to the method body.",
- 'examples': [
- """
-main() async {
- yield 0;
-}
-"""
- ],
- },
-
- 'ASYNC_MODIFIER_ON_ABSTRACT_METHOD': {
- 'id': 'VRISLY',
- 'template':
- "The modifier '#{modifier}' is not allowed on an abstract method.",
- 'options': ['--enable-async'],
- 'howToFix': "Try removing the '#{modifier}' modifier or adding a "
- "body to the method.",
- 'examples': [
- """
-abstract class A {
-method() async;
-}
-class B extends A {
-method() {}
-}
-main() {
-A a = new B();
-a.method();
-}
-"""
- ],
- },
-
- 'ASYNC_MODIFIER_ON_CONSTRUCTOR': {
- 'id': 'DHCFON',
- 'template': "The modifier '#{modifier}' is not allowed on constructors.",
- 'options': ['--enable-async'],
- 'howToFix': "Try removing the '#{modifier}' modifier.",
- 'examples': [
- """
-class A {
-A() async;
-}
-main() => new A();""",
- """
-class A {
-A();
-factory A.a() async* {}
-}
-main() => new A.a();"""
- ],
- },
-
- 'ASYNC_MODIFIER_ON_SETTER': {
- 'id': 'NMJLJE',
- 'template': "The modifier '#{modifier}' is not allowed on setters.",
- 'options': ['--enable-async'],
- 'howToFix': "Try removing the '#{modifier}' modifier.",
- 'examples': [
- """
-class A {
-set foo(v) async {}
-}
-main() => new A().foo = 0;"""
- ],
- },
-
- 'YIELDING_MODIFIER_ON_ARROW_BODY': {
- 'id': 'UOGLUX',
- 'template':
- "The modifier '#{modifier}' is not allowed on methods implemented "
- "using '=>'.",
- 'options': ['--enable-async'],
- 'howToFix': "Try removing the '#{modifier}' modifier or implementing "
- "the method body using a block: '{ ... }'.",
- 'examples': ["main() sync* => null;", "main() async* => null;"],
- },
-
- // TODO(johnniwinther): Check for 'async' as identifier.
- 'ASYNC_KEYWORD_AS_IDENTIFIER': {
- 'id': 'VTWSMA',
- 'template':
- "'#{keyword}' cannot be used as an identifier in a function body "
- "marked with '#{modifier}'.",
- 'options': ['--enable-async'],
- 'howToFix': "Try removing the '#{modifier}' modifier or renaming the "
- "identifier.",
- 'examples': [
- """
-main() async {
-var await;
-}""",
- """
-main() async* {
-var yield;
-}""",
- """
-main() sync* {
-var yield;
-}"""
- ],
- },
-
- 'RETURN_IN_GENERATOR': {
- 'id': 'AWGUVF',
- 'template':
- "'return' with a value is not allowed in a method body using the "
- "'#{modifier}' modifier.",
- 'howToFix': "Try removing the value, replacing 'return' with 'yield' "
- "or changing the method body modifier.",
- 'examples': [
- """
-foo() async* { return 0; }
-main() => foo();
-""",
- """
-foo() sync* { return 0; }
-main() => foo();
-"""
- ],
- },
-
- 'NATIVE_NOT_SUPPORTED': {
- 'id': 'QMMLUT',
- 'template': "'native' modifier is not supported.",
- 'howToFix': "Try removing the 'native' implementation or analyzing the "
- "code with the --allow-native-extensions option.",
- 'examples': [
- """
-main() native "Main";
-"""
- ],
- },
-
- 'DART_EXT_NOT_SUPPORTED': {
- 'id': 'JLPQFJ',
- 'template': "The 'dart-ext' scheme is not supported.",
- 'howToFix': "Try analyzing the code with the --allow-native-extensions "
- "option.",
- 'examples': [
- """
-import 'dart-ext:main';
-
-main() {}
-"""
- ],
- },
-
- 'LIBRARY_TAG_MUST_BE_FIRST': {
- 'id': 'JFUSRX',
- 'template':
- "The library declaration should come before other declarations.",
- 'howToFix': "Try moving the declaration to the top of the file.",
- 'examples': [
- """
-import 'dart:core';
-library foo;
-main() {}
-""",
- ],
- },
-
- 'ONLY_ONE_LIBRARY_TAG': {
- 'id': 'CCXFMY',
- 'template': "There can only be one library declaration.",
- 'howToFix': "Try removing all other library declarations.",
- 'examples': [
- """
-library foo;
-library bar;
-main() {}
-""",
- """
-library foo;
-import 'dart:core';
-library bar;
-main() {}
-""",
- ],
- },
-
- 'IMPORT_BEFORE_PARTS': {
- 'id': 'NSMOQI',
- 'template': "Import declarations should come before parts.",
- 'howToFix': "Try moving this import further up in the file.",
- 'examples': [
- {
- 'main.dart': """
-library test.main;
-part 'part.dart';
-import 'dart:core';
-main() {}
-""",
- 'part.dart': """
-part of test.main;
-""",
- }
- ],
- },
-
- 'EXPORT_BEFORE_PARTS': {
- 'id': 'KYJTTC',
- 'template': "Export declarations should come before parts.",
- 'howToFix': "Try moving this export further up in the file.",
- 'examples': [
- {
- 'main.dart': """
-library test.main;
-part 'part.dart';
-export 'dart:core';
-main() {}
-""",
- 'part.dart': """
-part of test.main;
-""",
- }
- ],
-
-//////////////////////////////////////////////////////////////////////////////
-// Patch errors start.
-//////////////////////////////////////////////////////////////////////////////
- },
-
- 'PATCH_RETURN_TYPE_MISMATCH': {
- 'id': 'DTOQDU',
- 'template': "Patch return type '#{patchReturnType}' does not match "
- "'#{originReturnType}' on origin method '#{methodName}'.",
- },
-
- 'PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH': {
- 'id': 'KJUUYC',
- 'template': "Required parameter count of patch method "
- "(#{patchParameterCount}) does not match parameter count on origin "
- "method '#{methodName}' (#{originParameterCount}).",
- },
-
- 'PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH': {
- 'id': 'GUTGTE',
- 'template': "Optional parameter count of patch method "
- "(#{patchParameterCount}) does not match parameter count on origin "
- "method '#{methodName}' (#{originParameterCount}).",
- },
-
- 'PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH': {
- 'id': 'MCHEIC',
- 'template': "Optional parameters of origin and patch method "
- "'#{methodName}' must both be either named or positional.",
- },
-
- 'PATCH_PARAMETER_MISMATCH': {
- 'id': 'XISHPB',
- 'template': "Patch method parameter '#{patchParameter}' does not match "
- "'#{originParameter}' on origin method '#{methodName}'.",
- },
-
- 'PATCH_PARAMETER_TYPE_MISMATCH': {
- 'id': 'UGRBYD',
- 'template': "Patch method parameter '#{parameterName}' type "
- "'#{patchParameterType}' does not match '#{originParameterType}' on "
- "origin method '#{methodName}'.",
- },
-
- 'PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION': {
- 'id': 'WSNMKD',
- 'template': "External method without an implementation.",
- },
-
- 'PATCH_POINT_TO_FUNCTION': {
- 'id': 'CAVBPN',
- 'template': "This is the function patch '#{functionName}'.",
- },
-
- 'PATCH_POINT_TO_CLASS': {
- 'id': 'TWDLDX',
- 'template': "This is the class patch '#{className}'.",
- },
-
- 'PATCH_POINT_TO_GETTER': {
- 'id': 'TRBBNY',
- 'template': "This is the getter patch '#{getterName}'.",
- },
-
- 'PATCH_POINT_TO_SETTER': {
- 'id': 'DAXDLW',
- 'template': "This is the setter patch '#{setterName}'.",
- },
-
- 'PATCH_POINT_TO_CONSTRUCTOR': {
- 'id': 'VYQISY',
- 'template': "This is the constructor patch '#{constructorName}'.",
- },
-
- 'PATCH_POINT_TO_PARAMETER': {
- 'id': 'TFPAGO',
- 'template': "This is the patch parameter '#{parameterName}'.",
- },
-
- 'PATCH_NON_EXISTING': {
- 'id': 'AWOACF',
- 'template': "Origin does not exist for patch '#{name}'.",
- },
-
- // TODO(ahe): Eventually, this error should be removed as it will be
- // handled by the regular parser.
- 'PATCH_NONPATCHABLE': {
- 'id': 'WQEPJI',
- 'template': "Only classes and functions can be patched.",
- },
-
- 'PATCH_NON_EXTERNAL': {
- 'id': 'MHLXNK',
- 'template': "Only external functions can be patched.",
- },
-
- 'PATCH_NON_CLASS': {
- 'id': 'UIALAB',
- 'template': "Patching non-class with class patch '#{className}'.",
- },
-
- 'PATCH_NON_GETTER': {
- 'id': 'VTNQCJ',
- 'template': "Cannot patch non-getter '#{name}' with getter patch.",
- },
-
- 'PATCH_NO_GETTER': {
- 'id': 'XOPDHD',
- 'template': "No getter found for getter patch '#{getterName}'.",
- },
-
- 'PATCH_NON_SETTER': {
- 'id': 'XBOMMN',
- 'template': "Cannot patch non-setter '#{name}' with setter patch.",
- },
-
- 'PATCH_NO_SETTER': {
- 'id': 'YITARQ',
- 'template': "No setter found for setter patch '#{setterName}'.",
- },
-
- 'PATCH_NON_CONSTRUCTOR': {
- 'id': 'TWAEQV',
- 'template': "Cannot patch non-constructor with constructor patch "
- "'#{constructorName}'.",
- },
-
- 'PATCH_NON_FUNCTION': {
- 'id': 'EDXBPI',
- 'template': "Cannot patch non-function with function patch "
- "'#{functionName}'.",
- },
-
- 'INJECTED_PUBLIC_MEMBER': {
- 'id': 'JGMXMI',
- 'template': "Non-patch members in patch libraries must be private.",
- },
-
- 'EXTERNAL_WITH_BODY': {
- 'id': 'GAVMSQ',
- 'template':
- "External function '#{functionName}' cannot have a function body.",
- 'options': ["--output-type=dart"],
- 'howToFix': "Try removing the 'external' modifier or the function body.",
- 'examples': [
- """
-external foo() => 0;
-main() => foo();
-""",
- """
-external foo() {}
-main() => foo();
-"""
- ],
-
-//////////////////////////////////////////////////////////////////////////////
-// Patch errors end.
-//////////////////////////////////////////////////////////////////////////////
- },
-
- 'EXPERIMENTAL_ASSERT_MESSAGE': {
- 'id': 'NENGIS',
- 'template': "Experimental language feature 'assertion with message'"
- " is not supported.",
- 'howToFix':
- "Use option '--assert-message' to use assertions with messages.",
- 'examples': [
- r'''
-main() {
-int n = -7;
-assert(n > 0, 'must be positive: $n');
-}
-'''
- ],
- },
-
- 'IMPORT_EXPERIMENTAL_MIRRORS': {
- 'id': 'SCJYPH',
- 'template': '''
-
-****************************************************************
-* WARNING: dart:mirrors support in dart2js is experimental,
-* and not recommended.
-* This implementation of mirrors is incomplete,
-* and often greatly increases the size of the generated
-* JavaScript code.
-*
-* Your app imports dart:mirrors via:'''
- '''
-$IMPORT_EXPERIMENTAL_MIRRORS_PADDING#{importChain}
-*
-* You can disable this message by using the --enable-experimental-mirrors
-* command-line flag.
-*
-* To learn what to do next, please visit:
-* http://dartlang.org/dart2js-reflection
-****************************************************************
-''',
- },
-
- 'DISALLOWED_LIBRARY_IMPORT': {
- 'id': 'OCSFJU',
- 'template': '''
-Your app imports the unsupported library '#{uri}' via:
-'''
- '''
-$DISALLOWED_LIBRARY_IMPORT_PADDING#{importChain}
-
-Use the --categories option to support import of '#{uri}'.
-''',
- },
-
- 'MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND': {
- 'id': 'JBTRRM',
- 'template': """
-dart:mirrors library is not supported when using this backend.
-
-Your app imports dart:mirrors via:"""
- """
-$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}""",
- },
-
- 'CALL_NOT_SUPPORTED_ON_NATIVE_CLASS': {
- 'id': 'HAULDW',
- 'template': "Non-supported 'call' member on a native class, or a "
- "subclass of a native class.",
- },
-
- 'DIRECTLY_THROWING_NSM': {
- 'id': 'XLTPCS',
- 'template': "This 'noSuchMethod' implementation is guaranteed to throw an "
- "exception. The generated code will be smaller if it is "
- "rewritten.",
- 'howToFix': "Rewrite to "
- "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.",
- },
-
- 'COMPLEX_THROWING_NSM': {
- 'id': 'PLCXVX',
- 'template': "This 'noSuchMethod' implementation is guaranteed to throw an "
- "exception. The generated code will be smaller and the compiler "
- "will be able to perform more optimizations if it is rewritten.",
- 'howToFix': "Rewrite to "
- "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.",
- },
-
- 'COMPLEX_RETURNING_NSM': {
- 'id': 'HUTCTQ',
- 'template': "Overriding 'noSuchMethod' causes the compiler to generate "
- "more code and prevents the compiler from doing some optimizations.",
- 'howToFix': "Consider removing this 'noSuchMethod' implementation."
- },
-
- 'UNRECOGNIZED_VERSION_OF_LOOKUP_MAP': {
- 'id': 'OVAFEW',
- 'template': "Unsupported version of package:lookup_map.",
- 'howToFix': DONT_KNOW_HOW_TO_FIX
- },
-};
diff --git a/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart b/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart
new file mode 100644
index 0000000..c8617cc
--- /dev/null
+++ b/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+/*
+DON'T EDIT. GENERATED. DON'T EDIT.
+This file has been generated by 'publish.dart' in the dart_messages package.
+
+Messages are maintained in `lib/shared_messages.dart` of that same package.
+After any change to that file, run `bin/publish.dart` to generate a new version
+of the json, dart2js and analyzer representations.
+*/
+import '../messages.dart' show MessageTemplate;
+
+enum SharedMessageKind {
+ exampleMessage
+}
+
+const Map<SharedMessageKind, MessageTemplate> TEMPLATES = const <SharedMessageKind, MessageTemplate>{
+ SharedMessageKind.exampleMessage: const MessageTemplate(
+ SharedMessageKind.exampleMessage,
+ "#use #named #arguments",
+ howToFix: "an explanation on how to fix things",
+ examples: const [
+ r'''
+ Some multiline example;
+ That generates the bug.''',
+ const {
+ 'fileA.dart': r'''
+ or a map from file to content.
+ again multiline''',
+ 'fileB.dart': r'''
+ with possibly multiple files.
+ muliline too''',
+ },
+ ]
+ ), // Generated. Don't edit.
+};
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index b529e1c..f394bdf 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -2,16 +2,81 @@
// 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.
+
+/**
+ * The messages in this file should meet the following guide lines:
+ *
+ * 1. The message should be a complete sentence starting with an uppercase
+ * letter, and ending with a period.
+ *
+ * 2. Reserved words and embedded identifiers should be in single quotes, so
+ * prefer double quotes for the complete message. For example, "The
+ * class '#{className}' can't use 'super'." Notice that the word 'class' in the
+ * preceding message is not quoted as it refers to the concept 'class', not the
+ * reserved word. On the other hand, 'super' refers to the reserved word. Do
+ * not quote 'null' and numeric literals.
+ *
+ * 3. Do not try to compose messages, as it can make translating them hard.
+ *
+ * 4. Try to keep the error messages short, but informative.
+ *
+ * 5. Use simple words and terminology, assume the reader of the message
+ * doesn't have an advanced degree in math, and that English is not the
+ * reader's native language. Do not assume any formal computer science
+ * training. For example, do not use Latin abbreviations (prefer "that is" over
+ * "i.e.", and "for example" over "e.g."). Also avoid phrases such as "if and
+ * only if" and "iff", that level of precision is unnecessary.
+ *
+ * 6. Prefer contractions when they are in common use, for example, prefer
+ * "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
+ * off-putting to people new to programming.
+ *
+ * 7. Use common terminology, preferably from the Dart Language
+ * Specification. This increases the user's chance of finding a good
+ * explanation on the web.
+ *
+ * 8. Do not try to be cute or funny. It is extremely frustrating to work on a
+ * product that crashes with a "tongue-in-cheek" message, especially if you did
+ * not want to use this product to begin with.
+ *
+ * 9. Do not lie, that is, do not write error messages containing phrases like
+ * "can't happen". If the user ever saw this message, it would be a
+ * lie. Prefer messages like: "Internal error: This function should not be
+ * called when 'x' is null.".
+ *
+ * 10. Prefer to not use imperative tone. That is, the message should not sound
+ * accusing or like it is ordering the user around. The computer should
+ * describe the problem, not criticize for violating the specification.
+ *
+ * Other things to keep in mind:
+ *
+ * An INFO message should always be preceded by a non-INFO message, and the
+ * INFO messages are additional details about the preceding non-INFO
+ * message. For example, consider duplicated elements. First report a WARNING
+ * or ERROR about the duplicated element, and then report an INFO about the
+ * location of the existing element.
+ *
+ * Generally, we want to provide messages that consists of three sentences:
+ * 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we
+ * combine the first two in [template] and the last in [howToFix].
+ */
+
library dart2js.messages;
-import 'package:dart_messages/shared_messages.dart' as shared_messages;
+import '../tokens/token.dart' show
+ ErrorToken,
+ Token;
-import '../tokens/token.dart' show ErrorToken, Token;
+import 'invariant.dart' show
+ invariant;
+import 'spannable.dart' show
+ CURRENT_ELEMENT_SPANNABLE;
-import 'invariant.dart' show invariant;
-import 'spannable.dart' show CURRENT_ELEMENT_SPANNABLE;
+import 'generated/shared_messages.dart' as shared_messages;
-import 'dart2js_messages.dart' as dart2js_messages;
+export 'generated/shared_messages.dart' show SharedMessageKind;
+
+const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
/// Keys for the [MessageTemplate]s.
enum MessageKind {
@@ -406,472 +471,13 @@
YIELDING_MODIFIER_ON_ARROW_BODY,
}
-const _KIND_TO_STRING_MAP = const <MessageKind, String>{
- MessageKind.ABSTRACT_CLASS_INSTANTIATION: "ABSTRACT_CLASS_INSTANTIATION",
- MessageKind.ABSTRACT_GETTER: "ABSTRACT_GETTER",
- MessageKind.ABSTRACT_METHOD: "ABSTRACT_METHOD",
- MessageKind.ABSTRACT_SETTER: "ABSTRACT_SETTER",
- MessageKind.ACCESSED_IN_CLOSURE: "ACCESSED_IN_CLOSURE",
- MessageKind.ACCESSED_IN_CLOSURE_HERE: "ACCESSED_IN_CLOSURE_HERE",
- MessageKind.ADDITIONAL_ARGUMENT: "ADDITIONAL_ARGUMENT",
- MessageKind.ADDITIONAL_TYPE_ARGUMENT: "ADDITIONAL_TYPE_ARGUMENT",
- MessageKind.ALREADY_INITIALIZED: "ALREADY_INITIALIZED",
- MessageKind.AMBIGUOUS_LOCATION: "AMBIGUOUS_LOCATION",
- MessageKind.AMBIGUOUS_REEXPORT: "AMBIGUOUS_REEXPORT",
- MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS:
- "ASSERT_IS_GIVEN_NAMED_ARGUMENTS",
- MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER: "ASSIGNING_FINAL_FIELD_IN_SUPER",
- MessageKind.ASSIGNING_METHOD: "ASSIGNING_METHOD",
- MessageKind.ASSIGNING_METHOD_IN_SUPER: "ASSIGNING_METHOD_IN_SUPER",
- MessageKind.ASSIGNING_TYPE: "ASSIGNING_TYPE",
- MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER: "ASYNC_KEYWORD_AS_IDENTIFIER",
- MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD:
- "ASYNC_MODIFIER_ON_ABSTRACT_METHOD",
- MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR: "ASYNC_MODIFIER_ON_CONSTRUCTOR",
- MessageKind.ASYNC_MODIFIER_ON_SETTER: "ASYNC_MODIFIER_ON_SETTER",
- MessageKind.AWAIT_MEMBER_NOT_FOUND: "AWAIT_MEMBER_NOT_FOUND",
- MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE:
- "AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE",
- MessageKind.BAD_INPUT_CHARACTER: "BAD_INPUT_CHARACTER",
- MessageKind.BEFORE_TOP_LEVEL: "BEFORE_TOP_LEVEL",
- MessageKind.BINARY_OPERATOR_BAD_ARITY: "BINARY_OPERATOR_BAD_ARITY",
- MessageKind.BODY_EXPECTED: "BODY_EXPECTED",
- MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
- "CALL_NOT_SUPPORTED_ON_NATIVE_CLASS",
- MessageKind.CANNOT_EXTEND: "CANNOT_EXTEND",
- MessageKind.CANNOT_EXTEND_ENUM: "CANNOT_EXTEND_ENUM",
- MessageKind.CANNOT_EXTEND_MALFORMED: "CANNOT_EXTEND_MALFORMED",
- MessageKind.CANNOT_FIND_CONSTRUCTOR: "CANNOT_FIND_CONSTRUCTOR",
- MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR:
- "CANNOT_FIND_UNNAMED_CONSTRUCTOR",
- MessageKind.CANNOT_IMPLEMENT: "CANNOT_IMPLEMENT",
- MessageKind.CANNOT_IMPLEMENT_ENUM: "CANNOT_IMPLEMENT_ENUM",
- MessageKind.CANNOT_IMPLEMENT_MALFORMED: "CANNOT_IMPLEMENT_MALFORMED",
- MessageKind.CANNOT_INSTANTIATE_ENUM: "CANNOT_INSTANTIATE_ENUM",
- MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE:
- "CANNOT_INSTANTIATE_TYPE_VARIABLE",
- MessageKind.CANNOT_INSTANTIATE_TYPEDEF: "CANNOT_INSTANTIATE_TYPEDEF",
- MessageKind.CANNOT_MIXIN: "CANNOT_MIXIN",
- MessageKind.CANNOT_MIXIN_ENUM: "CANNOT_MIXIN_ENUM",
- MessageKind.CANNOT_MIXIN_MALFORMED: "CANNOT_MIXIN_MALFORMED",
- MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD:
- "CANNOT_OVERRIDE_FIELD_WITH_METHOD",
- MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT:
- "CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT",
- MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD:
- "CANNOT_OVERRIDE_GETTER_WITH_METHOD",
- MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT:
- "CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT",
- MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD:
- "CANNOT_OVERRIDE_METHOD_WITH_FIELD",
- MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT:
- "CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT",
- MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER:
- "CANNOT_OVERRIDE_METHOD_WITH_GETTER",
- MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT:
- "CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT",
- MessageKind.CANNOT_RESOLVE: "CANNOT_RESOLVE",
- MessageKind.CANNOT_RESOLVE_AWAIT: "CANNOT_RESOLVE_AWAIT",
- MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE:
- "CANNOT_RESOLVE_AWAIT_IN_CLOSURE",
- MessageKind.CANNOT_RESOLVE_CONSTRUCTOR: "CANNOT_RESOLVE_CONSTRUCTOR",
- MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT:
- "CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT",
- MessageKind.CANNOT_RESOLVE_GETTER: "CANNOT_RESOLVE_GETTER",
- MessageKind.CANNOT_RESOLVE_IN_INITIALIZER: "CANNOT_RESOLVE_IN_INITIALIZER",
- MessageKind.CANNOT_RESOLVE_SETTER: "CANNOT_RESOLVE_SETTER",
- MessageKind.CANNOT_RESOLVE_TYPE: "CANNOT_RESOLVE_TYPE",
- MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR: "CANNOT_RETURN_FROM_CONSTRUCTOR",
- MessageKind.CLASS_NAME_EXPECTED: "CLASS_NAME_EXPECTED",
- MessageKind.COMPILER_CRASHED: "COMPILER_CRASHED",
- MessageKind.COMPLEX_RETURNING_NSM: "COMPLEX_RETURNING_NSM",
- MessageKind.COMPLEX_THROWING_NSM: "COMPLEX_THROWING_NSM",
- MessageKind.CONSIDER_ANALYZE_ALL: "CONSIDER_ANALYZE_ALL",
- MessageKind.CONST_CALLS_NON_CONST: "CONST_CALLS_NON_CONST",
- MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT:
- "CONST_CALLS_NON_CONST_FOR_IMPLICIT",
- MessageKind.CONST_CONSTRUCTOR_HAS_BODY: "CONST_CONSTRUCTOR_HAS_BODY",
- MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS:
- "CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS",
- MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR:
- "CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR",
- MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD:
- "CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD",
- MessageKind.CONST_LOOP_VARIABLE: "CONST_LOOP_VARIABLE",
- MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS: "CONST_MAP_KEY_OVERRIDES_EQUALS",
- MessageKind.CONST_WITHOUT_INITIALIZER: "CONST_WITHOUT_INITIALIZER",
- MessageKind.CONSTRUCTOR_CALL_EXPECTED: "CONSTRUCTOR_CALL_EXPECTED",
- MessageKind.CONSTRUCTOR_IS_NOT_CONST: "CONSTRUCTOR_IS_NOT_CONST",
- MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE: "CONSTRUCTOR_WITH_RETURN_TYPE",
- MessageKind.CYCLIC_CLASS_HIERARCHY: "CYCLIC_CLASS_HIERARCHY",
- MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS: "CYCLIC_COMPILE_TIME_CONSTANTS",
- MessageKind.CYCLIC_REDIRECTING_FACTORY: "CYCLIC_REDIRECTING_FACTORY",
- MessageKind.CYCLIC_TYPE_VARIABLE: "CYCLIC_TYPE_VARIABLE",
- MessageKind.CYCLIC_TYPEDEF: "CYCLIC_TYPEDEF",
- MessageKind.CYCLIC_TYPEDEF_ONE: "CYCLIC_TYPEDEF_ONE",
- MessageKind.DART_EXT_NOT_SUPPORTED: "DART_EXT_NOT_SUPPORTED",
- MessageKind.DEFERRED_COMPILE_TIME_CONSTANT: "DEFERRED_COMPILE_TIME_CONSTANT",
- MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION:
- "DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION",
- MessageKind.DEFERRED_LIBRARY_DART_2_DART: "DEFERRED_LIBRARY_DART_2_DART",
- MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX:
- "DEFERRED_LIBRARY_DUPLICATE_PREFIX",
- MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX:
- "DEFERRED_LIBRARY_WITHOUT_PREFIX",
- MessageKind.DEFERRED_OLD_SYNTAX: "DEFERRED_OLD_SYNTAX",
- MessageKind.DEFERRED_TYPE_ANNOTATION: "DEFERRED_TYPE_ANNOTATION",
- MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX:
- "DEPRECATED_TYPEDEF_MIXIN_SYNTAX",
- MessageKind.DIRECTLY_THROWING_NSM: "DIRECTLY_THROWING_NSM",
- MessageKind.DISALLOWED_LIBRARY_IMPORT: "DISALLOWED_LIBRARY_IMPORT",
- MessageKind.DUPLICATE_DEFINITION: "DUPLICATE_DEFINITION",
- MessageKind.DUPLICATE_EXPORT: "DUPLICATE_EXPORT",
- MessageKind.DUPLICATE_EXPORT_CONT: "DUPLICATE_EXPORT_CONT",
- MessageKind.DUPLICATE_EXPORT_DECL: "DUPLICATE_EXPORT_DECL",
- MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS: "DUPLICATE_EXTENDS_IMPLEMENTS",
- MessageKind.DUPLICATE_IMPLEMENTS: "DUPLICATE_IMPLEMENTS",
- MessageKind.DUPLICATE_IMPORT: "DUPLICATE_IMPORT",
- MessageKind.DUPLICATE_INITIALIZER: "DUPLICATE_INITIALIZER",
- MessageKind.DUPLICATE_LABEL: "DUPLICATE_LABEL",
- MessageKind.DUPLICATE_SUPER_INITIALIZER: "DUPLICATE_SUPER_INITIALIZER",
- MessageKind.DUPLICATE_TYPE_VARIABLE_NAME: "DUPLICATE_TYPE_VARIABLE_NAME",
- MessageKind.DUPLICATED_LIBRARY_NAME: "DUPLICATED_LIBRARY_NAME",
- MessageKind.DUPLICATED_LIBRARY_RESOURCE: "DUPLICATED_LIBRARY_RESOURCE",
- MessageKind.DUPLICATED_PART_OF: "DUPLICATED_PART_OF",
- MessageKind.DUPLICATED_RESOURCE: "DUPLICATED_RESOURCE",
- MessageKind.EMPTY_CATCH_DECLARATION: "EMPTY_CATCH_DECLARATION",
- MessageKind.EMPTY_ENUM_DECLARATION: "EMPTY_ENUM_DECLARATION",
- MessageKind.EMPTY_HIDE: "EMPTY_HIDE",
- MessageKind.EQUAL_MAP_ENTRY_KEY: "EQUAL_MAP_ENTRY_KEY",
- MessageKind.EMPTY_SHOW: "EMPTY_SHOW",
- MessageKind.EXISTING_DEFINITION: "EXISTING_DEFINITION",
- MessageKind.EXISTING_LABEL: "EXISTING_LABEL",
- MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD:
- "EXPECTED_IDENTIFIER_NOT_RESERVED_WORD",
- MessageKind.EXPERIMENTAL_ASSERT_MESSAGE: "EXPERIMENTAL_ASSERT_MESSAGE",
- MessageKind.EXPONENT_MISSING: "EXPONENT_MISSING",
- MessageKind.EXPORT_BEFORE_PARTS: "EXPORT_BEFORE_PARTS",
- MessageKind.EXTERNAL_WITH_BODY: "EXTERNAL_WITH_BODY",
- MessageKind.EXTRA_CATCH_DECLARATION: "EXTRA_CATCH_DECLARATION",
- MessageKind.EXTRA_FORMALS: "EXTRA_FORMALS",
- MessageKind.EXTRANEOUS_MODIFIER: "EXTRANEOUS_MODIFIER",
- MessageKind.EXTRANEOUS_MODIFIER_REPLACE: "EXTRANEOUS_MODIFIER_REPLACE",
- MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY:
- "FACTORY_REDIRECTION_IN_NON_FACTORY",
- MessageKind.FINAL_FUNCTION_TYPE_PARAMETER: "FINAL_FUNCTION_TYPE_PARAMETER",
- MessageKind.FINAL_WITHOUT_INITIALIZER: "FINAL_WITHOUT_INITIALIZER",
- MessageKind.FORIN_NOT_ASSIGNABLE: "FORIN_NOT_ASSIGNABLE",
- MessageKind.FORMAL_DECLARED_CONST: "FORMAL_DECLARED_CONST",
- MessageKind.FORMAL_DECLARED_STATIC: "FORMAL_DECLARED_STATIC",
- MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT:
- "FUNCTION_TYPE_FORMAL_WITH_DEFAULT",
- MessageKind.FUNCTION_WITH_INITIALIZER: "FUNCTION_WITH_INITIALIZER",
- MessageKind.GENERIC: "GENERIC",
- MessageKind.GETTER_MISMATCH: "GETTER_MISMATCH",
- MessageKind.GETTER_NOT_FOUND: "GETTER_NOT_FOUND",
- MessageKind.HEX_DIGIT_EXPECTED: "HEX_DIGIT_EXPECTED",
- MessageKind.HIDDEN_HINTS: "HIDDEN_HINTS",
- MessageKind.HIDDEN_IMPLICIT_IMPORT: "HIDDEN_IMPLICIT_IMPORT",
- MessageKind.HIDDEN_IMPORT: "HIDDEN_IMPORT",
- MessageKind.HIDDEN_WARNINGS: "HIDDEN_WARNINGS",
- MessageKind.HIDDEN_WARNINGS_HINTS: "HIDDEN_WARNINGS_HINTS",
- MessageKind.IF_NULL_ASSIGNING_TYPE: "IF_NULL_ASSIGNING_TYPE",
- MessageKind.ILLEGAL_CONST_FIELD_MODIFIER: "ILLEGAL_CONST_FIELD_MODIFIER",
- MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS: "ILLEGAL_CONSTRUCTOR_MODIFIERS",
- MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER: "ILLEGAL_FINAL_METHOD_MODIFIER",
- MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS:
- "ILLEGAL_MIXIN_APPLICATION_MODIFIERS",
- MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR: "ILLEGAL_MIXIN_CONSTRUCTOR",
- MessageKind.ILLEGAL_MIXIN_CYCLE: "ILLEGAL_MIXIN_CYCLE",
- MessageKind.ILLEGAL_MIXIN_OBJECT: "ILLEGAL_MIXIN_OBJECT",
- MessageKind.ILLEGAL_MIXIN_SUPER_USE: "ILLEGAL_MIXIN_SUPER_USE",
- MessageKind.ILLEGAL_MIXIN_SUPERCLASS: "ILLEGAL_MIXIN_SUPERCLASS",
- MessageKind.ILLEGAL_MIXIN_WITH_SUPER: "ILLEGAL_MIXIN_WITH_SUPER",
- MessageKind.ILLEGAL_SETTER_FORMALS: "ILLEGAL_SETTER_FORMALS",
- MessageKind.ILLEGAL_STATIC: "ILLEGAL_STATIC",
- MessageKind.ILLEGAL_SUPER_SEND: "ILLEGAL_SUPER_SEND",
- MessageKind.IMPORT_BEFORE_PARTS: "IMPORT_BEFORE_PARTS",
- MessageKind.IMPORT_EXPERIMENTAL_MIRRORS: "IMPORT_EXPERIMENTAL_MIRRORS",
- MessageKind.IMPORT_PART_OF: "IMPORT_PART_OF",
- MessageKind.IMPORT_PART_OF_HERE: "IMPORT_PART_OF_HERE",
- MessageKind.IMPORTED_HERE: "IMPORTED_HERE",
- MessageKind.INHERIT_GETTER_AND_METHOD: "INHERIT_GETTER_AND_METHOD",
- MessageKind.INHERITED_EXPLICIT_GETTER: "INHERITED_EXPLICIT_GETTER",
- MessageKind.INHERITED_IMPLICIT_GETTER: "INHERITED_IMPLICIT_GETTER",
- MessageKind.INHERITED_METHOD: "INHERITED_METHOD",
- MessageKind.INJECTED_PUBLIC_MEMBER: "INJECTED_PUBLIC_MEMBER",
- MessageKind.INIT_STATIC_FIELD: "INIT_STATIC_FIELD",
- MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED:
- "INITIALIZING_FORMAL_NOT_ALLOWED",
- MessageKind.INSTANCE_STATIC_SAME_NAME: "INSTANCE_STATIC_SAME_NAME",
- MessageKind.INSTANCE_STATIC_SAME_NAME_CONT: "INSTANCE_STATIC_SAME_NAME_CONT",
- MessageKind.INTERNAL_LIBRARY: "INTERNAL_LIBRARY",
- MessageKind.INTERNAL_LIBRARY_FROM: "INTERNAL_LIBRARY_FROM",
- MessageKind.INVALID_ARGUMENT_AFTER_NAMED: "INVALID_ARGUMENT_AFTER_NAMED",
- MessageKind.INVALID_AWAIT: "INVALID_AWAIT",
- MessageKind.INVALID_AWAIT_FOR: "INVALID_AWAIT_FOR",
- MessageKind.INVALID_AWAIT_FOR_IN: "INVALID_AWAIT_FOR_IN",
- MessageKind.INVALID_BREAK: "INVALID_BREAK",
- MessageKind.INVALID_CASE_DEFAULT: "INVALID_CASE_DEFAULT",
- MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS: "INVALID_CONSTRUCTOR_ARGUMENTS",
- MessageKind.INVALID_CONSTRUCTOR_NAME: "INVALID_CONSTRUCTOR_NAME",
- MessageKind.INVALID_CONTINUE: "INVALID_CONTINUE",
- MessageKind.INVALID_FOR_IN: "INVALID_FOR_IN",
- MessageKind.INVALID_INITIALIZER: "INVALID_INITIALIZER",
- MessageKind.INVALID_METADATA: "INVALID_METADATA",
- MessageKind.INVALID_METADATA_GENERIC: "INVALID_METADATA_GENERIC",
- MessageKind.INVALID_OVERRIDDEN_FIELD: "INVALID_OVERRIDDEN_FIELD",
- MessageKind.INVALID_OVERRIDDEN_GETTER: "INVALID_OVERRIDDEN_GETTER",
- MessageKind.INVALID_OVERRIDDEN_METHOD: "INVALID_OVERRIDDEN_METHOD",
- MessageKind.INVALID_OVERRIDDEN_SETTER: "INVALID_OVERRIDDEN_SETTER",
- MessageKind.INVALID_OVERRIDE_FIELD: "INVALID_OVERRIDE_FIELD",
- MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER:
- "INVALID_OVERRIDE_FIELD_WITH_GETTER",
- MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER:
- "INVALID_OVERRIDE_FIELD_WITH_SETTER",
- MessageKind.INVALID_OVERRIDE_GETTER: "INVALID_OVERRIDE_GETTER",
- MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD:
- "INVALID_OVERRIDE_GETTER_WITH_FIELD",
- MessageKind.INVALID_OVERRIDE_METHOD: "INVALID_OVERRIDE_METHOD",
- MessageKind.INVALID_OVERRIDE_SETTER: "INVALID_OVERRIDE_SETTER",
- MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD:
- "INVALID_OVERRIDE_SETTER_WITH_FIELD",
- MessageKind.INVALID_PACKAGE_CONFIG: "INVALID_PACKAGE_CONFIG",
- MessageKind.INVALID_PACKAGE_URI: "INVALID_PACKAGE_URI",
- MessageKind.INVALID_PARAMETER: "INVALID_PARAMETER",
- MessageKind.INVALID_RECEIVER_IN_INITIALIZER:
- "INVALID_RECEIVER_IN_INITIALIZER",
- MessageKind.INVALID_SOURCE_FILE_LOCATION: "INVALID_SOURCE_FILE_LOCATION",
- MessageKind.INVALID_SYMBOL: "INVALID_SYMBOL",
- MessageKind.INVALID_SYNC_MODIFIER: "INVALID_SYNC_MODIFIER",
- MessageKind.INVALID_TYPE_VARIABLE_BOUND: "INVALID_TYPE_VARIABLE_BOUND",
- MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME:
- "INVALID_UNNAMED_CONSTRUCTOR_NAME",
- MessageKind.INVALID_URI: "INVALID_URI",
- MessageKind.INVALID_USE_OF_SUPER: "INVALID_USE_OF_SUPER",
- MessageKind.INVALID_YIELD: "INVALID_YIELD",
- MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS:
- "JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS",
- MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER:
- "JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER",
- MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS:
- "JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS",
- MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS:
- "JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS",
- MessageKind.JS_PLACEHOLDER_CAPTURE: "JS_PLACEHOLDER_CAPTURE",
- MessageKind.LIBRARY_NAME_MISMATCH: "LIBRARY_NAME_MISMATCH",
- MessageKind.LIBRARY_NOT_FOUND: "LIBRARY_NOT_FOUND",
- MessageKind.LIBRARY_NOT_SUPPORTED: "LIBRARY_NOT_SUPPORTED",
- MessageKind.LIBRARY_TAG_MUST_BE_FIRST: "LIBRARY_TAG_MUST_BE_FIRST",
- MessageKind.MAIN_HAS_PART_OF: "MAIN_HAS_PART_OF",
- MessageKind.MAIN_NOT_A_FUNCTION: "MAIN_NOT_A_FUNCTION",
- MessageKind.MAIN_WITH_EXTRA_PARAMETER: "MAIN_WITH_EXTRA_PARAMETER",
- MessageKind.MALFORMED_STRING_LITERAL: "MALFORMED_STRING_LITERAL",
- MessageKind.MEMBER_NOT_FOUND: "MEMBER_NOT_FOUND",
- MessageKind.MEMBER_NOT_STATIC: "MEMBER_NOT_STATIC",
- MessageKind.MEMBER_USES_CLASS_NAME: "MEMBER_USES_CLASS_NAME",
- MessageKind.METHOD_NOT_FOUND: "METHOD_NOT_FOUND",
- MessageKind.MINUS_OPERATOR_BAD_ARITY: "MINUS_OPERATOR_BAD_ARITY",
- MessageKind.MIRROR_BLOAT: "MIRROR_BLOAT",
- MessageKind.MIRROR_IMPORT: "MIRROR_IMPORT",
- MessageKind.MIRROR_IMPORT_NO_USAGE: "MIRROR_IMPORT_NO_USAGE",
- MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT: "MIRRORS_CANNOT_FIND_IN_ELEMENT",
- MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY:
- "MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY",
- MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY:
- "MIRRORS_CANNOT_RESOLVE_IN_LIBRARY",
- MessageKind.MIRRORS_EXPECTED_STRING: "MIRRORS_EXPECTED_STRING",
- MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST:
- "MIRRORS_EXPECTED_STRING_OR_LIST",
- MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE:
- "MIRRORS_EXPECTED_STRING_OR_TYPE",
- MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST:
- "MIRRORS_EXPECTED_STRING_TYPE_OR_LIST",
- MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
- "MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND",
- MessageKind.MISSING_ARGUMENT: "MISSING_ARGUMENT",
- MessageKind.MISSING_ENUM_CASES: "MISSING_ENUM_CASES",
- MessageKind.MISSING_FACTORY_KEYWORD: "MISSING_FACTORY_KEYWORD",
- MessageKind.MISSING_FORMALS: "MISSING_FORMALS",
- MessageKind.MISSING_LIBRARY_NAME: "MISSING_LIBRARY_NAME",
- MessageKind.MISSING_MAIN: "MISSING_MAIN",
- MessageKind.MISSING_PART_OF_TAG: "MISSING_PART_OF_TAG",
- MessageKind.MISSING_TOKEN_AFTER_THIS: "MISSING_TOKEN_AFTER_THIS",
- MessageKind.MISSING_TOKEN_BEFORE_THIS: "MISSING_TOKEN_BEFORE_THIS",
- MessageKind.MISSING_TYPE_ARGUMENT: "MISSING_TYPE_ARGUMENT",
- MessageKind.MULTI_INHERITANCE: "MULTI_INHERITANCE",
- MessageKind.NAMED_ARGUMENT_NOT_FOUND: "NAMED_ARGUMENT_NOT_FOUND",
- MessageKind.NAMED_FUNCTION_EXPRESSION: "NAMED_FUNCTION_EXPRESSION",
- MessageKind.NAMED_PARAMETER_WITH_EQUALS: "NAMED_PARAMETER_WITH_EQUALS",
- MessageKind.NATIVE_NOT_SUPPORTED: "NATIVE_NOT_SUPPORTED",
- MessageKind.NO_BREAK_TARGET: "NO_BREAK_TARGET",
- MessageKind.NO_CATCH_NOR_FINALLY: "NO_CATCH_NOR_FINALLY",
- MessageKind.NO_COMMON_SUBTYPES: "NO_COMMON_SUBTYPES",
- MessageKind.NO_CONTINUE_TARGET: "NO_CONTINUE_TARGET",
- MessageKind.NO_INSTANCE_AVAILABLE: "NO_INSTANCE_AVAILABLE",
- MessageKind.NO_MATCHING_CONSTRUCTOR: "NO_MATCHING_CONSTRUCTOR",
- MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT:
- "NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT",
- MessageKind.NO_STATIC_OVERRIDE: "NO_STATIC_OVERRIDE",
- MessageKind.NO_STATIC_OVERRIDE_CONT: "NO_STATIC_OVERRIDE_CONT",
- MessageKind.NO_SUCH_LIBRARY_MEMBER: "NO_SUCH_LIBRARY_MEMBER",
- MessageKind.NO_SUCH_METHOD_IN_NATIVE: "NO_SUCH_METHOD_IN_NATIVE",
- MessageKind.NO_SUCH_SUPER_MEMBER: "NO_SUCH_SUPER_MEMBER",
- MessageKind.NO_SUPER_IN_STATIC: "NO_SUPER_IN_STATIC",
- MessageKind.NO_THIS_AVAILABLE: "NO_THIS_AVAILABLE",
- MessageKind.NON_CONST_BLOAT: "NON_CONST_BLOAT",
- MessageKind.NOT_A_COMPILE_TIME_CONSTANT: "NOT_A_COMPILE_TIME_CONSTANT",
- MessageKind.NOT_A_FIELD: "NOT_A_FIELD",
- MessageKind.NOT_A_PREFIX: "NOT_A_PREFIX",
- MessageKind.NOT_A_TYPE: "NOT_A_TYPE",
- MessageKind.NOT_ASSIGNABLE: "NOT_ASSIGNABLE",
- MessageKind.NOT_CALLABLE: "NOT_CALLABLE",
- MessageKind.NOT_INSTANCE_FIELD: "NOT_INSTANCE_FIELD",
- MessageKind.NOT_MORE_SPECIFIC: "NOT_MORE_SPECIFIC",
- MessageKind.NOT_MORE_SPECIFIC_SUBTYPE: "NOT_MORE_SPECIFIC_SUBTYPE",
- MessageKind.NOT_MORE_SPECIFIC_SUGGESTION: "NOT_MORE_SPECIFIC_SUGGESTION",
- MessageKind.NULL_NOT_ALLOWED: "NULL_NOT_ALLOWED",
- MessageKind.ONLY_ONE_LIBRARY_TAG: "ONLY_ONE_LIBRARY_TAG",
- MessageKind.OPERATOR_NAMED_PARAMETERS: "OPERATOR_NAMED_PARAMETERS",
- MessageKind.OPERATOR_NOT_FOUND: "OPERATOR_NOT_FOUND",
- MessageKind.OPERATOR_OPTIONAL_PARAMETERS: "OPERATOR_OPTIONAL_PARAMETERS",
- MessageKind.OPTIONAL_PARAMETER_IN_CATCH: "OPTIONAL_PARAMETER_IN_CATCH",
- MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE: "OVERRIDE_EQUALS_NOT_HASH_CODE",
- MessageKind.PARAMETER_NAME_EXPECTED: "PARAMETER_NAME_EXPECTED",
- MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH:
- "PARAMETER_WITH_MODIFIER_IN_CATCH",
- MessageKind.PARAMETER_WITH_TYPE_IN_CATCH: "PARAMETER_WITH_TYPE_IN_CATCH",
- MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION:
- "PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION",
- MessageKind.PATCH_NO_GETTER: "PATCH_NO_GETTER",
- MessageKind.PATCH_NO_SETTER: "PATCH_NO_SETTER",
- MessageKind.PATCH_NON_CLASS: "PATCH_NON_CLASS",
- MessageKind.PATCH_NON_CONSTRUCTOR: "PATCH_NON_CONSTRUCTOR",
- MessageKind.PATCH_NON_EXISTING: "PATCH_NON_EXISTING",
- MessageKind.PATCH_NON_EXTERNAL: "PATCH_NON_EXTERNAL",
- MessageKind.PATCH_NON_FUNCTION: "PATCH_NON_FUNCTION",
- MessageKind.PATCH_NON_GETTER: "PATCH_NON_GETTER",
- MessageKind.PATCH_NON_SETTER: "PATCH_NON_SETTER",
- MessageKind.PATCH_NONPATCHABLE: "PATCH_NONPATCHABLE",
- MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH:
- "PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH",
- MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH:
- "PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH",
- MessageKind.PATCH_PARAMETER_MISMATCH: "PATCH_PARAMETER_MISMATCH",
- MessageKind.PATCH_PARAMETER_TYPE_MISMATCH: "PATCH_PARAMETER_TYPE_MISMATCH",
- MessageKind.PATCH_POINT_TO_CLASS: "PATCH_POINT_TO_CLASS",
- MessageKind.PATCH_POINT_TO_CONSTRUCTOR: "PATCH_POINT_TO_CONSTRUCTOR",
- MessageKind.PATCH_POINT_TO_FUNCTION: "PATCH_POINT_TO_FUNCTION",
- MessageKind.PATCH_POINT_TO_GETTER: "PATCH_POINT_TO_GETTER",
- MessageKind.PATCH_POINT_TO_PARAMETER: "PATCH_POINT_TO_PARAMETER",
- MessageKind.PATCH_POINT_TO_SETTER: "PATCH_POINT_TO_SETTER",
- MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH:
- "PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH",
- MessageKind.PATCH_RETURN_TYPE_MISMATCH: "PATCH_RETURN_TYPE_MISMATCH",
- MessageKind.PLEASE_REPORT_THE_CRASH: "PLEASE_REPORT_THE_CRASH",
- MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS:
- "POSITIONAL_PARAMETER_WITH_EQUALS",
- MessageKind.POTENTIAL_MUTATION: "POTENTIAL_MUTATION",
- MessageKind.POTENTIAL_MUTATION_HERE: "POTENTIAL_MUTATION_HERE",
- MessageKind.POTENTIAL_MUTATION_IN_CLOSURE: "POTENTIAL_MUTATION_IN_CLOSURE",
- MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE:
- "POTENTIAL_MUTATION_IN_CLOSURE_HERE",
- MessageKind.PREAMBLE: "PREAMBLE",
- MessageKind.PREFIX_AS_EXPRESSION: "PREFIX_AS_EXPRESSION",
- MessageKind.PRIVATE_ACCESS: "PRIVATE_ACCESS",
- MessageKind.PRIVATE_IDENTIFIER: "PRIVATE_IDENTIFIER",
- MessageKind.PRIVATE_NAMED_PARAMETER: "PRIVATE_NAMED_PARAMETER",
- MessageKind.READ_SCRIPT_ERROR: "READ_SCRIPT_ERROR",
- MessageKind.READ_SELF_ERROR: "READ_SELF_ERROR",
- MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE: "REDIRECTING_CONSTRUCTOR_CYCLE",
- MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY:
- "REDIRECTING_CONSTRUCTOR_HAS_BODY",
- MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER:
- "REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER",
- MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT:
- "REDIRECTING_FACTORY_WITH_DEFAULT",
- MessageKind.REFERENCE_IN_INITIALIZATION: "REFERENCE_IN_INITIALIZATION",
- MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT:
- "REQUIRED_PARAMETER_WITH_DEFAULT",
- MessageKind.RETURN_IN_GENERATOR: "RETURN_IN_GENERATOR",
- MessageKind.RETURN_NOTHING: "RETURN_NOTHING",
- MessageKind.RETURN_VALUE_IN_VOID: "RETURN_VALUE_IN_VOID",
- MessageKind.SETTER_MISMATCH: "SETTER_MISMATCH",
- MessageKind.SETTER_NOT_FOUND: "SETTER_NOT_FOUND",
- MessageKind.SETTER_NOT_FOUND_IN_SUPER: "SETTER_NOT_FOUND_IN_SUPER",
- MessageKind.STATIC_FUNCTION_BLOAT: "STATIC_FUNCTION_BLOAT",
- MessageKind.STRING_EXPECTED: "STRING_EXPECTED",
- MessageKind.SUPER_CALL_TO_FACTORY: "SUPER_CALL_TO_FACTORY",
- MessageKind.SUPER_INITIALIZER_IN_OBJECT: "SUPER_INITIALIZER_IN_OBJECT",
- MessageKind.SWITCH_CASE_FORBIDDEN: "SWITCH_CASE_FORBIDDEN",
- MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL: "SWITCH_CASE_TYPES_NOT_EQUAL",
- MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE:
- "SWITCH_CASE_TYPES_NOT_EQUAL_CASE",
- MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS:
- "SWITCH_CASE_VALUE_OVERRIDES_EQUALS",
- MessageKind.TERNARY_OPERATOR_BAD_ARITY: "TERNARY_OPERATOR_BAD_ARITY",
- MessageKind.THIS_CALL_TO_FACTORY: "THIS_CALL_TO_FACTORY",
- MessageKind.THIS_IS_THE_DECLARATION: "THIS_IS_THE_DECLARATION",
- MessageKind.THIS_IS_THE_METHOD: "THIS_IS_THE_METHOD",
- MessageKind.THIS_IS_THE_PART_OF_TAG: "THIS_IS_THE_PART_OF_TAG",
- MessageKind.THIS_PROPERTY: "THIS_PROPERTY",
- MessageKind.THROW_WITHOUT_EXPRESSION: "THROW_WITHOUT_EXPRESSION",
- MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC:
- "TOP_LEVEL_VARIABLE_DECLARED_STATIC",
- MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH: "TYPE_ARGUMENT_COUNT_MISMATCH",
- MessageKind.TYPE_VARIABLE_IN_CONSTANT: "TYPE_VARIABLE_IN_CONSTANT",
- MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER:
- "TYPE_VARIABLE_WITHIN_STATIC_MEMBER",
- MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT: "TYPEDEF_FORMAL_WITH_DEFAULT",
- MessageKind.UNARY_OPERATOR_BAD_ARITY: "UNARY_OPERATOR_BAD_ARITY",
- MessageKind.UNBOUND_LABEL: "UNBOUND_LABEL",
- MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER: "UNIMPLEMENTED_EXPLICIT_GETTER",
- MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER: "UNIMPLEMENTED_EXPLICIT_SETTER",
- MessageKind.UNIMPLEMENTED_GETTER: "UNIMPLEMENTED_GETTER",
- MessageKind.UNIMPLEMENTED_GETTER_ONE: "UNIMPLEMENTED_GETTER_ONE",
- MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER: "UNIMPLEMENTED_IMPLICIT_GETTER",
- MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER: "UNIMPLEMENTED_IMPLICIT_SETTER",
- MessageKind.UNIMPLEMENTED_METHOD: "UNIMPLEMENTED_METHOD",
- MessageKind.UNIMPLEMENTED_METHOD_CONT: "UNIMPLEMENTED_METHOD_CONT",
- MessageKind.UNIMPLEMENTED_METHOD_ONE: "UNIMPLEMENTED_METHOD_ONE",
- MessageKind.UNIMPLEMENTED_SETTER: "UNIMPLEMENTED_SETTER",
- MessageKind.UNIMPLEMENTED_SETTER_ONE: "UNIMPLEMENTED_SETTER_ONE",
- MessageKind.UNMATCHED_TOKEN: "UNMATCHED_TOKEN",
- MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP:
- "UNRECOGNIZED_VERSION_OF_LOOKUP_MAP",
- MessageKind.UNSUPPORTED_BANG_EQ_EQ: "UNSUPPORTED_BANG_EQ_EQ",
- MessageKind.UNSUPPORTED_EQ_EQ_EQ: "UNSUPPORTED_EQ_EQ_EQ",
- MessageKind.UNSUPPORTED_LITERAL_SYMBOL: "UNSUPPORTED_LITERAL_SYMBOL",
- MessageKind.UNSUPPORTED_PREFIX_PLUS: "UNSUPPORTED_PREFIX_PLUS",
- MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP: "UNSUPPORTED_THROW_WITHOUT_EXP",
- MessageKind.UNTERMINATED_COMMENT: "UNTERMINATED_COMMENT",
- MessageKind.UNTERMINATED_STRING: "UNTERMINATED_STRING",
- MessageKind.UNTERMINATED_TOKEN: "UNTERMINATED_TOKEN",
- MessageKind.UNUSED_CLASS: "UNUSED_CLASS",
- MessageKind.UNUSED_LABEL: "UNUSED_LABEL",
- MessageKind.UNUSED_METHOD: "UNUSED_METHOD",
- MessageKind.UNUSED_TYPEDEF: "UNUSED_TYPEDEF",
- MessageKind.VAR_FUNCTION_TYPE_PARAMETER: "VAR_FUNCTION_TYPE_PARAMETER",
- MessageKind.VOID_EXPRESSION: "VOID_EXPRESSION",
- MessageKind.VOID_NOT_ALLOWED: "VOID_NOT_ALLOWED",
- MessageKind.VOID_VARIABLE: "VOID_VARIABLE",
- MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT:
- "WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT",
- MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT:
- "WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT",
- MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY:
- "YIELDING_MODIFIER_ON_ARROW_BODY",
-};
-
/// A message template for an error, warning, hint or info message generated
/// by the compiler. Each template is associated with a [MessageKind] that
/// uniquely identifies the message template.
// TODO(johnnniwinther): For Infos, consider adding a reference to the
// error/warning/hint that they belong to.
class MessageTemplate {
- final MessageKind kind;
-
- final String id;
+ final dynamic/*MessageKind | SharedMessageKind*/ kind;
/// Should describe what is wrong and why.
final String template;
@@ -892,8 +498,3176 @@
/// Additional options needed for the examples to work.
final List<String> options;
- const MessageTemplate(this.kind, this.id, this.template, this.howToFix,
- this.examples, this.options);
+ const MessageTemplate(
+ this.kind,
+ this.template,
+ {this.howToFix,
+ this.examples,
+ this.options: const <String>[]});
+
+ /// All templates used by the compiler.
+ ///
+ /// The map is complete mapping from [MessageKind] to their corresponding
+ /// [MessageTemplate].
+ // The key type is a union of MessageKind and SharedMessageKind.
+ static final Map<dynamic, MessageTemplate> TEMPLATES =
+ <dynamic, MessageTemplate>{}
+ ..addAll(shared_messages.TEMPLATES)
+ ..addAll(const<MessageKind, MessageTemplate>{
+ /// Do not use this. It is here for legacy and debugging. It violates item
+ /// 4 of the guide lines for error messages in the beginning of the file.
+ MessageKind.GENERIC:
+ const MessageTemplate(MessageKind.GENERIC, '#{text}'),
+
+ MessageKind.NOT_ASSIGNABLE:
+ const MessageTemplate(MessageKind.NOT_ASSIGNABLE,
+ "'#{fromType}' is not assignable to '#{toType}'."),
+
+ MessageKind.FORIN_NOT_ASSIGNABLE:
+ const MessageTemplate(MessageKind.FORIN_NOT_ASSIGNABLE,
+ "The element type '#{currentType}' of '#{expressionType}' "
+ "is not assignable to '#{elementType}'."),
+
+ MessageKind.VOID_EXPRESSION:
+ const MessageTemplate(MessageKind.VOID_EXPRESSION,
+ "Expression does not yield a value."),
+
+ MessageKind.VOID_VARIABLE:
+ const MessageTemplate(MessageKind.VOID_VARIABLE,
+ "Variable cannot be of type void."),
+
+ MessageKind.RETURN_VALUE_IN_VOID:
+ const MessageTemplate(MessageKind.RETURN_VALUE_IN_VOID,
+ "Cannot return value from void function."),
+
+ MessageKind.RETURN_NOTHING:
+ const MessageTemplate(MessageKind.RETURN_NOTHING,
+ "Value of type '#{returnType}' expected."),
+
+ MessageKind.MISSING_ARGUMENT:
+ const MessageTemplate(MessageKind.MISSING_ARGUMENT,
+ "Missing argument of type '#{argumentType}'."),
+
+ MessageKind.ADDITIONAL_ARGUMENT:
+ const MessageTemplate(MessageKind.ADDITIONAL_ARGUMENT,
+ "Additional argument."),
+
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND:
+ const MessageTemplate(MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ "No named argument '#{argumentName}' found on method."),
+
+ MessageKind.MEMBER_NOT_FOUND:
+ const MessageTemplate(MessageKind.MEMBER_NOT_FOUND,
+ "No member named '#{memberName}' in class '#{className}'."),
+
+ MessageKind.AWAIT_MEMBER_NOT_FOUND:
+ const MessageTemplate(MessageKind.AWAIT_MEMBER_NOT_FOUND,
+ "No member named 'await' in class '#{className}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to '#{functionName}'?",
+ examples: const ["""
+class A {
+ m() => await -3;
+}
+main() => new A().m();
+"""]),
+
+ MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE:
+ const MessageTemplate(MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE,
+ "No member named 'await' in class '#{className}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to the enclosing function?",
+ examples: const ["""
+class A {
+ m() => () => await -3;
+}
+main() => new A().m();
+"""]),
+
+ MessageKind.METHOD_NOT_FOUND:
+ const MessageTemplate(MessageKind.METHOD_NOT_FOUND,
+ "No method named '#{memberName}' in class '#{className}'."),
+
+ MessageKind.OPERATOR_NOT_FOUND:
+ const MessageTemplate(MessageKind.OPERATOR_NOT_FOUND,
+ "No operator '#{memberName}' in class '#{className}'."),
+
+ MessageKind.SETTER_NOT_FOUND:
+ const MessageTemplate(MessageKind.SETTER_NOT_FOUND,
+ "No setter named '#{memberName}' in class '#{className}'."),
+
+ MessageKind.SETTER_NOT_FOUND_IN_SUPER:
+ const MessageTemplate(MessageKind.SETTER_NOT_FOUND_IN_SUPER,
+ "No setter named '#{name}' in superclass of '#{className}'."),
+
+ MessageKind.GETTER_NOT_FOUND:
+ const MessageTemplate(MessageKind.GETTER_NOT_FOUND,
+ "No getter named '#{memberName}' in class '#{className}'."),
+
+ MessageKind.NOT_CALLABLE:
+ const MessageTemplate(MessageKind.NOT_CALLABLE,
+ "'#{elementName}' is not callable."),
+
+ MessageKind.MEMBER_NOT_STATIC:
+ const MessageTemplate(MessageKind.MEMBER_NOT_STATIC,
+ "'#{className}.#{memberName}' is not static."),
+
+ MessageKind.NO_INSTANCE_AVAILABLE:
+ const MessageTemplate(MessageKind.NO_INSTANCE_AVAILABLE,
+ "'#{name}' is only available in instance methods."),
+
+ MessageKind.NO_THIS_AVAILABLE:
+ const MessageTemplate(MessageKind.NO_THIS_AVAILABLE,
+ "'this' is only available in instance methods."),
+
+ MessageKind.PRIVATE_ACCESS:
+ const MessageTemplate(MessageKind.PRIVATE_ACCESS,
+ "'#{name}' is declared private within library "
+ "'#{libraryName}'."),
+
+ MessageKind.THIS_IS_THE_DECLARATION:
+ const MessageTemplate(MessageKind.THIS_IS_THE_DECLARATION,
+ "This is the declaration of '#{name}'."),
+
+ MessageKind.THIS_IS_THE_METHOD:
+ const MessageTemplate(MessageKind.THIS_IS_THE_METHOD,
+ "This is the method declaration."),
+
+ MessageKind.CANNOT_RESOLVE:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE,
+ "Cannot resolve '#{name}'."),
+
+ MessageKind.CANNOT_RESOLVE_AWAIT:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_AWAIT,
+ "Cannot resolve '#{name}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to '#{functionName}'?",
+ examples: const [
+ "main() => await -3;",
+ "foo() => await -3; main() => foo();"
+ ]),
+
+ MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE,
+ "Cannot resolve '#{name}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to the enclosing function?",
+ examples: const [
+ "main() { (() => await -3)(); }",
+ ]),
+
+ MessageKind.CANNOT_RESOLVE_IN_INITIALIZER:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_IN_INITIALIZER,
+ "Cannot resolve '#{name}'. It would be implicitly looked up on this "
+ "instance, but instances are not available in initializers.",
+ howToFix: "Try correcting the unresolved reference or move the "
+ "initialization to a constructor body.",
+ examples: const ["""
+class A {
+ var test = unresolvedName;
+}
+main() => new A();
+"""]),
+
+ MessageKind.CANNOT_RESOLVE_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_CONSTRUCTOR,
+ "Cannot resolve constructor '#{constructorName}'."),
+
+ MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT:
+ const MessageTemplate(
+ MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT,
+ "cannot resolve constructor '#{constructorName}' "
+ "for implicit super call.",
+ howToFix: "Try explicitly invoking a constructor of the super class",
+ examples: const ["""
+class A {
+ A.foo() {}
+}
+class B extends A {
+ B();
+}
+main() => new B();
+"""]),
+
+ MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME:
+ const MessageTemplate(MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
+ "Unnamed constructor name must be '#{name}'."),
+
+ MessageKind.INVALID_CONSTRUCTOR_NAME:
+ const MessageTemplate(MessageKind.INVALID_CONSTRUCTOR_NAME,
+ "Constructor name must start with '#{name}'."),
+
+ MessageKind.CANNOT_RESOLVE_TYPE:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_TYPE,
+ "Cannot resolve type '#{typeName}'."),
+
+ MessageKind.DUPLICATE_DEFINITION:
+ const MessageTemplate(MessageKind.DUPLICATE_DEFINITION,
+ "Duplicate definition of '#{name}'.",
+ howToFix: "Try to rename or remove this definition.",
+ examples: const ["""
+class C {
+ void f() {}
+ int get f => 1;
+}
+
+main() {
+ new C();
+}
+
+"""]),
+
+ MessageKind.EXISTING_DEFINITION:
+ const MessageTemplate(MessageKind.EXISTING_DEFINITION,
+ "Existing definition of '#{name}'."),
+
+ MessageKind.DUPLICATE_IMPORT:
+ const MessageTemplate(MessageKind.DUPLICATE_IMPORT,
+ "Duplicate import of '#{name}'."),
+
+ MessageKind.HIDDEN_IMPORT:
+ const MessageTemplate(MessageKind.HIDDEN_IMPORT,
+ "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
+ "from library '#{hidingUri}'.",
+ howToFix:
+ "Try adding 'hide #{name}' to the import of '#{hiddenUri}'.",
+ examples: const [
+ const {
+'main.dart':
+"""
+import 'dart:async'; // This imports a class Future.
+import 'future.dart';
+
+void main() => new Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}"""},
+
+ const {
+'main.dart':
+"""
+import 'future.dart';
+import 'dart:async'; // This imports a class Future.
+
+void main() => new Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}"""},
+
+ const {
+'main.dart':
+"""
+import 'export.dart';
+import 'dart:async'; // This imports a class Future.
+
+void main() => new Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}""",
+
+'export.dart':
+"""
+library export;
+
+export 'future.dart';"""},
+
+ const {
+'main.dart':
+"""
+import 'future.dart' as prefix;
+import 'dart:async' as prefix; // This imports a class Future.
+
+void main() => new prefix.Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}"""}]),
+
+
+ MessageKind.HIDDEN_IMPLICIT_IMPORT:
+ const MessageTemplate(MessageKind.HIDDEN_IMPLICIT_IMPORT,
+ "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
+ "from library '#{hidingUri}'.",
+ howToFix: "Try adding an explicit "
+ "'import \"#{hiddenUri}\" hide #{name}'.",
+ examples: const [
+ const {
+'main.dart':
+"""
+// This hides the implicit import of class Type from dart:core.
+import 'type.dart';
+
+void main() => new Type();""",
+
+'type.dart':
+"""
+library type;
+
+class Type {}"""},
+ const {
+'conflictsWithDart.dart':
+"""
+library conflictsWithDart;
+
+class Duration {
+ static var x = 100;
+}
+""",
+
+'conflictsWithDartAsWell.dart':
+"""
+library conflictsWithDartAsWell;
+
+class Duration {
+ static var x = 100;
+}
+""",
+
+'main.dart':
+r"""
+library testDartConflicts;
+
+import 'conflictsWithDart.dart';
+import 'conflictsWithDartAsWell.dart';
+
+main() {
+ print("Hail Caesar ${Duration.x}");
+}
+"""}]),
+
+ MessageKind.DUPLICATE_EXPORT:
+ const MessageTemplate(MessageKind.DUPLICATE_EXPORT,
+ "Duplicate export of '#{name}'.",
+ howToFix: "Try adding 'hide #{name}' to one of the exports.",
+ examples: const [const {
+'main.dart': """
+export 'decl1.dart';
+export 'decl2.dart';
+
+main() {}""",
+'decl1.dart': "class Class {}",
+'decl2.dart': "class Class {}"}]),
+
+ MessageKind.DUPLICATE_EXPORT_CONT:
+ const MessageTemplate(MessageKind.DUPLICATE_EXPORT_CONT,
+ "This is another export of '#{name}'."),
+
+ MessageKind.DUPLICATE_EXPORT_DECL:
+ const MessageTemplate(MessageKind.DUPLICATE_EXPORT_DECL,
+ "The exported '#{name}' from export #{uriString} is defined here."),
+
+ MessageKind.EMPTY_HIDE:
+ const MessageTemplate(MessageKind.EMPTY_HIDE,
+ "Library '#{uri}' doesn't export a '#{name}' declaration.",
+ howToFix: "Try removing '#{name}' the 'hide' clause.",
+ examples: const [
+ const {
+ 'main.dart': """
+import 'dart:core' hide Foo;
+
+main() {}"""},
+ const {
+'main.dart': """
+export 'dart:core' hide Foo;
+
+main() {}"""},
+]),
+
+ MessageKind.EMPTY_SHOW:
+ const MessageTemplate(MessageKind.EMPTY_SHOW,
+ "Library '#{uri}' doesn't export a '#{name}' declaration.",
+ howToFix: "Try removing '#{name}' from the 'show' clause.",
+ examples: const [
+ const {
+ 'main.dart': """
+import 'dart:core' show Foo;
+
+main() {}"""},
+ const {
+'main.dart': """
+export 'dart:core' show Foo;
+
+main() {}"""},
+]),
+
+ MessageKind.NOT_A_TYPE:
+ const MessageTemplate(MessageKind.NOT_A_TYPE,
+ "'#{node}' is not a type."),
+
+ MessageKind.NOT_A_PREFIX:
+ const MessageTemplate(MessageKind.NOT_A_PREFIX,
+ "'#{node}' is not a prefix."),
+
+ MessageKind.PREFIX_AS_EXPRESSION:
+ const MessageTemplate(MessageKind.PREFIX_AS_EXPRESSION,
+ "Library prefix '#{prefix}' is not a valid expression."),
+
+ MessageKind.CANNOT_FIND_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.CANNOT_FIND_CONSTRUCTOR,
+ "Cannot find constructor '#{constructorName}' in class "
+ "'#{className}'."),
+
+ MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR,
+ "Cannot find unnamed constructor in class "
+ "'#{className}'."),
+
+ MessageKind.CYCLIC_CLASS_HIERARCHY:
+ const MessageTemplate(MessageKind.CYCLIC_CLASS_HIERARCHY,
+ "'#{className}' creates a cycle in the class hierarchy."),
+
+ MessageKind.CYCLIC_REDIRECTING_FACTORY:
+ const MessageTemplate(MessageKind.CYCLIC_REDIRECTING_FACTORY,
+ 'Redirecting factory leads to a cyclic redirection.'),
+
+ MessageKind.INVALID_RECEIVER_IN_INITIALIZER:
+ const MessageTemplate(MessageKind.INVALID_RECEIVER_IN_INITIALIZER,
+ "Field initializer expected."),
+
+ MessageKind.NO_SUPER_IN_STATIC:
+ const MessageTemplate(MessageKind.NO_SUPER_IN_STATIC,
+ "'super' is only available in instance methods."),
+
+ MessageKind.DUPLICATE_INITIALIZER:
+ const MessageTemplate(MessageKind.DUPLICATE_INITIALIZER,
+ "Field '#{fieldName}' is initialized more than once."),
+
+ MessageKind.ALREADY_INITIALIZED:
+ const MessageTemplate(MessageKind.ALREADY_INITIALIZED,
+ "'#{fieldName}' was already initialized here."),
+
+ MessageKind.INIT_STATIC_FIELD:
+ const MessageTemplate(MessageKind.INIT_STATIC_FIELD,
+ "Cannot initialize static field '#{fieldName}'."),
+
+ MessageKind.NOT_A_FIELD:
+ const MessageTemplate(MessageKind.NOT_A_FIELD,
+ "'#{fieldName}' is not a field."),
+
+ MessageKind.CONSTRUCTOR_CALL_EXPECTED:
+ const MessageTemplate(MessageKind.CONSTRUCTOR_CALL_EXPECTED,
+ "only call to 'this' or 'super' constructor allowed."),
+
+ MessageKind.INVALID_FOR_IN:
+ const MessageTemplate(MessageKind.INVALID_FOR_IN,
+ "Invalid for-in variable declaration."),
+
+ MessageKind.INVALID_INITIALIZER:
+ const MessageTemplate(MessageKind.INVALID_INITIALIZER,
+ "Invalid initializer."),
+
+ MessageKind.FUNCTION_WITH_INITIALIZER:
+ const MessageTemplate(MessageKind.FUNCTION_WITH_INITIALIZER,
+ "Only constructors can have initializers."),
+
+ MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE:
+ const MessageTemplate(MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE,
+ "Cyclic constructor redirection."),
+
+ MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY:
+ const MessageTemplate(MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY,
+ "Redirecting constructor can't have a body."),
+
+ MessageKind.CONST_CONSTRUCTOR_HAS_BODY:
+ const MessageTemplate(MessageKind.CONST_CONSTRUCTOR_HAS_BODY,
+ "Const constructor or factory can't have a body.",
+ howToFix: "Remove the 'const' keyword or the body",
+ examples: const ["""
+class C {
+ const C() {}
+}
+
+main() => new C();"""]),
+
+ MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER:
+ const MessageTemplate(
+ MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER,
+ "Redirecting constructor cannot have other initializers."),
+
+ MessageKind.SUPER_INITIALIZER_IN_OBJECT:
+ const MessageTemplate(MessageKind.SUPER_INITIALIZER_IN_OBJECT,
+ "'Object' cannot have a super initializer."),
+
+ MessageKind.DUPLICATE_SUPER_INITIALIZER:
+ const MessageTemplate(MessageKind.DUPLICATE_SUPER_INITIALIZER,
+ "Cannot have more than one super initializer."),
+
+ MessageKind.SUPER_CALL_TO_FACTORY:
+ const MessageTemplate(MessageKind.SUPER_CALL_TO_FACTORY,
+ "The target of the superinitializer must be a generative "
+ "constructor.",
+ howToFix: "Try calling another constructor on the superclass.",
+ examples: const ["""
+class Super {
+ factory Super() => null;
+}
+class Class extends Super {}
+main() => new Class();
+""", """
+class Super {
+ factory Super() => null;
+}
+class Class extends Super {
+ Class();
+}
+main() => new Class();
+""", """
+class Super {
+ factory Super() => null;
+}
+class Class extends Super {
+ Class() : super();
+}
+main() => new Class();
+""", """
+class Super {
+ factory Super.foo() => null;
+}
+class Class extends Super {
+ Class() : super.foo();
+}
+main() => new Class();
+"""]),
+
+ MessageKind.THIS_CALL_TO_FACTORY:
+ const MessageTemplate(MessageKind.THIS_CALL_TO_FACTORY,
+ "The target of the redirection clause must be a generative "
+ "constructor",
+ howToFix: "Try redirecting to another constructor.",
+ examples: const ["""
+class Class {
+ factory Class() => null;
+ Class.foo() : this();
+}
+main() => new Class.foo();
+""", """
+class Class {
+ factory Class.foo() => null;
+ Class() : this.foo();
+}
+main() => new Class();
+"""]),
+
+ MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS:
+ const MessageTemplate(MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
+ "Arguments do not match the expected parameters of constructor "
+ "'#{constructorName}'."),
+
+ MessageKind.NO_MATCHING_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.NO_MATCHING_CONSTRUCTOR,
+ "'super' call arguments and constructor parameters do not match."),
+
+ MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT:
+ const MessageTemplate(MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT,
+ "Implicit 'super' call arguments and constructor parameters "
+ "do not match."),
+
+ MessageKind.CONST_CALLS_NON_CONST:
+ const MessageTemplate(MessageKind.CONST_CALLS_NON_CONST,
+ "'const' constructor cannot call a non-const constructor."),
+
+ MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT:
+ const MessageTemplate(MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT,
+ "'const' constructor cannot call a non-const constructor. "
+ "This constructor has an implicit call to a "
+ "super non-const constructor.",
+ howToFix: "Try making the super constructor const.",
+ examples: const ["""
+class C {
+ C(); // missing const
+}
+class D extends C {
+ final d;
+ const D(this.d);
+}
+main() => new D(0);"""]),
+
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS:
+ const MessageTemplate(
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
+ "Can't declare constructor 'const' on class #{className} "
+ "because the class contains non-final instance fields.",
+ howToFix: "Try making all fields final.",
+ examples: const ["""
+class C {
+ // 'a' must be declared final to allow for the const constructor.
+ var a;
+ const C(this.a);
+}
+
+main() => new C(0);"""]),
+
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD:
+ const MessageTemplate(
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD,
+ "This non-final field prevents using const constructors."),
+
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR:
+ const MessageTemplate(
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR,
+ "This const constructor is not allowed due to "
+ "non-final fields."),
+
+
+ MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED:
+ const MessageTemplate(MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED,
+ "Initializing formal parameter only allowed in generative "
+ "constructor."),
+
+ MessageKind.INVALID_PARAMETER:
+ const MessageTemplate(MessageKind.INVALID_PARAMETER,
+ "Cannot resolve parameter."),
+
+ MessageKind.NOT_INSTANCE_FIELD:
+ const MessageTemplate(MessageKind.NOT_INSTANCE_FIELD,
+ "'#{fieldName}' is not an instance field."),
+
+ MessageKind.THIS_PROPERTY:
+ const MessageTemplate(MessageKind.THIS_PROPERTY,
+ "Expected an identifier."),
+
+ MessageKind.NO_CATCH_NOR_FINALLY:
+ const MessageTemplate(MessageKind.NO_CATCH_NOR_FINALLY,
+ "Expected 'catch' or 'finally'."),
+
+ MessageKind.EMPTY_CATCH_DECLARATION:
+ const MessageTemplate(MessageKind.EMPTY_CATCH_DECLARATION,
+ "Expected an identifier in catch declaration."),
+
+ MessageKind.EXTRA_CATCH_DECLARATION:
+ const MessageTemplate(MessageKind.EXTRA_CATCH_DECLARATION,
+ "Extra parameter in catch declaration."),
+
+ MessageKind.PARAMETER_WITH_TYPE_IN_CATCH:
+ const MessageTemplate(MessageKind.PARAMETER_WITH_TYPE_IN_CATCH,
+ "Cannot use type annotations in catch."),
+
+ MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH:
+ const MessageTemplate(MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH,
+ "Cannot use modifiers in catch."),
+
+ MessageKind.OPTIONAL_PARAMETER_IN_CATCH:
+ const MessageTemplate(MessageKind.OPTIONAL_PARAMETER_IN_CATCH,
+ "Cannot use optional parameters in catch."),
+
+ MessageKind.THROW_WITHOUT_EXPRESSION:
+ const MessageTemplate(MessageKind.THROW_WITHOUT_EXPRESSION,
+ "Cannot use re-throw outside of catch block "
+ "(expression expected after 'throw')."),
+
+ MessageKind.UNBOUND_LABEL:
+ const MessageTemplate(MessageKind.UNBOUND_LABEL,
+ "Cannot resolve label '#{labelName}'."),
+
+ MessageKind.NO_BREAK_TARGET:
+ const MessageTemplate(MessageKind.NO_BREAK_TARGET,
+ "'break' statement not inside switch or loop."),
+
+ MessageKind.NO_CONTINUE_TARGET:
+ const MessageTemplate(MessageKind.NO_CONTINUE_TARGET,
+ "'continue' statement not inside loop."),
+
+ MessageKind.EXISTING_LABEL:
+ const MessageTemplate(MessageKind.EXISTING_LABEL,
+ "Original declaration of duplicate label '#{labelName}'."),
+
+ MessageKind.DUPLICATE_LABEL:
+ const MessageTemplate(MessageKind.DUPLICATE_LABEL,
+ "Duplicate declaration of label '#{labelName}'."),
+
+ MessageKind.UNUSED_LABEL:
+ const MessageTemplate(MessageKind.UNUSED_LABEL,
+ "Unused label '#{labelName}'."),
+
+ MessageKind.INVALID_CONTINUE:
+ const MessageTemplate(MessageKind.INVALID_CONTINUE,
+ "Target of continue is not a loop or switch case."),
+
+ MessageKind.INVALID_BREAK:
+ const MessageTemplate(MessageKind.INVALID_BREAK,
+ "Target of break is not a statement."),
+
+ MessageKind.DUPLICATE_TYPE_VARIABLE_NAME:
+ const MessageTemplate(MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
+ "Type variable '#{typeVariableName}' already declared."),
+
+ MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER:
+ const MessageTemplate(MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
+ "Cannot refer to type variable '#{typeVariableName}' "
+ "within a static member."),
+
+ MessageKind.TYPE_VARIABLE_IN_CONSTANT:
+ const MessageTemplate(MessageKind.TYPE_VARIABLE_IN_CONSTANT,
+ "Constant expressions can't refer to type variables.",
+ howToFix: "Try removing the type variable or replacing it with a "
+ "concrete type.",
+ examples: const ["""
+class C<T> {
+ const C();
+
+ m(T t) => const C<T>();
+}
+
+void main() => new C().m(null);
+"""
+]),
+
+ MessageKind.INVALID_TYPE_VARIABLE_BOUND:
+ const MessageTemplate(MessageKind.INVALID_TYPE_VARIABLE_BOUND,
+ "'#{typeArgument}' is not a subtype of bound '#{bound}' for "
+ "type variable '#{typeVariable}' of type '#{thisType}'.",
+ howToFix: "Try to change or remove the type argument.",
+ examples: const ["""
+class C<T extends num> {}
+
+// 'String' is not a valid instantiation of T with bound num.'.
+main() => new C<String>();
+"""]),
+
+ MessageKind.INVALID_USE_OF_SUPER:
+ const MessageTemplate(MessageKind.INVALID_USE_OF_SUPER,
+ "'super' not allowed here."),
+
+ MessageKind.INVALID_CASE_DEFAULT:
+ const MessageTemplate(MessageKind.INVALID_CASE_DEFAULT,
+ "'default' only allowed on last case of a switch."),
+
+ MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL:
+ const MessageTemplate(MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
+ "'case' expressions do not all have type '#{type}'."),
+
+ MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE:
+ const MessageTemplate(MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
+ "'case' expression of type '#{type}'."),
+
+ MessageKind.SWITCH_CASE_FORBIDDEN:
+ const MessageTemplate(MessageKind.SWITCH_CASE_FORBIDDEN,
+ "'case' expression may not be of type '#{type}'."),
+
+ MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS:
+ const MessageTemplate(MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
+ "'case' expression type '#{type}' overrides 'operator =='."),
+
+ MessageKind.INVALID_ARGUMENT_AFTER_NAMED:
+ const MessageTemplate(MessageKind.INVALID_ARGUMENT_AFTER_NAMED,
+ "Unnamed argument after named argument."),
+
+ MessageKind.INVALID_AWAIT_FOR_IN:
+ const MessageTemplate(MessageKind.INVALID_AWAIT_FOR_IN,
+ "'await' is only supported in methods with an 'async' or "
+ "'async*' body modifier.",
+ howToFix: "Try adding 'async' or 'async*' to the method body or "
+ "removing the 'await' keyword.",
+ examples: const [
+ """
+main(o) sync* {
+ await for (var e in o) {}
+}"""]),
+
+ MessageKind.INVALID_AWAIT:
+ const MessageTemplate(MessageKind.INVALID_AWAIT,
+ "'await' is only supported in methods with an 'async' or "
+ "'async*' body modifier.",
+ howToFix: "Try adding 'async' or 'async*' to the method body.",
+ examples: const [
+ """
+main(o) sync* {
+ await null;
+}"""]),
+
+ MessageKind.INVALID_YIELD:
+ const MessageTemplate(MessageKind.INVALID_YIELD,
+ "'yield' is only supported in methods with a 'sync*' or "
+ "'async*' body modifier.",
+ howToFix: "Try adding 'sync*' or 'async*' to the method body.",
+ examples: const [
+ """
+main(o) async {
+ yield 0;
+}"""]),
+
+ MessageKind.NOT_A_COMPILE_TIME_CONSTANT:
+ const MessageTemplate(MessageKind.NOT_A_COMPILE_TIME_CONSTANT,
+ "Not a compile-time constant."),
+
+ MessageKind.DEFERRED_COMPILE_TIME_CONSTANT:
+ const MessageTemplate(MessageKind.DEFERRED_COMPILE_TIME_CONSTANT,
+ "A deferred value cannot be used as a compile-time constant."),
+
+ MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION:
+ const MessageTemplate(
+ MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION,
+ "A deferred class cannot be used to create a "
+ "compile-time constant."),
+
+ MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS:
+ const MessageTemplate(MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS,
+ "Cycle in the compile-time constant computation."),
+
+ MessageKind.CONSTRUCTOR_IS_NOT_CONST:
+ const MessageTemplate(MessageKind.CONSTRUCTOR_IS_NOT_CONST,
+ "Constructor is not a 'const' constructor."),
+
+ MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS:
+ const MessageTemplate(MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
+ "Const-map key type '#{type}' overrides 'operator =='."),
+
+ MessageKind.NO_SUCH_LIBRARY_MEMBER:
+ const MessageTemplate(MessageKind.NO_SUCH_LIBRARY_MEMBER,
+ "'#{libraryName}' has no member named '#{memberName}'."),
+
+ MessageKind.CANNOT_INSTANTIATE_TYPEDEF:
+ const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
+ "Cannot instantiate typedef '#{typedefName}'."),
+
+ MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT,
+ "Non-optional parameters can't have a default value.",
+ howToFix:
+ "Try removing the default value or making the parameter optional.",
+ examples: const ["""
+main() {
+ foo(a: 1) => print(a);
+ foo(2);
+}""", """
+main() {
+ foo(a = 1) => print(a);
+ foo(2);
+}"""]),
+
+ MessageKind.NAMED_PARAMETER_WITH_EQUALS:
+ const MessageTemplate(MessageKind.NAMED_PARAMETER_WITH_EQUALS,
+ "Named optional parameters can't use '=' to specify a default "
+ "value.",
+ howToFix: "Try replacing '=' with ':'.",
+ examples: const ["""
+main() {
+ foo({a = 1}) => print(a);
+ foo(a: 2);
+}"""]),
+
+ MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS:
+ const MessageTemplate(MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS,
+ "Positional optional parameters can't use ':' to specify a "
+ "default value.",
+ howToFix: "Try replacing ':' with '='.",
+ examples: const ["""
+main() {
+ foo([a: 1]) => print(a);
+ foo(2);
+}"""]),
+
+ MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT,
+ "A parameter of a typedef can't specify a default value.",
+ howToFix:
+ "Try removing the default value.",
+ examples: const ["""
+typedef void F([int arg = 0]);
+
+main() {
+ F f;
+}""", """
+typedef void F({int arg: 0});
+
+main() {
+ F f;
+}"""]),
+
+ MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT,
+ "A function type parameter can't specify a default value.",
+ howToFix:
+ "Try removing the default value.",
+ examples: const ["""
+foo(f(int i, [a = 1])) {}
+
+main() {
+ foo(1, 2);
+}""", """
+foo(f(int i, {a: 1})) {}
+
+main() {
+ foo(1, a: 2);
+}"""]),
+
+ MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT,
+ "A parameter of a redirecting factory constructor can't specify a "
+ "default value.",
+ howToFix:
+ "Try removing the default value.",
+ examples: const ["""
+class A {
+ A([a]);
+ factory A.foo([a = 1]) = A;
+}
+
+main() {
+ new A.foo(1);
+}""", """
+class A {
+ A({a});
+ factory A.foo({a: 1}) = A;
+}
+
+main() {
+ new A.foo(a: 1);
+}"""]),
+
+ MessageKind.FORMAL_DECLARED_CONST:
+ const MessageTemplate(MessageKind.FORMAL_DECLARED_CONST,
+ "A formal parameter can't be declared const.",
+ howToFix: "Try removing 'const'.",
+ examples: const ["""
+foo(const x) {}
+main() => foo(42);
+""", """
+foo({const x}) {}
+main() => foo(42);
+""", """
+foo([const x]) {}
+main() => foo(42);
+"""]),
+
+ MessageKind.FORMAL_DECLARED_STATIC:
+ const MessageTemplate(MessageKind.FORMAL_DECLARED_STATIC,
+ "A formal parameter can't be declared static.",
+ howToFix: "Try removing 'static'.",
+ examples: const ["""
+foo(static x) {}
+main() => foo(42);
+""", """
+foo({static x}) {}
+main() => foo(42);
+""", """
+foo([static x]) {}
+main() => foo(42);
+"""]),
+
+ MessageKind.FINAL_FUNCTION_TYPE_PARAMETER:
+ const MessageTemplate(MessageKind.FINAL_FUNCTION_TYPE_PARAMETER,
+ "A function type parameter can't be declared final.",
+ howToFix: "Try removing 'final'.",
+ examples: const ["""
+foo(final int x(int a)) {}
+main() => foo((y) => 42);
+""", """
+foo({final int x(int a)}) {}
+main() => foo((y) => 42);
+""", """
+foo([final int x(int a)]) {}
+main() => foo((y) => 42);
+"""]),
+
+ MessageKind.VAR_FUNCTION_TYPE_PARAMETER:
+ const MessageTemplate(MessageKind.VAR_FUNCTION_TYPE_PARAMETER,
+ "A function type parameter can't be declared with 'var'.",
+ howToFix: "Try removing 'var'.",
+ examples: const ["""
+foo(var int x(int a)) {}
+main() => foo((y) => 42);
+""", """
+foo({var int x(int a)}) {}
+main() => foo((y) => 42);
+""", """
+foo([var int x(int a)]) {}
+main() => foo((y) => 42);
+"""]),
+
+ MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE:
+ const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
+ "Cannot instantiate type variable '#{typeVariableName}'."),
+
+ MessageKind.CYCLIC_TYPE_VARIABLE:
+ const MessageTemplate(MessageKind.CYCLIC_TYPE_VARIABLE,
+ "Type variable '#{typeVariableName}' is a supertype of itself."),
+
+ MessageKind.CYCLIC_TYPEDEF:
+ const MessageTemplate(MessageKind.CYCLIC_TYPEDEF,
+ "A typedef can't refer to itself.",
+ howToFix: "Try removing all references to '#{typedefName}' "
+ "in the definition of '#{typedefName}'.",
+ examples: const ["""
+typedef F F(); // The return type 'F' is a self-reference.
+main() { F f = null; }"""]),
+
+ MessageKind.CYCLIC_TYPEDEF_ONE:
+ const MessageTemplate(MessageKind.CYCLIC_TYPEDEF_ONE,
+ "A typedef can't refer to itself through another typedef.",
+ howToFix:
+ "Try removing all references to "
+ "'#{otherTypedefName}' in the definition of '#{typedefName}'.",
+ examples: const ["""
+typedef G F(); // The return type 'G' is a self-reference through typedef 'G'.
+typedef F G(); // The return type 'F' is a self-reference through typedef 'F'.
+main() { F f = null; }""",
+"""
+typedef G F(); // The return type 'G' creates a self-reference.
+typedef H G(); // The return type 'H' creates a self-reference.
+typedef H(F f); // The argument type 'F' creates a self-reference.
+main() { F f = null; }"""]),
+
+ MessageKind.CLASS_NAME_EXPECTED:
+ const MessageTemplate(MessageKind.CLASS_NAME_EXPECTED,
+ "Class name expected."),
+
+ MessageKind.CANNOT_EXTEND:
+ const MessageTemplate(MessageKind.CANNOT_EXTEND,
+ "'#{type}' cannot be extended."),
+
+ MessageKind.CANNOT_IMPLEMENT:
+ const MessageTemplate(MessageKind.CANNOT_IMPLEMENT,
+ "'#{type}' cannot be implemented."),
+
+ // TODO(johnnwinther): Split messages into reasons for malformedness.
+ MessageKind.CANNOT_EXTEND_MALFORMED:
+ const MessageTemplate(MessageKind.CANNOT_EXTEND_MALFORMED,
+ "Class '#{className}' can't extend the type '#{malformedType}' "
+ "because it is malformed.",
+ howToFix:
+ "Try correcting the malformed type annotation or removing the "
+ "'extends' clause.",
+ examples: const ["""
+class A extends Malformed {}
+main() => new A();"""]),
+
+ MessageKind.CANNOT_IMPLEMENT_MALFORMED:
+ const MessageTemplate(MessageKind.CANNOT_IMPLEMENT_MALFORMED,
+ "Class '#{className}' can't implement the type '#{malformedType}' "
+ "because it is malformed.",
+ howToFix:
+ "Try correcting the malformed type annotation or removing the "
+ "type from the 'implements' clause.",
+ examples: const ["""
+class A implements Malformed {}
+main() => new A();"""]),
+
+ MessageKind.CANNOT_MIXIN_MALFORMED:
+ const MessageTemplate(MessageKind.CANNOT_MIXIN_MALFORMED,
+ "Class '#{className}' can't mixin the type '#{malformedType}' "
+ "because it is malformed.",
+ howToFix:
+ "Try correcting the malformed type annotation or removing the "
+ "type from the 'with' clause.",
+ examples: const ["""
+class A extends Object with Malformed {}
+main() => new A();"""]),
+
+ MessageKind.CANNOT_MIXIN:
+ const MessageTemplate(MessageKind.CANNOT_MIXIN,
+ "The type '#{type}' can't be mixed in.",
+ howToFix: "Try removing '#{type}' from the 'with' clause.",
+ examples: const ["""
+class C extends Object with String {}
+
+main() => new C();
+""", """
+typedef C = Object with String;
+
+main() => new C();
+"""]),
+
+ MessageKind.CANNOT_EXTEND_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_EXTEND_ENUM,
+ "Class '#{className}' can't extend the type '#{enumType}' because "
+ "it is declared by an enum.",
+ howToFix: "Try making '#{enumType}' a normal class or removing the "
+ "'extends' clause.",
+ examples: const ["""
+enum Enum { A }
+class B extends Enum {}
+main() => new B();"""]),
+
+ MessageKind.CANNOT_IMPLEMENT_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_IMPLEMENT_ENUM,
+ "Class '#{className}' can't implement the type '#{enumType}' "
+ "because it is declared by an enum.",
+ howToFix: "Try making '#{enumType}' a normal class or removing the "
+ "type from the 'implements' clause.",
+ examples: const ["""
+enum Enum { A }
+class B implements Enum {}
+main() => new B();"""]),
+
+ MessageKind.CANNOT_MIXIN_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_MIXIN_ENUM,
+ "Class '#{className}' can't mixin the type '#{enumType}' because it "
+ "is declared by an enum.",
+ howToFix: "Try making '#{enumType}' a normal class or removing the "
+ "type from the 'with' clause.",
+ examples: const ["""
+enum Enum { A }
+class B extends Object with Enum {}
+main() => new B();"""]),
+
+ MessageKind.CANNOT_INSTANTIATE_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_ENUM,
+ "Enum type '#{enumName}' cannot be instantiated.",
+ howToFix: "Try making '#{enumType}' a normal class or use an enum "
+ "constant.",
+ examples: const ["""
+enum Enum { A }
+main() => new Enum(0);""", """
+enum Enum { A }
+main() => const Enum(0);"""]),
+
+ MessageKind.EMPTY_ENUM_DECLARATION:
+ const MessageTemplate(MessageKind.EMPTY_ENUM_DECLARATION,
+ "Enum '#{enumName}' must contain at least one value.",
+ howToFix: "Try adding an enum constant or making #{enumName} a "
+ "normal class.",
+ examples: const ["""
+enum Enum {}
+main() { Enum e; }"""]),
+
+ MessageKind.MISSING_ENUM_CASES:
+ const MessageTemplate(MessageKind.MISSING_ENUM_CASES,
+ "Missing enum constants in switch statement: #{enumValues}.",
+ howToFix: "Try adding the missing constants or a default case.",
+ examples: const ["""
+enum Enum { A, B }
+main() {
+ switch (Enum.A) {
+ case Enum.B: break;
+ }
+}""", """
+enum Enum { A, B, C }
+main() {
+ switch (Enum.A) {
+ case Enum.B: break;
+ }
+}"""]),
+
+ MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS:
+ const MessageTemplate(MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
+ "'#{type}' can not be both extended and implemented."),
+
+ MessageKind.DUPLICATE_IMPLEMENTS:
+ const MessageTemplate(MessageKind.DUPLICATE_IMPLEMENTS,
+ "'#{type}' must not occur more than once "
+ "in the implements clause."),
+
+ MessageKind.MULTI_INHERITANCE:
+ const MessageTemplate(MessageKind.MULTI_INHERITANCE,
+ "Dart2js does not currently support inheritance of the same class "
+ "with different type arguments: Both #{firstType} and #{secondType} "
+ "are supertypes of #{thisType}."),
+
+ MessageKind.ILLEGAL_SUPER_SEND:
+ const MessageTemplate(MessageKind.ILLEGAL_SUPER_SEND,
+ "'#{name}' cannot be called on super."),
+
+ MessageKind.NO_SUCH_SUPER_MEMBER:
+ const MessageTemplate(MessageKind.NO_SUCH_SUPER_MEMBER,
+ "Cannot resolve '#{memberName}' in a superclass of '#{className}'."),
+
+ MessageKind.ADDITIONAL_TYPE_ARGUMENT:
+ const MessageTemplate(MessageKind.ADDITIONAL_TYPE_ARGUMENT,
+ "Additional type argument."),
+
+ MessageKind.MISSING_TYPE_ARGUMENT:
+ const MessageTemplate(MessageKind.MISSING_TYPE_ARGUMENT,
+ "Missing type argument."),
+
+ // TODO(johnniwinther): Use ADDITIONAL_TYPE_ARGUMENT or
+ // MISSING_TYPE_ARGUMENT instead.
+ MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH:
+ const MessageTemplate(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
+ "Incorrect number of type arguments on '#{type}'."),
+
+ MessageKind.GETTER_MISMATCH:
+ const MessageTemplate(MessageKind.GETTER_MISMATCH,
+ "Setter disagrees on: '#{modifiers}'."),
+
+ MessageKind.SETTER_MISMATCH:
+ const MessageTemplate(MessageKind.SETTER_MISMATCH,
+ "Getter disagrees on: '#{modifiers}'."),
+
+ MessageKind.ILLEGAL_SETTER_FORMALS:
+ const MessageTemplate(MessageKind.ILLEGAL_SETTER_FORMALS,
+ "A setter must have exactly one argument."),
+
+ MessageKind.NO_STATIC_OVERRIDE:
+ const MessageTemplate(MessageKind.NO_STATIC_OVERRIDE,
+ "Static member cannot override instance member '#{memberName}' of "
+ "'#{className}'."),
+
+ MessageKind.NO_STATIC_OVERRIDE_CONT:
+ const MessageTemplate(MessageKind.NO_STATIC_OVERRIDE_CONT,
+ "This is the instance member that cannot be overridden "
+ "by a static member."),
+
+ MessageKind.INSTANCE_STATIC_SAME_NAME:
+ const MessageTemplate(MessageKind.INSTANCE_STATIC_SAME_NAME,
+ "Instance member '#{memberName}' and static member of "
+ "superclass '#{className}' have the same name."),
+
+ MessageKind.INSTANCE_STATIC_SAME_NAME_CONT:
+ const MessageTemplate(MessageKind.INSTANCE_STATIC_SAME_NAME_CONT,
+ "This is the static member with the same name."),
+
+ MessageKind.INVALID_OVERRIDE_METHOD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_METHOD,
+ "The type '#{declaredType}' of method '#{name}' declared in "
+ "'#{class}' is not a subtype of the overridden method type "
+ "'#{inheritedType}' inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDDEN_METHOD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_METHOD,
+ "This is the overridden method '#{name}' declared in class "
+ "'#{class}'."),
+
+ MessageKind.INVALID_OVERRIDE_GETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_GETTER,
+ "The type '#{declaredType}' of getter '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden getter inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDDEN_GETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_GETTER,
+ "This is the overridden getter '#{name}' declared in class "
+ "'#{class}'."),
+
+ MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD,
+ "The type '#{declaredType}' of field '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden getter inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER,
+ "The type '#{declaredType}' of getter '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden field inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDE_SETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_SETTER,
+ "The type '#{declaredType}' of setter '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden setter inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDDEN_SETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_SETTER,
+ "This is the overridden setter '#{name}' declared in class "
+ "'#{class}'."),
+
+ MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD,
+ "The type '#{declaredType}' of field '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden setter inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER,
+ "The type '#{declaredType}' of setter '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden field inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDE_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD,
+ "The type '#{declaredType}' of field '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden field inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDDEN_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_FIELD,
+ "This is the overridden field '#{name}' declared in class "
+ "'#{class}'."),
+
+ MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD:
+ const MessageTemplate(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD,
+ "Method '#{name}' in '#{class}' can't override field from "
+ "'#{inheritedClass}'."),
+
+ MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT,
+ "This is the field that cannot be overridden by a method."),
+
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD,
+ "Field '#{name}' in '#{class}' can't override method from "
+ "'#{inheritedClass}'."),
+
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT,
+ "This is the method that cannot be overridden by a field."),
+
+ MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD:
+ const MessageTemplate(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD,
+ "Method '#{name}' in '#{class}' can't override getter from "
+ "'#{inheritedClass}'."),
+
+ MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT,
+ "This is the getter that cannot be overridden by a method."),
+
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER:
+ const MessageTemplate(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER,
+ "Getter '#{name}' in '#{class}' can't override method from "
+ "'#{inheritedClass}'."),
+
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT,
+ "This is the method that cannot be overridden by a getter."),
+
+ MessageKind.MISSING_FORMALS:
+ const MessageTemplate(MessageKind.MISSING_FORMALS,
+ "Formal parameters are missing."),
+
+ MessageKind.EXTRA_FORMALS:
+ const MessageTemplate(MessageKind.EXTRA_FORMALS,
+ "Formal parameters are not allowed here."),
+
+ MessageKind.UNARY_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.UNARY_OPERATOR_BAD_ARITY,
+ "Operator '#{operatorName}' must have no parameters."),
+
+ MessageKind.MINUS_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.MINUS_OPERATOR_BAD_ARITY,
+ "Operator '-' must have 0 or 1 parameters."),
+
+ MessageKind.BINARY_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.BINARY_OPERATOR_BAD_ARITY,
+ "Operator '#{operatorName}' must have exactly 1 parameter."),
+
+ MessageKind.TERNARY_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.TERNARY_OPERATOR_BAD_ARITY,
+ "Operator '#{operatorName}' must have exactly 2 parameters."),
+
+ MessageKind.OPERATOR_OPTIONAL_PARAMETERS:
+ const MessageTemplate(MessageKind.OPERATOR_OPTIONAL_PARAMETERS,
+ "Operator '#{operatorName}' cannot have optional parameters."),
+
+ MessageKind.OPERATOR_NAMED_PARAMETERS:
+ const MessageTemplate(MessageKind.OPERATOR_NAMED_PARAMETERS,
+ "Operator '#{operatorName}' cannot have named parameters."),
+
+ MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE:
+ const MessageTemplate(MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE,
+ "Cannot have return type for constructor."),
+
+ MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR,
+ "Constructors can't return values.",
+ howToFix: "Remove the return statement or use a factory constructor.",
+ examples: const ["""
+class C {
+ C() {
+ return 1;
+ }
+}
+
+main() => new C();"""]),
+
+ MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER:
+ const MessageTemplate(MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER,
+ "Cannot have final modifier on method."),
+
+ MessageKind.ILLEGAL_CONST_FIELD_MODIFIER:
+ const MessageTemplate(MessageKind.ILLEGAL_CONST_FIELD_MODIFIER,
+ "Cannot have const modifier on non-static field.",
+ howToFix:
+ "Try adding a static modifier, or removing the const modifier.",
+ examples: const ["""
+class C {
+ const int a = 1;
+}
+
+main() => new C();"""]),
+
+ MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS:
+ const MessageTemplate(MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS,
+ "Illegal constructor modifiers: '#{modifiers}'."),
+
+ MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
+ "Illegal mixin application modifiers: '#{modifiers}'."),
+
+ MessageKind.ILLEGAL_MIXIN_SUPERCLASS:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_SUPERCLASS,
+ "Class used as mixin must have Object as superclass."),
+
+ MessageKind.ILLEGAL_MIXIN_OBJECT:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_OBJECT,
+ "Cannot use Object as mixin."),
+
+ MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR,
+ "Class used as mixin cannot have non-factory constructor."),
+
+ MessageKind.ILLEGAL_MIXIN_CYCLE:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_CYCLE,
+ "Class used as mixin introduces mixin cycle: "
+ "'#{mixinName1}' <-> '#{mixinName2}'."),
+
+ MessageKind.ILLEGAL_MIXIN_WITH_SUPER:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_WITH_SUPER,
+ "Cannot use class '#{className}' as a mixin because it uses "
+ "'super'."),
+
+ MessageKind.ILLEGAL_MIXIN_SUPER_USE:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_SUPER_USE,
+ "Use of 'super' in class used as mixin."),
+
+ MessageKind.PARAMETER_NAME_EXPECTED:
+ const MessageTemplate(MessageKind.PARAMETER_NAME_EXPECTED,
+ "parameter name expected."),
+
+ MessageKind.CANNOT_RESOLVE_GETTER:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_GETTER,
+ "Cannot resolve getter."),
+
+ MessageKind.CANNOT_RESOLVE_SETTER:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_SETTER,
+ "Cannot resolve setter."),
+
+ MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER:
+ const MessageTemplate(MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER,
+ "Cannot assign a value to final field '#{name}' "
+ "in superclass '#{superclassName}'."),
+
+ MessageKind.ASSIGNING_METHOD:
+ const MessageTemplate(MessageKind.ASSIGNING_METHOD,
+ "Cannot assign a value to a method."),
+
+ MessageKind.ASSIGNING_METHOD_IN_SUPER:
+ const MessageTemplate(MessageKind.ASSIGNING_METHOD_IN_SUPER,
+ "Cannot assign a value to method '#{name}' "
+ "in superclass '#{superclassName}'."),
+
+ MessageKind.ASSIGNING_TYPE:
+ const MessageTemplate(MessageKind.ASSIGNING_TYPE,
+ "Cannot assign a value to a type."),
+
+ MessageKind.IF_NULL_ASSIGNING_TYPE:
+ const MessageTemplate(MessageKind.IF_NULL_ASSIGNING_TYPE,
+ "Cannot assign a value to a type. Note that types are never null, "
+ "so this ??= assignment has no effect.",
+ howToFix: "Try removing the '??=' assignment.",
+ examples: const [
+ "class A {} main() { print(A ??= 3);}",
+ ]),
+
+ MessageKind.VOID_NOT_ALLOWED:
+ const MessageTemplate(MessageKind.VOID_NOT_ALLOWED,
+ "Type 'void' can't be used here because it isn't a return type.",
+ howToFix:
+ "Try removing 'void' keyword or replace it with 'var', 'final', "
+ "or a type.",
+ examples: const [
+ "void x; main() {}",
+ "foo(void x) {} main() { foo(null); }",
+ ]),
+
+ MessageKind.NULL_NOT_ALLOWED:
+ const MessageTemplate(MessageKind.NULL_NOT_ALLOWED,
+ "`null` can't be used here."),
+
+ MessageKind.BEFORE_TOP_LEVEL:
+ const MessageTemplate(MessageKind.BEFORE_TOP_LEVEL,
+ "Part header must come before top-level definitions."),
+
+ MessageKind.IMPORT_PART_OF:
+ const MessageTemplate(MessageKind.IMPORT_PART_OF,
+ "The imported library must not have a 'part-of' directive.",
+ howToFix: "Try removing the 'part-of' directive or replacing the "
+ "import of the library with a 'part' directive.",
+ examples: const [const {
+'main.dart': """
+library library;
+
+import 'part.dart';
+
+main() {}
+""",
+
+'part.dart': """
+part of library;
+"""}]),
+
+ MessageKind.IMPORT_PART_OF_HERE:
+ const MessageTemplate(MessageKind.IMPORT_PART_OF_HERE,
+ "The library is imported here."),
+
+ MessageKind.MAIN_HAS_PART_OF:
+ const MessageTemplate(MessageKind.MAIN_HAS_PART_OF,
+ "The main application file must not have a 'part-of' directive.",
+ howToFix: "Try removing the 'part-of' directive or starting "
+ "compilation from another file.",
+ examples: const [const {
+'main.dart': """
+part of library;
+
+main() {}
+"""}]),
+
+ MessageKind.LIBRARY_NAME_MISMATCH:
+ const MessageTemplate(MessageKind.LIBRARY_NAME_MISMATCH,
+ "Expected part of library name '#{libraryName}'.",
+ howToFix: "Try changing the directive to 'part of #{libraryName};'.",
+ examples: const [const {
+'main.dart': """
+library lib.foo;
+
+part 'part.dart';
+
+main() {}
+""",
+
+'part.dart': """
+part of lib.bar;
+"""}]),
+
+ MessageKind.MISSING_LIBRARY_NAME:
+ const MessageTemplate(MessageKind.MISSING_LIBRARY_NAME,
+ "Library has no name. Part directive expected library name "
+ "to be '#{libraryName}'.",
+ howToFix: "Try adding 'library #{libraryName};' to the library.",
+ examples: const [const {
+'main.dart': """
+part 'part.dart';
+
+main() {}
+""",
+
+'part.dart': """
+part of lib.foo;
+"""}]),
+
+ MessageKind.THIS_IS_THE_PART_OF_TAG:
+ const MessageTemplate(MessageKind.THIS_IS_THE_PART_OF_TAG,
+ "This is the part of directive."),
+
+ MessageKind.MISSING_PART_OF_TAG:
+ const MessageTemplate(MessageKind.MISSING_PART_OF_TAG,
+ "This file has no part-of tag, but it is being used as a part."),
+
+ MessageKind.DUPLICATED_PART_OF:
+ const MessageTemplate(MessageKind.DUPLICATED_PART_OF,
+ "Duplicated part-of directive."),
+
+ MessageKind.DUPLICATED_LIBRARY_NAME:
+ const MessageTemplate(MessageKind.DUPLICATED_LIBRARY_NAME,
+ "Duplicated library name '#{libraryName}'."),
+
+ MessageKind.DUPLICATED_RESOURCE:
+ const MessageTemplate(MessageKind.DUPLICATED_RESOURCE,
+ "The resource '#{resourceUri}' is loaded through both "
+ "'#{canonicalUri1}' and '#{canonicalUri2}'."),
+
+ MessageKind.DUPLICATED_LIBRARY_RESOURCE:
+ const MessageTemplate(MessageKind.DUPLICATED_LIBRARY_RESOURCE,
+ "The library '#{libraryName}' in '#{resourceUri}' is loaded through "
+ "both '#{canonicalUri1}' and '#{canonicalUri2}'."),
+
+ // This is used as an exception.
+ MessageKind.INVALID_SOURCE_FILE_LOCATION:
+ const MessageTemplate(MessageKind.INVALID_SOURCE_FILE_LOCATION, '''
+Invalid offset (#{offset}) in source map.
+File: #{fileName}
+Length: #{length}'''),
+
+ MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC:
+ const MessageTemplate(MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC,
+ "Top-level variable cannot be declared static."),
+
+ MessageKind.REFERENCE_IN_INITIALIZATION:
+ const MessageTemplate(MessageKind.REFERENCE_IN_INITIALIZATION,
+ "Variable '#{variableName}' is referenced during its "
+ "initialization.",
+ howToFix:
+ "If you are trying to reference a shadowed variable, rename "
+ "one of the variables.",
+ examples: const ["""
+foo(t) {
+ var t = t;
+ return t;
+}
+
+main() => foo(1);
+"""]),
+
+ MessageKind.CONST_WITHOUT_INITIALIZER:
+ const MessageTemplate(MessageKind.CONST_WITHOUT_INITIALIZER,
+ "A constant variable must be initialized.",
+ howToFix: "Try adding an initializer or "
+ "removing the 'const' modifier.",
+ examples: const ["""
+void main() {
+ const c; // This constant variable must be initialized.
+}"""]),
+
+ MessageKind.FINAL_WITHOUT_INITIALIZER:
+ const MessageTemplate(MessageKind.FINAL_WITHOUT_INITIALIZER,
+ "A final variable must be initialized.",
+ howToFix: "Try adding an initializer or "
+ "removing the 'final' modifier.",
+ examples: const [
+ "class C { static final field; } main() => C.field;"]),
+
+ MessageKind.CONST_LOOP_VARIABLE:
+ const MessageTemplate(MessageKind.CONST_LOOP_VARIABLE,
+ "A loop variable cannot be constant.",
+ howToFix: "Try remove the 'const' modifier or "
+ "replacing it with a 'final' modifier.",
+ examples: const ["""
+void main() {
+ for (const c in []) {}
+}"""]),
+
+ MessageKind.MEMBER_USES_CLASS_NAME:
+ const MessageTemplate(MessageKind.MEMBER_USES_CLASS_NAME,
+ "Member variable can't have the same name as the class it is "
+ "declared in.",
+ howToFix: "Try renaming the variable.",
+ examples: const ["""
+class A { var A; }
+main() {
+ var a = new A();
+ a.A = 1;
+}
+""", """
+class A { static var A; }
+main() => A.A = 1;
+"""]),
+
+ MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT:
+ const MessageTemplate(
+ MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
+ "Wrong number of arguments to assert. Should be 1, but given "
+ "#{argumentCount}."),
+
+ MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS:
+ const MessageTemplate(MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
+ "'assert' takes no named arguments, but given #{argumentCount}."),
+
+ MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY:
+ const MessageTemplate(MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY,
+ "Factory redirection only allowed in factories."),
+
+ MessageKind.MISSING_FACTORY_KEYWORD:
+ const MessageTemplate(MessageKind.MISSING_FACTORY_KEYWORD,
+ "Did you forget a factory keyword here?"),
+
+ MessageKind.NO_SUCH_METHOD_IN_NATIVE:
+ const MessageTemplate(MessageKind.NO_SUCH_METHOD_IN_NATIVE,
+ "'NoSuchMethod' is not supported for classes that extend native "
+ "classes."),
+
+ MessageKind.DEFERRED_LIBRARY_DART_2_DART:
+ const MessageTemplate(MessageKind.DEFERRED_LIBRARY_DART_2_DART,
+ "Deferred loading is not supported by the dart backend yet. "
+ "The output will not be split."),
+
+ MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX:
+ const MessageTemplate(MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX,
+ "This import is deferred but there is no prefix keyword.",
+ howToFix: "Try adding a prefix to the import."),
+
+ MessageKind.DEFERRED_OLD_SYNTAX:
+ const MessageTemplate(MessageKind.DEFERRED_OLD_SYNTAX,
+ "The DeferredLibrary annotation is obsolete.",
+ howToFix:
+ "Use the \"import 'lib.dart' deferred as prefix\" syntax instead."),
+
+ MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX:
+ const MessageTemplate(MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX,
+ "The prefix of this deferred import is not unique.",
+ howToFix: "Try changing the import prefix."),
+
+ MessageKind.DEFERRED_TYPE_ANNOTATION:
+ const MessageTemplate(MessageKind.DEFERRED_TYPE_ANNOTATION,
+ "The type #{node} is deferred. "
+ "Deferred types are not valid as type annotations.",
+ howToFix:
+ "Try using a non-deferred abstract class as an interface."),
+
+ MessageKind.ILLEGAL_STATIC:
+ const MessageTemplate(MessageKind.ILLEGAL_STATIC,
+ "Modifier static is only allowed on functions declared in "
+ "a class."),
+
+ MessageKind.STATIC_FUNCTION_BLOAT:
+ const MessageTemplate(MessageKind.STATIC_FUNCTION_BLOAT,
+ "Using '#{class}.#{name}' may lead to unnecessarily large "
+ "generated code.",
+ howToFix:
+ "Try adding '@MirrorsUsed(...)' as described at "
+ "https://goo.gl/Akrrog."),
+
+ MessageKind.NON_CONST_BLOAT:
+ const MessageTemplate(MessageKind.NON_CONST_BLOAT,
+ "Using 'new #{name}' may lead to unnecessarily large generated "
+ "code.",
+ howToFix:
+ "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
+ "described at https://goo.gl/Akrrog."),
+
+ MessageKind.STRING_EXPECTED:
+ const MessageTemplate(MessageKind.STRING_EXPECTED,
+ "Expected a 'String', but got an instance of '#{type}'."),
+
+ MessageKind.PRIVATE_IDENTIFIER:
+ const MessageTemplate(MessageKind.PRIVATE_IDENTIFIER,
+ "'#{value}' is not a valid Symbol name because it starts with "
+ "'_'."),
+
+ MessageKind.PRIVATE_NAMED_PARAMETER:
+ const MessageTemplate(MessageKind.PRIVATE_NAMED_PARAMETER,
+ "Named optional parameter can't have a library private name.",
+ howToFix:
+ "Try removing the '_' or making the parameter positional or "
+ "required.",
+ examples: const ["""foo({int _p}) {} main() => foo();"""]),
+
+ MessageKind.UNSUPPORTED_LITERAL_SYMBOL:
+ const MessageTemplate(MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
+ "Symbol literal '##{value}' is currently unsupported by dart2js."),
+
+ MessageKind.INVALID_SYMBOL:
+ const MessageTemplate(MessageKind.INVALID_SYMBOL, '''
+'#{value}' is not a valid Symbol name because is not:
+ * an empty String,
+ * a user defined operator,
+ * a qualified non-private identifier optionally followed by '=', or
+ * a qualified non-private identifier followed by '.' and a user-defined '''
+"operator."),
+
+ MessageKind.AMBIGUOUS_REEXPORT:
+ const MessageTemplate(MessageKind.AMBIGUOUS_REEXPORT,
+ "'#{name}' is (re)exported by multiple libraries."),
+
+ MessageKind.AMBIGUOUS_LOCATION:
+ const MessageTemplate(MessageKind.AMBIGUOUS_LOCATION,
+ "'#{name}' is defined here."),
+
+ MessageKind.IMPORTED_HERE:
+ const MessageTemplate(MessageKind.IMPORTED_HERE,
+ "'#{name}' is imported here."),
+
+ MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE:
+ const MessageTemplate(MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE,
+ "The class '#{class}' overrides 'operator==', "
+ "but not 'get hashCode'."),
+
+ MessageKind.INTERNAL_LIBRARY_FROM:
+ const MessageTemplate(MessageKind.INTERNAL_LIBRARY_FROM,
+ "Internal library '#{resolvedUri}' is not accessible from "
+ "'#{importingUri}'."),
+
+ MessageKind.INTERNAL_LIBRARY:
+ const MessageTemplate(MessageKind.INTERNAL_LIBRARY,
+ "Internal library '#{resolvedUri}' is not accessible."),
+
+ MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS:
+ const MessageTemplate(
+ MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS,
+ "Js-interop class '#{cls}' cannot extend from the non js-interop "
+ "class '#{superclass}'.",
+ howToFix: "Annotate the superclass with @JS.",
+ examples: const [
+ """
+ import 'package:js/js.dart';
+
+ class Foo { }
+
+ @JS()
+ class Bar extends Foo { }
+
+ main() {
+ new Bar();
+ }
+ """]),
+
+ MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER:
+ const MessageTemplate(
+ MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER,
+ "Member '#{member}' in js-interop class '#{cls}' is not external.",
+ howToFix: "Mark all interop methods external",
+ examples: const [
+ """
+ import 'package:js/js.dart';
+
+ @JS()
+ class Foo {
+ bar() {}
+ }
+
+ main() {
+ new Foo().bar();
+ }
+ """]),
+
+ MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS:
+ const MessageTemplate(
+ MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS,
+ "Js-interop method '#{method}' has named arguments but is not "
+ "a factory constructor of an @anonymous @JS class.",
+ howToFix: "Remove all named arguments from js-interop method or "
+ "in the case of a factory constructor annotate the class "
+ "as @anonymous.",
+ examples: const [
+ """
+ import 'package:js/js.dart';
+
+ @JS()
+ class Foo {
+ external bar(foo, {baz});
+ }
+
+ main() {
+ new Foo().bar(4, baz: 5);
+ }
+ """]),
+
+ MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS:
+ const MessageTemplate(
+ MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
+ "Parameter '#{parameter}' in anonymous js-interop class '#{cls}' "
+ "object literal constructor is positional instead of named."
+ ".",
+ howToFix: "Make all arguments in external factory object literal "
+ "constructors named.",
+ examples: const [
+ """
+ import 'package:js/js.dart';
+
+ @anonymous
+ @JS()
+ class Foo {
+ external factory Foo(foo, {baz});
+ }
+
+ main() {
+ new Foo(5, baz: 5);
+ }
+ """]),
+
+ MessageKind.LIBRARY_NOT_FOUND:
+ const MessageTemplate(MessageKind.LIBRARY_NOT_FOUND,
+ "Library not found '#{resolvedUri}'."),
+
+ MessageKind.LIBRARY_NOT_SUPPORTED:
+ const MessageTemplate(MessageKind.LIBRARY_NOT_SUPPORTED,
+ "Library not supported '#{resolvedUri}'.",
+ howToFix: "Try removing the dependency or enabling support using "
+ "the '--categories' option.",
+ examples: const [/*
+ """
+ import 'dart:io';
+ main() {}
+ """
+ */]),
+ // TODO(johnniwinther): Enable example when message_kind_test.dart
+ // supports library loader callbacks.
+
+ MessageKind.UNSUPPORTED_EQ_EQ_EQ:
+ const MessageTemplate(MessageKind.UNSUPPORTED_EQ_EQ_EQ,
+ "'===' is not an operator. "
+ "Did you mean '#{lhs} == #{rhs}' or 'identical(#{lhs}, #{rhs})'?"),
+
+ MessageKind.UNSUPPORTED_BANG_EQ_EQ:
+ const MessageTemplate(MessageKind.UNSUPPORTED_BANG_EQ_EQ,
+ "'!==' is not an operator. "
+ "Did you mean '#{lhs} != #{rhs}' or '!identical(#{lhs}, #{rhs})'?"),
+
+ MessageKind.UNSUPPORTED_PREFIX_PLUS:
+ const MessageTemplate(MessageKind.UNSUPPORTED_PREFIX_PLUS,
+ "'+' is not a prefix operator. ",
+ howToFix: "Try removing '+'.",
+ examples: const [
+ "main() => +2; // No longer a valid way to write '2'"
+ ]),
+
+ MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP:
+ const MessageTemplate(MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP,
+ "No expression after 'throw'. "
+ "Did you mean 'rethrow'?"),
+
+ MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX:
+ const MessageTemplate(MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX,
+ "'typedef' not allowed here. ",
+ howToFix: "Try replacing 'typedef' with 'class'.",
+ examples: const [
+ """
+class B { }
+class M1 { }
+typedef C = B with M1; // Need to replace 'typedef' with 'class'.
+main() { new C(); }
+"""]),
+
+ MessageKind.MIRRORS_EXPECTED_STRING:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "and a 'String' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
+// 'Foo' is a type literal, not a string.
+@MirrorsUsed(symbols: const [Foo])
+import 'dart:mirrors';
+
+class Foo {}
+
+main() {}
+"""]),
+
+ MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "and a 'String' or 'Type' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
+// 'main' is a method, not a class.
+@MirrorsUsed(targets: const [main])
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+ MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "and a 'String' or 'List' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
+// 'Foo' is not a string.
+@MirrorsUsed(symbols: Foo)
+import 'dart:mirrors';
+
+class Foo {}
+
+main() {}
+"""]),
+
+ MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "but a 'String', 'Type', or 'List' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
+// '1' is not a string.
+@MirrorsUsed(targets: 1)
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+ MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY:
+ const MessageTemplate(
+ MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY,
+ "Can't find '#{name}' in the current library.",
+ // TODO(ahe): The closest identifiers in edit distance would be nice.
+ howToFix: "Did you forget to add an import?",
+ examples: const [
+ """
+// 'window' is not in scope because dart:html isn't imported.
+@MirrorsUsed(targets: 'window')
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+ MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY:
+ const MessageTemplate(MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
+ "Can't find '#{name}' in the library '#{library}'.",
+ // TODO(ahe): The closest identifiers in edit distance would be nice.
+ howToFix: "Is '#{name}' spelled right?",
+ examples: const [
+ """
+// 'List' is misspelled.
+@MirrorsUsed(targets: 'dart.core.Lsit')
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+ MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT:
+ const MessageTemplate(MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT,
+ "Can't find '#{name}' in '#{element}'.",
+ // TODO(ahe): The closest identifiers in edit distance would be nice.
+ howToFix: "Is '#{name}' spelled right?",
+ examples: const [
+ """
+// 'addAll' is misspelled.
+@MirrorsUsed(targets: 'dart.core.List.addAl')
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+ MessageKind.INVALID_URI:
+ const MessageTemplate(MessageKind.INVALID_URI,
+ "'#{uri}' is not a valid URI.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ """
+// can't have a '[' in a URI
+import '../../Udyn[mic ils/expect.dart';
+
+main() {}
+"""]),
+
+ MessageKind.INVALID_PACKAGE_CONFIG:
+ const MessageTemplate(MessageKind.INVALID_PACKAGE_CONFIG,
+ """Package config file '#{uri}' is invalid.
+#{exception}""",
+ howToFix: DONT_KNOW_HOW_TO_FIX
+ ),
+
+ MessageKind.INVALID_PACKAGE_URI:
+ const MessageTemplate(MessageKind.INVALID_PACKAGE_URI,
+ "'#{uri}' is not a valid package URI (#{exception}).",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ """
+// can't have a 'top level' package URI
+import 'package:foo.dart';
+
+main() {}
+""", """
+// can't have 2 slashes
+import 'package://foo/foo.dart';
+
+main() {}
+""", """
+// package name must be valid
+import 'package:not\valid/foo.dart';
+
+main() {}
+"""]),
+
+ MessageKind.READ_SCRIPT_ERROR:
+ const MessageTemplate(MessageKind.READ_SCRIPT_ERROR,
+ "Can't read '#{uri}' (#{exception}).",
+ // Don't know how to fix since the underlying error is unknown.
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ """
+// 'foo.dart' does not exist.
+import 'foo.dart';
+
+main() {}
+"""]),
+
+ MessageKind.READ_SELF_ERROR:
+ const MessageTemplate(MessageKind.READ_SELF_ERROR,
+ "#{exception}",
+ // Don't know how to fix since the underlying error is unknown.
+ howToFix: DONT_KNOW_HOW_TO_FIX),
+
+ MessageKind.EXTRANEOUS_MODIFIER:
+ const MessageTemplate(MessageKind.EXTRANEOUS_MODIFIER,
+ "Can't have modifier '#{modifier}' here.",
+ howToFix: "Try removing '#{modifier}'.",
+ examples: const [
+ "var String foo; main(){}",
+ // "var get foo; main(){}",
+ "var set foo; main(){}",
+ "var final foo; main(){}",
+ "var var foo; main(){}",
+ "var const foo; main(){}",
+ "var abstract foo; main(){}",
+ "var static foo; main(){}",
+ "var external foo; main(){}",
+ "get var foo; main(){}",
+ "set var foo; main(){}",
+ "final var foo; main(){}",
+ "var var foo; main(){}",
+ "const var foo; main(){}",
+ "abstract var foo; main(){}",
+ "static var foo; main(){}",
+ "external var foo; main(){}"]),
+
+ MessageKind.EXTRANEOUS_MODIFIER_REPLACE:
+ const MessageTemplate(MessageKind.EXTRANEOUS_MODIFIER_REPLACE,
+ "Can't have modifier '#{modifier}' here.",
+ howToFix:
+ "Try replacing modifier '#{modifier}' with 'var', 'final', "
+ "or a type.",
+ examples: const [
+ // "get foo; main(){}",
+ "set foo; main(){}",
+ "abstract foo; main(){}",
+ "static foo; main(){}",
+ "external foo; main(){}"]),
+
+ MessageKind.ABSTRACT_CLASS_INSTANTIATION:
+ const MessageTemplate(MessageKind.ABSTRACT_CLASS_INSTANTIATION,
+ "Can't instantiate abstract class.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["abstract class A {} main() { new A(); }"]),
+
+ MessageKind.BODY_EXPECTED:
+ const MessageTemplate(MessageKind.BODY_EXPECTED,
+ "Expected a function body or '=>'.",
+ // TODO(ahe): In some scenarios, we can suggest removing the 'static'
+ // keyword.
+ howToFix: "Try adding {}.",
+ examples: const [
+ "main();"]),
+
+ MessageKind.MIRROR_BLOAT:
+ const MessageTemplate(MessageKind.MIRROR_BLOAT,
+ "#{count} methods retained for use by dart:mirrors out of #{total}"
+ " total methods (#{percentage}%)."),
+
+ MessageKind.MIRROR_IMPORT:
+ const MessageTemplate(MessageKind.MIRROR_IMPORT,
+ "Import of 'dart:mirrors'."),
+
+ MessageKind.MIRROR_IMPORT_NO_USAGE:
+ const MessageTemplate(MessageKind.MIRROR_IMPORT_NO_USAGE,
+ "This import is not annotated with @MirrorsUsed, which may lead to "
+ "unnecessarily large generated code.",
+ howToFix:
+ "Try adding '@MirrorsUsed(...)' as described at "
+ "https://goo.gl/Akrrog."),
+
+ MessageKind.JS_PLACEHOLDER_CAPTURE:
+ const MessageTemplate(
+ MessageKind.JS_PLACEHOLDER_CAPTURE,
+ "JS code must not use '#' placeholders inside functions.",
+ howToFix:
+ "Use an immediately called JavaScript function to capture the"
+ " the placeholder values as JavaScript function parameters."),
+
+ MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT:
+ const MessageTemplate(
+ MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT,
+ "Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant."),
+
+ MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD:
+ const MessageTemplate(MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+ "'#{keyword}' is a reserved word and can't be used here.",
+ howToFix: "Try using a different name.",
+ examples: const ["do() {} main() {}"]),
+
+ MessageKind. NAMED_FUNCTION_EXPRESSION:
+ const MessageTemplate(MessageKind.NAMED_FUNCTION_EXPRESSION,
+ "Function expression '#{name}' cannot be named.",
+ howToFix: "Try removing the name.",
+ examples: const ["main() { var f = func() {}; }"]),
+
+ MessageKind.UNUSED_METHOD:
+ const MessageTemplate(MessageKind.UNUSED_METHOD,
+ "The method '#{name}' is never called.",
+ howToFix: "Consider deleting it.",
+ examples: const ["deadCode() {} main() {}"]),
+
+ MessageKind.UNUSED_CLASS:
+ const MessageTemplate(MessageKind.UNUSED_CLASS,
+ "The class '#{name}' is never used.",
+ howToFix: "Consider deleting it.",
+ examples: const ["class DeadCode {} main() {}"]),
+
+ MessageKind.UNUSED_TYPEDEF:
+ const MessageTemplate(MessageKind.UNUSED_TYPEDEF,
+ "The typedef '#{name}' is never used.",
+ howToFix: "Consider deleting it.",
+ examples: const ["typedef DeadCode(); main() {}"]),
+
+ MessageKind.ABSTRACT_METHOD:
+ const MessageTemplate(MessageKind.ABSTRACT_METHOD,
+ "The method '#{name}' has no implementation in "
+ "class '#{class}'.",
+ howToFix: "Try adding a body to '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+class Class {
+ method();
+}
+main() => new Class().method();
+"""]),
+
+ MessageKind.ABSTRACT_GETTER:
+ const MessageTemplate(MessageKind.ABSTRACT_GETTER,
+ "The getter '#{name}' has no implementation in "
+ "class '#{class}'.",
+ howToFix: "Try adding a body to '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+class Class {
+ get getter;
+}
+main() => new Class();
+"""]),
+
+ MessageKind.ABSTRACT_SETTER:
+ const MessageTemplate(MessageKind.ABSTRACT_SETTER,
+ "The setter '#{name}' has no implementation in "
+ "class '#{class}'.",
+ howToFix: "Try adding a body to '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+class Class {
+ set setter(_);
+}
+main() => new Class();
+"""]),
+
+ MessageKind.INHERIT_GETTER_AND_METHOD:
+ const MessageTemplate(MessageKind.INHERIT_GETTER_AND_METHOD,
+ "The class '#{class}' can't inherit both getters and methods "
+ "by the named '#{name}'.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["""
+class A {
+ get member => null;
+}
+class B {
+ member() {}
+}
+class Class implements A, B {
+}
+main() => new Class();
+"""]),
+
+ MessageKind.INHERITED_METHOD:
+ const MessageTemplate(MessageKind.INHERITED_METHOD,
+ "The inherited method '#{name}' is declared here in class "
+ "'#{class}'."),
+
+ MessageKind.INHERITED_EXPLICIT_GETTER:
+ const MessageTemplate(MessageKind.INHERITED_EXPLICIT_GETTER,
+ "The inherited getter '#{name}' is declared here in class "
+ "'#{class}'."),
+
+ MessageKind.INHERITED_IMPLICIT_GETTER:
+ const MessageTemplate(MessageKind.INHERITED_IMPLICIT_GETTER,
+ "The inherited getter '#{name}' is implicitly declared by this "
+ "field in class '#{class}'."),
+
+ MessageKind.UNIMPLEMENTED_METHOD_ONE:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD_ONE,
+ "'#{class}' doesn't implement '#{method}' "
+ "declared in '#{declarer}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+abstract class I {
+ m();
+}
+class C implements I {}
+main() => new C();
+""", """
+abstract class I {
+ m();
+}
+class C extends I {}
+main() => new C();
+"""]),
+
+ MessageKind.UNIMPLEMENTED_METHOD:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD,
+ "'#{class}' doesn't implement '#{method}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+abstract class I {
+ m();
+}
+
+abstract class J {
+ m();
+}
+
+class C implements I, J {}
+
+main() {
+ new C();
+}
+""", """
+abstract class I {
+ m();
+}
+
+abstract class J {
+ m();
+}
+
+class C extends I implements J {}
+
+main() {
+ new C();
+}
+"""]),
+
+ MessageKind.UNIMPLEMENTED_METHOD_CONT:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD_CONT,
+ "The method '#{name}' is declared here in class '#{class}'."),
+
+ MessageKind.UNIMPLEMENTED_SETTER_ONE:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_SETTER_ONE,
+ "'#{class}' doesn't implement the setter '#{name}' "
+ "declared in '#{declarer}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+abstract class I {
+ set m(_);
+}
+class C implements I {}
+class D implements I {
+ set m(_) {}
+}
+main() {
+ new D().m = 0;
+ new C();
+}
+"""]),
+
+ MessageKind.UNIMPLEMENTED_SETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_SETTER,
+ "'#{class}' doesn't implement the setter '#{name}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+abstract class I {
+ set m(_);
+}
+abstract class J {
+ set m(_);
+}
+class C implements I, J {}
+main() => new C();
+""", """
+abstract class I {
+ set m(_);
+}
+abstract class J {
+ set m(_);
+}
+class C extends I implements J {}
+main() => new C();
+"""]),
+
+ MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER,
+ "The setter '#{name}' is declared here in class '#{class}'."),
+
+ MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER,
+ "The setter '#{name}' is implicitly declared by this field "
+ "in class '#{class}'."),
+
+ MessageKind.UNIMPLEMENTED_GETTER_ONE:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_GETTER_ONE,
+ "'#{class}' doesn't implement the getter '#{name}' "
+ "declared in '#{declarer}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+abstract class I {
+ get m;
+}
+class C implements I {}
+main() => new C();
+""", """
+abstract class I {
+ get m;
+}
+class C extends I {}
+main() => new C();
+"""]),
+
+ MessageKind.UNIMPLEMENTED_GETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_GETTER,
+ "'#{class}' doesn't implement the getter '#{name}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
+abstract class I {
+ get m;
+}
+abstract class J {
+ get m;
+}
+class C implements I, J {}
+main() => new C();
+""", """
+abstract class I {
+ get m;
+}
+abstract class J {
+ get m;
+}
+class C extends I implements J {}
+main() => new C();
+"""]),
+
+ MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER,
+ "The getter '#{name}' is declared here in class '#{class}'."),
+
+ MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER,
+ "The getter '#{name}' is implicitly declared by this field "
+ "in class '#{class}'."),
+
+ MessageKind.INVALID_METADATA:
+ const MessageTemplate(MessageKind.INVALID_METADATA,
+ "A metadata annotation must be either a reference to a compile-time "
+ "constant variable or a call to a constant constructor.",
+ howToFix:
+ "Try using a different constant value or referencing it through a "
+ "constant variable.",
+ examples: const [
+'@Object main() {}',
+'@print main() {}']),
+
+ MessageKind.INVALID_METADATA_GENERIC:
+ const MessageTemplate(MessageKind.INVALID_METADATA_GENERIC,
+ "A metadata annotation using a constant constructor cannot use type "
+ "arguments.",
+ howToFix:
+ "Try removing the type arguments or referencing the constant "
+ "through a constant variable.",
+ examples: const ['''
+class C<T> {
+ const C();
+}
+@C<int>() main() {}
+''']),
+
+ MessageKind.EQUAL_MAP_ENTRY_KEY:
+ const MessageTemplate(MessageKind.EQUAL_MAP_ENTRY_KEY,
+ "An entry with the same key already exists in the map.",
+ howToFix:
+ "Try removing the previous entry or changing the key in one "
+ "of the entries.",
+ examples: const ["""
+main() {
+ var m = const {'foo': 1, 'foo': 2};
+}"""]),
+
+ MessageKind.BAD_INPUT_CHARACTER:
+ const MessageTemplate(MessageKind.BAD_INPUT_CHARACTER,
+ "Character U+#{characterHex} isn't allowed here.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["""
+main() {
+ String x = ç;
+}
+"""]),
+
+ MessageKind.UNTERMINATED_STRING:
+ const MessageTemplate(MessageKind.UNTERMINATED_STRING,
+ "String must end with #{quote}.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["""
+main() {
+ return '
+;
+}
+""",
+"""
+main() {
+ return \"
+;
+}
+""",
+"""
+main() {
+ return r'
+;
+}
+""",
+"""
+main() {
+ return r\"
+;
+}
+""",
+"""
+main() => '''
+""",
+"""
+main() => \"\"\"
+""",
+"""
+main() => r'''
+""",
+"""
+main() => r\"\"\"
+"""]),
+
+ MessageKind.UNMATCHED_TOKEN:
+ const MessageTemplate(MessageKind.UNMATCHED_TOKEN,
+ "Can't find '#{end}' to match '#{begin}'.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const[
+ "main(",
+ "main(){",
+ "main(){]}",
+ ]),
+
+ MessageKind.UNTERMINATED_TOKEN:
+ const MessageTemplate(MessageKind.UNTERMINATED_TOKEN,
+ // This is a fall-back message that shouldn't happen.
+ "Incomplete token."),
+
+ MessageKind.EXPONENT_MISSING:
+ const MessageTemplate(MessageKind.EXPONENT_MISSING,
+ "Numbers in exponential notation should always contain an exponent"
+ " (an integer number with an optional sign).",
+ howToFix:
+ "Make sure there is an exponent, and remove any whitespace "
+ "before it.",
+ examples: const ["""
+main() {
+ var i = 1e;
+}
+"""]),
+
+ MessageKind.HEX_DIGIT_EXPECTED:
+ const MessageTemplate(MessageKind.HEX_DIGIT_EXPECTED,
+ "A hex digit (0-9 or A-F) must follow '0x'.",
+ howToFix:
+ DONT_KNOW_HOW_TO_FIX, // Seems obvious from the error message.
+ examples: const ["""
+main() {
+ var i = 0x;
+}
+"""]),
+
+ MessageKind.MALFORMED_STRING_LITERAL:
+ const MessageTemplate(MessageKind.MALFORMED_STRING_LITERAL,
+ r"A '$' has special meaning inside a string, and must be followed by "
+ "an identifier or an expression in curly braces ({}).",
+ howToFix: r"Try adding a backslash (\) to escape the '$'.",
+ examples: const [r"""
+main() {
+ return '$';
+}
+""",
+r'''
+main() {
+ return "$";
+}
+''',
+r"""
+main() {
+ return '''$''';
+}
+""",
+r'''
+main() {
+ return """$""";
+}
+''']),
+
+ MessageKind.UNTERMINATED_COMMENT:
+ const MessageTemplate(MessageKind.UNTERMINATED_COMMENT,
+ "Comment starting with '/*' must end with '*/'.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [r"""
+main() {
+}
+/*"""]),
+
+ MessageKind.MISSING_TOKEN_BEFORE_THIS:
+ const MessageTemplate(MessageKind.MISSING_TOKEN_BEFORE_THIS,
+ "Expected '#{token}' before this.",
+ // Consider the second example below: the parser expects a ')' before
+ // 'y', but a ',' would also have worked. We don't have enough
+ // information to give a good suggestion.
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ "main() => true ? 1;",
+ "main() => foo(x: 1 y: 2);",
+ ]),
+
+ MessageKind.MISSING_TOKEN_AFTER_THIS:
+ const MessageTemplate(MessageKind.MISSING_TOKEN_AFTER_THIS,
+ "Expected '#{token}' after this.",
+ // See [MISSING_TOKEN_BEFORE_THIS], we don't have enough information
+ // to give a good suggestion.
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ "main(x) {x}",
+"""
+class S1 {}
+class S2 {}
+class S3 {}
+class A = S1 with S2, S3
+main() => new A();
+"""
+]),
+
+ MessageKind.CONSIDER_ANALYZE_ALL:
+ const MessageTemplate(MessageKind.CONSIDER_ANALYZE_ALL,
+ "Could not find '#{main}'. Nothing will be analyzed.",
+ howToFix: "Try using '--analyze-all' to analyze everything.",
+ examples: const ['']),
+
+ MessageKind.MISSING_MAIN:
+ const MessageTemplate(MessageKind.MISSING_MAIN,
+ "Could not find '#{main}'.",
+ howToFix: "Try adding a method named '#{main}' to your program."
+ /* No example, test uses '--analyze-only' which will produce the above
+ * message [CONSIDER_ANALYZE_ALL]. An example for a human operator
+ * would be an empty file.*/),
+
+ MessageKind.MAIN_NOT_A_FUNCTION:
+ const MessageTemplate(MessageKind.MAIN_NOT_A_FUNCTION,
+ "'#{main}' is not a function.",
+ howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
+ examples: const ['var main;']),
+
+ MessageKind.MAIN_WITH_EXTRA_PARAMETER:
+ const MessageTemplate(MessageKind.MAIN_WITH_EXTRA_PARAMETER,
+ "'#{main}' cannot have more than two parameters.",
+ howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
+ examples: const ['main(a, b, c) {}']),
+
+ MessageKind.COMPILER_CRASHED:
+ const MessageTemplate(MessageKind.COMPILER_CRASHED,
+ "The compiler crashed when compiling this element."),
+
+ MessageKind.PLEASE_REPORT_THE_CRASH:
+ const MessageTemplate(MessageKind.PLEASE_REPORT_THE_CRASH, '''
+The compiler is broken.
+
+When compiling the above element, the compiler crashed. It is not
+possible to tell if this is caused by a problem in your program or
+not. Regardless, the compiler should not crash.
+
+The Dart team would greatly appreciate if you would take a moment to
+report this problem at http://dartbug.com/new.
+
+Please include the following information:
+
+* the name and version of your operating system,
+
+* the Dart SDK build number (#{buildId}), and
+
+* the entire message you see here (including the full stack trace
+ below as well as the source location above).
+'''),
+
+ MessageKind.POTENTIAL_MUTATION:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION,
+ "Variable '#{variableName}' is not known to be of type "
+ "'#{shownType}' because it is potentially mutated in the scope for "
+ "promotion."),
+
+ MessageKind.POTENTIAL_MUTATION_HERE:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION_HERE,
+ "Variable '#{variableName}' is potentially mutated here."),
+
+ MessageKind.POTENTIAL_MUTATION_IN_CLOSURE:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION_IN_CLOSURE,
+ "Variable '#{variableName}' is not known to be of type "
+ "'#{shownType}' because it is potentially mutated within a closure."),
+
+ MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE,
+ "Variable '#{variableName}' is potentially mutated in a "
+ "closure here."),
+
+ MessageKind.ACCESSED_IN_CLOSURE:
+ const MessageTemplate(MessageKind.ACCESSED_IN_CLOSURE,
+ "Variable '#{variableName}' is not known to be of type "
+ "'#{shownType}' because it is accessed by a closure in the scope for "
+ "promotion and potentially mutated in the scope of "
+ "'#{variableName}'."),
+
+ MessageKind.ACCESSED_IN_CLOSURE_HERE:
+ const MessageTemplate(MessageKind.ACCESSED_IN_CLOSURE_HERE,
+ "Variable '#{variableName}' is accessed in a closure here."),
+
+ MessageKind.NOT_MORE_SPECIFIC:
+ const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC,
+ "Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not more specific than the "
+ "known type '#{knownType}' of '#{variableName}'."),
+
+ MessageKind.NOT_MORE_SPECIFIC_SUBTYPE:
+ const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
+ "Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not a subtype of the "
+ "known type '#{knownType}' of '#{variableName}'."),
+
+ MessageKind.NOT_MORE_SPECIFIC_SUGGESTION:
+ const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+ "Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not more specific than the "
+ "known type '#{knownType}' of '#{variableName}'.",
+ howToFix:
+ "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'."),
+
+ MessageKind.NO_COMMON_SUBTYPES:
+ const MessageTemplate(MessageKind.NO_COMMON_SUBTYPES,
+ "Types '#{left}' and '#{right}' have no common subtypes."),
+
+ MessageKind.HIDDEN_WARNINGS_HINTS:
+ const MessageTemplate(MessageKind.HIDDEN_WARNINGS_HINTS,
+ "#{warnings} warning(s) and #{hints} hint(s) suppressed in #{uri}."),
+
+ MessageKind.HIDDEN_WARNINGS:
+ const MessageTemplate(MessageKind.HIDDEN_WARNINGS,
+ "#{warnings} warning(s) suppressed in #{uri}."),
+
+ MessageKind.HIDDEN_HINTS:
+ const MessageTemplate(MessageKind.HIDDEN_HINTS,
+ "#{hints} hint(s) suppressed in #{uri}."),
+
+ MessageKind.PREAMBLE:
+ const MessageTemplate(MessageKind.PREAMBLE,
+ "When run on the command-line, the compiled output might"
+ " require a preamble file located in:\n"
+ " <sdk>/lib/_internal/js_runtime/lib/preambles."),
+
+ MessageKind.INVALID_SYNC_MODIFIER:
+ const MessageTemplate(MessageKind.INVALID_SYNC_MODIFIER,
+ "Invalid modifier 'sync'.",
+ howToFix: "Try replacing 'sync' with 'sync*'.",
+ examples: const [
+ "main() sync {}"
+ ]),
+
+ MessageKind.INVALID_AWAIT_FOR:
+ const MessageTemplate(MessageKind.INVALID_AWAIT_FOR,
+ "'await' is only supported on for-in loops.",
+ howToFix: "Try rewriting the loop as a for-in loop or removing the "
+ "'await' keyword.",
+ examples: const ["""
+main() async* {
+ await for (int i = 0; i < 10; i++) {}
+}
+"""]),
+
+ MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD:
+ const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD,
+ "The modifier '#{modifier}' is not allowed on an abstract method.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier or adding a "
+ "body to the method.",
+ examples: const ["""
+abstract class A {
+ method() async;
+}
+class B extends A {
+ method() {}
+}
+main() {
+ A a = new B();
+ a.method();
+}
+"""]),
+
+ MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR,
+ "The modifier '#{modifier}' is not allowed on constructors.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier.",
+ examples: const ["""
+class A {
+ A() async;
+}
+main() => new A();""",
+
+"""
+class A {
+ A();
+ factory A.a() async* {}
+}
+main() => new A.a();"""]),
+
+ MessageKind.ASYNC_MODIFIER_ON_SETTER:
+ const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_SETTER,
+ "The modifier '#{modifier}' is not allowed on setters.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier.",
+ examples: const ["""
+class A {
+ set foo(v) async {}
+}
+main() => new A().foo = 0;"""]),
+
+ MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY:
+ const MessageTemplate(MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY,
+ "The modifier '#{modifier}' is not allowed on methods implemented "
+ "using '=>'.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier or implementing "
+ "the method body using a block: '{ ... }'.",
+ examples: const ["main() sync* => null;", "main() async* => null;"]),
+
+ // TODO(johnniwinther): Check for 'async' as identifier.
+ MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER:
+ const MessageTemplate(MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER,
+ "'#{keyword}' cannot be used as an identifier in a function body "
+ "marked with '#{modifier}'.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier or renaming the "
+ "identifier.",
+ examples: const ["""
+main() async {
+ var await;
+}""",
+"""
+main() async* {
+ var yield;
+}""",
+"""
+main() sync* {
+ var yield;
+}"""]),
+
+ MessageKind.RETURN_IN_GENERATOR:
+ const MessageTemplate(MessageKind.RETURN_IN_GENERATOR,
+ "'return' with a value is not allowed in a method body using the "
+ "'#{modifier}' modifier.",
+ howToFix: "Try removing the value, replacing 'return' with 'yield' "
+ "or changing the method body modifier.",
+ examples: const [
+"""
+foo() async* { return 0; }
+main() => foo();
+""",
+
+"""
+foo() sync* { return 0; }
+main() => foo();
+"""]),
+
+ MessageKind.NATIVE_NOT_SUPPORTED:
+ const MessageTemplate(MessageKind.NATIVE_NOT_SUPPORTED,
+ "'native' modifier is not supported.",
+ howToFix: "Try removing the 'native' implementation or analyzing the "
+ "code with the --allow-native-extensions option.",
+ examples: const ["""
+main() native "Main";
+"""]),
+
+ MessageKind.DART_EXT_NOT_SUPPORTED:
+ const MessageTemplate(MessageKind.DART_EXT_NOT_SUPPORTED,
+ "The 'dart-ext' scheme is not supported.",
+ howToFix: "Try analyzing the code with the --allow-native-extensions "
+ "option.",
+ examples: const ["""
+import 'dart-ext:main';
+
+main() {}
+"""]),
+
+ MessageKind.LIBRARY_TAG_MUST_BE_FIRST:
+ const MessageTemplate(MessageKind.LIBRARY_TAG_MUST_BE_FIRST,
+ "The library declaration should come before other declarations.",
+ howToFix: "Try moving the declaration to the top of the file.",
+ examples: const [
+"""
+import 'dart:core';
+library foo;
+main() {}
+""",
+ ]),
+
+ MessageKind.ONLY_ONE_LIBRARY_TAG:
+ const MessageTemplate(MessageKind.ONLY_ONE_LIBRARY_TAG,
+ "There can only be one library declaration.",
+ howToFix: "Try removing all other library declarations.",
+ examples: const [
+"""
+library foo;
+library bar;
+main() {}
+""",
+"""
+library foo;
+import 'dart:core';
+library bar;
+main() {}
+""",
+ ]),
+
+ MessageKind.IMPORT_BEFORE_PARTS:
+ const MessageTemplate(MessageKind.IMPORT_BEFORE_PARTS,
+ "Import declarations should come before parts.",
+ howToFix: "Try moving this import further up in the file.",
+ examples: const [
+ const <String, String>{
+ 'main.dart': """
+library test.main;
+part 'part.dart';
+import 'dart:core';
+main() {}
+""",
+ 'part.dart': """
+part of test.main;
+""",
+ }]),
+
+ MessageKind.EXPORT_BEFORE_PARTS:
+ const MessageTemplate(MessageKind.EXPORT_BEFORE_PARTS,
+ "Export declarations should come before parts.",
+ howToFix: "Try moving this export further up in the file.",
+ examples: const [
+ const <String, String>{
+ 'main.dart': """
+library test.main;
+part 'part.dart';
+export 'dart:core';
+main() {}
+""",
+ 'part.dart': """
+part of test.main;
+""",
+ }]),
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Patch errors start.
+ //////////////////////////////////////////////////////////////////////////////
+
+ MessageKind.PATCH_RETURN_TYPE_MISMATCH:
+ const MessageTemplate(MessageKind.PATCH_RETURN_TYPE_MISMATCH,
+ "Patch return type '#{patchReturnType}' does not match "
+ "'#{originReturnType}' on origin method '#{methodName}'."),
+
+ MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH:
+ const MessageTemplate(
+ MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
+ "Required parameter count of patch method "
+ "(#{patchParameterCount}) does not match parameter count on origin "
+ "method '#{methodName}' (#{originParameterCount})."),
+
+ MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH:
+ const MessageTemplate(
+ MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
+ "Optional parameter count of patch method "
+ "(#{patchParameterCount}) does not match parameter count on origin "
+ "method '#{methodName}' (#{originParameterCount})."),
+
+ MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH:
+ const MessageTemplate(
+ MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
+ "Optional parameters of origin and patch method "
+ "'#{methodName}' must both be either named or positional."),
+
+ MessageKind.PATCH_PARAMETER_MISMATCH:
+ const MessageTemplate(MessageKind.PATCH_PARAMETER_MISMATCH,
+ "Patch method parameter '#{patchParameter}' does not match "
+ "'#{originParameter}' on origin method '#{methodName}'."),
+
+ MessageKind.PATCH_PARAMETER_TYPE_MISMATCH:
+ const MessageTemplate(MessageKind.PATCH_PARAMETER_TYPE_MISMATCH,
+ "Patch method parameter '#{parameterName}' type "
+ "'#{patchParameterType}' does not match '#{originParameterType}' on "
+ "origin method '#{methodName}'."),
+
+ MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION:
+ const MessageTemplate(MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION,
+ "External method without an implementation."),
+
+ MessageKind.PATCH_POINT_TO_FUNCTION:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_FUNCTION,
+ "This is the function patch '#{functionName}'."),
+
+ MessageKind.PATCH_POINT_TO_CLASS:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_CLASS,
+ "This is the class patch '#{className}'."),
+
+ MessageKind.PATCH_POINT_TO_GETTER:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_GETTER,
+ "This is the getter patch '#{getterName}'."),
+
+ MessageKind.PATCH_POINT_TO_SETTER:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_SETTER,
+ "This is the setter patch '#{setterName}'."),
+
+ MessageKind.PATCH_POINT_TO_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_CONSTRUCTOR,
+ "This is the constructor patch '#{constructorName}'."),
+
+ MessageKind.PATCH_POINT_TO_PARAMETER:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_PARAMETER,
+ "This is the patch parameter '#{parameterName}'."),
+
+ MessageKind.PATCH_NON_EXISTING:
+ const MessageTemplate(MessageKind.PATCH_NON_EXISTING,
+ "Origin does not exist for patch '#{name}'."),
+
+ // TODO(ahe): Eventually, this error should be removed as it will be
+ // handled by the regular parser.
+ MessageKind.PATCH_NONPATCHABLE:
+ const MessageTemplate(MessageKind.PATCH_NONPATCHABLE,
+ "Only classes and functions can be patched."),
+
+ MessageKind.PATCH_NON_EXTERNAL:
+ const MessageTemplate(MessageKind.PATCH_NON_EXTERNAL,
+ "Only external functions can be patched."),
+
+ MessageKind.PATCH_NON_CLASS:
+ const MessageTemplate(MessageKind.PATCH_NON_CLASS,
+ "Patching non-class with class patch '#{className}'."),
+
+ MessageKind.PATCH_NON_GETTER:
+ const MessageTemplate(MessageKind.PATCH_NON_GETTER,
+ "Cannot patch non-getter '#{name}' with getter patch."),
+
+ MessageKind.PATCH_NO_GETTER:
+ const MessageTemplate(MessageKind.PATCH_NO_GETTER,
+ "No getter found for getter patch '#{getterName}'."),
+
+ MessageKind.PATCH_NON_SETTER:
+ const MessageTemplate(MessageKind.PATCH_NON_SETTER,
+ "Cannot patch non-setter '#{name}' with setter patch."),
+
+ MessageKind.PATCH_NO_SETTER:
+ const MessageTemplate(MessageKind.PATCH_NO_SETTER,
+ "No setter found for setter patch '#{setterName}'."),
+
+ MessageKind.PATCH_NON_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.PATCH_NON_CONSTRUCTOR,
+ "Cannot patch non-constructor with constructor patch "
+ "'#{constructorName}'."),
+
+ MessageKind.PATCH_NON_FUNCTION:
+ const MessageTemplate(MessageKind.PATCH_NON_FUNCTION,
+ "Cannot patch non-function with function patch "
+ "'#{functionName}'."),
+
+ MessageKind.INJECTED_PUBLIC_MEMBER:
+ const MessageTemplate(MessageKind.INJECTED_PUBLIC_MEMBER,
+ "Non-patch members in patch libraries must be private."),
+
+ MessageKind.EXTERNAL_WITH_BODY:
+ const MessageTemplate(MessageKind.EXTERNAL_WITH_BODY,
+ "External function '#{functionName}' cannot have a function body.",
+ options: const ["--output-type=dart"],
+ howToFix:
+ "Try removing the 'external' modifier or the function body.",
+ examples: const ["""
+external foo() => 0;
+main() => foo();
+""", """
+external foo() {}
+main() => foo();
+"""]),
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Patch errors end.
+ //////////////////////////////////////////////////////////////////////////////
+
+ MessageKind.EXPERIMENTAL_ASSERT_MESSAGE:
+ const MessageTemplate(MessageKind.EXPERIMENTAL_ASSERT_MESSAGE,
+ "Experimental language feature 'assertion with message'"
+ " is not supported.",
+ howToFix:
+ "Use option '--assert-message' to use assertions with messages.",
+ examples: const [r'''
+main() {
+ int n = -7;
+ assert(n > 0, 'must be positive: $n');
+}
+''']),
+
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS:
+ const MessageTemplate(MessageKind.IMPORT_EXPERIMENTAL_MIRRORS, r'''
+
+****************************************************************
+* WARNING: dart:mirrors support in dart2js is experimental,
+* and not recommended.
+* This implementation of mirrors is incomplete,
+* and often greatly increases the size of the generated
+* JavaScript code.
+*
+* Your app imports dart:mirrors via:''''''
+$IMPORT_EXPERIMENTAL_MIRRORS_PADDING#{importChain}
+*
+* You can disable this message by using the --enable-experimental-mirrors
+* command-line flag.
+*
+* To learn what to do next, please visit:
+* http://dartlang.org/dart2js-reflection
+****************************************************************
+'''),
+
+ MessageKind.DISALLOWED_LIBRARY_IMPORT:
+ const MessageTemplate(MessageKind.DISALLOWED_LIBRARY_IMPORT, '''
+Your app imports the unsupported library '#{uri}' via:
+''''''
+$DISALLOWED_LIBRARY_IMPORT_PADDING#{importChain}
+
+Use the --categories option to support import of '#{uri}'.
+'''),
+
+ MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
+ const MessageTemplate(
+ MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
+ """
+dart:mirrors library is not supported when using this backend.
+
+Your app imports dart:mirrors via:""""""
+$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}"""),
+
+ MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
+ const MessageTemplate(MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
+ "Non-supported 'call' member on a native class, or a "
+ "subclass of a native class."),
+
+ MessageKind.DIRECTLY_THROWING_NSM:
+ const MessageTemplate(MessageKind.DIRECTLY_THROWING_NSM,
+ "This 'noSuchMethod' implementation is guaranteed to throw an "
+ "exception. The generated code will be smaller if it is "
+ "rewritten.",
+ howToFix: "Rewrite to "
+ "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'."),
+
+ MessageKind.COMPLEX_THROWING_NSM:
+ const MessageTemplate(MessageKind.COMPLEX_THROWING_NSM,
+ "This 'noSuchMethod' implementation is guaranteed to throw an "
+ "exception. The generated code will be smaller and the compiler "
+ "will be able to perform more optimizations if it is rewritten.",
+ howToFix: "Rewrite to "
+ "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'."),
+
+ MessageKind.COMPLEX_RETURNING_NSM:
+ const MessageTemplate(MessageKind.COMPLEX_RETURNING_NSM,
+ "Overriding 'noSuchMethod' causes the compiler to generate "
+ "more code and prevents the compiler from doing some optimizations.",
+ howToFix: "Consider removing this 'noSuchMethod' implementation."),
+
+ MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP:
+ const MessageTemplate(MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP,
+ "Unsupported version of package:lookup_map.",
+ howToFix: DONT_KNOW_HOW_TO_FIX),
+
+ }); // End of TEMPLATES.
+
+ /// Padding used before and between import chains in the message for
+ /// [MessageKind.IMPORT_EXPERIMENTAL_MIRRORS].
+ static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n* ';
+
+ /// Padding used before and between import chains in the message for
+ /// [MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND].
+ static const String MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING = '\n ';
+
+ /// Padding used before and between import chains in the message for
+ /// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
+ static const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n ';
toString() => template;
@@ -901,42 +3675,7 @@
return new Message(this, arguments, terse);
}
- bool get hasHowToFix =>
- howToFix != null && howToFix != dart2js_messages.DONT_KNOW_HOW_TO_FIX;
-
- static final Map<MessageKind, MessageTemplate> TEMPLATES =
- _constructMessageTemplates();
-
- static String get IMPORT_EXPERIMENTAL_MIRRORS_PADDING =>
- dart2js_messages.IMPORT_EXPERIMENTAL_MIRRORS_PADDING;
-
- static String get MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING =>
- dart2js_messages.MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING;
-
- static String get DISALLOWED_LIBRARY_IMPORT_PADDING =>
- dart2js_messages.DISALLOWED_LIBRARY_IMPORT_PADDING;
-
- static Map<MessageKind, MessageTemplate> _constructMessageTemplates() {
- Map<MessageKind, MessageTemplate> result = <MessageKind, MessageTemplate>{};
- for (MessageKind kind in MessageKind.values) {
- String name = _KIND_TO_STRING_MAP[kind];
- if (name == null) {
- throw new ArgumentError("No mapping for $kind in _KIND_TO_STRING_MAP");
- }
- Map data =
- shared_messages.MESSAGES[name] ?? dart2js_messages.MESSAGES[name];
- if (data == null) throw new ArgumentError.value(name);
-
- String id = data['id'];
- String template = data['template'];
- String howToFix = data['howToFix'];
- List examples = data['examples'];
- List<String> options = data['options'] ?? const <String>[];
- result[kind] =
- new MessageTemplate(kind, id, template, howToFix, examples, options);
- }
- return result;
- }
+ bool get hasHowToFix => howToFix != null && howToFix != DONT_KNOW_HOW_TO_FIX;
}
class Message {
@@ -946,13 +3685,10 @@
String message;
Message(this.template, this.arguments, this.terse) {
- assert(() {
- computeMessage();
- return true;
- });
+ assert(() { computeMessage(); return true; });
}
- MessageKind get kind => template.kind;
+ dynamic/*MessageKind | SharedMessageKind*/ get kind => template.kind;
String computeMessage() {
if (message == null) {
@@ -963,7 +3699,7 @@
assert(invariant(
CURRENT_ELEMENT_SPANNABLE,
kind == MessageKind.GENERIC ||
- !message.contains(new RegExp(r'#\{.+\}')),
+ !message.contains(new RegExp(r'#\{.+\}')),
message: 'Missing arguments in error message: "$message"'));
if (!terse && template.hasHowToFix) {
String howToFix = template.howToFix;
@@ -980,8 +3716,8 @@
return computeMessage();
}
- bool operator ==(other) {
- if (other is! Message) return false;
+ bool operator==(other) {
+ if (other is !Message) return false;
return (template == other.template) && (toString() == other.toString());
}
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 207954d..d909a47 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -54,7 +54,7 @@
compiler.dumpInfoTask._constantToNode.forEach((constant, node) {
// TODO(sigmund): add dependencies on other constants
var size = compiler.dumpInfoTask._nodeToSize[node];
- var code = jsAst.prettyPrint(node, compiler).getText();
+ var code = jsAst.prettyPrint(node, compiler);
var info = new ConstantInfo(
size: size, code: code, outputUnit: _unitInfoForConstant(constant));
_constantToInfo[constant] = info;
@@ -529,7 +529,7 @@
// Concatenate rendered ASTs.
StringBuffer sb = new StringBuffer();
for (jsAst.Node ast in code) {
- sb.writeln(jsAst.prettyPrint(ast, compiler).getText());
+ sb.writeln(jsAst.prettyPrint(ast, compiler));
}
return sb.toString();
}
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index c25e955..469081c 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -11,6 +11,8 @@
Compiler;
import '../constants/constructors.dart';
import '../constants/expressions.dart';
+import '../core_types.dart' show
+ CoreClasses;
import '../dart_types.dart';
import '../resolution/scope.dart' show
Scope;
@@ -1430,7 +1432,7 @@
/// Returns `true` if this class implements [Function] either by directly
/// implementing the interface or by providing a [call] method.
- bool implementsFunction(Compiler compiler);
+ bool implementsFunction(CoreClasses coreClasses);
/// Returns `true` if this class extends [cls] directly or indirectly.
///
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 550b3c9..3f0d70c 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -13,6 +13,8 @@
import '../constants/constant_constructors.dart';
import '../constants/constructors.dart';
import '../constants/expressions.dart';
+import '../core_types.dart' show
+ CoreClasses;
import '../dart_types.dart';
import '../diagnostics/messages.dart' show
MessageTemplate;
@@ -2706,8 +2708,8 @@
backendMembers.forEach(f);
}
- bool implementsFunction(Compiler compiler) {
- return asInstanceOf(compiler.coreClasses.functionClass) != null ||
+ bool implementsFunction(CoreClasses coreClasses) {
+ return asInstanceOf(coreClasses.functionClass) != null ||
callType != null;
}
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index f897876..f9608ba 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -413,6 +413,9 @@
FunctionSignature signature = function.functionSignature;
signature.forEachOptionalParameter((ParameterElement element) {
ast.Expression defaultValue = element.initializer;
+ // TODO(25566): The default value of a parameter of a redirecting factory
+ // constructor comes from the corresponding parameter of the target.
+
// If this is a default value from a different context (because
// the current function is synthetic, e.g., a constructor from
// a mixin application), we have to start a new inferrer visitor
@@ -1482,54 +1485,50 @@
return super.handleTypeLiteralInvoke(arguments);
}
- /// Handle constructor invocation of [element].
- T handleConstructorSend(ast.Send node, ConstructorElement element) {
+ /// Handle constructor invocation of [constructor].
+ T handleConstructorSend(ast.Send node, ConstructorElement constructor) {
+ ConstructorElement target = constructor.implementation;
ArgumentsTypes arguments = analyzeArguments(node.arguments);
if (visitingInitializers) {
if (ast.Initializers.isConstructorRedirect(node)) {
isConstructorRedirect = true;
} else if (ast.Initializers.isSuperConstructorCall(node)) {
seenSuperConstructorCall = true;
- analyzeSuperConstructorCall(element, arguments);
+ analyzeSuperConstructorCall(constructor, arguments);
}
}
- // If we are looking at a new expression on a forwarding factory,
- // we have to forward the call to the effective target of the
- // factory.
- if (element.isFactoryConstructor) {
- // TODO(herhut): Remove the while loop once effectiveTarget forwards to
- // patches.
- while (element.isFactoryConstructor) {
- ConstructorElement constructor = element;
- if (!constructor.isRedirectingFactory) break;
- element = constructor.effectiveTarget.implementation;
- }
+ // If we are looking at a new expression on a forwarding factory, we have to
+ // forward the call to the effective target of the factory.
+ // TODO(herhut): Remove the loop once effectiveTarget forwards to patches.
+ while (target.isFactoryConstructor) {
+ if (!target.isRedirectingFactory) break;
+ target = target.effectiveTarget.implementation;
}
- if (compiler.backend.isForeign(element)) {
- return handleForeignSend(node, element);
+ if (compiler.backend.isForeign(target)) {
+ return handleForeignSend(node, target);
}
Selector selector = elements.getSelector(node);
TypeMask mask = elements.getTypeMask(node);
// In erroneous code the number of arguments in the selector might not
// match the function element.
// TODO(polux): return nonNullEmpty and check it doesn't break anything
- if (!selector.applies(element, compiler.world) ||
- (mask != null && !mask.canHit(element, selector, compiler.world))) {
+ if (!selector.applies(target, compiler.world) ||
+ (mask != null && !mask.canHit(target, selector, compiler.world))) {
return types.dynamicType;
}
- T returnType = handleStaticSend(node, selector, mask, element, arguments);
- if (Elements.isGrowableListConstructorCall(element, node, compiler)) {
+ T returnType = handleStaticSend(node, selector, mask, target, arguments);
+ if (Elements.isGrowableListConstructorCall(constructor, node, compiler)) {
return inferrer.concreteTypes.putIfAbsent(
node, () => types.allocateList(
types.growableListType, node, outermostElement,
types.nonNullEmpty(), 0));
- } else if (Elements.isFixedListConstructorCall(element, node, compiler)
- || Elements.isFilledListConstructorCall(element, node, compiler)) {
+ } else if (Elements.isFixedListConstructorCall(constructor, node, compiler)
+ || Elements.isFilledListConstructorCall(constructor, node, compiler)) {
int length = findLength(node);
T elementType =
- Elements.isFixedListConstructorCall(element, node, compiler)
+ Elements.isFixedListConstructorCall(constructor, node, compiler)
? types.nullType
: arguments.positional[1];
@@ -1537,15 +1536,14 @@
node, () => types.allocateList(
types.fixedListType, node, outermostElement,
elementType, length));
- } else if (Elements.isConstructorOfTypedArraySubclass(element, compiler)) {
+ } else if (
+ Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
int length = findLength(node);
- ConstructorElement constructor = element.implementation;
- constructor = constructor.effectiveTarget;
T elementType = inferrer.returnTypeOfElement(
- constructor.enclosingClass.lookupMember('[]'));
+ target.enclosingClass.lookupMember('[]'));
return inferrer.concreteTypes.putIfAbsent(
node, () => types.allocateList(
- types.nonNullExact(constructor.enclosingClass), node,
+ types.nonNullExact(target.enclosingClass), node,
outermostElement, elementType, length));
} else {
return returnType;
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index 967de65..7f5b996 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -102,8 +102,12 @@
}
}
+abstract class BufferedCodeOutput {
+ String getText();
+}
+
/// [CodeOutput] using a [StringBuffer] as backend.
-class CodeBuffer extends AbstractCodeOutput {
+class CodeBuffer extends AbstractCodeOutput implements BufferedCodeOutput {
StringBuffer buffer = new StringBuffer();
@override
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 0e384c3..2ef185b 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -18,6 +18,8 @@
Node,
Send;
+import 'code_output.dart' show
+ CodeBuffer;
import 'source_file.dart';
import 'source_information.dart';
@@ -113,6 +115,32 @@
SourceInformationProcessor createProcessor(SourceMapper mapper) {
return new PositionSourceInformationProcessor(mapper);
}
+
+ @override
+ void onComplete() {}
+
+ @override
+ SourceInformation buildSourceMappedMarker() {
+ return const SourceMappedMarker();
+ }
+}
+
+/// Marker used to tag the root nodes of source-mapped code.
+///
+/// This is needed to be able to distinguish JavaScript nodes that shouldn't
+/// have source locations (like the premable) from the nodes that should
+/// (like functions compiled from Dart code).
+class SourceMappedMarker extends SourceInformation {
+ const SourceMappedMarker();
+
+ @override
+ String get shortText => '';
+
+ @override
+ List<SourceLocation> get sourceLocations => const <SourceLocation>[];
+
+ @override
+ SourceSpan get sourceSpan => new SourceSpan(null, null, null);
}
/// [SourceInformationBuilder] that generates [PositionSourceInformation].
@@ -225,10 +253,31 @@
final int closingPosition;
CodePosition(this.startPosition, this.endPosition, this.closingPosition);
+
+ int getPosition(CodePositionKind kind) {
+ switch (kind) {
+ case CodePositionKind.START:
+ return startPosition;
+ case CodePositionKind.END:
+ return endPosition;
+ case CodePositionKind.CLOSING:
+ return closingPosition;
+ }
+ }
+
+ String toString() {
+ return 'CodePosition(start=$startPosition,'
+ 'end=$endPosition,closing=$closingPosition)';
+ }
+}
+
+/// A map from a [js.Node] to its [CodePosition].
+abstract class CodePositionMap {
+ CodePosition operator [](js.Node node);
}
/// Registry for mapping [js.Node]s to their [CodePosition].
-class CodePositionRecorder {
+class CodePositionRecorder implements CodePositionMap {
Map<js.Node, CodePosition> _codePositionMap =
new Map<js.Node, CodePosition>.identity();
@@ -247,204 +296,107 @@
CodePosition operator [](js.Node node) => _codePositionMap[node];
}
+/// Enum values for the part of a Dart node used for the source location offset.
enum SourcePositionKind {
+ /// The source mapping should point to the start of the Dart node.
+ ///
+ /// For instance the first '(' for the `(*)()` call and 'f' of both the
+ /// `foo()` and the `*.bar()` call:
+ ///
+ /// (foo().bar())()
+ /// ^ // the start of the `(*)()` node
+ /// ^ // the start of the `foo()` node
+ /// ^ // the start of the `*.bar()` node
+ ///
START,
- CLOSING,
- END,
+
+ /// The source mapping should point an inner position of the Dart node.
+ ///
+ /// For instance the second '(' of the `(*)()` call, the 'f' of the `foo()`
+ /// call and the 'b' of the `*.bar()` call:
+ ///
+ /// (foo().bar())()
+ /// ^ // the inner position of the `(*)()` node
+ /// ^ // the inner position of the `foo()` node
+ /// ^ // the inner position of the `*.bar()` node
+ ///
+ /// For function expressions the inner position is the closing brace or the
+ /// arrow:
+ ///
+ /// foo() => () {}
+ /// ^ // the inner position of the 'foo' function
+ /// ^ // the inner position of the closure
+ ///
+ INNER,
}
+SourceLocation getSourceLocation(
+ SourceInformation sourceInformation,
+ [SourcePositionKind sourcePositionKind = SourcePositionKind.START]) {
+ if (sourceInformation == null) return null;
+ switch (sourcePositionKind) {
+ case SourcePositionKind.START:
+ return sourceInformation.startPosition;
+ case SourcePositionKind.INNER:
+ return sourceInformation.closingPosition;
+ }
+}
+
+/// Enum values for the part of the JavaScript node used for the JavaScript
+/// code offset of a source mapping.
enum CodePositionKind {
+ /// The source mapping is put on left-most offset of the node.
+ ///
+ /// For instance on the 'f' of a function or 'r' of a return statement:
+ ///
+ /// foo: function() { return 0; }
+ /// ^ // the function start position
+ /// ^ // the return start position
START,
+
+ /// The source mapping is put on the closing token.
+ ///
+ /// For instance on the '}' of a function or the ';' of a return statement:
+ ///
+ /// foo: function() { return 0; }
+ /// ^ // the function closing position
+ /// ^ // the return closing position
+ ///
CLOSING,
+
+ /// The source mapping is put at the end of the code for the node.
+ ///
+ /// For instance after '}' of a function or after the ';' of a return
+ /// statement:
+ ///
+ /// foo: function() { return 0; }
+ /// ^ // the function end position
+ /// ^ // the return end position
+ ///
END,
}
/// Processor that associates [SourceLocation]s from [SourceInformation] on
/// [js.Node]s with the target offsets in a [SourceMapper].
-class PositionSourceInformationProcessor
- extends js.BaseVisitor implements SourceInformationProcessor {
- final CodePositionRecorder codePositions = new CodePositionRecorder();
- final SourceMapper sourceMapper;
+class PositionSourceInformationProcessor implements SourceInformationProcessor {
+ final CodePositionRecorder codePositionRecorder = new CodePositionRecorder();
+ CodePositionMap codePositionMap;
+ List<TraceListener> traceListeners;
- PositionSourceInformationProcessor(this.sourceMapper);
-
- void process(js.Node node) {
- node.accept(this);
- }
-
- void visitChildren(js.Node node) {
- node.visitChildren(this);
- }
-
- CodePosition getCodePosition(js.Node node) {
- return codePositions[node];
- }
-
- /// Associates [sourceInformation] with the JavaScript [node].
- ///
- /// The offset into the JavaScript code is computed by pulling the
- /// [codePositionKind] from the code positions associated with
- /// [codePositionNode].
- ///
- /// The mapped Dart source location is computed by pulling the
- /// [sourcePositionKind] source location from [sourceInformation].
- void apply(js.Node node,
- js.Node codePositionNode,
- CodePositionKind codePositionKind,
- SourceInformation sourceInformation,
- SourcePositionKind sourcePositionKind) {
- if (sourceInformation != null) {
- CodePosition codePosition = getCodePosition(codePositionNode);
- // We should always have recorded the needed code positions.
- assert(invariant(
- NO_LOCATION_SPANNABLE,
- codePosition != null,
- message:
- "Code position missing for "
- "${nodeToString(codePositionNode)}:\n"
- "${DebugPrinter.prettyPrint(node)}"));
- if (codePosition == null) return;
- int codeLocation;
- SourceLocation sourceLocation;
- switch (codePositionKind) {
- case CodePositionKind.START:
- codeLocation = codePosition.startPosition;
- break;
- case CodePositionKind.CLOSING:
- codeLocation = codePosition.closingPosition;
- break;
- case CodePositionKind.END:
- codeLocation = codePosition.endPosition;
- break;
- }
- switch (sourcePositionKind) {
- case SourcePositionKind.START:
- sourceLocation = sourceInformation.startPosition;
- break;
- case SourcePositionKind.CLOSING:
- sourceLocation = sourceInformation.closingPosition;
- break;
- case SourcePositionKind.END:
- sourceLocation = sourceInformation.endPosition;
- break;
- }
- if (codeLocation != null && sourceLocation != null) {
- sourceMapper.register(node, codeLocation, sourceLocation);
- }
+ PositionSourceInformationProcessor(
+ SourceMapper sourceMapper,
+ [Coverage coverage]) {
+ codePositionMap = coverage != null
+ ? new CodePositionCoverage(codePositionRecorder, coverage)
+ : codePositionRecorder;
+ traceListeners = [new PositionTraceListener(sourceMapper)];
+ if (coverage != null) {
+ traceListeners.add(new CoverageListener(coverage));
}
}
- @override
- visitNode(js.Node node) {
- SourceInformation sourceInformation = node.sourceInformation;
- if (sourceInformation != null) {
- /// Associates the left-most position of the JS code with the left-most
- /// position of the Dart code.
- apply(node,
- node, CodePositionKind.START,
- sourceInformation, SourcePositionKind.START);
- }
- visitChildren(node);
- }
-
- @override
- visitFun(js.Fun node) {
- SourceInformation sourceInformation = node.sourceInformation;
- if (sourceInformation != null) {
- /// Associates the end brace of the JavaScript function with the end brace
- /// of the Dart function (or the `;` in case of arrow notation).
- apply(node,
- node, CodePositionKind.CLOSING,
- sourceInformation, SourcePositionKind.CLOSING);
- }
-
- visitChildren(node);
- }
-
- @override
- visitExpressionStatement(js.ExpressionStatement node) {
- visitChildren(node);
- }
-
- @override
- visitBinary(js.Binary node) {
- visitChildren(node);
- }
-
- @override
- visitAccess(js.PropertyAccess node) {
- visitChildren(node);
- }
-
- @override
- visitCall(js.Call node) {
- SourceInformation sourceInformation = node.sourceInformation;
- if (sourceInformation != null) {
- if (node.target is js.PropertyAccess) {
- js.PropertyAccess access = node.target;
- js.Node target = access;
- bool pureAccess = false;
- while (target is js.PropertyAccess) {
- js.PropertyAccess targetAccess = target;
- if (targetAccess.receiver is js.VariableUse ||
- targetAccess.receiver is js.This) {
- pureAccess = true;
- break;
- } else {
- target = targetAccess.receiver;
- }
- }
- if (pureAccess) {
- // a.m() this.m() a.b.c.d.m()
- // ^ ^ ^
- apply(
- node,
- node,
- CodePositionKind.START,
- sourceInformation,
- SourcePositionKind.START);
- } else {
- // *.m() *.a.b.c.d.m()
- // ^ ^
- apply(
- node,
- access.selector,
- CodePositionKind.START,
- sourceInformation,
- SourcePositionKind.CLOSING);
- }
- } else if (node.target is js.VariableUse) {
- // m()
- // ^
- apply(
- node,
- node,
- CodePositionKind.START,
- sourceInformation,
- SourcePositionKind.START);
- } else if (node.target is js.Fun || node.target is js.New) {
- // function(){}() new Function("...")()
- // ^ ^
- apply(
- node,
- node.target,
- CodePositionKind.END,
- sourceInformation,
- SourcePositionKind.CLOSING);
- } else {
- assert(invariant(NO_LOCATION_SPANNABLE, false,
- message: "Unexpected property access ${nodeToString(node)}:\n"
- "${DebugPrinter.prettyPrint(node)}"));
- // Don't know....
- apply(
- node,
- node,
- CodePositionKind.START,
- sourceInformation,
- SourcePositionKind.START);
- }
- }
- visitChildren(node);
+ void process(js.Node node, CodeBuffer codeBuffer) {
+ new JavaScriptTracer(codePositionMap, traceListeners).apply(node);
}
@override
@@ -452,7 +404,776 @@
int startPosition,
int endPosition,
int closingPosition) {
- codePositions.registerPositions(
+ codePositionRecorder.registerPositions(
node, startPosition, endPosition, closingPosition);
}
}
+
+/// [TraceListener] that register [SourceLocation]s with a [SourceMapper].
+class PositionTraceListener extends TraceListener {
+ final SourceMapper sourceMapper;
+
+ PositionTraceListener(this.sourceMapper);
+
+ @override
+ void onStep(js.Node node, Offset offset, StepKind kind) {
+ SourceInformation sourceInformation = node.sourceInformation;
+ if (sourceInformation == null) return;
+
+ SourcePositionKind sourcePositionKind = SourcePositionKind.START;
+ switch (kind) {
+ case StepKind.FUN:
+ sourcePositionKind = SourcePositionKind.INNER;
+ break;
+ case StepKind.CALL:
+ CallPosition callPosition =
+ CallPosition.getSemanticPositionForCall(node);
+ sourcePositionKind = callPosition.sourcePositionKind;
+ break;
+ case StepKind.NEW:
+ case StepKind.RETURN:
+ case StepKind.BREAK:
+ case StepKind.CONTINUE:
+ case StepKind.THROW:
+ case StepKind.EXPRESSION_STATEMENT:
+ case StepKind.IF_CONDITION:
+ case StepKind.FOR_INITIALIZER:
+ case StepKind.FOR_CONDITION:
+ case StepKind.FOR_UPDATE:
+ case StepKind.WHILE_CONDITION:
+ case StepKind.DO_CONDITION:
+ case StepKind.SWITCH_EXPRESSION:
+ break;
+ }
+ int codeLocation = offset.subexpressionOffset;
+ SourceLocation sourceLocation =
+ getSourceLocation(sourceInformation, sourcePositionKind);
+ if (codeLocation != null && sourceLocation != null) {
+ sourceMapper.register(node, codeLocation, sourceLocation);
+ }
+ }
+}
+
+/// The position of a [js.Call] node.
+class CallPosition {
+ final js.Node node;
+ final CodePositionKind codePositionKind;
+ final SourcePositionKind sourcePositionKind;
+
+ CallPosition(this.node, this.codePositionKind, this.sourcePositionKind);
+
+ /// Computes the [CallPosition] for [node].
+ static CallPosition getSemanticPositionForCall(js.Call node) {
+ if (node.target is js.PropertyAccess) {
+ js.PropertyAccess access = node.target;
+ js.Node target = access;
+ bool pureAccess = false;
+ while (target is js.PropertyAccess) {
+ js.PropertyAccess targetAccess = target;
+ if (targetAccess.receiver is js.VariableUse ||
+ targetAccess.receiver is js.This) {
+ pureAccess = true;
+ break;
+ } else {
+ target = targetAccess.receiver;
+ }
+ }
+ if (pureAccess) {
+ // a.m() this.m() a.b.c.d.m()
+ // ^ ^ ^
+ return new CallPosition(
+ node,
+ CodePositionKind.START,
+ SourcePositionKind.START);
+ } else {
+ // *.m() *.a.b.c.d.m()
+ // ^ ^
+ return new CallPosition(
+ access.selector,
+ CodePositionKind.START,
+ SourcePositionKind.INNER);
+ }
+ } else if (node.target is js.VariableUse) {
+ // m()
+ // ^
+ return new CallPosition(
+ node,
+ CodePositionKind.START,
+ SourcePositionKind.START);
+ } else if (node.target is js.Fun || node.target is js.New) {
+ // function(){}() new Function("...")()
+ // ^ ^
+ return new CallPosition(
+ node.target,
+ CodePositionKind.END,
+ SourcePositionKind.INNER);
+ } else if (node.target is js.Binary || node.target is js.Call) {
+ // (0,a)() m()()
+ // ^ ^
+ return new CallPosition(
+ node.target,
+ CodePositionKind.END,
+ SourcePositionKind.INNER);
+ } else {
+ assert(invariant(NO_LOCATION_SPANNABLE, false,
+ message: "Unexpected property access ${nodeToString(node)}:\n"
+ "${DebugPrinter.prettyPrint(node)}"));
+ // Don't know....
+ return new CallPosition(
+ node,
+ CodePositionKind.START,
+ SourcePositionKind.START);
+ }
+ }
+}
+
+class Offset {
+ /// The offset of the enclosing statement relative to the beginning of the
+ /// file.
+ ///
+ /// For instance:
+ ///
+ /// foo().bar(baz());
+ /// ^ // the statement offset of the `foo()` call
+ /// ^ // the statement offset of the `*.bar()` call
+ /// ^ // the statement offset of the `baz()` call
+ ///
+ final int statementOffset;
+
+ /// The `subexpression` offset of the step. This is the (mostly) unique
+ /// offset relative to the beginning of the file, that identifies the
+ /// current of execution.
+ ///
+ /// For instance:
+ ///
+ /// foo().bar(baz());
+ /// ^ // the subexpression offset of the `foo()` call
+ /// ^ // the subexpression offset of the `*.bar()` call
+ /// ^ // the subexpression offset of the `baz()` call
+ ///
+ /// Here, even though the JavaScript node for the `*.bar()` call contains
+ /// the `foo()` its execution is identified by the `bar` identifier more than
+ /// the foo identifier.
+ ///
+ final int subexpressionOffset;
+
+ /// The `left-to-right` offset of the step. This is like [subexpressionOffset]
+ /// bute restricted so that the offset of each subexpression in execution
+ /// order is monotonically increasing.
+ ///
+ /// For instance:
+ ///
+ /// foo().bar(baz());
+ /// ^ // the left-to-right offset of the `foo()` call
+ /// ^ // the left-to-right offset of the `*.bar()` call
+ /// ^ // the left-to-right offset of the `baz()` call
+ ///
+ /// Here, `baz()` is executed before `foo()` so we need to use 'f' as its best
+ /// position under the restriction.
+ ///
+ final int leftToRightOffset;
+
+ Offset(this.statementOffset, this.leftToRightOffset, this.subexpressionOffset);
+
+ String toString() {
+ return 'Offset[statementOffset=$statementOffset,'
+ 'leftToRightOffset=$leftToRightOffset,'
+ 'subexpressionOffset=$subexpressionOffset]';
+ }
+}
+
+enum BranchKind {
+ CONDITION,
+ LOOP,
+ CATCH,
+ FINALLY,
+ CASE,
+}
+
+enum StepKind {
+ FUN,
+ CALL,
+ NEW,
+ RETURN,
+ BREAK,
+ CONTINUE,
+ THROW,
+ EXPRESSION_STATEMENT,
+ IF_CONDITION,
+ FOR_INITIALIZER,
+ FOR_CONDITION,
+ FOR_UPDATE,
+ WHILE_CONDITION,
+ DO_CONDITION,
+ SWITCH_EXPRESSION,
+}
+
+/// Listener for the [JavaScriptTracer].
+abstract class TraceListener {
+ /// Called before [root] node is procesed by the [JavaScriptTracer].
+ void onStart(js.Node root) {}
+
+ /// Called after [root] node has been procesed by the [JavaScriptTracer].
+ void onEnd(js.Node root) {}
+
+ /// Called when a branch of the given [kind] is started. [value] is provided
+ /// to distinguish true/false branches of [BranchKind.CONDITION] and cases of
+ /// [Branch.CASE].
+ void pushBranch(BranchKind kind, [value]) {}
+
+ /// Called when the current branch ends.
+ void popBranch() {}
+
+ /// Called when [node] defines a step of the given [kind] at the given
+ /// [offset] when the generated JavaScript code.
+ void onStep(js.Node node, Offset offset, StepKind kind) {}
+}
+
+/// Visitor that computes the [js.Node]s the are part of the JavaScript
+/// steppable execution and thus needs source mapping locations.
+class JavaScriptTracer extends js.BaseVisitor {
+ final CodePositionMap codePositions;
+ final List<TraceListener> listeners;
+
+ /// The steps added by subexpressions.
+ List steps = [];
+
+ /// The offset of the current statement.
+ int statementOffset;
+
+ /// The current offset in left-to-right progression.
+ int leftToRightOffset;
+
+ /// The offset of the surrounding statement, used for the first subexpression.
+ int offsetPosition;
+
+ bool active;
+
+ JavaScriptTracer(this.codePositions,
+ this.listeners,
+ {this.active: false});
+
+ void notifyStart(js.Node node) {
+ listeners.forEach((listener) => listener.onStart(node));
+ }
+
+ void notifyEnd(js.Node node) {
+ listeners.forEach((listener) => listener.onEnd(node));
+ }
+
+ void notifyPushBranch(BranchKind kind, [value]) {
+ if (active) {
+ listeners.forEach((listener) => listener.pushBranch(kind, value));
+ }
+ }
+
+ void notifyPopBranch() {
+ if (active) {
+ listeners.forEach((listener) => listener.popBranch());
+ }
+ }
+
+ void notifyStep(js.Node node, Offset offset, StepKind kind) {
+ if (active) {
+ listeners.forEach((listener) => listener.onStep(node, offset, kind));
+ }
+ }
+
+ void apply(js.Node node) {
+ notifyStart(node);
+ node.accept(this);
+ notifyEnd(node);
+ }
+
+ @override
+ visitNode(js.Node node) {
+ node.visitChildren(this);
+ }
+
+ visit(js.Node node, [BranchKind branch, value]) {
+ if (node != null) {
+ if (branch != null) {
+ notifyPushBranch(branch, value);
+ node.accept(this);
+ notifyPopBranch();
+ } else {
+ node.accept(this);
+ }
+ }
+ }
+
+ visitList(List<js.Node> nodeList) {
+ if (nodeList != null) {
+ for (js.Node node in nodeList) {
+ visit(node);
+ }
+ }
+ }
+
+ @override
+ visitFun(js.Fun node) {
+ bool activeBefore = active;
+ if (!active) {
+ active = node.sourceInformation != null;
+ }
+ visit(node.body);
+ leftToRightOffset = statementOffset =
+ getSyntaxOffset(node, kind: CodePositionKind.CLOSING);
+ Offset offset = getOffsetForNode(node, statementOffset);
+ notifyStep(node, offset, StepKind.FUN);
+ active = activeBefore;
+ }
+
+ @override
+ visitBlock(js.Block node) {
+ for (js.Statement statement in node.statements) {
+ visit(statement);
+ }
+ }
+
+ int getSyntaxOffset(js.Node node,
+ {CodePositionKind kind: CodePositionKind.START}) {
+ CodePosition codePosition = codePositions[node];
+ if (codePosition != null) {
+ return codePosition.getPosition(kind);
+ }
+ return null;
+ }
+
+ visitSubexpression(js.Node parent,
+ js.Expression child,
+ int codeOffset,
+ StepKind kind) {
+ var oldSteps = steps;
+ steps = [];
+ offsetPosition = codeOffset;
+ visit(child);
+ if (steps.isEmpty) {
+ notifyStep(parent,
+ getOffsetForNode(parent, offsetPosition),
+ kind);
+ }
+ steps = oldSteps;
+ }
+
+ @override
+ visitExpressionStatement(js.ExpressionStatement node) {
+ statementOffset = getSyntaxOffset(node);
+ visitSubexpression(
+ node, node.expression, statementOffset,
+ StepKind.EXPRESSION_STATEMENT);
+ statementOffset = null;
+ leftToRightOffset = null;
+ }
+
+ @override
+ visitEmptyStatement(js.EmptyStatement node) {}
+
+ @override
+ visitCall(js.Call node) {
+ visit(node.target);
+ int oldPosition = offsetPosition;
+ offsetPosition = null;
+ visitList(node.arguments);
+ offsetPosition = oldPosition;
+ CallPosition callPosition =
+ CallPosition.getSemanticPositionForCall(node);
+ js.Node positionNode = callPosition.node;
+ int callOffset = getSyntaxOffset(
+ positionNode, kind: callPosition.codePositionKind);
+ if (offsetPosition == null) {
+ offsetPosition = callOffset;
+ }
+ Offset offset = getOffsetForNode(positionNode, offsetPosition);
+ notifyStep(node, offset, StepKind.CALL);
+ steps.add(node);
+ offsetPosition = null;
+ }
+
+ @override
+ visitNew(js.New node) {
+ visit(node.target);
+ visitList(node.arguments);
+ notifyStep(
+ node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.NEW);
+ steps.add(node);
+ offsetPosition = null;
+ }
+
+ @override
+ visitAccess(js.PropertyAccess node) {
+ visit(node.receiver);
+ visit(node.selector);
+ }
+
+ @override
+ visitVariableUse(js.VariableUse node) {}
+
+ @override
+ visitLiteralBool(js.LiteralBool node) {}
+
+ @override
+ visitLiteralString(js.LiteralString node) {}
+
+ @override
+ visitLiteralNumber(js.LiteralNumber node) {}
+
+ @override
+ visitLiteralNull(js.LiteralNull node) {}
+
+ @override
+ visitName(js.Name node) {}
+
+ @override
+ visitVariableDeclarationList(js.VariableDeclarationList node) {
+ visitList(node.declarations);
+ }
+
+ @override
+ visitVariableDeclaration(js.VariableDeclaration node) {}
+
+ @override
+ visitVariableInitialization(js.VariableInitialization node) {
+ visit(node.leftHandSide);
+ visit(node.value);
+ }
+
+ @override
+ visitAssignment(js.Assignment node) {
+ visit(node.leftHandSide);
+ visit(node.value);
+ }
+
+ @override
+ visitIf(js.If node) {
+ statementOffset = getSyntaxOffset(node);
+ visitSubexpression(node, node.condition, statementOffset,
+ StepKind.IF_CONDITION);
+ statementOffset = null;
+ visit(node.then, BranchKind.CONDITION, true);
+ visit(node.otherwise, BranchKind.CONDITION, false);
+ }
+
+ @override
+ visitFor(js.For node) {
+ int offset = statementOffset = getSyntaxOffset(node);
+ statementOffset = offset;
+ leftToRightOffset = null;
+ if (node.init != null) {
+ visitSubexpression(node, node.init, getSyntaxOffset(node),
+ StepKind.FOR_INITIALIZER);
+ }
+
+ if (node.condition != null) {
+ visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
+ StepKind.FOR_CONDITION);
+ }
+
+ notifyPushBranch(BranchKind.LOOP);
+ visit(node.body);
+
+ statementOffset = offset;
+ if (node.update != null) {
+ visitSubexpression(node, node.update, getSyntaxOffset(node.update),
+ StepKind.FOR_UPDATE);
+ }
+
+ notifyPopBranch();
+ }
+
+ @override
+ visitWhile(js.While node) {
+ statementOffset = getSyntaxOffset(node);
+ if (node.condition != null) {
+ visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
+ StepKind.WHILE_CONDITION);
+ }
+ statementOffset = null;
+ leftToRightOffset = null;
+
+ visit(node.body, BranchKind.LOOP);
+ }
+
+ @override
+ visitDo(js.Do node) {
+ statementOffset = getSyntaxOffset(node);
+ visit(node.body);
+ if (node.condition != null) {
+ visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
+ StepKind.DO_CONDITION);
+ }
+ statementOffset = null;
+ leftToRightOffset = null;
+ }
+
+ @override
+ visitBinary(js.Binary node) {
+ visit(node.left);
+ visit(node.right);
+ }
+
+ @override
+ visitThis(js.This node) {}
+
+ @override
+ visitReturn(js.Return node) {
+ statementOffset = getSyntaxOffset(node);
+ visit(node.value);
+ notifyStep(
+ node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.RETURN);
+ statementOffset = null;
+ leftToRightOffset = null;
+ }
+
+ @override
+ visitThrow(js.Throw node) {
+ statementOffset = getSyntaxOffset(node);
+ visit(node.expression);
+ notifyStep(
+ node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.THROW);
+ statementOffset = null;
+ leftToRightOffset = null;
+ }
+
+ @override
+ visitContinue(js.Continue node) {
+ statementOffset = getSyntaxOffset(node);
+ notifyStep(
+ node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.CONTINUE);
+ statementOffset = null;
+ leftToRightOffset = null;
+ }
+
+ @override
+ visitBreak(js.Break node) {
+ statementOffset = getSyntaxOffset(node);
+ notifyStep(
+ node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.BREAK);
+ statementOffset = null;
+ leftToRightOffset = null;
+ }
+
+ @override
+ visitTry(js.Try node) {
+ visit(node.body);
+ visit(node.catchPart, BranchKind.CATCH);
+ visit(node.finallyPart, BranchKind.FINALLY);
+ }
+
+ @override
+ visitCatch(js.Catch node) {
+ visit(node.body);
+ }
+
+ @override
+ visitConditional(js.Conditional node) {
+ visit(node.condition);
+ visit(node.then, BranchKind.CONDITION, true);
+ visit(node.otherwise, BranchKind.CONDITION, false);
+ }
+
+ @override
+ visitPrefix(js.Prefix node) {
+ visit(node.argument);
+ }
+
+ @override
+ visitPostfix(js.Postfix node) {
+ visit(node.argument);
+ }
+
+ @override
+ visitObjectInitializer(js.ObjectInitializer node) {
+ visitList(node.properties);
+ }
+
+ @override
+ visitProperty(js.Property node) {
+ visit(node.name);
+ visit(node.value);
+ }
+
+ @override
+ visitRegExpLiteral(js.RegExpLiteral node) {}
+
+ @override
+ visitSwitch(js.Switch node) {
+ statementOffset = getSyntaxOffset(node);
+ visitSubexpression(node, node.key, getSyntaxOffset(node),
+ StepKind.SWITCH_EXPRESSION);
+ statementOffset = null;
+ leftToRightOffset = null;
+ for (int i = 0; i < node.cases.length; i++) {
+ visit(node.cases[i], BranchKind.CASE, i);
+ }
+ }
+
+ @override
+ visitCase(js.Case node) {
+ visit(node.expression);
+ visit(node.body);
+ }
+
+ @override
+ visitDefault(js.Default node) {
+ visit(node.body);
+ }
+
+ @override
+ visitArrayInitializer(js.ArrayInitializer node) {
+ visitList(node.elements);
+ }
+
+ @override
+ visitArrayHole(js.ArrayHole node) {}
+
+ @override
+ visitLabeledStatement(js.LabeledStatement node) {
+ statementOffset = getSyntaxOffset(node);
+ visit(node.body);
+ statementOffset = null;
+ }
+
+ Offset getOffsetForNode(js.Node node, int codeOffset) {
+ if (codeOffset == null) {
+ CodePosition codePosition = codePositions[node];
+ if (codePosition != null) {
+ codeOffset = codePosition.startPosition;
+ }
+ }
+ if (leftToRightOffset != null && leftToRightOffset < codeOffset) {
+ leftToRightOffset = codeOffset;
+ }
+ if (leftToRightOffset == null) {
+ leftToRightOffset = statementOffset;
+ }
+ return new Offset(statementOffset, leftToRightOffset, codeOffset);
+ }
+}
+
+
+class Coverage {
+ Set<js.Node> _nodesWithInfo = new Set<js.Node>();
+ int _nodesWithInfoCount = 0;
+ Set<js.Node> _nodesWithoutInfo = new Set<js.Node>();
+ int _nodesWithoutInfoCount = 0;
+ Map<Type, int> _nodesWithoutInfoCountByType = <Type, int>{};
+ Set<js.Node> _nodesWithoutOffset = new Set<js.Node>();
+ int _nodesWithoutOffsetCount = 0;
+
+ void registerNodeWithInfo(js.Node node) {
+ _nodesWithInfo.add(node);
+ }
+
+ void registerNodeWithoutInfo(js.Node node) {
+ _nodesWithoutInfo.add(node);
+ }
+
+ void registerNodesWithoutOffset(js.Node node) {
+ _nodesWithoutOffset.add(node);
+ }
+
+ void collapse() {
+ _nodesWithInfoCount += _nodesWithInfo.length;
+ _nodesWithInfo.clear();
+ _nodesWithoutOffsetCount += _nodesWithoutOffset.length;
+ _nodesWithoutOffset.clear();
+
+ _nodesWithoutInfoCount += _nodesWithoutInfo.length;
+ for (js.Node node in _nodesWithoutInfo) {
+ if (node is js.ExpressionStatement) {
+ _nodesWithoutInfoCountByType.putIfAbsent(
+ node.expression.runtimeType, () => 0);
+ _nodesWithoutInfoCountByType[node.expression.runtimeType]++;
+ } else {
+ _nodesWithoutInfoCountByType.putIfAbsent(
+ node.runtimeType, () => 0);
+ _nodesWithoutInfoCountByType[node.runtimeType]++;
+ }
+ }
+ _nodesWithoutInfo.clear();
+ }
+
+ String getCoverageReport() {
+ collapse();
+ StringBuffer sb = new StringBuffer();
+ int total = _nodesWithInfoCount + _nodesWithoutInfoCount;
+ if (total > 0) {
+ sb.write(_nodesWithoutInfoCount);
+ sb.write('/');
+ sb.write(total);
+ sb.write(' (');
+ sb.write((100.0 * _nodesWithInfoCount / total).toStringAsFixed(2));
+ sb.write('%) nodes with info.');
+ } else {
+ sb.write('No nodes.');
+ }
+ if (_nodesWithoutOffsetCount > 0) {
+ sb.write(' ');
+ sb.write(_nodesWithoutOffsetCount);
+ sb.write(' node');
+ if (_nodesWithoutOffsetCount > 1) {
+ sb.write('s');
+ }
+ sb.write(' without offset.');
+ }
+ if (_nodesWithoutInfoCount > 0) {
+ sb.write('\nNodes without info (');
+ sb.write(_nodesWithoutInfoCount);
+ sb.write(') by runtime type:');
+ _nodesWithoutInfoCountByType.forEach((Type type, int count) {
+ sb.write('\n ');
+ sb.write(count);
+ sb.write(' ');
+ sb.write(type);
+ sb.write(' node');
+ if (count > 1) {
+ sb.write('s');
+ }
+ });
+ sb.write('\n');
+ }
+ return sb.toString();
+ }
+
+ String toString() => getCoverageReport();
+}
+
+/// [TraceListener] that registers [onStep] callbacks with [coverage].
+class CoverageListener extends TraceListener {
+ final Coverage coverage;
+
+ CoverageListener(this.coverage);
+
+ @override
+ void onStep(js.Node node, Offset offset, StepKind kind) {
+ SourceInformation sourceInformation = node.sourceInformation;
+ if (sourceInformation != null) {
+ coverage.registerNodeWithInfo(node);
+ } else {
+ coverage.registerNodeWithoutInfo(node);
+ }
+ }
+
+ @override
+ void onEnd(js.Node node) {
+ coverage.collapse();
+ }
+}
+
+/// [CodePositionMap] that registers calls with [Coverage].
+class CodePositionCoverage implements CodePositionMap {
+ final CodePositionMap codePositions;
+ final Coverage coverage;
+
+ CodePositionCoverage(this.codePositions, this.coverage);
+
+ @override
+ CodePosition operator [](js.Node node) {
+ CodePosition codePosition = codePositions[node];
+ if (codePosition == null) {
+ coverage.registerNodesWithoutOffset(node);
+ }
+ return codePosition;
+ }
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index 1855755..0138b41 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -21,6 +21,8 @@
/// Interface for passing source information, for instance for use in source
/// maps, through the backend.
abstract class SourceInformation extends JavaScriptNodeSourceInformation {
+ const SourceInformation();
+
SourceSpan get sourceSpan;
/// The source location associated with the start of the JS node.
@@ -47,6 +49,12 @@
SourceInformationBuilder createBuilderForContext(AstElement element) {
return const SourceInformationBuilder();
}
+
+ /// Generate [SourceInformation] marker for non-preamble code.
+ SourceInformation buildSourceMappedMarker() => null;
+
+ /// Called when compilation has completed.
+ void onComplete() {}
}
/// Interface for generating [SourceInformation].
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
index 988c77d..8cae566 100644
--- a/pkg/compiler/lib/src/io/start_end_information.dart
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -116,7 +116,7 @@
}
class StartEndSourceInformationStrategy
- implements JavaScriptSourceInformationStrategy {
+ extends JavaScriptSourceInformationStrategy {
const StartEndSourceInformationStrategy();
@override
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 3a9fd2e..df510a8 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -20,12 +20,30 @@
import 'js_source_mapping.dart';
-CodeBuffer prettyPrint(Node node,
- Compiler compiler,
- {DumpInfoTask monitor,
- bool allowVariableMinification: true,
- Renamer renamerForNames:
- JavaScriptPrintingOptions.identityRenamer}) {
+String prettyPrint(
+ Node node,
+ Compiler compiler,
+ {bool allowVariableMinification: true,
+ Renamer renamerForNames: JavaScriptPrintingOptions.identityRenamer}) {
+ // TODO(johnniwinther): Do we need all the options here?
+ JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
+ shouldCompressOutput: compiler.enableMinification,
+ minifyLocalVariables: allowVariableMinification,
+ preferSemicolonToNewlineInMinifiedOutput: USE_LAZY_EMITTER,
+ renamerForNames: renamerForNames);
+ SimpleJavaScriptPrintingContext context =
+ new SimpleJavaScriptPrintingContext();
+ Printer printer = new Printer(options, context);
+ printer.visit(node);
+ return context.getText();
+}
+
+CodeBuffer createCodeBuffer(
+ Node node,
+ Compiler compiler,
+ {DumpInfoTask monitor,
+ bool allowVariableMinification: true,
+ Renamer renamerForNames: JavaScriptPrintingOptions.identityRenamer}) {
JavaScriptSourceInformationStrategy sourceInformationFactory =
compiler.backend.sourceInformationStrategy;
JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
@@ -35,14 +53,14 @@
renamerForNames: renamerForNames);
CodeBuffer outBuffer = new CodeBuffer();
SourceInformationProcessor sourceInformationProcessor =
- sourceInformationFactory.createProcessor(
- new SourceLocationsMapper(outBuffer));
+ sourceInformationFactory.createProcessor(
+ new SourceLocationsMapper(outBuffer));
Dart2JSJavaScriptPrintingContext context =
new Dart2JSJavaScriptPrintingContext(
compiler.reporter, monitor, outBuffer, sourceInformationProcessor);
Printer printer = new Printer(options, context);
printer.visit(node);
- sourceInformationProcessor.process(node);
+ sourceInformationProcessor.process(node, outBuffer);
return outBuffer;
}
@@ -137,13 +155,13 @@
/// A [js.Literal] that represents the string result of unparsing [ast].
///
/// When its string [value] is requested, the node pretty-prints the given
- /// [ast] and, if [protectForEval] is true, wraps the resulting
- /// string in parenthesis. The result is also escaped.
+ /// [ast] and, if [protectForEval] is true, wraps the resulting string in
+ /// parenthesis. The result is also escaped.
UnparsedNode(this.tree, this._compiler, this._protectForEval);
LiteralString get _literal {
if (_cachedLiteral == null) {
- String text = prettyPrint(tree, _compiler).getText();
+ String text = prettyPrint(tree, _compiler);
if (_protectForEval) {
if (tree is Fun) text = '($text)';
if (tree is LiteralExpression) {
@@ -164,6 +182,12 @@
String get value => _literal.value;
}
+/// True if the given template consists of just a placeholder. Such templates
+/// are sometimes used to manually promote the type of an expression.
+bool isIdentityTemplate(Template template) {
+ return template.ast is InterpolatedExpression;
+}
+
/// Returns `true` if [template] will immediately give a TypeError if the first
/// placeholder is `null` or `undefined`.
bool isNullGuardOnFirstArgument(Template template) {
diff --git a/pkg/compiler/lib/src/js/js_debug.dart b/pkg/compiler/lib/src/js/js_debug.dart
index 43ec130..c8cbd0de 100644
--- a/pkg/compiler/lib/src/js/js_debug.dart
+++ b/pkg/compiler/lib/src/js/js_debug.dart
@@ -7,7 +7,12 @@
library js.debug;
import 'package:js_ast/js_ast.dart';
-import '../util/util.dart' show Indentation, Tagging;
+
+import '../io/code_output.dart' show
+ BufferedCodeOutput;
+import '../util/util.dart' show
+ Indentation,
+ Tagging;
/// Unparse the JavaScript [node].
String nodeToString(Node node) {
@@ -25,8 +30,8 @@
class DebugPrinter extends BaseVisitor with Indentation, Tagging<Node> {
StringBuffer sb = new StringBuffer();
- void visitNodeWithChildren(Node node, String type) {
- openNode(node, type);
+ void visitNodeWithChildren(Node node, String type, [Map params]) {
+ openNode(node, type, params);
node.visitChildren(this);
closeNode();
}
@@ -42,6 +47,11 @@
}
@override
+ void visitBinary(Binary node) {
+ visitNodeWithChildren(node, '${node.runtimeType}', {'op': node.op});
+ }
+
+ @override
void visitLiteralString(LiteralString node) {
openAndCloseNode(node, '${node.runtimeType}', {'value': node.value});
}
@@ -57,7 +67,8 @@
}
/// Simple printing context that doesn't throw on errors.
-class LenientPrintingContext extends SimpleJavaScriptPrintingContext {
+class LenientPrintingContext extends SimpleJavaScriptPrintingContext
+ implements BufferedCodeOutput {
@override
void error(String message) {
buffer.write('>>$message<<');
diff --git a/pkg/compiler/lib/src/js/js_source_mapping.dart b/pkg/compiler/lib/src/js/js_source_mapping.dart
index 0378a58..cd72e35 100644
--- a/pkg/compiler/lib/src/js/js_source_mapping.dart
+++ b/pkg/compiler/lib/src/js/js_source_mapping.dart
@@ -5,7 +5,10 @@
library js.source_mapping;
import 'js.dart';
-import '../io/code_output.dart' show SourceLocations;
+import '../io/code_output.dart' show
+ BufferedCodeOutput,
+ CodeBuffer,
+ SourceLocations;
import '../io/source_information.dart' show
SourceLocation,
SourceInformation,
@@ -64,5 +67,5 @@
/// Process the source information and code positions for the [node] and all
/// its children.
- void process(Node node) {}
+ void process(Node node, BufferedCodeOutput code) {}
}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 05b00d1..7407ef7 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -502,7 +502,7 @@
bool enabledNoSuchMethod = false;
- final SourceInformationStrategy sourceInformationStrategy;
+ SourceInformationStrategy sourceInformationStrategy;
final BackendHelpers helpers;
final BackendImpacts impacts;
@@ -520,7 +520,7 @@
this.sourceInformationStrategy =
generateSourceMap
? (useNewSourceInfo
- ? const PositionSourceInformationStrategy()
+ ? new PositionSourceInformationStrategy()
: const StartEndSourceInformationStrategy())
: const JavaScriptSourceInformationStrategy(),
helpers = new BackendHelpers(compiler),
@@ -940,14 +940,14 @@
final Map<String, Set<ClassElement>> interceptedClassesCache =
new Map<String, Set<ClassElement>>();
+ final Set<ClassElement> _noClasses = new Set<ClassElement>();
- /**
- * Returns a set of interceptor classes that contain a member named
- * [name]. Returns [:null:] if there is no class.
- */
+ /// Returns a set of interceptor classes that contain a member named [name]
+ ///
+ /// Returns an empty set if there is no class. Do not modify the returned set.
Set<ClassElement> getInterceptedClassesOn(String name) {
Set<Element> intercepted = interceptedElements[name];
- if (intercepted == null) return null;
+ if (intercepted == null) return _noClasses;
return interceptedClassesCache.putIfAbsent(name, () {
// Populate the cache by running through all the elements and
// determine if the given selector applies to them.
@@ -974,13 +974,12 @@
Iterable<MixinApplicationElement> uses = classWorld.mixinUsesOf(mixin);
Set<ClassElement> result = null;
for (MixinApplicationElement use in uses) {
- Iterable<ClassElement> subclasses = classWorld.strictSubclassesOf(use);
- for (ClassElement subclass in subclasses) {
+ classWorld.forEachStrictSubclassOf(use, (ClassElement subclass) {
if (isNativeOrExtendsNative(subclass)) {
if (result == null) result = new Set<ClassElement>();
result.add(subclass);
}
- }
+ });
}
return result;
}
@@ -1251,6 +1250,10 @@
addInterceptors(helpers.jsFixedArrayClass, enqueuer, registry);
addInterceptors(helpers.jsExtendableArrayClass, enqueuer, registry);
addInterceptors(helpers.jsUnmodifiableArrayClass, enqueuer, registry);
+ // Literal lists can be translated into calls to these functions:
+ enqueueInResolution(helpers.jsArrayTypedConstructor, registry);
+ enqueueInResolution(helpers.setRuntimeTypeInfo, registry);
+ enqueueInResolution(helpers.getTypeArgumentByIndex, registry);
} else if (cls == coreClasses.intClass ||
cls == helpers.jsIntClass) {
addInterceptors(helpers.jsIntClass, enqueuer, registry);
@@ -1630,7 +1633,12 @@
}
}
- generatedCode[element] = functionCompiler.compile(work);
+ jsAst.Fun function = functionCompiler.compile(work);
+ if (function.sourceInformation == null) {
+ function = function.withSourceInformation(
+ sourceInformationStrategy.buildSourceMappedMarker());
+ }
+ generatedCode[element] = function;
WorldImpact worldImpact =
impactTransformer.transformCodegenImpact(work.registry.worldImpact);
compiler.dumpInfoTask.registerImpact(element, worldImpact);
@@ -1661,7 +1669,7 @@
*/
String getGeneratedCode(Element element) {
assert(invariant(element, element.isDeclaration));
- return jsAst.prettyPrint(generatedCode[element], compiler).getText();
+ return jsAst.prettyPrint(generatedCode[element], compiler);
}
int assembleProgram() {
@@ -2191,7 +2199,7 @@
});
// 4) all overriding members of subclasses/subtypes (should be resolved)
if (compiler.world.hasAnyStrictSubtype(cls)) {
- for (ClassElement subcls in compiler.world.strictSubtypesOf(cls)) {
+ compiler.world.forEachStrictSubtypeOf(cls, (ClassElement subcls) {
subcls.forEachClassMember((Member member) {
if (memberNames.contains(member.name)) {
// TODO(20993): find out why this assertion fails.
@@ -2202,7 +2210,7 @@
}
}
});
- }
+ });
}
// 5) all its closures
List<LocalFunctionElement> closures = closureMap[cls];
@@ -2509,13 +2517,13 @@
compiler.enabledInvokeOn = true;
}
}
-
+/*
CodeBuffer codeOf(Element element) {
return generatedCode.containsKey(element)
? jsAst.prettyPrint(generatedCode[element], compiler)
: null;
}
-
+*/
FunctionElement helperForBadMain() => helpers.badMain;
FunctionElement helperForMissingMain() => helpers.missingMain;
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index f25e13b..29e6743 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -652,4 +652,4 @@
}
return _closure;
}
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index bc8ed93..1815ee2 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -91,7 +91,10 @@
js.Fun buildFunction(tree_ir.FunctionDefinition function) {
registerDefaultParameterValues(function.element);
currentFunction = function.element;
- visitStatement(function.body);
+ tree_ir.Statement statement = function.body;
+ while (statement != null) {
+ statement = visitStatement(statement);
+ }
List<js.Parameter> parameters = new List<js.Parameter>();
Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>();
@@ -121,6 +124,9 @@
if (assign.op != null) break; // Compound assignment.
js.VariableUse use = assign.leftHandSide;
+ // Do not touch non-local variables.
+ if (!usedVariableNames.contains(use.name)) break;
+
// We cannot declare a variable more than once.
if (!declaredVariables.add(use.name)) break;
@@ -144,6 +150,9 @@
if (assign.op != null) break pullFromForLoop; // Compound assignment.
js.VariableUse use = assign.leftHandSide;
+ // Do not touch non-local variables.
+ if (!usedVariableNames.contains(use.name)) break pullFromForLoop;
+
// We cannot declare a variable more than once.
if (!declaredVariables.add(use.name)) break pullFromForLoop;
@@ -218,9 +227,11 @@
List<js.Expression> visitExpressionList(
List<tree_ir.Expression> expressions) {
- return new List<js.Expression>.generate(expressions.length,
- (int index) => visitExpression(expressions[index]),
- growable: false);
+ List<js.Expression> result = new List<js.Expression>(expressions.length);
+ for (int i = 0; i < expressions.length; ++i) {
+ result[i] = visitExpression(expressions[i]);
+ }
+ return result;
}
giveup(tree_ir.Node node,
@@ -364,26 +375,6 @@
}
@override
- js.Expression visitLiteralMap(tree_ir.LiteralMap node) {
- ConstructorElement constructor;
- if (node.entries.isEmpty) {
- constructor = glue.mapLiteralConstructorEmpty;
- } else {
- constructor = glue.mapLiteralConstructor;
- }
- List<js.Expression> entries =
- new List<js.Expression>(2 * node.entries.length);
- for (int i = 0; i < node.entries.length; i++) {
- entries[2 * i] = visitExpression(node.entries[i].key);
- entries[2 * i + 1] = visitExpression(node.entries[i].value);
- }
- List<js.Expression> args = entries.isEmpty
- ? <js.Expression>[]
- : <js.Expression>[new js.ArrayInitializer(entries)];
- return buildStaticInvoke(constructor, args);
- }
-
- @override
js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) {
return new js.Binary(
node.operator,
@@ -405,13 +396,19 @@
///
/// Even if the class is never instantiated, a JS constructor must be emitted
/// so the 'instanceof' expression does not throw an exception at runtime.
- ///
- /// It does not help to ask the class world if the class is instantiated,
- /// because it could still get tree-shaken if it is unused after optimization.
- void registerInstanceofCheck(ClassElement class_) {
- // TODO(asgerf): This is the only hook we have to ensure the JS constructor
- // gets emitted, but it is very imprecise. We should do better.
- registry.registerInstantiatedClass(class_);
+ bool tryRegisterInstanceofCheck(ClassElement class_) {
+ if (glue.classWorld.isInstantiated(class_)) {
+ // Ensure the class remains instantiated during backend tree-shaking.
+ // TODO(asgerf): We could have a more precise hook to inform the emitter
+ // that the JS constructor function is needed, without the class being
+ // instantiated.
+ registry.registerInstantiatedClass(class_);
+ return true;
+ }
+ // Will throw if the JS constructor is not emitted, so do not allow the
+ // instanceof check. This should only happen when certain optimization
+ // passes are disabled, as the type check itself is trivial.
+ return false;
}
@override
@@ -435,8 +432,8 @@
// TODO(sra): Implement fast cast via calling 'boolTypeCast'.
} else if (node.isTypeTest &&
node.typeArguments.isEmpty &&
- glue.mayGenerateInstanceofCheck(type)) {
- registerInstanceofCheck(clazz);
+ glue.mayGenerateInstanceofCheck(type) &&
+ tryRegisterInstanceofCheck(clazz)) {
return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]);
}
@@ -618,14 +615,15 @@
}
@override
- void visitExpressionStatement(tree_ir.ExpressionStatement node) {
+ visitExpressionStatement(tree_ir.ExpressionStatement node) {
js.Expression exp = visitExpression(node.expression);
if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
// Emit as 'return exp' to assist local analysis in the VM.
accumulator.add(new js.Return(exp));
+ return null;
} else {
accumulator.add(new js.ExpressionStatement(exp));
- visitStatement(node.next);
+ return node.next;
}
}
@@ -639,7 +637,7 @@
}
@override
- void visitIf(tree_ir.If node) {
+ visitIf(tree_ir.If node) {
js.Expression condition = visitExpression(node.condition);
int usesBefore = fallthrough.useCount;
// Unless the 'else' part ends the method. make sure to terminate any
@@ -651,21 +649,22 @@
if (thenHasFallthrough) {
js.Statement elseBody = buildBodyStatement(node.elseStatement);
accumulator.add(new js.If(condition, thenBody, elseBody));
+ return null;
} else {
// The 'then' body cannot complete normally, so emit a short 'if'
// and put the 'else' body after it.
accumulator.add(new js.If.noElse(condition, thenBody));
- visitStatement(node.elseStatement);
+ return node.elseStatement;
}
}
@override
- void visitLabeledStatement(tree_ir.LabeledStatement node) {
+ visitLabeledStatement(tree_ir.LabeledStatement node) {
fallthrough.push(node.next);
js.Statement body = buildBodyStatement(node.body);
fallthrough.pop();
accumulator.add(insertLabel(node.label, body));
- visitStatement(node.next);
+ return node.next;
}
/// Creates a name for [label] if it does not already have one.
@@ -697,7 +696,9 @@
js.Statement buildBodyStatement(tree_ir.Statement statement) {
List<js.Statement> savedAccumulator = accumulator;
accumulator = <js.Statement>[];
- visitStatement(statement);
+ while (statement != null) {
+ statement = visitStatement(statement);
+ }
js.Statement result = _bodyAsStatement();
accumulator = savedAccumulator;
return result;
@@ -706,7 +707,9 @@
js.Block buildBodyBlock(tree_ir.Statement statement) {
List<js.Statement> savedAccumulator = accumulator;
accumulator = <js.Statement>[];
- visitStatement(statement);
+ while (statement != null) {
+ statement = visitStatement(statement);
+ }
js.Statement result = new js.Block(accumulator);
accumulator = savedAccumulator;
return result;
@@ -717,7 +720,7 @@
}
@override
- void visitFor(tree_ir.For node) {
+ visitFor(tree_ir.For node) {
js.Expression condition = visitExpression(node.condition);
shortBreak.push(node.next);
shortContinue.push(node);
@@ -744,12 +747,11 @@
loopNode = new js.For(init, condition, update, body);
}
accumulator.add(insertLabel(node.label, loopNode));
- visitStatement(node.next);
+ return node.next;
}
@override
void visitWhileTrue(tree_ir.WhileTrue node) {
- js.Expression condition = new js.LiteralBool(true);
// A short break in the while will jump to the current fallthrough target.
shortBreak.push(fallthrough.target);
shortContinue.push(node);
@@ -764,7 +766,8 @@
fallthrough.use();
}
shortBreak.pop();
- accumulator.add(insertLabel(node.label, new js.While(condition, jsBody)));
+ accumulator.add(
+ insertLabel(node.label, new js.For(null, null, null, jsBody)));
}
bool isNull(tree_ir.Expression node) {
@@ -824,17 +827,14 @@
registry.registerInstantiatedClosure(classElement.methodElement);
}
js.Expression instance = new js.New(
- glue.constructorAccess(classElement),
- visitExpressionList(node.arguments))
+ glue.constructorAccess(classElement),
+ visitExpressionList(node.arguments))
.withSourceInformation(node.sourceInformation);
- List<tree_ir.Expression> typeInformation = node.typeInformation;
- assert(typeInformation.isEmpty ||
- typeInformation.length == classElement.typeVariables.length);
- if (typeInformation.isNotEmpty) {
+ tree_ir.Expression typeInformation = node.typeInformation;
+ if (typeInformation != null) {
FunctionElement helper = glue.getAddRuntimeTypeInformation();
- js.Expression typeArguments = new js.ArrayInitializer(
- visitExpressionList(typeInformation));
+ js.Expression typeArguments = visitExpression(typeInformation);
return buildStaticHelperInvocation(helper,
<js.Expression>[instance, typeArguments],
sourceInformation: node.sourceInformation);
@@ -921,8 +921,7 @@
registry.registerStaticUse(
new StaticUse.staticSet(node.element.declaration));
js.Expression field = glue.staticFieldAccess(node.element);
- js.Expression value = visitExpression(node.value);
- return new js.Assignment(field, value);
+ return makeAssignment(field, node.value, compound: node.compound);
}
@override
@@ -987,7 +986,17 @@
@override
js.Expression visitTypeExpression(tree_ir.TypeExpression node) {
List<js.Expression> arguments = visitExpressionList(node.arguments);
- return glue.generateTypeRepresentation(node.dartType, arguments, registry);
+ switch (node.kind) {
+ case tree_ir.TypeExpressionKind.COMPLETE:
+ return glue.generateTypeRepresentation(
+ node.dartType, arguments, registry);
+ case tree_ir.TypeExpressionKind.INSTANCE:
+ // We expect only flat types for the INSTANCE representation.
+ assert(node.dartType ==
+ (node.dartType.element as ClassElement).thisType);
+ registry.registerInstantiatedClass(glue.listClass);
+ return new js.ArrayInitializer(arguments);
+ }
}
js.Node handleForeignCode(tree_ir.ForeignCode node) {
@@ -1015,14 +1024,14 @@
}
@override
- void visitYield(tree_ir.Yield node) {
+ visitYield(tree_ir.Yield node) {
js.Expression value = visitExpression(node.input);
accumulator.add(new js.DartYield(value, node.hasStar));
- visitStatement(node.next);
+ return node.next;
}
@override
- void visitNullCheck(tree_ir.NullCheck node) {
+ visitNullCheck(tree_ir.NullCheck node) {
js.Expression value = visitExpression(node.value);
// TODO(sra): Try to use the selector even when [useSelector] is false. The
// reason we use 'toString' is that it is always defined so avoids a slow
@@ -1044,7 +1053,7 @@
} else {
accumulator.add(new js.ExpressionStatement(access));
}
- visitStatement(node.next);
+ return node.next;
}
@override
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index b7d4c24..46ef1a5 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -228,8 +228,7 @@
ClassWorld classWorld = _compiler.world;
if (classWorld.isUsedAsMixin(cls)) return true;
- Iterable<ClassElement> subclasses = _compiler.world.strictSubclassesOf(cls);
- return subclasses.any((ClassElement subclass) {
+ return _compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) {
return !_backend.rti.isTrivialSubstitution(subclass, cls);
});
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 034dd10..6e0619b 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -103,7 +103,7 @@
}
if (tracer != null) {
- tracer.traceCompilation(element.name, null);
+ tracer.traceCompilation('$element', null);
}
cps.FunctionDefinition cpsFunction = compileToCpsIr(element);
optimizeCpsBeforeInlining(cpsFunction);
@@ -131,6 +131,49 @@
}
}
+ String stringify(cps.FunctionDefinition node) {
+ return new SExpressionStringifier().withTypes().visit(node);
+ }
+
+ /// For debugging purposes, replace a call to [applyCpsPass] with a call
+ /// to [debugCpsPass] to check that this pass is idempotent.
+ ///
+ /// This runs [pass] followed by shrinking reductions, and then checks that
+ /// one more run of [pass] does not change the IR. The intermediate shrinking
+ /// reductions pass is omitted if [pass] itself is shrinking reductions.
+ ///
+ /// If [targetName] is given, functions whose name contains that substring
+ /// will be dumped out if the idempotency test fails.
+ void debugCpsPass(cps_opt.Pass makePass(),
+ cps.FunctionDefinition cpsFunction,
+ [String targetName]) {
+ String original = stringify(cpsFunction);
+ cps_opt.Pass pass = makePass();
+ pass.rewrite(cpsFunction);
+ assert(checkCpsIntegrity(cpsFunction, pass.passName));
+ if (pass is! ShrinkingReducer) {
+ new ShrinkingReducer().rewrite(cpsFunction);
+ }
+ String before = stringify(cpsFunction);
+ makePass().rewrite(cpsFunction);
+ String after = stringify(cpsFunction);
+ if (before != after) {
+ print('SExpression changed for ${cpsFunction.element}');
+ if (targetName != null && '${cpsFunction.element}'.contains(targetName)) {
+ print(original);
+ print('\n-->\n');
+ print(before);
+ print('\n-->\n');
+ print(after);
+ compiler.outputProvider('original', 'dump')..add(original)..close();
+ compiler.outputProvider('before', 'dump')..add(before)..close();
+ compiler.outputProvider('after', 'dump')..add(after)..close();
+ }
+ }
+ traceGraph(pass.passName, cpsFunction);
+ dumpTypedIr(pass.passName, cpsFunction);
+ }
+
void applyCpsPass(cps_opt.Pass pass, cps.FunctionDefinition cpsFunction) {
cpsOptimizationTask.measureSubtask(pass.passName, () {
pass.rewrite(cpsFunction);
@@ -141,8 +184,10 @@
}
cps.FunctionDefinition compileToCpsIr(AstElement element) {
- cps.FunctionDefinition cpsFunction =
- cpsBuilderTask.buildNode(element, typeSystem);
+ cps.FunctionDefinition cpsFunction = inliner.cache.getUnoptimized(element);
+ if (cpsFunction != null) return cpsFunction;
+
+ cpsFunction = cpsBuilderTask.buildNode(element, typeSystem);
if (cpsFunction == null) {
if (cpsBuilderTask.bailoutMessage == null) {
giveUp('unable to build cps definition of $element');
@@ -157,6 +202,11 @@
// insert fewer getInterceptor calls.
applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
applyCpsPass(new UnsugarVisitor(glue), cpsFunction);
+ applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
+ applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
+ applyCpsPass(new InsertRefinements(typeSystem), cpsFunction);
+
+ inliner.cache.putUnoptimized(element, cpsFunction);
return cpsFunction;
}
@@ -208,9 +258,6 @@
void optimizeCpsBeforeInlining(cps.FunctionDefinition cpsFunction) {
cpsOptimizationTask.measure(() {
- applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
- applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
- applyCpsPass(new InsertRefinements(typeSystem), cpsFunction);
applyCpsPass(new TypePropagator(this), cpsFunction);
applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
applyCpsPass(new ShrinkingReducer(), cpsFunction);
@@ -219,9 +266,16 @@
void optimizeCpsAfterInlining(cps.FunctionDefinition cpsFunction) {
cpsOptimizationTask.measure(() {
+ applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
+ applyCpsPass(new ShrinkingReducer(), cpsFunction);
applyCpsPass(new RedundantRefinementEliminator(typeSystem), cpsFunction);
+ applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
+ applyCpsPass(new TypePropagator(this, recomputeAll: true), cpsFunction);
+ applyCpsPass(new ShrinkingReducer(), cpsFunction);
applyCpsPass(new EagerlyLoadStatics(), cpsFunction);
applyCpsPass(new GVN(compiler, typeSystem), cpsFunction);
+ applyCpsPass(new DuplicateBranchEliminator(), cpsFunction);
+ applyCpsPass(new ShrinkingReducer(), cpsFunction);
applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
applyCpsPass(new BoundsChecker(typeSystem, compiler.world), cpsFunction);
applyCpsPass(new LoopInvariantBranchMotion(), cpsFunction);
@@ -230,6 +284,7 @@
applyCpsPass(new MutableVariableEliminator(), cpsFunction);
applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
+ applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
applyCpsPass(new ShrinkingReducer(), cpsFunction);
applyCpsPass(new OptimizeInterceptors(backend, typeSystem), cpsFunction);
applyCpsPass(new BackwardNullCheckRemover(typeSystem), cpsFunction);
@@ -267,7 +322,7 @@
treeOptimizationTask.measure(() {
applyTreePass(new StatementRewriter());
- applyTreePass(new VariableMerger());
+ applyTreePass(new VariableMerger(minifying: compiler.enableMinification));
applyTreePass(new LoopRewriter());
applyTreePass(new LogicalRewriter());
applyTreePass(new PullIntoInitializers());
diff --git a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
index 290d563..f6ebd07 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -274,8 +274,17 @@
compiler.backend.typeImplementation.computeType(compiler.resolution));
}
- // Integer checks don't verify that the number is not -0.0.
- bool isInt(ConstantValue constant) => constant.isInt || constant.isMinusZero;
+ // Integer checks report true for -0.0, INFINITY, and -INFINITY. At
+ // runtime an 'X is int' check is implemented as:
+ //
+ // typeof(X) === "number" && Math.floor(X) === X
+ //
+ // We consistently match that runtime semantics at compile time as well.
+ bool isInt(ConstantValue constant) {
+ return constant.isInt || constant.isMinusZero ||
+ constant.isPositiveInfinity ||
+ constant.isNegativeInfinity;
+ }
bool isDouble(ConstantValue constant)
=> constant.isDouble && !constant.isMinusZero;
bool isString(ConstantValue constant) => constant.isString;
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 99d383c..eca1917 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -49,6 +49,8 @@
import '../dart_types.dart';
import '../deferred_load.dart' show
DeferredLoadTask;
+import '../diagnostics/invariant.dart' show
+ DEBUG_MODE;
import '../dump_info.dart' show
DumpInfoTask;
import '../elements/elements.dart';
diff --git a/pkg/compiler/lib/src/js_backend/namer_names.dart b/pkg/compiler/lib/src/js_backend/namer_names.dart
index 60e1597..31a1747 100644
--- a/pkg/compiler/lib/src/js_backend/namer_names.dart
+++ b/pkg/compiler/lib/src/js_backend/namer_names.dart
@@ -8,7 +8,12 @@
int get _kind;
_NamerName get _target => this;
- toString() => throw new UnsupportedError("Cannot convert a name to a string");
+ String toString() {
+ if (DEBUG_MODE) {
+ return 'Name($key)';
+ }
+ throw new UnsupportedError("Cannot convert a name to a string");
+ }
}
enum _NamerNameKinds {
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 849fae3..1501a93 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -236,8 +236,7 @@
classesNeedingRti.add(cls);
// TODO(ngeoffray): This should use subclasses, not subtypes.
- Iterable<ClassElement> classes = compiler.world.strictSubtypesOf(cls);
- classes.forEach((ClassElement sub) {
+ compiler.world.forEachStrictSubtypeOf(cls, (ClassElement sub) {
potentiallyAddForRti(sub);
});
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index fb34fae..f2c1ded 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -74,6 +74,7 @@
TypeCheck,
TypeChecks,
TypeVariableHandler;
+import '../../js/js_debug.dart';
import '../../universe/call_structure.dart' show
CallStructure;
import '../../universe/selector.dart' show
@@ -1609,9 +1610,8 @@
outputBuffers[mainOutputUnit] = mainOutput;
- mainOutput.addBuffer(jsAst.prettyPrint(program,
- compiler,
- monitor: compiler.dumpInfoTask));
+ mainOutput.addBuffer(jsAst.createCodeBuffer(
+ program, compiler, monitor: compiler.dumpInfoTask));
if (compiler.deferredMapUri != null) {
outputDeferredMap();
@@ -2055,9 +2055,8 @@
outputBuffers[outputUnit] = output;
- output.addBuffer(jsAst.prettyPrint(outputAsts[outputUnit],
- compiler,
- monitor: compiler.dumpInfoTask));
+ output.addBuffer(jsAst.createCodeBuffer(
+ outputAsts[outputUnit], compiler, monitor: compiler.dumpInfoTask));
// Make a unique hash of the code (before the sourcemaps are added)
// This will be used to retrieve the initializing function from the global
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index dbc6c9b..eb66c1a 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -22,6 +22,8 @@
ClosureClassMap,
ClosureFieldElement,
CapturedVariable;
+import '../core_types.dart' show
+ CoreClasses;
import '../dart_types.dart' show
DartType,
FunctionType,
@@ -34,6 +36,7 @@
import '../elements/elements.dart' show
ClassElement,
ConstructorBodyElement,
+ ConstructorElement,
Element,
Elements,
ElementKind,
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
index 96838ac..a0b9b48 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
@@ -159,15 +159,16 @@
program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
+ // TODO(johnnniwinther): Support source maps in this emitter.
for (int i = 0; i < fragmentsCode.length; ++i) {
- String code = js.prettyPrint(fragmentsCode[i], compiler).getText();
+ String code = js.createCodeBuffer(fragmentsCode[i], compiler).getText();
totalSize += code.length;
compiler.outputProvider(fragments[i+1].outputFileName, deferredExtension)
..add(code)
..close();
}
- String mainCode = js.prettyPrint(mainAst, compiler).getText();
+ String mainCode = js.createCodeBuffer(mainAst, compiler).getText();
compiler.outputProvider(mainFragment.outputFileName, 'js')
..add(buildGeneratedBy(compiler))
..add(mainCode)
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index 43aa528..fdea7ff 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -178,12 +178,42 @@
}
List<jsAst.DeferredNumber> reifyDefaultArguments(FunctionElement function) {
+ function = function.implementation;
FunctionSignature signature = function.functionSignature;
if (signature.optionalParameterCount == 0) return const [];
+
+ // Optional parameters of redirecting factory constructors take their
+ // defaults from the corresponding parameters of the redirection target.
+ Map<ParameterElement, ParameterElement> targetParameterMap;
+ if (function is ConstructorElement) {
+ // TODO(sra): dart2js generates a redirecting factory constructor body
+ // that has the signature of the redirecting constructor that calls the
+ // redirection target. This is wrong - it should have the signature of the
+ // target. This would make the reified default arguments trivial.
+
+ ConstructorElement constructor = function;
+ while (constructor.isRedirectingFactory &&
+ !constructor.isCyclicRedirection) {
+ // TODO(sra): Remove the loop once effectiveTarget forwards to patches.
+ constructor = constructor.effectiveTarget.implementation;
+ }
+
+ if (constructor != function) {
+ if (signature.hasOptionalParameters) {
+ targetParameterMap =
+ mapRedirectingFactoryConstructorOptionalParameters(
+ signature, constructor.functionSignature);
+ }
+ }
+ }
+
List<jsAst.DeferredNumber> defaultValues = <jsAst.DeferredNumber>[];
for (ParameterElement element in signature.optionalParameters) {
- ConstantValue constant =
- _backend.constants.getConstantValueForVariable(element);
+ ParameterElement parameter =
+ (targetParameterMap == null) ? element : targetParameterMap[element];
+ ConstantValue constant = (parameter == null)
+ ? null
+ : _backend.constants.getConstantValueForVariable(parameter);
jsAst.Expression expression = (constant == null)
? new jsAst.LiteralNull()
: _emitter.constantReference(constant);
@@ -192,6 +222,40 @@
return defaultValues;
}
+ Map<ParameterElement, ParameterElement>
+ mapRedirectingFactoryConstructorOptionalParameters(
+ FunctionSignature source, FunctionSignature target) {
+ var map = <ParameterElement, ParameterElement>{};
+
+ if (source.optionalParametersAreNamed !=
+ target.optionalParametersAreNamed) {
+ // No legal optional arguments due to mismatch between named vs positional
+ // optional arguments.
+ return map;
+ }
+
+ if (source.optionalParametersAreNamed) {
+ for (ParameterElement element in source.optionalParameters) {
+ for (ParameterElement redirectedElement in target.optionalParameters) {
+ if (element.name == redirectedElement.name) {
+ map[element] = redirectedElement;
+ break;
+ }
+ }
+ }
+ } else {
+ int i = source.requiredParameterCount;
+ for (ParameterElement element in source.orderedOptionalParameters) {
+ if (i >= target.requiredParameterCount && i < target.parameterCount) {
+ map[element] =
+ target.orderedOptionalParameters[i - target.requiredParameterCount];
+ }
+ ++i;
+ }
+ }
+ return map;
+ }
+
jsAst.Expression reifyMetadata(MetadataAnnotation annotation) {
ConstantValue constant =
_backend.constants.getConstantValueForMetadata(annotation);
@@ -229,9 +293,8 @@
_MetadataEntry _addGlobalMetadata(jsAst.Node node) {
String nameToKey(jsAst.Name name) => "${name.key}";
- String printed = jsAst.prettyPrint(node, _compiler,
- renamerForNames: nameToKey)
- .getText();
+ String printed = jsAst.prettyPrint(
+ node, _compiler, renamerForNames: nameToKey);
return _globalMetadataMap.putIfAbsent(printed, () {
_BoundMetadataEntry result = new _BoundMetadataEntry(node);
if (_compiler.hasIncrementalSupport) {
@@ -366,4 +429,4 @@
node.accept(this);
return _foundUnboundToken;
}
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index 61c1b08..9c48f4d 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -35,6 +35,7 @@
JavaScriptBackend get backend => compiler.backend;
TypeTestRegistry get typeTestRegistry => emitterTask.typeTestRegistry;
+ CoreClasses get coreClasses => compiler.coreClasses;
Set<ClassElement> get checkedClasses =>
typeTestRegistry.checkedClasses;
@@ -181,7 +182,7 @@
}
if (superclass != null &&
- superclass != compiler.coreClasses.objectClass &&
+ superclass != coreClasses.objectClass &&
!haveSameTypeVariables(cls, superclass)) {
// We cannot inherit the generated substitutions, because the type
// variable layout for this class is different. Instead we generate
@@ -217,7 +218,7 @@
// A class that defines a `call` method implicitly implements
// [Function] and needs checks for all typedefs that are used in is-checks.
- if (checkedClasses.contains(compiler.coreClasses.functionClass) ||
+ if (checkedClasses.contains(coreClasses.functionClass) ||
checkedFunctionTypes.isNotEmpty) {
Element call = cls.lookupLocalMember(Identifiers.call);
if (call == null) {
@@ -228,8 +229,8 @@
FunctionElement callFunction = call;
// A superclass might already implement the Function interface. In such
// a case, we can avoid emiting the is test here.
- if (!cls.superclass.implementsFunction(compiler)) {
- _generateInterfacesIsTests(compiler.coreClasses.functionClass,
+ if (!cls.superclass.implementsFunction(coreClasses)) {
+ _generateInterfacesIsTests(coreClasses.functionClass,
generateIsTest,
generateSubstitution,
generated);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 9e81bca..65d0519 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -281,7 +281,7 @@
isSplit ? buildDeferredInitializerGlobal() : new js.Block.empty(),
code]);
- mainOutput.addBuffer(js.prettyPrint(program, compiler,
+ mainOutput.addBuffer(js.createCodeBuffer(program, compiler,
monitor: compiler.dumpInfoTask));
if (shouldGenerateSourceMap) {
@@ -335,7 +335,7 @@
buildDeferredInitializerGlobal(),
js.js.statement('$deferredInitializersGlobal.current = #', code)]);
- output.addBuffer(js.prettyPrint(program, compiler,
+ output.addBuffer(js.createCodeBuffer(program, compiler,
monitor: compiler.dumpInfoTask));
// Make a unique hash of the code (before the sourcemaps are added)
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 438dbe6..cd61a71 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -111,6 +111,9 @@
static NativeBehavior get PURE => NativeBehavior._makePure();
static NativeBehavior get PURE_ALLOCATION =>
NativeBehavior._makePure(isAllocation: true);
+ static NativeBehavior get CHANGES_OTHER => NativeBehavior._makeChangesOther();
+ static NativeBehavior get DEPENDS_OTHER => NativeBehavior._makeDependsOther();
+
String toString() {
return 'NativeBehavior('
@@ -132,6 +135,18 @@
return behavior;
}
+ static NativeBehavior _makeChangesOther() {
+ // TODO(25544): Have a distinct effect instead of using static properties to
+ // model 'other' effects.
+ return _makePure()..sideEffects.setChangesStaticProperty();
+ }
+
+ static NativeBehavior _makeDependsOther() {
+ // TODO(25544): Have a distinct effect instead of using static properties to
+ // model 'other' effects.
+ return _makePure()..sideEffects.setDependsOnStaticPropertyStore();
+ }
+
/// Processes the type specification string of a call to JS and stores the
/// result in the [typesReturned] and [typesInstantiated]. It furthermore
/// computes the side effects, and, if given, invokes [setSideEffects] with
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index a23a490..36feaa4 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -6,7 +6,8 @@
import '../common.dart';
import '../common/names.dart' show
- Identifiers;
+ Identifiers,
+ Names;
import '../common/resolution.dart' show
Resolution;
import '../compiler.dart' show
@@ -76,9 +77,12 @@
/// Compute all members of [cls] and checked that [cls] implements its
/// interface unless it is abstract or declares a `noSuchMethod` method.
void computeAllMembers() {
- Map<Name, Member> declaredMembers = computeMembers(null, null);
- if (!cls.isAbstract &&
- !declaredMembers.containsKey(const PublicName('noSuchMethod'))) {
+ computeMembers(null, null);
+ if (!cls.isAbstract) {
+ Member member = classMembers[Names.noSuchMethod_];
+ if (member != null && !member.declarer.isObject) {
+ return;
+ }
// Check for unimplemented members on concrete classes that neither have
// a `@proxy` annotation nor declare a `noSuchMethod` method.
checkInterfaceImplementation();
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 540ba50..0c8e57c 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -4198,9 +4198,11 @@
// If the isolate library is not used, we just generate code
// to fetch the static state.
String name = backend.namer.staticStateHolder;
- push(new HForeignCode(js.js.parseForeignJS(name),
- backend.dynamicType,
- <HInstruction>[]));
+ push(new HForeignCode(
+ js.js.parseForeignJS(name),
+ backend.dynamicType,
+ <HInstruction>[],
+ nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
} else {
// Call a helper method from the isolate library. The isolate
// library uses its own isolate structure, that encapsulates
@@ -4478,7 +4480,7 @@
js.js.parseForeignJS("$isolateName = #"),
backend.dynamicType,
<HInstruction>[pop()],
- nativeBehavior: native.NativeBehavior.PURE,
+ nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
effects: sideEffects));
}
@@ -4488,7 +4490,8 @@
}
push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
backend.dynamicType,
- <HInstruction>[]));
+ <HInstruction>[],
+ nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
}
void handleForeignSend(ast.Send node, FunctionElement element) {
@@ -4837,8 +4840,7 @@
ClassWorld classWorld = compiler.world;
if (classWorld.isUsedAsMixin(cls)) return true;
- Iterable<ClassElement> subclasses = compiler.world.strictSubclassesOf(cls);
- return subclasses.any((ClassElement subclass) {
+ return compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) {
return !rti.isTrivialSubstitution(subclass, cls);
});
}
@@ -7147,21 +7149,64 @@
FunctionSignature targetSignature = targetConstructor.functionSignature;
FunctionSignature redirectingSignature =
redirectingConstructor.functionSignature;
- redirectingSignature.forEachRequiredParameter((ParameterElement element) {
- inputs.add(localsHandler.readLocal(element));
- });
+
+ List<Element> targetRequireds = targetSignature.requiredParameters;
+ List<Element> redirectingRequireds
+ = redirectingSignature.requiredParameters;
+
List<Element> targetOptionals =
targetSignature.orderedOptionalParameters;
List<Element> redirectingOptionals =
redirectingSignature.orderedOptionalParameters;
- int i = 0;
- for (; i < redirectingOptionals.length; i++) {
- ParameterElement parameter = redirectingOptionals[i];
+
+ // TODO(25579): This code can do the wrong thing redirecting constructor and
+ // the target do not correspond. It is correct if there is no
+ // warning. Ideally the redirecting constructor and the target would be the
+ // same function.
+
+ void loadLocal(ParameterElement parameter) {
inputs.add(localsHandler.readLocal(parameter));
}
- for (; i < targetOptionals.length; i++) {
- inputs.add(handleConstantForOptionalParameter(targetOptionals[i]));
+ void loadPosition(int position, ParameterElement optionalParameter) {
+ if (position < redirectingRequireds.length) {
+ loadLocal(redirectingRequireds[position]);
+ } else if (position < redirectingSignature.parameterCount &&
+ !redirectingSignature.optionalParametersAreNamed) {
+ loadLocal(redirectingOptionals[position - redirectingRequireds.length]);
+ } else if (optionalParameter != null) {
+ inputs.add(handleConstantForOptionalParameter(optionalParameter));
+ } else {
+ // Wrong.
+ inputs.add(graph.addConstantNull(compiler));
+ }
}
+
+ int position = 0;
+
+ for (ParameterElement targetParameter in targetRequireds) {
+ loadPosition(position++, null);
+ }
+
+ if (targetOptionals.isNotEmpty) {
+ if (targetSignature.optionalParametersAreNamed) {
+ for (ParameterElement parameter in targetOptionals) {
+ ParameterElement redirectingParameter =
+ redirectingOptionals.firstWhere(
+ (p) => p.name == parameter.name,
+ orElse: () => null);
+ if (redirectingParameter == null) {
+ inputs.add(handleConstantForOptionalParameter(parameter));
+ } else {
+ inputs.add(localsHandler.readLocal(redirectingParameter));
+ }
+ }
+ } else {
+ for (ParameterElement parameter in targetOptionals) {
+ loadPosition(position++, parameter);
+ }
+ }
+ }
+
ClassElement targetClass = targetConstructor.enclosingClass;
if (backend.classNeedsRti(targetClass)) {
ClassElement cls = redirectingConstructor.enclosingClass;
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 9cfb66b..8d5e08f 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -100,8 +100,7 @@
// All intercepted classes extend `Interceptor`, so if the receiver can't be
// a class extending `Interceptor` then it can be called directly.
return new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, classWorld)
- .intersection(receiver.instructionType, classWorld)
- .isEmpty;
+ .isDisjoint(receiver.instructionType, classWorld);
}
HInstruction tryComputeConstantInterceptor(
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index c98ceb1..a8d82ae 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -593,8 +593,7 @@
// Intersection of int and double return conflicting, so
// we don't optimize on numbers to preserve the runtime semantics.
if (!(left.isNumberOrNull(compiler) && right.isNumberOrNull(compiler))) {
- TypeMask intersection = leftType.intersection(rightType, compiler.world);
- if (intersection.isEmpty && !intersection.isNullable) {
+ if (leftType.isDisjoint(rightType, compiler.world)) {
return makeFalse();
}
}
@@ -737,8 +736,7 @@
: new TypeMask.nonNullSubtype(element, classWorld);
if (expressionMask.union(typeMask, classWorld) == typeMask) {
return graph.addConstantBool(true, compiler);
- } else if (expressionMask.intersection(typeMask,
- compiler.world).isEmpty) {
+ } else if (expressionMask.isDisjoint(typeMask, compiler.world)) {
return graph.addConstantBool(false, compiler);
}
}
@@ -2154,10 +2152,8 @@
if (nonEscapingReceivers.contains(second)) return false;
// Typed arrays of different types might have a shared buffer.
if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true;
- TypeMask intersection = first.instructionType.intersection(
+ return !first.instructionType.isDisjoint(
second.instructionType, compiler.world);
- if (intersection.isEmpty) return false;
- return true;
}
bool isFinal(Element element) {
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index a940e71..7cd149e 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -682,6 +682,9 @@
} else {
constantNum = constant;
}
+ if (constantNum.isPositiveInfinity || constantNum.isNegativeInfinity) {
+ return info.newUnboundRange();
+ }
if (constantNum.isMinusZero) constantNum = new IntConstantValue(0);
Value value = info.newIntValue(constantNum.primitiveValue);
return info.newNormalizedRange(value, value);
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
index 3b3a74a..1ada85b 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
@@ -292,14 +292,6 @@
return node;
}
- Expression visitLiteralMap(LiteralMap node) {
- super.visitLiteralMap(node);
- if (node.type != null) {
- ++impureCounter; // Type casts can throw.
- }
- return node;
- }
-
Expression visitTypeOperator(TypeOperator node) {
super.visitTypeOperator(node);
if (!node.isTypeTest) {
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index f23533c..1c92ff5 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -372,6 +372,7 @@
exp is CreateInvocationMirror ||
exp is CreateInstance ||
exp is CreateBox ||
+ exp is TypeExpression ||
exp is GetStatic && exp.element.isFunction ||
exp is Interceptor ||
exp is ApplyBuiltinOperator ||
@@ -579,13 +580,11 @@
}
Expression visitLogicalOperator(LogicalOperator node) {
- node.left = visitExpression(node.left);
-
// Impure expressions may not propagate across the branch.
inEmptyEnvironment(() {
node.right = visitExpression(node.right);
});
-
+ node.left = visitExpression(node.left);
return node;
}
@@ -739,31 +738,32 @@
return node;
}
- Expression visitLiteralMap(LiteralMap node) {
- // Process arguments right-to-left, the opposite of evaluation order.
- for (LiteralMapEntry entry in node.entries.reversed) {
- entry.value = visitExpression(entry.value);
- entry.key = visitExpression(entry.key);
- }
- return node;
- }
-
Expression visitTypeOperator(TypeOperator node) {
_rewriteList(node.typeArguments);
node.value = visitExpression(node.value);
return node;
}
- bool sameVariable(Expression e1, Expression e2) {
- return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
- }
-
bool isCompoundableBuiltin(Expression e) {
return e is ApplyBuiltinOperator &&
- e.arguments.length == 2 &&
+ e.arguments.length >= 2 &&
isCompoundableOperator(e.operator);
}
+ /// Converts a compoundable operator application into the right-hand side for
+ /// use in a compound assignment, discarding the left-hand value.
+ ///
+ /// For example, for `x + y + z` it returns `y + z`.
+ Expression contractCompoundableBuiltin(ApplyBuiltinOperator e) {
+ assert(isCompoundableBuiltin(e));
+ if (e.arguments.length > 2) {
+ assert(e.operator == BuiltinOperator.StringConcatenate);
+ return new ApplyBuiltinOperator(e.operator, e.arguments.skip(1).toList());
+ } else {
+ return e.arguments[1];
+ }
+ }
+
void destroyVariableUse(VariableUse node) {
--node.variable.readCount;
}
@@ -774,13 +774,12 @@
if (isCompoundableBuiltin(node.value)) {
ApplyBuiltinOperator rhs = node.value;
Expression left = rhs.arguments[0];
- Expression right = rhs.arguments[1];
if (left is GetField &&
left.field == node.field &&
- sameVariable(left.object, node.object)) {
- destroyVariableUse(left.object);
+ samePrimary(left.object, node.object)) {
+ destroyPrimaryExpression(left.object);
node.compound = rhs.operator;
- node.value = right;
+ node.value = contractCompoundableBuiltin(rhs);
}
}
node.object = visitExpression(node.object);
@@ -800,6 +799,16 @@
Expression visitSetStatic(SetStatic node) {
allowRhsPropagation.add(true);
node.value = visitExpression(node.value);
+ if (isCompoundableBuiltin(node.value)) {
+ ApplyBuiltinOperator rhs = node.value;
+ Expression left = rhs.arguments[0];
+ if (left is GetStatic &&
+ left.element == node.element &&
+ !left.useLazyGetter) {
+ node.compound = rhs.operator;
+ node.value = contractCompoundableBuiltin(rhs);
+ }
+ }
allowRhsPropagation.removeLast();
return node;
}
@@ -814,6 +823,9 @@
}
Expression visitCreateInstance(CreateInstance node) {
+ if (node.typeInformation != null) {
+ node.typeInformation = visitExpression(node.typeInformation);
+ }
_rewriteList(node.arguments);
return node;
}
@@ -859,14 +871,13 @@
if (isCompoundableBuiltin(node.value)) {
ApplyBuiltinOperator rhs = node.value;
Expression left = rhs.arguments[0];
- Expression right = rhs.arguments[1];
if (left is GetIndex &&
- sameVariable(left.object, node.object) &&
- sameVariable(left.index, node.index)) {
- destroyVariableUse(left.object);
- destroyVariableUse(left.index);
+ samePrimary(left.object, node.object) &&
+ samePrimary(left.index, node.index)) {
+ destroyPrimaryExpression(left.object);
+ destroyPrimaryExpression(left.index);
node.compound = rhs.operator;
- node.value = right;
+ node.value = contractCompoundableBuiltin(rhs);
}
}
node.index = visitExpression(node.index);
@@ -1244,8 +1255,8 @@
@override
Statement visitYield(Yield node) {
- node.input = visitExpression(node.input);
node.next = visitStatement(node.next);
+ node.input = visitExpression(node.input);
return node;
}
@@ -1358,3 +1369,22 @@
new VariableUseVisitor(callback).visitExpression(node);
}
}
+
+bool sameVariable(Expression e1, Expression e2) {
+ return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
+}
+
+/// True if [e1] and [e2] are primary expressions (expressions without
+/// subexpressions) with the same value.
+bool samePrimary(Expression e1, Expression e2) {
+ return sameVariable(e1, e2) || (e1 is This && e2 is This);
+}
+
+/// Decrement the reference count for [e] if it is a variable use.
+void destroyPrimaryExpression(Expression e) {
+ if (e is VariableUse) {
+ --e.variable.readCount;
+ } else {
+ assert(e is This);
+ }
+}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
index fb31f02..bcc16ca 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
@@ -12,22 +12,19 @@
/// This phase cleans up artifacts introduced by the translation through CPS,
/// where each source variable is translated into several copies. The copies
/// are merged again when they are not live simultaneously.
-class VariableMerger extends RecursiveVisitor implements Pass {
+class VariableMerger implements Pass {
String get passName => 'Variable merger';
- void rewrite(FunctionDefinition node) {
- rewriteFunction(node);
- visitStatement(node.body);
- }
+ final bool minifying;
- /// Rewrites the given function.
- /// This is called for the outermost function and inner functions.
- void rewriteFunction(FunctionDefinition node) {
- BlockGraphBuilder builder = new BlockGraphBuilder();
- builder.build(node);
+ VariableMerger({this.minifying: false});
+
+ void rewrite(FunctionDefinition node) {
+ BlockGraphBuilder builder = new BlockGraphBuilder()..build(node);
_computeLiveness(builder.blocks);
- Map<Variable, Variable> subst =
- _computeRegisterAllocation(builder.blocks, node.parameters);
+ PriorityPairs priority = new PriorityPairs()..build(node);
+ Map<Variable, Variable> subst = _computeRegisterAllocation(
+ builder.blocks, node.parameters, priority, minifying: minifying);
new SubstituteVariables(subst).apply(node);
}
}
@@ -248,6 +245,54 @@
}
}
+/// Collects prioritized variable pairs -- pairs that lead to significant code
+/// reduction if merged into one variable.
+///
+/// These arise from moving assigments `v1 = v2`, and compoundable assignments
+/// `v1 = v2 [+] E` where [+] is a compoundable operator.
+//
+// TODO(asgerf): We could have a more fine-grained priority level. All pairs
+// are treated as equally important, but some pairs can eliminate more than
+// one assignment.
+// Also, some assignments are more important to remove than others, as they
+// can block a later optimization, such rewriting a loop, or removing the
+// 'else' part of an 'if'.
+//
+class PriorityPairs extends RecursiveVisitor {
+ final Map<Variable, List<Variable>> _priority = <Variable, List<Variable>>{};
+
+ void build(FunctionDefinition node) {
+ visitStatement(node.body);
+ }
+
+ void _prioritize(Variable x, Variable y) {
+ _priority.putIfAbsent(x, () => new List<Variable>()).add(y);
+ _priority.putIfAbsent(y, () => new List<Variable>()).add(x);
+ }
+
+ visitAssign(Assign node) {
+ super.visitAssign(node);
+ Expression value = node.value;
+ if (value is VariableUse) {
+ _prioritize(node.variable, value.variable);
+ } else if (value is ApplyBuiltinOperator &&
+ isCompoundableOperator(value.operator) &&
+ value.arguments[0] is VariableUse) {
+ VariableUse use = value.arguments[0];
+ _prioritize(node.variable, use.variable);
+ }
+ }
+
+ /// Returns the other half of every priority pair containing [variable].
+ List<Variable> getPriorityPairsWith(Variable variable) {
+ return _priority[variable] ?? const <Variable>[];
+ }
+
+ bool hasPriorityPairs(Variable variable) {
+ return _priority.containsKey(variable);
+ }
+}
+
/// Computes liveness information of the given control-flow graph.
///
/// The results are stored in [Block.liveIn] and [Block.liveOut].
@@ -331,14 +376,6 @@
}
}
-/// For testing purposes, this flag can be passed to merge variables that
-/// originated from different source variables.
-///
-/// Correctness should not depend on the fact that we only merge variables
-/// originating from the same source variable. Setting this flag makes a bug
-/// more likely to provoke a test case failure.
-const bool NO_PRESERVE_VARS = const bool.fromEnvironment('NO_PRESERVE_VARS');
-
/// Based on liveness information, computes a map of variable substitutions to
/// merge variables.
///
@@ -348,23 +385,30 @@
///
/// We then compute a graph coloring, where the color of a node denotes which
/// variable it will be substituted by.
-///
-/// We never merge variables that originated from distinct source variables,
-/// so we build a separate register interference graph for each source variable.
Map<Variable, Variable> _computeRegisterAllocation(List<Block> blocks,
- List<Variable> parameters) {
+ List<Variable> parameters,
+ PriorityPairs priority,
+ {bool minifying}) {
Map<Variable, Set<Variable>> interference = <Variable, Set<Variable>>{};
- /// Group for the given variable. We attempt to merge variables in the same
- /// group.
- /// By default, variables are grouped based on their source variable name,
- /// but this can be disabled for testing purposes.
- String group(Variable variable) {
- if (NO_PRESERVE_VARS) return '';
- // Group variables based on the source variable's name, not its element,
- // so if multiple locals are declared with the same name, they will
- // map to the same (hoisted) variable in the output.
- return variable.element == null ? '' : variable.element.name;
+ bool allowUnmotivatedMerge(Variable x, Variable y) {
+ if (minifying) return true;
+ // Do not allow merging temporaries with named variables if they are
+ // not connected by a phi. That would leads to confusing mergings like:
+ // var v0 = receiver.length;
+ // ==>
+ // receiver = receiver.length;
+ return x.element?.name == y.element?.name;
+ }
+
+ bool allowPhiMerge(Variable x, Variable y) {
+ if (minifying) return true;
+ // Temporaries may be merged with a named variable if this eliminates a phi.
+ // The presence of the phi implies that the two variables can contain the
+ // same value, so it is not that confusing that they get the same name.
+ return x.element == null ||
+ y.element == null ||
+ x.element.name == y.element.name;
}
Set<Variable> empty = new Set<Variable>();
@@ -372,12 +416,10 @@
// At the assignment to a variable x, add an edge to every variable that is
// live after the assignment (if it came from the same source variable).
for (Block block in blocks) {
- // Group the liveOut set by source variable.
- Map<String, Set<Variable>> liveOut = <String, Set<Variable>>{};
+ // Track the live set while traversing the block.
+ Set<Variable> live = new Set<Variable>();
for (Variable variable in block.liveOut) {
- liveOut.putIfAbsent(
- group(variable),
- () => new Set<Variable>()).add(variable);
+ live.add(variable);
interference.putIfAbsent(variable, () => new Set<Variable>());
}
// Get variables that are live at the catch block.
@@ -388,8 +430,6 @@
for (VariableAccess access in block.accesses.reversed) {
Variable variable = access.variable;
interference.putIfAbsent(variable, () => new Set<Variable>());
- Set<Variable> live =
- liveOut.putIfAbsent(group(variable), () => new Set<Variable>());
if (access.isRead) {
live.add(variable);
} else {
@@ -410,42 +450,89 @@
List<Variable> variables = interference.keys.toList();
variables.sort((x, y) => interference[y].length - interference[x].length);
- Map<String, List<Variable>> registers = <String, List<Variable>>{};
+ List<Variable> registers = <Variable>[];
Map<Variable, Variable> subst = <Variable, Variable>{};
- // Parameters are special in that they must have a ParameterElement and
- // cannot be merged with each other. Ensure that they are not substituted.
- // Other variables can still be substituted by a parameter.
- for (Variable parameter in parameters) {
- if (parameter.isCaptured) continue;
- subst[parameter] = parameter;
- registers[group(parameter)] = <Variable>[parameter];
+ /// Called when [variable] has been assigned [target] as its register/color.
+ /// Will immediately try to satisfy its priority pairs by assigning the same
+ /// color the other half of each pair.
+ void searchPriorityPairs(Variable variable, Variable target) {
+ if (!priority.hasPriorityPairs(variable)) {
+ return; // Most variables (around 90%) do not have priority pairs.
+ }
+ List<Variable> worklist = <Variable>[variable];
+ while (worklist.isNotEmpty) {
+ Variable v1 = worklist.removeLast();
+ for (Variable v2 in priority.getPriorityPairsWith(v1)) {
+ // If v2 already has a color, we cannot change it.
+ if (subst.containsKey(v2)) continue;
+
+ // Do not merge differently named variables.
+ if (!allowPhiMerge(v1, v2)) continue;
+
+ // Ensure the graph coloring remains valid. If a neighbour of v2 already
+ // has the desired color, we cannot assign the same color to v2.
+ if (interference[v2].any((v3) => subst[v3] == target)) continue;
+
+ subst[v2] = target;
+ target.element ??= v2.element; // Preserve the name.
+ worklist.add(v2);
+ }
+ }
}
+ void assignRegister(Variable variable, Variable registerRepresentative) {
+ subst[variable] = registerRepresentative;
+ // Ensure this register is never assigned to a variable with another name.
+ // This also ensures that named variables keep their name when merged
+ // with a temporary.
+ registerRepresentative.element ??= variable.element;
+ searchPriorityPairs(variable, registerRepresentative);
+ }
+
+ void assignNewRegister(Variable variable) {
+ registers.add(variable);
+ subst[variable] = variable;
+ searchPriorityPairs(variable, variable);
+ }
+
+ // Parameters cannot be merged with each other. Ensure that they are not
+ // substituted. Other variables can still be substituted by a parameter.
+ for (Variable parameter in parameters) {
+ if (parameter.isCaptured) continue;
+ registers.add(parameter);
+ subst[parameter] = parameter;
+ }
+
+ // Try to merge parameters with locals to eliminate phis.
+ for (Variable parameter in parameters) {
+ searchPriorityPairs(parameter, parameter);
+ }
+
+ v1loop:
for (Variable v1 in variables) {
- // Parameters have already been assigned a substitute; skip those.
+ // Ignore if the variable has already been assigned a register.
if (subst.containsKey(v1)) continue;
- List<Variable> register = registers[group(v1)];
-
- // Optimization: For the first variable in a group, allocate a new color
- // without iterating over its interference edges.
- if (register == null) {
- registers[group(v1)] = <Variable>[v1];
- subst[v1] = v1;
- continue;
- }
-
// Optimization: If there are no interference edges for this variable,
- // assign it the first color without copying the register list.
+ // find a color for it without copying the register list.
Set<Variable> interferenceSet = interference[v1];
if (interferenceSet.isEmpty) {
- subst[v1] = register[0];
+ // Use the first register where naming constraints allow the merge.
+ for (Variable v2 in registers) {
+ if (allowUnmotivatedMerge(v1, v2)) {
+ assignRegister(v1, v2);
+ continue v1loop;
+ }
+ }
+ // No register allows merging with this one, create a new register.
+ assignNewRegister(v1);
continue;
}
// Find an unused color.
- Set<Variable> potential = new Set<Variable>.from(register);
+ Set<Variable> potential = new Set<Variable>.from(
+ registers.where((v2) => allowUnmotivatedMerge(v1, v2)));
for (Variable v2 in interferenceSet) {
Variable v2subst = subst[v2];
if (v2subst != null) {
@@ -456,10 +543,9 @@
if (potential.isEmpty) {
// If no free color was found, add this variable as a new color.
- register.add(v1);
- subst[v1] = v1;
+ assignNewRegister(v1);
} else {
- subst[v1] = potential.first;
+ assignRegister(v1, potential.first);
}
}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index b846c87..15dc292 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -504,7 +504,7 @@
return new CreateInstance(
node.classElement,
translateArguments(node.arguments),
- translateArguments(node.typeInformation),
+ getVariableUseOrNull(node.typeInformation),
node.sourceInformation);
}
@@ -543,17 +543,6 @@
translateArguments(node.values));
}
- Expression visitLiteralMap(cps_ir.LiteralMap node) {
- return new LiteralMap(
- node.dartType,
- new List<LiteralMapEntry>.generate(node.entries.length, (int index) {
- return new LiteralMapEntry(
- getVariableUse(node.entries[index].key),
- getVariableUse(node.entries[index].value));
- })
- );
- }
-
Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
return new ReifyRuntimeType(
getVariableUse(node.value), node.sourceInformation);
@@ -568,6 +557,7 @@
Expression visitTypeExpression(cps_ir.TypeExpression node) {
return new TypeExpression(
+ node.kind,
node.dartType,
node.arguments.map(getVariableUse).toList());
}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index 19eeb05..2b4d301 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -13,6 +13,8 @@
import '../cps_ir/builtin_operator.dart';
export '../cps_ir/builtin_operator.dart';
+import '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind;
+export '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind;
// These imports are only used for the JavaScript specific nodes. If we want to
// support more than one native backend, we should probably create better
@@ -114,7 +116,8 @@
assert(host != null);
}
- String toString() => element == null ? 'Variable' : element.toString();
+ String toString() =>
+ element == null ? 'Variable.${hashCode}' : element.toString();
}
/// Read the value of a variable.
@@ -312,25 +315,6 @@
}
}
-class LiteralMapEntry {
- Expression key;
- Expression value;
-
- LiteralMapEntry(this.key, this.value);
-}
-
-class LiteralMap extends Expression {
- final InterfaceType type;
- final List<LiteralMapEntry> entries;
-
- LiteralMap(this.type, this.entries);
-
- accept(ExpressionVisitor visitor) => visitor.visitLiteralMap(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitLiteralMap(this, arg);
- }
-}
-
/// Type test or type cast.
///
/// Note that if this is a type test, then [type] cannot be `Object`, `dynamic`,
@@ -688,7 +672,7 @@
class CreateInstance extends Expression {
ClassElement classElement;
List<Expression> arguments;
- List<Expression> typeInformation;
+ Expression typeInformation;
SourceInformation sourceInformation;
CreateInstance(this.classElement, this.arguments,
@@ -760,8 +744,9 @@
Element element;
Expression value;
SourceInformation sourceInformation;
+ BuiltinOperator compound;
- SetStatic(this.element, this.value, this.sourceInformation);
+ SetStatic(this.element, this.value, this.sourceInformation, {this.compound});
accept(ExpressionVisitor visitor) => visitor.visitSetStatic(this);
accept1(ExpressionVisitor1 visitor, arg) => visitor.visitSetStatic(this, arg);
@@ -920,10 +905,11 @@
/// are replaced by the values in [arguments].
/// (See documentation on the TypeExpression CPS node for more details.)
class TypeExpression extends Expression {
+ final TypeExpressionKind kind;
final DartType dartType;
final List<Expression> arguments;
- TypeExpression(this.dartType, this.arguments);
+ TypeExpression(this.kind, this.dartType, this.arguments);
accept(ExpressionVisitor visitor) {
return visitor.visitTypeExpression(this);
@@ -999,7 +985,6 @@
E visitLogicalOperator(LogicalOperator node);
E visitNot(Not node);
E visitLiteralList(LiteralList node);
- E visitLiteralMap(LiteralMap node);
E visitTypeOperator(TypeOperator node);
E visitGetField(GetField node);
E visitSetField(SetField node);
@@ -1037,7 +1022,6 @@
E visitLogicalOperator(LogicalOperator node, A arg);
E visitNot(Not node, A arg);
E visitLiteralList(LiteralList node, A arg);
- E visitLiteralMap(LiteralMap node, A arg);
E visitTypeOperator(TypeOperator node, A arg);
E visitGetField(GetField node, A arg);
E visitSetField(SetField node, A arg);
@@ -1156,13 +1140,6 @@
node.values.forEach(visitExpression);
}
- visitLiteralMap(LiteralMap node) {
- node.entries.forEach((LiteralMapEntry entry) {
- visitExpression(entry.key);
- visitExpression(entry.value);
- });
- }
-
visitTypeOperator(TypeOperator node) {
visitExpression(node.value);
node.typeArguments.forEach(visitExpression);
@@ -1243,7 +1220,7 @@
visitCreateInstance(CreateInstance node) {
node.arguments.forEach(visitExpression);
- node.typeInformation.forEach(visitExpression);
+ if (node.typeInformation != null) visitExpression(node.typeInformation);
}
visitReifyRuntimeType(ReifyRuntimeType node) {
@@ -1390,14 +1367,6 @@
return node;
}
- visitLiteralMap(LiteralMap node) {
- node.entries.forEach((LiteralMapEntry entry) {
- entry.key = visitExpression(entry.key);
- entry.value = visitExpression(entry.value);
- });
- return node;
- }
-
visitTypeOperator(TypeOperator node) {
node.value = visitExpression(node.value);
_replaceExpressions(node.typeArguments);
@@ -1492,7 +1461,9 @@
visitCreateInstance(CreateInstance node) {
_replaceExpressions(node.arguments);
- _replaceExpressions(node.typeInformation);
+ if (node.typeInformation != null) {
+ node.typeInformation = visitExpression(node.typeInformation);
+ }
return node;
}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
index 979647a..6d2ce7e 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -414,16 +414,6 @@
return "list [$values]";
}
- String visitLiteralMap(LiteralMap node) {
- List<String> entries = new List<String>();
- node.entries.forEach((LiteralMapEntry entry) {
- String key = visitExpression(entry.key);
- String value = visitExpression(entry.value);
- entries.add("$key: $value");
- });
- return "map [${entries.join(', ')}]";
- }
-
String visitConstant(Constant node) {
return "${node.value.toStructuredString()}";
}
@@ -533,7 +523,9 @@
@override
String visitTypeExpression(TypeExpression node) {
- return node.dartType.toString();
+ String kind = '${node.kind}'.split('.').last;
+ String args = node.arguments.map(visitExpression).join(', ');
+ return 'TypeExpression($kind, ${node.dartType}, $args)';
}
@override
diff --git a/pkg/compiler/lib/src/types/constants.dart b/pkg/compiler/lib/src/types/constants.dart
index 1129465..e7ecab1 100644
--- a/pkg/compiler/lib/src/types/constants.dart
+++ b/pkg/compiler/lib/src/types/constants.dart
@@ -36,15 +36,15 @@
@override
TypeMask visitDouble(DoubleConstantValue constant, Compiler compiler) {
- // We have to distinguish -0.0 from 0, but for all practical purposes
- // -0.0 is an integer.
- // TODO(17235): this kind of special casing should only happen in the
- // backend.
- if (constant.isMinusZero &&
- compiler.backend.constantSystem.isInt(constant)) {
- return compiler.typesTask.uint31Type;
+ // We have to recognize double constants that are 'is int'.
+ if (compiler.backend.constantSystem.isInt(constant)) {
+ if (constant.isMinusZero) {
+ return compiler.typesTask.uint31Type;
+ } else {
+ assert(constant.isPositiveInfinity || constant.isNegativeInfinity);
+ return compiler.typesTask.intType;
+ }
}
- assert(!compiler.backend.constantSystem.isInt(constant));
return compiler.typesTask.doubleType;
}
diff --git a/pkg/compiler/lib/src/types/flat_type_mask.dart b/pkg/compiler/lib/src/types/flat_type_mask.dart
index 6516d96..914e673 100644
--- a/pkg/compiler/lib/src/types/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/types/flat_type_mask.dart
@@ -358,6 +358,47 @@
}
}
+ bool isDisjoint(TypeMask other, ClassWorld classWorld) {
+ if (other is! FlatTypeMask) return other.isDisjoint(this, classWorld);
+ FlatTypeMask flatOther = other;
+
+ if (isNullable && flatOther.isNullable) return false;
+ if (isEmpty || flatOther.isEmpty) return true;
+ if (base == flatOther.base) return false;
+ if (isExact && flatOther.isExact) return true;
+
+ if (isExact) return !flatOther.contains(base, classWorld);
+ if (flatOther.isExact) return !contains(flatOther.base, classWorld);
+
+ // Normalization guarantees that isExact === !isSubclass && !isSubtype.
+ // Both are subclass or subtype masks, so if there is a subclass
+ // relationship, they are not disjoint.
+ if (classWorld.isSubclassOf(flatOther.base, base)) return false;
+ if (classWorld.isSubclassOf(base, flatOther.base)) return false;
+
+ // Two different base classes have no common subclass unless one is a
+ // subclass of the other (checked above).
+ if (isSubclass && flatOther.isSubclass) return true;
+
+ return _isDisjointHelper(this, flatOther, classWorld);
+ }
+
+ static bool _isDisjointHelper(
+ FlatTypeMask a, FlatTypeMask b, ClassWorld classWorld) {
+ if (!a.isSubclass && b.isSubclass) {
+ return _isDisjointHelper(b, a, classWorld);
+ }
+ assert(a.isSubclass || a.isSubtype);
+ assert(b.isSubtype);
+ var elements = a.isSubclass
+ ? classWorld.strictSubclassesOf(a.base)
+ : classWorld.strictSubtypesOf(a.base);
+ for (var element in elements) {
+ if (classWorld.isSubtypeOf(element, b.base)) return false;
+ }
+ return true;
+ }
+
TypeMask intersectionSame(FlatTypeMask other, ClassWorld classWorld) {
assert(base == other.base);
// The two masks share the base type, so we must chose the most
@@ -685,16 +726,7 @@
if (xSubset == null) return null;
Iterable<ClassElement> ySubset = containedSubset(y, classWorld);
if (ySubset == null) return null;
- Iterable<ClassElement> smallSet, largeSet;
- if (xSubset.length <= ySubset.length) {
- smallSet = xSubset;
- largeSet = ySubset;
- } else {
- smallSet = ySubset;
- largeSet = xSubset;
- }
- var result = smallSet.where((ClassElement each) => largeSet.contains(each));
- return result.toSet();
+ return xSubset.toSet().intersection(ySubset.toSet());
}
static Iterable<ClassElement> containedSubset(FlatTypeMask x,
diff --git a/pkg/compiler/lib/src/types/forwarding_type_mask.dart b/pkg/compiler/lib/src/types/forwarding_type_mask.dart
index ce29f50..a4400c6 100644
--- a/pkg/compiler/lib/src/types/forwarding_type_mask.dart
+++ b/pkg/compiler/lib/src/types/forwarding_type_mask.dart
@@ -84,6 +84,10 @@
return forwardTo.union(other, classWorld);
}
+ bool isDisjoint(TypeMask other, ClassWorld classWorld) {
+ return forwardTo.isDisjoint(other, classWorld);
+ }
+
TypeMask intersection(TypeMask other, ClassWorld classWorld) {
return forwardTo.intersection(other, classWorld);
}
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index 3339738..736df0d 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.dart
@@ -329,6 +329,10 @@
*/
TypeMask union(TypeMask other, ClassWorld classWorld);
+
+ /// Returns whether the intersection of this and [other] is empty.
+ bool isDisjoint(TypeMask other, ClassWorld classWorld);
+
/**
* Returns a type mask representing the intersection of [this] and [other].
*/
diff --git a/pkg/compiler/lib/src/types/union_type_mask.dart b/pkg/compiler/lib/src/types/union_type_mask.dart
index 4a8397e..6166349 100644
--- a/pkg/compiler/lib/src/types/union_type_mask.dart
+++ b/pkg/compiler/lib/src/types/union_type_mask.dart
@@ -118,11 +118,11 @@
// TODO(sigmund, johnniwinther): computing length here (and below) is
// expensive. If we can't prevent `flatten` from being called a lot, it
// might be worth caching results.
- size = classWorld.strictSubclassesOf(candidate).length;
- assert(size <= classWorld.strictSubtypesOf(candidate).length);
+ size = classWorld.strictSubclassCount(candidate);
+ assert(size <= classWorld.strictSubtypeCount(candidate));
} else {
kind = FlatTypeMask.SUBTYPE;
- size = classWorld.strictSubtypesOf(candidate).length;
+ size = classWorld.strictSubtypeCount(candidate);
}
// Update the best candidate if the new one is better.
if (bestElement == null || size < bestSize) {
@@ -152,12 +152,17 @@
TypeMask intersection(var other, ClassWorld classWorld) {
other = TypeMask.nonForwardingMask(other);
if (!other.isUnion && disjointMasks.contains(other)) return other;
+ if (other.isUnion && this == other) return this;
List<TypeMask> intersections = <TypeMask>[];
for (TypeMask current in disjointMasks) {
if (other.isUnion) {
- for (FlatTypeMask flatOther in other.disjointMasks) {
- intersections.add(current.intersection(flatOther, classWorld));
+ if (other.disjointMasks.contains(current)) {
+ intersections.add(current);
+ } else {
+ for (FlatTypeMask flatOther in other.disjointMasks) {
+ intersections.add(current.intersection(flatOther, classWorld));
+ }
}
} else {
intersections.add(current.intersection(other, classWorld));
@@ -166,6 +171,13 @@
return new TypeMask.unionOf(intersections, classWorld);
}
+ bool isDisjoint(TypeMask other, ClassWorld classWorld) {
+ for (var current in disjointMasks) {
+ if (!current.isDisjoint(other, classWorld)) return false;
+ }
+ return true;
+ }
+
TypeMask nullable() {
if (isNullable) return this;
List<FlatTypeMask> newList = new List<FlatTypeMask>.from(disjointMasks);
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index d895de2..3790a03 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -6,6 +6,7 @@
import 'dart:collection' show
IterableBase;
+import '../common.dart';
import '../elements/elements.dart' show
ClassElement;
import '../util/enumset.dart' show
@@ -92,12 +93,14 @@
return mask;
}
+ final ClassHierarchyNode parentNode;
final ClassElement cls;
final EnumSet<Instantiation> _mask =
new EnumSet<Instantiation>.fromValues(
const <Instantiation>[Instantiation.UNINSTANTIATED]);
ClassElement _leastUpperInstantiatedSubclass;
+ int _instantiatedSubclassCount = 0;
/// `true` if [cls] has been directly instantiated.
///
@@ -111,14 +114,23 @@
void set isDirectlyInstantiated(bool value) {
if (value != isDirectlyInstantiated) {
+ ClassHierarchyNode parent = parentNode;
if (value) {
_mask.remove(Instantiation.UNINSTANTIATED);
_mask.add(Instantiation.DIRECTLY_INSTANTIATED);
+ while (parent != null) {
+ parent._updateInstantiatedSubclassCount(1);
+ parent = parent.parentNode;
+ }
} else {
_mask.remove(Instantiation.DIRECTLY_INSTANTIATED);
if (_mask.isEmpty) {
_mask.add(Instantiation.UNINSTANTIATED);
}
+ while (parent != null) {
+ parent._updateInstantiatedSubclassCount(-1);
+ parent = parent.parentNode;
+ }
}
}
}
@@ -131,12 +143,18 @@
/// class C extends B {}
/// main() => [new B(), new C()];
///
- bool get isIndirectlyInstantiated =>
- _mask.contains(Instantiation.INDIRECTLY_INSTANTIATED);
+ bool get isIndirectlyInstantiated => _instantiatedSubclassCount > 0;
- void set isIndirectlyInstantiated(bool value) {
- if (value != isIndirectlyInstantiated) {
- if (value) {
+ /// The number of strict subclasses that are directly or indirectly
+ /// instantiated.
+ int get instantiatedSubclassCount => _instantiatedSubclassCount;
+
+ void _updateInstantiatedSubclassCount(int change) {
+ bool before = isIndirectlyInstantiated;
+ _instantiatedSubclassCount += change;
+ bool after = isIndirectlyInstantiated;
+ if (before != after) {
+ if (after) {
_mask.remove(Instantiation.UNINSTANTIATED);
_mask.add(Instantiation.INDIRECTLY_INSTANTIATED);
} else {
@@ -151,7 +169,11 @@
/// The nodes for the direct subclasses of [cls].
Link<ClassHierarchyNode> _directSubclasses = const Link<ClassHierarchyNode>();
- ClassHierarchyNode(this.cls);
+ ClassHierarchyNode(this.parentNode, this.cls) {
+ if (parentNode != null) {
+ parentNode.addDirectSubclass(this);
+ }
+ }
/// Adds [subclass] as a direct subclass of [cls].
void addDirectSubclass(ClassHierarchyNode subclass) {
@@ -177,24 +199,6 @@
/// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
///
- /// The directly instantiated, indirectly instantiated and uninstantiated
- /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
- /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
- /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
- Iterable<ClassElement> subclasses(
- {bool includeDirectlyInstantiated: true,
- bool includeIndirectlyInstantiated: true,
- bool includeUninstantiated: true,
- bool strict: false}) {
- EnumSet<Instantiation> mask = createMask(
- includeDirectlyInstantiated: includeDirectlyInstantiated,
- includeIndirectlyInstantiated:includeIndirectlyInstantiated,
- includeUninstantiated: includeUninstantiated);
- return subclassesByMask(mask, strict: strict);
- }
-
- /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
- ///
/// Subclasses are included if their instantiation properties intersect with
/// their corresponding [Instantiation] values in [mask]. If [strict] is
/// `true`, [cls] itself is _not_ returned.
@@ -205,6 +209,65 @@
this, mask, includeRoot: !strict);
}
+ /// Applies [predicate] to each subclass of [cls] matching the criteria
+ /// specified by [mask] and [strict]. If [predicate] returns `true` on a
+ /// class, visitation is stopped immediately and the function returns `true`.
+ ///
+ /// [predicate] is applied to subclasses if their instantiation properties
+ /// intersect with their corresponding [Instantiation] values in [mask]. If
+ /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
+ bool anySubclass(
+ bool predicate(ClassElement cls),
+ EnumSet<Instantiation> mask,
+ {bool strict: false}) {
+
+ ForEach wrapper(ClassElement cls) {
+ return predicate(cls) ? ForEach.STOP : ForEach.CONTINUE;
+ }
+ return forEachSubclass(wrapper, mask, strict: strict) == ForEach.STOP;
+ }
+
+ /// Applies [f] to each subclass of [cls] matching the criteria specified by
+ /// [mask] and [strict].
+ ///
+ /// [f] is a applied to subclasses if their instantiation properties intersect
+ /// with their corresponding [Instantiation] values in [mask]. If [strict] is
+ /// `true`, [f] is _not_ called on [cls] itself.
+ ///
+ /// The visitation of subclasses can be cut short by the return value of [f].
+ /// If [ForEach.STOP] is returned, no further classes are visited and the
+ /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
+ /// subclasses of the last visited class are skipped, but visitation
+ /// continues. The return value of the function is either [ForEach.STOP], if
+ /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
+ /// the end.
+ ForEach forEachSubclass(
+ ForEachFunction f,
+ EnumSet<Instantiation> mask,
+ {bool strict: false}) {
+ ForEach forEach;
+ if (!strict && mask.intersects(_mask)) {
+ forEach = f(cls);
+ }
+ // Interpret `forEach == null` as `forEach == ForEach.CONTINUE`.
+ forEach ??= ForEach.CONTINUE;
+
+ if (forEach == ForEach.CONTINUE) {
+ if (mask.contains(Instantiation.UNINSTANTIATED) || isInstantiated) {
+ for (ClassHierarchyNode subclass in _directSubclasses) {
+ ForEach subForEach = subclass.forEachSubclass(f, mask);
+ if (subForEach == ForEach.STOP) {
+ return subForEach;
+ }
+ }
+ }
+ }
+ if (forEach == ForEach.STOP) {
+ return forEach;
+ }
+ return ForEach.CONTINUE;
+ }
+
/// Returns the most specific subclass of [cls] (including [cls]) that is
/// directly instantiated or a superclass of all directly instantiated
/// subclasses. If [cls] is not instantiated, `null` is returned.
@@ -275,7 +338,8 @@
if (instantiatedOnly && !child.isInstantiated) {
continue;
}
- if (withRespectTo != null && !child.subclasses().any(isRelatedTo)) {
+ if (withRespectTo != null &&
+ !child.anySubclass(isRelatedTo, ClassHierarchyNode.ALL)) {
continue;
}
if (needsComma) {
@@ -367,22 +431,31 @@
ClassElement get cls => node.cls;
- /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
- ///
- /// The directly instantiated, indirectly instantiated and uninstantiated
- /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
- /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
- /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
- Iterable<ClassElement> subclasses(
- {bool includeDirectlyInstantiated: true,
- bool includeIndirectlyInstantiated: true,
- bool includeUninstantiated: true,
- bool strict: false}) {
- EnumSet<Instantiation> mask = ClassHierarchyNode.createMask(
- includeDirectlyInstantiated: includeDirectlyInstantiated,
- includeIndirectlyInstantiated:includeIndirectlyInstantiated,
- includeUninstantiated: includeUninstantiated);
- return subclassesByMask(mask, strict: strict);
+ /// Returns the number of directly instantiated subtypes of [cls].
+ int get instantiatedSubtypeCount {
+ int count = node.instantiatedSubclassCount;
+ if (_directSubtypes != null) {
+ for (ClassHierarchyNode subtypeNode in _directSubtypes) {
+ if (subtypeNode.isDirectlyInstantiated) {
+ count++;
+ }
+ count += subtypeNode.instantiatedSubclassCount;
+ }
+ }
+ return count;
+ }
+
+ /// Returns `true` if all instantiated subtypes of [cls] are subclasses of
+ /// [cls].
+ bool get hasOnlyInstantiatedSubclasses {
+ if (_directSubtypes != null) {
+ for (ClassHierarchyNode subtypeNode in _directSubtypes) {
+ if (subtypeNode.isInstantiated) {
+ return false;
+ }
+ }
+ }
+ return true;
}
/// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
@@ -414,7 +487,6 @@
return subtypesByMask(mask, strict: strict);
}
-
/// Returns an [Iterable] of the subtypes of [cls] possibly including [cls].
///
/// Subtypes are included if their instantiation properties intersect with
@@ -434,6 +506,91 @@
includeRoot: !strict);
}
+ /// Applies [predicate] to each subclass of [cls] matching the criteria
+ /// specified by [mask] and [strict]. If [predicate] returns `true` on a
+ /// class, visitation is stopped immediately and the function returns `true`.
+ ///
+ /// [predicate] is applied to subclasses if their instantiation properties
+ /// intersect with their corresponding [Instantiation] values in [mask]. If
+ /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
+ bool anySubclass(
+ bool predicate(ClassElement cls),
+ EnumSet<Instantiation> mask,
+ {bool strict: false}) {
+ return node.anySubclass(predicate, mask, strict: strict);
+ }
+
+ /// Applies [f] to each subclass of [cls] matching the criteria specified by
+ /// [mask] and [strict].
+ ///
+ /// [f] is a applied to subclasses if their instantiation properties intersect
+ /// with their corresponding [Instantiation] values in [mask]. If [strict] is
+ /// `true`, [f] is _not_ called on [cls] itself.
+ ///
+ /// The visitation of subclasses can be cut short by the return value of [f].
+ /// If [ForEach.STOP] is returned, no further classes are visited and the
+ /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
+ /// subclasses of the last visited class are skipped, but visitation
+ /// continues. The return value of the function is either [ForEach.STOP], if
+ /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
+ /// the end.
+ ForEach forEachSubclass(
+ ForEachFunction f,
+ EnumSet<Instantiation> mask,
+ {bool strict: false}) {
+ return node.forEachSubclass(f, mask, strict: strict);
+ }
+
+ /// Applies [predicate] to each subtype of [cls] matching the criteria
+ /// specified by [mask] and [strict]. If [predicate] returns `true` on a
+ /// class, visitation is stopped immediately and the function returns `true`.
+ ///
+ /// [predicate] is applied to subtypes if their instantiation properties
+ /// intersect with their corresponding [Instantiation] values in [mask]. If
+ /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
+ bool anySubtype(
+ bool predicate(ClassElement cls),
+ EnumSet<Instantiation> mask,
+ {bool strict: false}) {
+
+ ForEach wrapper(ClassElement cls) {
+ return predicate(cls) ? ForEach.STOP : ForEach.CONTINUE;
+ }
+ return forEachSubtype(wrapper, mask, strict: strict) == ForEach.STOP;
+ }
+
+ /// Applies [f] to each subtype of [cls] matching the criteria specified by
+ /// [mask] and [strict].
+ ///
+ /// [f] is a applied to subtypes if their instantiation properties intersect
+ /// with their corresponding [Instantiation] values in [mask]. If [strict] is
+ /// `true`, [f] is _not_ called on [cls] itself.
+ ///
+ /// The visitation of subtypes can be cut short by the return value of [f].
+ /// If [ForEach.STOP] is returned, no further classes are visited and the
+ /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
+ /// subclasses of the last visited class are skipped, but visitation
+ /// continues. The return value of the function is either [ForEach.STOP], if
+ /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
+ /// the end.
+ ForEach forEachSubtype(
+ ForEachFunction f,
+ EnumSet<Instantiation> mask,
+ {bool strict: false}) {
+ ForEach forEach = node.forEachSubclass(f, mask, strict: strict);
+ forEach ??= ForEach.CONTINUE;
+ if (forEach == ForEach.CONTINUE && _directSubtypes != null) {
+ for (ClassHierarchyNode subclass in _directSubtypes) {
+ ForEach subForEach = subclass.forEachSubclass(f, mask);
+ if (subForEach == ForEach.STOP) {
+ return subForEach;
+ }
+ }
+ }
+ assert(forEach != ForEach.SKIP_SUBCLASSES);
+ return forEach;
+ }
+
/// Adds [subtype] as a subtype of [cls].
void addSubtype(ClassHierarchyNode subtype) {
if (node.contains(subtype.cls)) {
@@ -695,3 +852,20 @@
return false;
}
}
+
+/// Enum values returned from the [ForEachFunction] provided to the `forEachX`
+/// functions of [ClassHierarchyNode] and [ClassSet]. The value is used to
+/// control the continued iteration.
+enum ForEach {
+ /// Iteration continues.
+ CONTINUE,
+ /// Iteration stops immediately.
+ STOP,
+ /// Iteration skips the subclasses of the current class.
+ SKIP_SUBCLASSES,
+}
+
+/// Visiting function used for the `forEachX` functions of [ClassHierarchyNode]
+/// and [ClassSet]. The return value controls the continued iteration. If `null`
+/// is returned, iteration continues to the end.
+typedef ForEach ForEachFunction(ClassElement cls);
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 30b2081..da08fb6 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -93,6 +93,18 @@
/// including [cls] itself.
Iterable<ClassElement> strictSubclassesOf(ClassElement cls);
+ /// Returns the number of live classes that extend [cls] _not_
+ /// including [cls] itself.
+ int strictSubclassCount(ClassElement cls);
+
+ /// Applies [f] to each live class that extend [cls] _not_ including [cls]
+ /// itself.
+ void forEachStrictSubclassOf(ClassElement cls, ForEach f(ClassElement cls));
+
+ /// Returns `true` if [predicate] applies to any live class that extend [cls]
+ /// _not_ including [cls] itself.
+ bool anyStrictSubclassOf(ClassElement cls, bool predicate(ClassElement cls));
+
/// Returns an iterable over the directly instantiated that implement [cls]
/// possibly including [cls] itself, if it is live.
Iterable<ClassElement> subtypesOf(ClassElement cls);
@@ -101,6 +113,18 @@
/// including [cls] if it is live.
Iterable<ClassElement> strictSubtypesOf(ClassElement cls);
+ /// Returns the number of live classes that implement [cls] _not_
+ /// including [cls] itself.
+ int strictSubtypeCount(ClassElement cls);
+
+ /// Applies [f] to each live class that implements [cls] _not_ including [cls]
+ /// itself.
+ void forEachStrictSubtypeOf(ClassElement cls, ForEach f(ClassElement cls));
+
+ /// Returns `true` if [predicate] applies to any live class that implements
+ /// [cls] _not_ including [cls] itself.
+ bool anyStrictSubtypeOf(ClassElement cls, bool predicate(ClassElement cls));
+
/// Returns `true` if [a] and [b] have any known common subtypes.
bool haveAnyCommonSubtypes(ClassElement a, ClassElement b);
@@ -248,6 +272,36 @@
ClassHierarchyNode.DIRECTLY_INSTANTIATED, strict: true);
}
+ /// Returns the number of live classes that extend [cls] _not_
+ /// including [cls] itself.
+ int strictSubclassCount(ClassElement cls) {
+ ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
+ if (subclasses == null) return 0;
+ return subclasses.instantiatedSubclassCount;
+ }
+
+ /// Applies [f] to each live class that extend [cls] _not_ including [cls]
+ /// itself.
+ void forEachStrictSubclassOf(ClassElement cls, ForEach f(ClassElement cls)) {
+ ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
+ if (subclasses == null) return;
+ subclasses.forEachSubclass(
+ f,
+ ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+ strict: true);
+ }
+
+ /// Returns `true` if [predicate] applies to any live class that extend [cls]
+ /// _not_ including [cls] itself.
+ bool anyStrictSubclassOf(ClassElement cls, bool predicate(ClassElement cls)) {
+ ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
+ if (subclasses == null) return false;
+ return subclasses.anySubclass(
+ predicate,
+ ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+ strict: true);
+ }
+
/// Returns an iterable over the directly instantiated that implement [cls]
/// possibly including [cls] itself, if it is live.
Iterable<ClassElement> subtypesOf(ClassElement cls) {
@@ -272,6 +326,36 @@
}
}
+ /// Returns the number of live classes that implement [cls] _not_
+ /// including [cls] itself.
+ int strictSubtypeCount(ClassElement cls) {
+ ClassSet classSet = _classSets[cls.declaration];
+ if (classSet == null) return 0;
+ return classSet.instantiatedSubtypeCount;
+ }
+
+ /// Applies [f] to each live class that implements [cls] _not_ including [cls]
+ /// itself.
+ void forEachStrictSubtypeOf(ClassElement cls, ForEach f(ClassElement cls)) {
+ ClassSet classSet = _classSets[cls.declaration];
+ if (classSet == null) return;
+ classSet.forEachSubtype(
+ f,
+ ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+ strict: true);
+ }
+
+ /// Returns `true` if [predicate] applies to any live class that extend [cls]
+ /// _not_ including [cls] itself.
+ bool anyStrictSubtypeOf(ClassElement cls, bool predicate(ClassElement cls)) {
+ ClassSet classSet = _classSets[cls.declaration];
+ if (classSet == null) return false;
+ return classSet.anySubtype(
+ predicate,
+ ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+ strict: true);
+ }
+
/// Returns `true` if [a] and [b] have any known common subtypes.
bool haveAnyCommonSubtypes(ClassElement a, ClassElement b) {
ClassSet classSetA = _classSets[a.declaration];
@@ -298,7 +382,7 @@
/// Returns `true` if any directly instantiated class other than [cls]
/// implements [cls].
bool hasAnyStrictSubtype(ClassElement cls) {
- return !strictSubtypesOf(cls).isEmpty;
+ return strictSubtypeCount(cls) > 0;
}
/// Returns `true` if all directly instantiated classes that implement [cls]
@@ -306,10 +390,12 @@
bool hasOnlySubclasses(ClassElement cls) {
// TODO(johnniwinther): move this to ClassSet?
if (cls == objectClass) return true;
- Iterable<ClassElement> subtypes = strictSubtypesOf(cls);
- if (subtypes == null) return true;
- Iterable<ClassElement> subclasses = strictSubclassesOf(cls);
- return subclasses != null && (subclasses.length == subtypes.length);
+ ClassSet classSet = _classSets[cls.declaration];
+ if (classSet == null) {
+ // Vacuously true.
+ return true;
+ }
+ return classSet.hasOnlyInstantiatedSubclasses;
}
@override
@@ -501,11 +587,11 @@
ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) {
cls = cls.declaration;
return _classHierarchyNodes.putIfAbsent(cls, () {
- ClassHierarchyNode node = new ClassHierarchyNode(cls);
+ ClassHierarchyNode parentNode;
if (cls.superclass != null) {
- _ensureClassHierarchyNode(cls.superclass).addDirectSubclass(node);
+ parentNode = _ensureClassHierarchyNode(cls.superclass);
}
- return node;
+ return new ClassHierarchyNode(parentNode, cls);
});
}
@@ -534,31 +620,28 @@
});
}
- void _updateClassHierarchyNodeForClass(
- ClassElement cls,
- {bool directlyInstantiated: false,
- bool indirectlyInstantiated: false}) {
- ClassHierarchyNode node = getClassHierarchyNode(cls);
- bool changed = false;
- if (directlyInstantiated && !node.isDirectlyInstantiated) {
- node.isDirectlyInstantiated = true;
- changed = true;
- }
- if (indirectlyInstantiated && !node.isIndirectlyInstantiated) {
- node.isIndirectlyInstantiated = true;
- changed = true;
- }
- if (changed && cls.superclass != null) {
- _updateClassHierarchyNodeForClass(
- cls.superclass, indirectlyInstantiated: true);
- }
+ void _updateSuperClassHierarchyNodeForClass(ClassHierarchyNode node) {
// Ensure that classes implicitly implementing `Function` are in its
// subtype set.
+ ClassElement cls = node.cls;
if (cls != coreClasses.functionClass &&
- cls.implementsFunction(compiler)) {
+ cls.implementsFunction(coreClasses)) {
ClassSet subtypeSet = _ensureClassSet(coreClasses.functionClass);
subtypeSet.addSubtype(node);
}
+ if (!node.isInstantiated && node.parentNode != null) {
+ _updateSuperClassHierarchyNodeForClass(node.parentNode);
+ }
+ }
+
+ void _updateClassHierarchyNodeForClass(
+ ClassElement cls,
+ {bool directlyInstantiated: false}) {
+ ClassHierarchyNode node = getClassHierarchyNode(cls);
+ _updateSuperClassHierarchyNodeForClass(node);
+ if (directlyInstantiated) {
+ node.isDirectlyInstantiated = true;
+ }
}
void populate() {
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 3b7e3ea..922f69a 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -13,12 +13,9 @@
path: ../../sdk/lib/_internal/js_runtime
sdk_library_metadata:
path: ../../sdk/lib/_internal/sdk_library_metadata
- dart2js_info:
- path: ../../../../dart2js_info
+ dart2js_info: ^0.2.4
lookup_map:
path: ../lookup_map
- dart_messages:
- path: ../dart_messages
# Uncomment if running gclient, so you can depend directly on the downloaded
# versions of dart2js's transitive dependencies:
diff --git a/pkg/dart_messages/bin/json_converter.dart b/pkg/dart_messages/bin/json_converter.dart
deleted file mode 100644
index 8d9b8ca..0000000
--- a/pkg/dart_messages/bin/json_converter.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:convert';
-import 'dart:io';
-
-import '../lib/shared_messages.dart' as shared_messages;
-
-/// Translates the shared messages in `../lib/shared_messages` to JSON and
-/// emits it into `../lib/shared_messages.json`.
-void main() {
- var input = shared_messages.MESSAGES;
- var outPath =
- Platform.script.resolve('../lib/shared_messages.json').toFilePath();
- print("Input: ${input.length} entries");
- print("Output: $outPath");
- new File(outPath).writeAsStringSync(JSON.encode(shared_messages.MESSAGES));
- print("Done");
-}
diff --git a/pkg/dart_messages/bin/message_id.dart b/pkg/dart_messages/bin/message_id.dart
index 2d7ed53..f94b384 100644
--- a/pkg/dart_messages/bin/message_id.dart
+++ b/pkg/dart_messages/bin/message_id.dart
@@ -23,7 +23,7 @@
/// Computes a random message ID that hasn't been used before.
void main() {
var usedIds =
- shared_messages.MESSAGES.values.map((entry) => entry['id']).toSet();
+ shared_messages.MESSAGES.values.map((entry) => entry.id).toSet();
print("${usedIds.length} existing ids");
diff --git a/pkg/dart_messages/bin/publish.dart b/pkg/dart_messages/bin/publish.dart
new file mode 100644
index 0000000..c7b9c11
--- /dev/null
+++ b/pkg/dart_messages/bin/publish.dart
@@ -0,0 +1,224 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import '../lib/shared_messages.dart';
+
+const String jsonPath = '../lib/generated/shared_messages.json';
+const String dart2jsPath =
+ '../../compiler/lib/src/diagnostics/generated/shared_messages.dart';
+const String analyzerPath =
+ '../../analyzer/lib/src/generated/generated/shared_messages.dart';
+
+final String dontEditWarning = """
+/*
+DON'T EDIT. GENERATED. DON'T EDIT.
+This file has been generated by 'publish.dart' in the dart_messages package.
+
+Messages are maintained in `lib/shared_messages.dart` of that same package.
+After any change to that file, run `bin/publish.dart` to generate a new version
+of the json, dart2js and analyzer representations.
+*/""";
+
+const String copyrightHeader = '''
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.''';
+
+void markAsReadonly(String path) {
+ // TODO(15078): mark as read-only. Currently not possible:
+ // http://dartbug.com/15078.
+}
+
+void emitJson() {
+ var input = MESSAGES;
+ var outPath = Platform.script.resolve(jsonPath).toFilePath();
+ print("Emitting JSON:");
+ print(" Input: ${input.length} entries");
+ print(" Output: $outPath");
+ new File(outPath).writeAsStringSync(messagesAsJson);
+ print("Emitting JSON done.");
+}
+
+/// Escapes the given string [str].
+///
+/// The parameter [str] may be `null` in which case the result is "null".
+String escapeString(String str) {
+ return JSON.encode(str);
+}
+
+/// Emits the messages in dart2js format.
+///
+/// The dart2js-format consists of two entities:
+/// 1. the `MessageKind` enum, and
+/// 2. the MessageKind-to-Template map `TEMPLATES`.
+///
+/// The template is an instance of MessageTemplate:
+///
+/// const MessageTemplate(
+/// this.kind,
+/// this.template,
+/// {this.howToFix,
+/// this.examples,
+/// this.options: const <String>[]});
+///
+/// A sample output thus looks as follows:
+///
+/// enum MessageKind {
+/// EXAMPLE_MESSAGE,
+/// }
+///
+/// const Map<MessageKind, MessageTemplate> {
+/// EXAMPLE_MESSAGE: const MessageTemplate(
+/// EXAMPLE_MESSAGE,
+/// "Don't use #foo with #bar",
+/// howToFix: "Just don't do it",
+/// options: const ['--some-flag']),
+/// examples: const ['''
+/// some example with bad code;'''],
+/// };
+void emitDart2js() {
+ var input = MESSAGES;
+ var outPath = Platform.script.resolve(dart2jsPath).toFilePath();
+ print("Emitting dart2js:");
+ print(" Input: ${input.length} entries");
+ print(" Output: $outPath");
+
+ var enumIds = input.keys.toList();
+
+ StringBuffer out = new StringBuffer();
+ out.writeln(copyrightHeader);
+ out.writeln(dontEditWarning);
+ out.writeln("import '../messages.dart' show MessageTemplate;");
+ out.writeln();
+ out.write(("enum SharedMessageKind {\n "));
+ // We generate on one line on purpose, so that users are less likely to
+ // modify the generated file.
+ out.writeln(enumIds.join(",\n "));
+ out.writeln("}");
+ out.writeln();
+ out.writeln("const Map<SharedMessageKind, MessageTemplate> TEMPLATES = "
+ "const <SharedMessageKind, MessageTemplate>{ ");
+ input.forEach((name, message) {
+ out.writeln(" SharedMessageKind.$name: const MessageTemplate(");
+ // TODO(floitsch): include id.
+ out.writeln(" SharedMessageKind.$name,");
+ out.write(" ");
+ out.write(escapeString(message.template));
+ if (message.howToFix != null) {
+ out.write(",\n howToFix: ${escapeString(message.howToFix)}");
+ }
+ if (message.options != null) {
+ out.write(",\n options: const [");
+ out.write(message.options.map(escapeString).join(","));
+ out.writeln("]");
+ }
+ if (message.examples != null) {
+ out.writeln(",\n examples: const [");
+ for (var example in message.examples) {
+ if (example is String) {
+ out.writeln(" r'''");
+ out.write(example);
+ out.write("'''");
+ } else if (example is Map) {
+ out.writeln(" const {");
+ example.forEach((String fileName, String content) {
+ out.writeln(" '$fileName': r'''");
+ out.write(content);
+ out.writeln("''',");
+ });
+ out.write(" }");
+ }
+ out.writeln(",");
+ }
+ out.writeln(" ]");
+ }
+ out.writeln(" ), // Generated. Don't edit.");
+ });
+ out.writeln("};");
+
+ new File(outPath).writeAsStringSync(out.toString());
+ print("Emitting dart2js done.");
+}
+
+String convertToAnalyzerTemplate(String template, holeOrder) {
+ var holeMap;
+ if (holeOrder != null) {
+ holeMap = {};
+ for (int i = 0; i < holeOrder.length; i++) {
+ holeMap[holeOrder[i]] = i;
+ }
+ }
+ int seenHoles = 0;
+ return template.replaceAllMapped(new RegExp(r"#\w+"), (Match match) {
+ if (holeMap != null) {
+ String holeName = match[0].substring(1);
+ int index = holeMap[holeName];
+ if (index == null) {
+ throw "Couldn't find hole-position for $holeName $holeMap";
+ }
+ return "{$index}";
+ } else {
+ return "{${seenHoles++}}";
+ }
+ });
+}
+
+/// Emits the messages in analyzer format.
+///
+/// Messages are encoded as instances of `ErrorCode` classes where the
+/// corresponding class is given by the `category` field of the Message.
+///
+/// All instances are stored as top-level const variables.
+///
+/// A sample output looks as follows:
+///
+/// const FooCategoryErrorCode EXAMPLE_MESSAGE = const FooCategoryErrorCode(
+/// "EXAMPLE_MESSAGE",
+/// "Don't use {0} with {1}",
+/// "Just don't do it");
+void emitAnalyzer() {
+ var input = MESSAGES;
+ var outPath = Platform.script.resolve(analyzerPath).toFilePath();
+ print("Emitting analyzer:");
+ print(" Input: ${input.length} entries");
+ print(" Output: $outPath");
+
+ StringBuffer out = new StringBuffer();
+ out.writeln(copyrightHeader);
+ out.writeln(dontEditWarning);
+ out.writeln("import 'package:analyzer/src/generated/error.dart';");
+ out.writeln();
+ input.forEach((name, message) {
+ Category category = message.category;
+ String className = category.name + "Code";
+ out.writeln("const $className $name = const $className(");
+ out.writeln(" '$name',");
+
+ String template = message.template;
+ List holeOrder = message.templateHoleOrder;
+ String analyzerTemplate = convertToAnalyzerTemplate(template, holeOrder);
+ out.write(" ");
+ out.write(escapeString(analyzerTemplate));
+ out.write(",\n ");
+ out.write(escapeString(message.howToFix));
+ out.writeln("); // Generated. Don't edit.");
+ });
+
+ new File(outPath).writeAsStringSync(out.toString());
+ print("Emitting analyzer done.");
+}
+
+/// Translates the shared messages in `../lib/shared_messages.dart` to JSON,
+/// dart2js, and analyzer formats.
+///
+/// Emits the json-output to [jsonPath], the dart2js-output to [dart2jsPath],
+/// and the analyzer-output to [analyzerPath].
+void main() {
+ emitJson();
+ emitDart2js();
+ emitAnalyzer();
+}
diff --git a/pkg/dart_messages/lib/generated/shared_messages.json b/pkg/dart_messages/lib/generated/shared_messages.json
new file mode 100644
index 0000000..606bc60
--- /dev/null
+++ b/pkg/dart_messages/lib/generated/shared_messages.json
@@ -0,0 +1 @@
+{"exampleMessage":{"id":"use an Id generated by bin/message_id.dart","category":"AnalysisOptionsError","template":"#use #named #arguments","howToFix":"an explanation on how to fix things"}}
\ No newline at end of file
diff --git a/pkg/dart_messages/lib/shared_messages.dart b/pkg/dart_messages/lib/shared_messages.dart
index bd51f58..896f52a 100644
--- a/pkg/dart_messages/lib/shared_messages.dart
+++ b/pkg/dart_messages/lib/shared_messages.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// An update to this file must be followed by regenerating the corresponding
-// json file. Use `json_converter.dart` in the bin directory.
+// json, dart2js and analyzer file. Use `publish.dart` in the bin directory.
//
// Every message in this file must have an id. Use `message_id.dart` in the
// bin directory to generate a fresh one.
@@ -58,5 +58,78 @@
// 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we
// combine the first two in [template] and the last in [howToFix].
-final Map<String, Map> MESSAGES = {
+import 'dart:convert';
+
+/// Encodes the category of the message.
+///
+/// This is currently only used in the analyzer.
+// TODO(floitsch): encode severity and type in the category, so we can generate
+// the corresponding ErrorCode subclasses.
+class Category {
+ static final analysisOptionsError = new Category("AnalysisOptionsError");
+
+ static final analysisOptionsWarning = new Category("AnalysisOptionsWarning");
+
+ static final checkedModeCompileTimeError = new Category(
+ "CheckedModeCompileTimeError");
+
+ final String name;
+
+ Category(this.name);
+}
+
+
+class Message {
+ final String id;
+ final Category category;
+ final String template;
+ // The analyzer fills holes positionally (and not named). The following field
+ // overrides the order of the holes.
+ // For example the template "The argument #field in #cls is bad", could have
+ // the order `["cls", "field"]', which means that the analyzer would first
+ // provide the class `cls` and then only `field`.
+ // This list is generally `null`, but when it is provided it must contain all
+ // holes.
+ final List templateHoleOrder;
+ final String howToFix;
+ final List<String> options;
+ final List examples;
+
+ Message({this.id, this.category, this.template, this.templateHoleOrder,
+ this.howToFix, this.options, this.examples});
+}
+
+String get messagesAsJson {
+ var jsonified = {};
+ MESSAGES.forEach((String name, Message message) {
+ jsonified[name] = {
+ 'id': message.id,
+ 'category': message.category.name,
+ 'template': message.template,
+ 'howToFix': message.howToFix
+ };
+ });
+ return JSON.encode(jsonified);
+}
+
+final Map<String, Message> MESSAGES = {
+ 'exampleMessage': new Message(
+ id: 'use an Id generated by bin/message_id.dart',
+ category: Category.analysisOptionsError,
+ template: "#use #named #arguments",
+ templateHoleOrder: ["arguments", "named", "use"],
+ howToFix: "an explanation on how to fix things",
+ examples: [r'''
+ Some multiline example;
+ That generates the bug.''',
+ {
+ 'fileA.dart': '''
+ or a map from file to content.
+ again multiline''',
+ 'fileB.dart': '''
+ with possibly multiple files.
+ muliline too'''
+ }
+ ]
+ ),
};
diff --git a/pkg/dart_messages/lib/shared_messages.json b/pkg/dart_messages/lib/shared_messages.json
deleted file mode 100644
index 9e26dfe..0000000
--- a/pkg/dart_messages/lib/shared_messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/pkg/dart_messages/test/dart_messages_test.dart b/pkg/dart_messages/test/dart_messages_test.dart
index 3983773..b0ef4a5 100644
--- a/pkg/dart_messages/test/dart_messages_test.dart
+++ b/pkg/dart_messages/test/dart_messages_test.dart
@@ -2,7 +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.
-import 'dart:convert';
import 'dart:io';
import '../lib/shared_messages.dart';
@@ -12,14 +11,14 @@
if (packageRoot == null || packageRoot == "") {
throw new UnsupportedError("This test requires a package root.");
}
- var jsonUri =
- Uri.parse(packageRoot).resolve('dart_messages/shared_messages.json');
+ var jsonUri = Uri.parse(packageRoot).resolve(
+ 'dart_messages/generated/shared_messages.json');
var jsonPath = jsonUri.toFilePath();
var content = new File(jsonPath).readAsStringSync();
- if (JSON.encode(MESSAGES) != content) {
+ if (messagesAsJson != content) {
print("The content of the Dart messages and the corresponding JSON file");
print("is not the same.");
- print("Please run bin/json_converter to update the JSON file.");
+ print("Please run bin/publish.dart to update the JSON file.");
throw "Content is not the same";
}
}
@@ -27,7 +26,7 @@
void testIdsAreUnique() {
var usedIds = new Set();
for (var entry in MESSAGES.values) {
- var id = entry['id'];
+ var id = entry.id;
if (!usedIds.add(id)) {
throw "Id appears twice: $id";
}
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index b6d11aa..07a20f1 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -195,7 +195,9 @@
/// This tag interface has no behaviour but must be implemented by any class
/// that is to be stored on a [Node] as source information.
-abstract class JavaScriptNodeSourceInformation {}
+abstract class JavaScriptNodeSourceInformation {
+ const JavaScriptNodeSourceInformation();
+}
abstract class Node {
JavaScriptNodeSourceInformation get sourceInformation => _sourceInformation;
@@ -1075,7 +1077,7 @@
LiteralNumber(this.value);
int get precedenceLevel => value.startsWith('-') ? UNARY : PRIMARY;
-
+
accept(NodeVisitor visitor) => visitor.visitLiteralNumber(this);
LiteralNumber _clone() => new LiteralNumber(value);
}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 8f29f55..4f93259 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -26,6 +26,7 @@
analysis_server/test/analysis/get_errors_test: Skip # runtime error, Issue 22180
analysis_server/test/integration/analysis/analysis_options_test: RuntimeError # Issue 24796
analyzer/test/generated/all_the_rest_test: Fail # Issue 21772
+analyzer_cli/test/driver_test: Fail # Issue 25471
[ $compiler == dart2js ]
analyzer_cli/test/*: SkipByDesign # Only meant to run on vm
@@ -44,11 +45,15 @@
analysis_server/test/services/index/store/codec_test: Pass, Slow
analysis_server/test/socket_server_test: Pass, Slow # Issue 19756, 21628
analyzer/test/dart/element/element_test: Pass, Slow # Issue 24914
+analyzer/test/dart/ast/ast_test: Pass, Slow # Issue 19756, 21628
+analyzer/test/dart/ast/utilities_test: Pass, Slow # Issue 19756, 21628
+analyzer/test/dart/ast/visitor_test: Pass, Slow # Issue 19756, 21628
analyzer/test/enum_test: Slow, Pass, Fail # Issue 21323
analyzer/test/generated/all_the_rest_test: Pass, Slow # Issue 21628
analyzer/test/generated/ast_test: Pass, Slow # Issue 21628
analyzer/test/generated/compile_time_error_code_test: Pass, Slow
analyzer/test/generated/compile_time_error_code_test: Pass, Slow # Issue 21628
+analyzer/test/generated/constant_test.dart: Pass, Slow # Issue 24914
analyzer/test/generated/declaration_resolver_test: Pass, Slow # Issue 24914
analyzer/test/generated/element_test: Pass, Slow # Issue 21628
analyzer/test/generated/engine_test: SkipSlow
@@ -66,9 +71,13 @@
analyzer/test/src/context/cache_test: Pass, Slow # Issue 21628
analyzer/test/src/context/context_test: Pass, Timeout # dartbug.com/23658
analyzer/test/src/dart/element/element_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/prelinker_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/resynthesize_strong_test: Pass, Slow
analyzer/test/src/summary/resynthesize_test: Pass, Slow
analyzer/test/src/summary/summary_sdk_test: Pass, Slow # Issue 24914
-analyzer/test/src/summary/summary_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/summarize_ast_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/summarize_elements_strong_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/summarize_elements_test: Pass, Slow # Issue 24914
analyzer/test/src/task/dart_test: Pass, Slow # Issue 21628
analyzer/test/src/task/dart_work_manager_test: Pass, Slow # Issue 21628
analyzer/test/src/task/driver_test: Pass, Slow # Issue 21628
@@ -152,12 +161,13 @@
observe/test/unique_message_test: SkipByDesign # Uses dart:io.
dart_messages/test/dart_messages_test: Skip # Uses dart:io.
-[ $runtime == vm && ($arch == simarm64 || $arch == simarm || $arch == simarmv5te || $arch == simmips || $arch == armv5te) ]
+[ $runtime == vm && ($arch == simarm64 || $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simmips || $arch == armv6 || $arch == armv5te) ]
# Timeout. These are not unit tests. They do not run efficiently on our
# simulator or low-end devices.
*: Skip
[ $runtime == vm ]
+analyzer/test/file_system/physical_resource_provider_test: Pass, Fail # Issue 25472
# Skip tests on the VM if the package depends on dart:html
mutation_observer: Skip
diff --git a/pkg/typed_mock/README.md b/pkg/typed_mock/README.md
index 2414318..2b24907 100644
--- a/pkg/typed_mock/README.md
+++ b/pkg/typed_mock/README.md
@@ -2,6 +2,213 @@
It is inspired by [Mockito](https://code.google.com/p/mockito/).
-The existing "mock" package suffers from using method names as strings,
-which makes it impossible to use code-completion, static validation,
-search and refactoring.
+Features of this package:
+- Code-completion, static validation, search and refactoring all work properly with mocks.
+- Much better error messages for unit testing.
+- Works with concrete and abstract classes.
+- Does not use mirrors.
+- No dependent packages.
+
+Other Mock libraries for Dart:
+- https://pub.dartlang.org/packages/mockito
+- https://pub.dartlang.org/packages/mock (deprecated)
+
+## Tutorial
+
+Let's take the simple case of making sure that a method is called. The first step is to create a mock of the object, as shown below. One nice feature of Dart is that all classes automatically define interfaces, so you don't need to separately define the interface.
+
+```dart
+import 'package:typed_mock/typed_mock.dart';
+
+class Dog {
+ String speak() => "Woof!";
+}
+
+class MockDog extends TypedMock implements Dog {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+```
+
+All of the magic happens because of the noSuchMethod() function. None of the functions for Animal are actually defined because we used `implements` instead of `extends`. Therefore, all calls to this object will end up in `noSuchMethod()`.
+
+#### Verify a function is called
+
+Here's the code to verify that the function is called:
+
+```dart
+
+void main() {
+ final dog = new MockDog();
+ verifyZeroInteractions(dog);
+ dog.speak();
+ verify(dog.speak()).once();
+ verifyNoMoreInteractions(dog);
+}
+```
+
+One of the interesting features of typed_mock is that it internally tracks all calls to each mock object, then tracks which calls have been matched with a verify() call and which not. Therefore, typed_mock is able to detect unexpected calls, even if those calls are made to methods that didn't exist when the test was written. This can be a good incentive to update your tests whenever you change a class.
+
+After creating the `MockAnimal` object, we call `verifyZeroInteractions()` to make sure that the object starts in a clean state. Next we call the `speak()` method, then prove that the speak function was actually called with `verify().once()`.
+
+There are several other functions for verifying calls that can be used instead of `once()`:
+- `atLeastOnce()` Ensure the function was called one or more times.
+- `times(n)` Ensure the function was called exactly `n` times.
+- `atLeast(n)` Ensure the function was called `n` or more times.
+- `atMost(n)` Ensure the function was called no more than `n` times.
+- `any()` Mark the function call as verified if it was called, but don't fail if it wasn't called.
+- `never()` Ensure the function was never called. It's often better to use `verifyNoMoreInteractions()` instead.
+
+#### Configure the mock to return a value
+
+Here's how to return a value from `speak()`:
+
+```dart
+void main() {
+ final dog = new MockDog();
+ when(dog.speak()).thenReturn("woof");
+ final s = dog.speak();
+ print("$s");
+ verify(dog.speak()).once();
+ verifyNoMoreInteractions(dog);
+}
+```
+
+What if `speak()` took the name of an animal as a parameter? When typed_mock tracks a function call, the call tracking is based on the function name and the parameters. For example:
+
+
+```dart
+import 'package:typed_mock/typed_mock.dart';
+
+abstract class Animal {
+ String speak();
+}
+
+class MockAnimal extends TypedMock implements Animal {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+void main() {
+ final animal = new MockAnimal();
+ when(animal.speak("dog")).thenReturn("woof");
+ final s = animal.speak();
+ print("$s");
+ verify(animal.speak("dog")).once();
+}
+```
+
+Note that you can reset the call and verify tracking using `resetInteractions()`. However, there is no way to reset the `when()` calls. Create a new mock instead.
+
+You can define different results based on the value of the parameter. Notice that the calls to `verify()` explicitly states the parameter value:
+
+```dart
+void main() {
+ final animal = new MockAnimal();
+ when(animal.speak("cat")).thenReturn("meow");
+ when(animal.speak("dog")).thenReturn("woof");
+ final s = animal.speak("cat"); // Prints: meow
+ verify(animal.speak("cat")).once();
+ verify(animal.speak("dog")).never();
+}
+```
+
+#### Match any value for a parameter
+
+Sometimes you don't care about the exact value of the parameter. That's when `anyString` is used, along with its siblings `anyInt`, `anyBool` and `anyObject`.
+
+The value `anyString` is a matcher that matches any String value. For example, here's how to use `anyString` in a call to `when()`:
+
+```dart
+void main() {
+ final animal = new MockAnimal();
+ when(animal.speak(anyString)).thenReturn("meow");
+ final s1 = animal.speak("cat");
+ final s2 = animal.speak("dog");
+ print("$s1 $s2"); // Prints: meow meow
+ verify(animal.speak(anyString)).times(2);
+}
+```
+
+You can also use `anyString` in `verify()` calls, even if the `when()` calls use exact values. For example:
+
+```dart
+void main() {
+ final animal = new MockAnimal();
+ when(animal.speak("cat")).thenReturn("meow");
+ when(animal.speak("dog")).thenReturn("woof");
+ var s
+ s = animal.speak("cat");
+ s = animal.speak("cat");
+ s = animal.speak("dog");
+ verify(animal.speak(anyString)).times(3);
+}
+```
+
+You can use `anyString` as the parameter for calculated values:
+```dart
+ when(animal.speak(anyString)).thenInvoke((String s) => 'The $s speaks!');
+```
+
+In addition to `thenReturn()` and `thenInvoke()`, typed_mock supports `thenReturnList()` and `thenThrow()`. See the link at the end of this document for examples.
+
+#### Mocking operator[] and operator[]=
+
+The typed_mock package is able to track set and get access with operators `[]=` and `[]`, respectively. There's nothing special about these operators - they are just functions with non-alphanumeric names that takes two or one parameters. As with other functions, typed_mock tracks both the index and the value as needed. Note the syntax to verify that a particular array element was assigned a particular value. The act of assigning true is tracked separately from the act of assigning false. The syntax is straightforward.
+
+```dart
+import 'package:typed_mock/typed_mock.dart';
+
+abstract class Tracker {
+ operator [](int index);
+ operator []=(int index, bool b);
+}
+
+class MockTracker extends TypedMock implements Tracker {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+void main() {
+ final tracker = new MockTracker();
+ tracker[2] = true;
+ when(tracker[3]).thenReturn(false);
+ when(tracker[4]).thenReturn(true);
+ bool x = tracker[3];
+ bool y = tracker[4];
+ print("$x $y");
+ verify(tracker[1] = true).never();
+ verify(tracker[2] = false).never();
+ verify(tracker[2] = true).once();
+ verify(tracker[3]).once();
+ verify(tracker[4]).once();
+ verify(tracker[5]).never();
+}
+```
+
+#### Passing mocks as closures
+
+Passing a mock as a function parameter may not behave as you expect because a hidden function is called in the mock to get the closure. The solution is to wrap the call in a separate closure. For example, the call to `verifyNoMoreInteractions()` fails because the reference to `dog.speak` caused a hidden function to be called in `MockDog`.
+
+```dart
+void doSomething(String myfunc()) {}
+
+void main() {
+ final dog = new MockDog();
+ doSomething(dog.speak);
+ verifyNoMoreInteractions(dog);
+}
+```
+
+The solution is as follows:
+
+```dart
+void doSomething(String myfunc()) {}
+
+void main() {
+ final dog = new MockDog();
+ doSomething(() => dog.speak());
+ verifyNoMoreInteractions(dog);
+}
+```
+
+## More Information
+
+For additional examples, see the [unit tests](https://github.com/dart-lang/sdk/blob/master/pkg/typed_mock/test/typed_mock_test.dart).
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 78c5a58..11f84fc 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -629,10 +629,10 @@
},
{
# dart binary for running precompiled snapshots without the compiler.
- 'target_name': 'dart_precompiled',
+ 'target_name': 'dart_precompiled_runtime',
'type': 'executable',
'dependencies': [
- 'libdart_precompiled',
+ 'libdart_precompiled_runtime',
'libdart_builtin',
'libdart_io',
'build_observatory#host',
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 29d2884..e8b8d73 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -21,9 +21,9 @@
// when the isolate shuts down.
class IsolateData {
public:
- explicit IsolateData(const char* url,
- const char* package_root,
- const char* packages_file)
+ IsolateData(const char* url,
+ const char* package_root,
+ const char* packages_file)
: script_url(strdup(url)),
package_root(NULL),
packages_file(NULL),
@@ -36,14 +36,17 @@
this->packages_file = strdup(packages_file);
}
}
-#if 0
+
~IsolateData() {
free(script_url);
+ script_url = NULL;
free(package_root);
+ package_root = NULL;
free(packages_file);
+ packages_file = NULL;
free(udp_receive_buffer);
+ udp_receive_buffer = NULL;
}
-#endif
char* script_url;
char* package_root;
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index 707686f..f542dde 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -17,6 +17,7 @@
'libdart_deps': ['libdart_lib_nosnapshot', 'libdart_lib',
'libdart_vm_nosnapshot', 'libdart_vm',
+ 'libdart_vm_precompiled_runtime',
'libdouble_conversion',],
},
'targets': [
@@ -55,11 +56,11 @@
},
},
{
- 'target_name': 'libdart_precompiled',
+ 'target_name': 'libdart_precompiled_runtime',
'type': 'static_library',
'dependencies': [
'libdart_lib',
- 'libdart_vm_precompiled',
+ 'libdart_vm_precompiled_runtime',
'libdouble_conversion',
'generate_version_cc_file#host',
],
@@ -81,7 +82,7 @@
'defines': [
# The only effect of DART_SHARED_LIB is to export the Dart API entries.
'DART_SHARED_LIB',
- 'DART_PRECOMPILED',
+ 'DART_PRECOMPILED_RUNTIME',
],
'direct_dependent_settings': {
'include_dirs': [
diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc
index c7a2164..aa985da 100644
--- a/runtime/lib/errors.cc
+++ b/runtime/lib/errors.cc
@@ -67,8 +67,8 @@
String::CheckedHandle(arguments->NativeArgAt(2));
const String& dst_name = String::CheckedHandle(arguments->NativeArgAt(3));
const String& error_msg = String::CheckedHandle(arguments->NativeArgAt(4));
- const String& src_type_name =
- String::Handle(Type::Handle(src_value.GetType()).UserVisibleName());
+ const String& src_type_name = String::Handle(
+ AbstractType::Handle(src_value.GetType()).UserVisibleName());
Exceptions::CreateAndThrowTypeError(location, src_type_name,
dst_type_name, dst_name, error_msg);
UNREACHABLE();
diff --git a/runtime/lib/expando_patch.dart b/runtime/lib/expando_patch.dart
index 0c9427c..df0234d 100644
--- a/runtime/lib/expando_patch.dart
+++ b/runtime/lib/expando_patch.dart
@@ -131,7 +131,8 @@
(object is bool) ||
(object is num) ||
(object is String)) {
- throw new ArgumentError(object);
+ throw new ArgumentError.value(object,
+ "Expandos are not allowed on strings, numbers, booleans or null");
}
}
diff --git a/runtime/lib/function.cc b/runtime/lib/function.cc
index 607e29e..b7424f5 100644
--- a/runtime/lib/function.cc
+++ b/runtime/lib/function.cc
@@ -28,21 +28,21 @@
}
-DEFINE_NATIVE_ENTRY(FunctionImpl_equals, 2) {
- const Instance& receiver = Instance::CheckedHandle(
+DEFINE_NATIVE_ENTRY(Closure_equals, 2) {
+ const Closure& receiver = Closure::CheckedHandle(
zone, arguments->NativeArgAt(0));
- ASSERT(receiver.IsClosure());
GET_NATIVE_ARGUMENT(Instance, other, arguments->NativeArgAt(1));
ASSERT(!other.IsNull());
if (receiver.raw() == other.raw()) return Bool::True().raw();
if (other.IsClosure()) {
- const Function& func_a = Function::Handle(Closure::function(receiver));
- const Function& func_b = Function::Handle(Closure::function(other));
+ const Function& func_a = Function::Handle(receiver.function());
+ const Function& func_b = Function::Handle(Closure::Cast(other).function());
if (func_a.raw() == func_b.raw()) {
ASSERT(!func_a.IsImplicitStaticClosureFunction());
if (func_a.IsImplicitInstanceClosureFunction()) {
- const Context& context_a = Context::Handle(Closure::context(receiver));
- const Context& context_b = Context::Handle(Closure::context(other));
+ const Context& context_a = Context::Handle(receiver.context());
+ const Context& context_b = Context::Handle(
+ Closure::Cast(other).context());
const Object& receiver_a = Object::Handle(context_a.At(0));
const Object& receiver_b = Object::Handle(context_b.At(0));
if (receiver_a.raw() == receiver_b.raw()) return Bool::True().raw();
@@ -53,48 +53,38 @@
}
-DEFINE_NATIVE_ENTRY(FunctionImpl_hashCode, 1) {
- const Instance& receiver = Instance::CheckedHandle(
+DEFINE_NATIVE_ENTRY(Closure_hashCode, 1) {
+ const Closure& receiver = Closure::CheckedHandle(
zone, arguments->NativeArgAt(0));
- if (receiver.IsClosure()) {
- const Function& func = Function::Handle(Closure::function(receiver));
- // Hash together name, class name and signature.
- const Class& cls = Class::Handle(func.Owner());
- intptr_t result = String::Handle(func.name()).Hash();
- result += String::Handle(func.Signature()).Hash();
- result += String::Handle(cls.Name()).Hash();
- // Finalize hash value like for strings so that it fits into a smi.
- result += result << 3;
- result ^= result >> 11;
- result += result << 15;
- result &= ((static_cast<intptr_t>(1) << String::kHashBits) - 1);
- return Smi::New(result);
- }
- UNREACHABLE();
- return Object::null();
+ const Function& func = Function::Handle(receiver.function());
+ // Hash together name, class name and signature.
+ const Class& cls = Class::Handle(func.Owner());
+ intptr_t result = String::Handle(func.name()).Hash();
+ result += String::Handle(func.Signature()).Hash();
+ result += String::Handle(cls.Name()).Hash();
+ // Finalize hash value like for strings so that it fits into a smi.
+ result += result << 3;
+ result ^= result >> 11;
+ result += result << 15;
+ result &= ((static_cast<intptr_t>(1) << String::kHashBits) - 1);
+ return Smi::New(result);
}
-DEFINE_NATIVE_ENTRY(FunctionImpl_clone, 1) {
- const Instance& receiver = Instance::CheckedHandle(
+DEFINE_NATIVE_ENTRY(Closure_clone, 1) {
+ const Closure& receiver = Closure::CheckedHandle(
zone, arguments->NativeArgAt(0));
- ASSERT(receiver.IsClosure());
- if (receiver.IsClosure()) {
- const Function& func =
- Function::Handle(zone, Closure::function(receiver));
- const Context& ctx =
- Context::Handle(zone, Closure::context(receiver));
- Context& cloned_ctx =
- Context::Handle(zone, Context::New(ctx.num_variables()));
- cloned_ctx.set_parent(Context::Handle(zone, ctx.parent()));
- Object& inst = Object::Handle(zone);
- for (int i = 0; i < ctx.num_variables(); i++) {
- inst = ctx.At(i);
- cloned_ctx.SetAt(i, inst);
- }
- return Closure::New(func, cloned_ctx);
+ const Function& func = Function::Handle(zone, receiver.function());
+ const Context& ctx = Context::Handle(zone, receiver.context());
+ Context& cloned_ctx =
+ Context::Handle(zone, Context::New(ctx.num_variables()));
+ cloned_ctx.set_parent(Context::Handle(zone, ctx.parent()));
+ Object& inst = Object::Handle(zone);
+ for (int i = 0; i < ctx.num_variables(); i++) {
+ inst = ctx.At(i);
+ cloned_ctx.SetAt(i, inst);
}
- return Object::null();
+ return Closure::New(func, cloned_ctx);
}
diff --git a/runtime/lib/function.dart b/runtime/lib/function.dart
index d91ce66..6c1d5cc 100644
--- a/runtime/lib/function.dart
+++ b/runtime/lib/function.dart
@@ -2,13 +2,15 @@
// 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 _FunctionImpl implements Function {
+class _Closure implements Function {
- bool operator ==(other) native "FunctionImpl_equals";
+ bool operator ==(other) native "Closure_equals";
- int get hashCode native "FunctionImpl_hashCode";
+ int get hashCode native "Closure_hashCode";
- _FunctionImpl get call => this;
+ _Closure get call => this;
- _FunctionImpl _clone() native "FunctionImpl_clone";
+ _Closure _clone() native "Closure_clone";
+
+ // The type_arguments_, function_, and context_ fields are not declared here.
}
diff --git a/runtime/lib/immutable_map.dart b/runtime/lib/immutable_map.dart
index 2377c8c..b8d0d3c 100644
--- a/runtime/lib/immutable_map.dart
+++ b/runtime/lib/immutable_map.dart
@@ -11,8 +11,9 @@
V operator [](Object key) {
- // TODO(hausner): Since the keys are sorted, we could do a binary
- // search. But is it worth it?
+ // To preserve the key-value order of the map literal, the keys are
+ // not sorted. Need to do linear search or implement an additional
+ // lookup table.
for (int i = 0; i < _kvPairs.length - 1; i += 2) {
if (key == _kvPairs[i]) {
return _kvPairs[i+1];
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 773bac4..4e1fce8 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -226,11 +226,11 @@
if (closure.IsClosure()) {
Function& func = Function::Handle();
- func = Closure::function(closure);
+ func = Closure::Cast(closure).function();
if (func.IsImplicitClosureFunction() && func.is_static()) {
#if defined(DEBUG)
Context& ctx = Context::Handle();
- ctx = Closure::context(closure);
+ ctx = Closure::Cast(closure).context();
ASSERT(ctx.num_variables() == 0);
#endif
// Get the parent function so that we get the right function name.
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 05453f8..564db22 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -139,12 +139,18 @@
// This covers the default constructor and forwarding constructors.
has_extra_parameter_info = false;
}
+ if (func.IsSignatureFunction() &&
+ (func.token_pos() == Token::kNoSourcePos)) {
+ // Signature functions (except those describing typedefs) get canonicalized,
+ // hence do not have a token position, and therefore cannot be reparsed.
+ has_extra_parameter_info = false;
+ }
Array& param_descriptor = Array::Handle();
if (has_extra_parameter_info) {
// Reparse the function for the following information:
// * The default value of a parameter.
- // * Whether a parameters has been deflared as final.
+ // * Whether a parameters has been declared as final.
// * Any metadata associated with the parameter.
const Object& result =
Object::Handle(Parser::ParseFunctionParameters(func));
@@ -237,18 +243,21 @@
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
args.SetAt(1, type);
args.SetAt(2, String::Handle(cls.Name()));
- args.SetAt(3, Bool::Get(cls.NumTypeParameters() != 0));
- args.SetAt(4, cls.NumTypeParameters() == 0 ? Bool::False() : is_declaration);
+ args.SetAt(3, Bool::Get(cls.IsGeneric()));
+ args.SetAt(4, cls.IsGeneric() ? is_declaration : Bool::False());
args.SetAt(5, owner_mirror);
return CreateMirror(Symbols::_LocalTypedefMirror(), args);
}
-static RawInstance* CreateFunctionTypeMirror(const Class& cls,
- const AbstractType& type) {
- const Array& args = Array::Handle(Array::New(2));
+static RawInstance* CreateFunctionTypeMirror(const AbstractType& type) {
+ ASSERT(type.IsFunctionType());
+ const Class& cls = Class::Handle(FunctionType::Cast(type).scope_class());
+ const Function& func = Function::Handle(FunctionType::Cast(type).signature());
+ const Array& args = Array::Handle(Array::New(3));
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
- args.SetAt(1, type);
+ args.SetAt(1, MirrorReference::Handle(MirrorReference::New(func)));
+ args.SetAt(2, type);
return CreateMirror(Symbols::_LocalFunctionTypeMirror(), args);
}
@@ -304,22 +313,6 @@
return CreateMirror(Symbols::_LocalVariableMirror(), args);
}
-static RawFunction* CallMethod(const Class& cls) {
- if (cls.IsSignatureClass()) {
- return cls.signature_function();
- }
-
- Class& lookup_cls = Class::Handle(cls.raw());
- Function& call_function = Function::Handle();
- do {
- call_function = lookup_cls.LookupDynamicFunction(Symbols::Call());
- if (!call_function.IsNull()) {
- return call_function.raw();
- }
- lookup_cls = lookup_cls.SuperClass();
- } while (!lookup_cls.IsNull());
- return Function::null();
-}
static RawInstance* CreateClassMirror(const Class& cls,
const AbstractType& type,
@@ -335,14 +328,8 @@
ASSERT(!type.IsNull());
ASSERT(type.IsFinalized());
- if (cls.IsSignatureClass()) {
- if (cls.IsCanonicalSignatureClass()) {
- // We represent function types as canonical signature classes.
- return CreateFunctionTypeMirror(cls, type);
- } else {
- // We represent typedefs as non-canonical signature classes.
- return CreateTypedefMirror(cls, type, is_declaration, owner_mirror);
- }
+ if (cls.IsTypedefClass()) {
+ return CreateTypedefMirror(cls, type, is_declaration, owner_mirror);
}
const Error& error = Error::Handle(cls.EnsureIsFinalized(Thread::Current()));
@@ -554,6 +541,16 @@
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsCanonical() || type.IsTypeParameter() || type.IsBoundedType());
+ if (type.IsFunctionType()) {
+ const Class& scope_class =
+ Class::Handle(FunctionType::Cast(type).scope_class());
+ if (scope_class.IsTypedefClass()) {
+ return CreateTypedefMirror(scope_class,
+ type, Bool::False(), Object::null_instance());
+ } else {
+ return CreateFunctionTypeMirror(type);
+ }
+ }
if (type.HasResolvedTypeClass()) {
const Class& cls = Class::Handle(type.type_class());
// Handle void and dynamic types.
@@ -785,8 +782,8 @@
const TypeArguments& type_args =
TypeArguments::Handle(instantiator.arguments());
Error& bound_error = Error::Handle();
- AbstractType& result =
- AbstractType::Handle(type.InstantiateFrom(type_args, &bound_error));
+ AbstractType& result = AbstractType::Handle(
+ type.InstantiateFrom(type_args, &bound_error, NULL, Heap::kOld));
if (!bound_error.IsNull()) {
Exceptions::PropagateError(bound_error);
UNREACHABLE();
@@ -828,12 +825,10 @@
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsFinalized());
- ASSERT(type.HasResolvedTypeClass());
+ ASSERT(type.IsFunctionType() || type.HasResolvedTypeClass());
const Class& cls = Class::Handle(type.type_class());
ASSERT(!cls.IsNull());
- if (cls.IsDynamicClass() ||
- cls.IsVoidClass() ||
- (cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass())) {
+ if (cls.IsDynamicClass() || cls.IsVoidClass() || cls.IsTypedefClass()) {
Exceptions::ThrowArgumentError(type);
UNREACHABLE();
}
@@ -911,8 +906,9 @@
owner_mirror,
arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
- const Class& cls = Class::Handle(ref.GetClassReferent());
- const Function& func = Function::Handle(CallMethod(cls));
+ // TODO(rmacnak): Return get:call() method on class _Closure instead?
+ // This now returns the result of invoking that call getter.
+ const Function& func = Function::Handle(ref.GetFunctionReferent());
ASSERT(!func.IsNull());
return CreateMethodMirror(func, owner_mirror, AbstractType::Handle());
}
@@ -921,8 +917,7 @@
DEFINE_NATIVE_ENTRY(FunctionTypeMirror_parameters, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
- const Class& cls = Class::Handle(ref.GetClassReferent());
- const Function& func = Function::Handle(cls.signature_function());
+ const Function& func = Function::Handle(ref.GetFunctionReferent());
return CreateParameterMirrorList(func, owner);
}
@@ -932,8 +927,7 @@
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType,
instantiator,
arguments->NativeArgAt(1));
- const Class& cls = Class::Handle(ref.GetClassReferent());
- const Function& func = Function::Handle(CallMethod(cls));
+ const Function& func = Function::Handle(ref.GetFunctionReferent());
ASSERT(!func.IsNull());
AbstractType& type = AbstractType::Handle(func.result_type());
return InstantiateType(type, instantiator);
@@ -953,10 +947,6 @@
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsFinalized());
- if (!type.HasResolvedTypeClass()) {
- Exceptions::ThrowArgumentError(type);
- UNREACHABLE();
- }
const Class& cls = Class::Handle(type.type_class());
const AbstractType& super_type = AbstractType::Handle(cls.super_type());
ASSERT(super_type.IsNull() || super_type.IsFinalized());
@@ -968,10 +958,6 @@
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsFinalized());
- if (!type.HasResolvedTypeClass()) {
- Exceptions::ThrowArgumentError(type);
- UNREACHABLE();
- }
const Class& cls = Class::Handle(type.type_class());
const AbstractType& super_type = AbstractType::Handle(cls.super_type());
return InstantiateType(super_type, type);
@@ -982,10 +968,6 @@
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsFinalized());
- if (!type.HasResolvedTypeClass()) {
- Exceptions::ThrowArgumentError(type);
- UNREACHABLE();
- }
const Class& cls = Class::Handle(type.type_class());
const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
@@ -999,10 +981,6 @@
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsFinalized());
- if (!type.HasResolvedTypeClass()) {
- Exceptions::ThrowArgumentError(type);
- UNREACHABLE();
- }
const Class& cls = Class::Handle(type.type_class());
const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
@@ -1027,10 +1005,6 @@
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsFinalized());
- if (!type.HasResolvedTypeClass()) {
- Exceptions::ThrowArgumentError(type);
- UNREACHABLE();
- }
const Class& cls = Class::Handle(type.type_class());
const AbstractType& mixin_type = AbstractType::Handle(cls.mixin());
ASSERT(mixin_type.IsNull() || mixin_type.IsFinalized());
@@ -1045,10 +1019,6 @@
arguments->NativeArgAt(1));
PROPAGATE_IF_MALFORMED(type);
ASSERT(type.IsFinalized());
- if (!type.HasResolvedTypeClass()) {
- Exceptions::ThrowArgumentError(type);
- UNREACHABLE();
- }
const Class& cls = Class::Handle(type.type_class());
const AbstractType& mixin_type = AbstractType::Handle(cls.mixin());
if (mixin_type.IsNull()) {
@@ -1166,13 +1136,11 @@
entry = entries.GetNext();
if (entry.IsClass()) {
const Class& klass = Class::Cast(entry);
- // We filter out function signature classes and dynamic.
+ // We filter out mixin application classes and dynamic.
// TODO(12478): Should not need to filter out dynamic.
// Note that the VM does not consider mixin application aliases to be
// mixin applications.
- if (!klass.IsCanonicalSignatureClass() &&
- !klass.IsDynamicClass() &&
- !klass.IsMixinApplication()) {
+ if (!klass.IsDynamicClass() && !klass.IsMixinApplication()) {
type = klass.DeclarationType();
member_mirror = CreateClassMirror(klass,
type,
@@ -1307,9 +1275,8 @@
// setters, assume the result is a closure and mark its function as invisible,
// so it will not appear in stack traces. Whenever we support
// ObjectMirror.evaluate this will need to be separated.
- ASSERT(Instance::Cast(result).IsClosure());
- const Function& func =
- Function::Handle(Closure::function(Instance::Cast(result)));
+ ASSERT(result.IsClosure());
+ const Function& func = Function::Handle(Closure::Cast(result).function());
func.set_is_visible(false);
func.set_is_debuggable(false);
@@ -1317,10 +1284,9 @@
}
DEFINE_NATIVE_ENTRY(TypedefMirror_declaration, 1) {
- GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
- const Class& cls = Class::Handle(type.type_class());
- // We represent typedefs as non-canonical signature classes.
- ASSERT(cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass());
+ GET_NON_NULL_NATIVE_ARGUMENT(FunctionType, type, arguments->NativeArgAt(0));
+ const Class& cls = Class::Handle(type.scope_class());
+ ASSERT(cls.IsTypedefClass());
return CreateTypedefMirror(cls,
AbstractType::Handle(cls.DeclarationType()),
Bool::True(), // is_declaration
@@ -1454,7 +1420,7 @@
DEFINE_NATIVE_ENTRY(InstanceMirror_computeType, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
- const Type& type = Type::Handle(instance.GetType());
+ const AbstractType& type = AbstractType::Handle(instance.GetType());
// The static type of null is specified to be the bottom type, however, the
// runtime type of null is the Null type, which we correctly return here.
return type.Canonicalize();
@@ -1479,10 +1445,10 @@
Type& instantiator = Type::Handle();
if (closure.IsClosure()) {
const TypeArguments& arguments =
- TypeArguments::Handle(Closure::GetTypeArguments(closure));
+ TypeArguments::Handle(closure.GetTypeArguments());
const Class& cls =
Class::Handle(Isolate::Current()->object_store()->object_class());
- instantiator = Type::New(cls, arguments, Scanner::kNoSourcePos);
+ instantiator = Type::New(cls, arguments, Token::kNoSourcePos);
instantiator.SetIsFinalized();
}
return CreateMethodMirror(function,
@@ -1708,8 +1674,8 @@
// The type arguments of the redirection type are instantiated from the
// type arguments of the type reflected by the class mirror.
Error& bound_error = Error::Handle();
- redirect_type ^= redirect_type.InstantiateFrom(type_arguments,
- &bound_error);
+ redirect_type ^= redirect_type.InstantiateFrom(
+ type_arguments, &bound_error, NULL, Heap::kOld);
if (!bound_error.IsNull()) {
Exceptions::PropagateError(bound_error);
UNREACHABLE();
@@ -2003,7 +1969,7 @@
}
Script& script = Script::Handle();
- intptr_t token_pos = Scanner::kNoSourcePos;
+ intptr_t token_pos = Token::kNoSourcePos;
if (decl.IsFunction()) {
const Function& func = Function::Cast(decl);
@@ -2015,8 +1981,7 @@
token_pos = func.token_pos();
} else if (decl.IsClass()) {
const Class& cls = Class::Cast(decl);
- const bool is_typedef = cls.IsSignatureClass() &&
- !cls.IsCanonicalSignatureClass();
+ const bool is_typedef = cls.IsTypedefClass();
if (cls.is_synthesized_class() &&
!is_typedef &&
!cls.is_mixin_app_alias() &&
@@ -2058,7 +2023,7 @@
}
ASSERT(!script.IsNull());
- ASSERT(token_pos != Scanner::kNoSourcePos);
+ ASSERT(token_pos != Token::kNoSourcePos);
const String& uri = String::Handle(script.url());
intptr_t from_line = 0;
@@ -2077,15 +2042,25 @@
DEFINE_NATIVE_ENTRY(TypedefMirror_referent, 1) {
- GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
- const Class& cls = Class::Handle(type.type_class());
+ GET_NON_NULL_NATIVE_ARGUMENT(FunctionType, type, arguments->NativeArgAt(0));
+ const Class& cls = Class::Handle(type.scope_class());
+ ASSERT(cls.IsTypedefClass());
const Function& sig_func = Function::Handle(cls.signature_function());
- const Class& sig_cls = Class::Handle(sig_func.signature_class());
-
- AbstractType& referent_type = AbstractType::Handle(sig_cls.DeclarationType());
- referent_type = InstantiateType(referent_type, type);
-
- return CreateFunctionTypeMirror(sig_cls, referent_type);
+ FunctionType& referent_type = FunctionType::Handle(sig_func.SignatureType());
+ // If the scope class of the function type is not generic, replace it with
+ // Closure class (Function::SignatureType() keeps it).
+ ASSERT(cls.raw() == referent_type.scope_class());
+ if (!cls.IsGeneric()) {
+ referent_type = FunctionType::New(
+ Class::Handle(Isolate::Current()->object_store()->closure_class()),
+ TypeArguments::Handle(referent_type.arguments()),
+ sig_func,
+ referent_type.token_pos());
+ referent_type ^= ClassFinalizer::FinalizeType(
+ cls, referent_type, ClassFinalizer::kCanonicalize);
+ }
+ referent_type ^= InstantiateType(referent_type, type);
+ return CreateFunctionTypeMirror(referent_type);
}
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 0a839fb..78835a4 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -945,7 +945,8 @@
class _LocalFunctionTypeMirror extends _LocalClassMirror
implements FunctionTypeMirror {
- _LocalFunctionTypeMirror(reflectee, reflectedType)
+ final _functionReflectee;
+ _LocalFunctionTypeMirror(reflectee, this._functionReflectee, reflectedType)
: super(reflectee, reflectedType, null, null, false, false, false, false, false);
bool get _isAnonymousMixinApplication => false;
@@ -962,7 +963,7 @@
MethodMirror _callMethod;
MethodMirror get callMethod {
if (_callMethod == null) {
- _callMethod = this._FunctionTypeMirror_call_method(_reflectee);
+ _callMethod = _FunctionTypeMirror_call_method(_functionReflectee);
}
return _callMethod;
}
@@ -971,7 +972,7 @@
TypeMirror get returnType {
if (_returnType == null) {
_returnType = reflectType(
- _FunctionTypeMirror_return_type(_reflectee, _instantiator));
+ _FunctionTypeMirror_return_type(_functionReflectee, _instantiator));
}
return _returnType;
}
@@ -979,7 +980,7 @@
List<ParameterMirror> _parameters = null;
List<ParameterMirror> get parameters {
if (_parameters == null) {
- _parameters = _FunctionTypeMirror_parameters(_reflectee);
+ _parameters = _FunctionTypeMirror_parameters(_functionReflectee);
_parameters = new UnmodifiableListView(_parameters);
}
return _parameters;
@@ -990,16 +991,17 @@
get typeVariables => emptyList;
get typeArguments => emptyList;
get metadata => emptyList;
+ get location => null;
String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
- MethodMirror _FunctionTypeMirror_call_method(reflectee)
+ MethodMirror _FunctionTypeMirror_call_method(functionReflectee)
native "FunctionTypeMirror_call_method";
- static Type _FunctionTypeMirror_return_type(reflectee, instantiator)
+ static Type _FunctionTypeMirror_return_type(functionReflectee, instantiator)
native "FunctionTypeMirror_return_type";
- List<ParameterMirror> _FunctionTypeMirror_parameters(reflectee)
+ List<ParameterMirror> _FunctionTypeMirror_parameters(functionReflectee)
native "FunctionTypeMirror_parameters";
}
@@ -1648,7 +1650,7 @@
native "Mirrors_makeLocalTypeMirror";
static Expando<ClassMirror> _declarationCache = new Expando("ClassMirror");
- static Expando<TypeMirror> _instanitationCache = new Expando("TypeMirror");
+ static Expando<TypeMirror> _instantiationCache = new Expando("TypeMirror");
static ClassMirror reflectClass(Type key) {
var classMirror = _declarationCache[key];
@@ -1656,17 +1658,17 @@
classMirror = makeLocalClassMirror(key);
_declarationCache[key] = classMirror;
if (!classMirror._isGeneric) {
- _instanitationCache[key] = classMirror;
+ _instantiationCache[key] = classMirror;
}
}
return classMirror;
}
static TypeMirror reflectType(Type key) {
- var typeMirror = _instanitationCache[key];
+ var typeMirror = _instantiationCache[key];
if (typeMirror == null) {
typeMirror = makeLocalTypeMirror(key);
- _instanitationCache[key] = typeMirror;
+ _instantiationCache[key] = typeMirror;
if (typeMirror is ClassMirror && !typeMirror._isGeneric) {
_declarationCache[key] = typeMirror;
}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 72fcc3e..d0eb27c 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -88,7 +88,7 @@
// found.
Function& function = Function::Handle();
if (instance.IsClosure()) {
- function = Closure::function(instance);
+ function = Closure::Cast(instance).function();
} else {
Class& instance_class = Class::Handle(instance.clazz());
function = instance_class.LookupDynamicFunction(member_name);
@@ -179,7 +179,8 @@
if (FLAG_trace_type_checks) {
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Native Object.instanceOf: result %s\n", result_str);
- const Type& instance_type = Type::Handle(instance.GetType());
+ const AbstractType& instance_type =
+ AbstractType::Handle(instance.GetType());
OS::Print(" instance type: %s\n",
String::Handle(instance_type.Name()).ToCString());
OS::Print(" test type: %s\n", String::Handle(type.Name()).ToCString());
@@ -289,7 +290,8 @@
if (FLAG_trace_type_checks) {
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Object.as: result %s\n", result_str);
- const Type& instance_type = Type::Handle(instance.GetType());
+ const AbstractType& instance_type =
+ AbstractType::Handle(instance.GetType());
OS::Print(" instance type: %s\n",
String::Handle(instance_type.Name()).ToCString());
OS::Print(" cast type: %s\n", String::Handle(type.Name()).ToCString());
diff --git a/runtime/lib/type_patch.dart b/runtime/lib/type_patch.dart
index 67d7db5..5d0f305 100644
--- a/runtime/lib/type_patch.dart
+++ b/runtime/lib/type_patch.dart
@@ -13,6 +13,10 @@
class _Type extends _AbstractType {
}
+// Equivalent of RawFunctionType.
+class _FunctionType extends _AbstractType {
+}
+
// Equivalent of RawTypeRef.
class _TypeRef extends _AbstractType {
}
diff --git a/runtime/observatory/lib/src/debugger/debugger_location.dart b/runtime/observatory/lib/src/debugger/debugger_location.dart
index caf5f57..7688712 100644
--- a/runtime/observatory/lib/src/debugger/debugger_location.dart
+++ b/runtime/observatory/lib/src/debugger/debugger_location.dart
@@ -401,13 +401,14 @@
// Complete the line.
var sharedPrefix = '${script.name}:';
List completions = [];
- for (var line in script.lines) {
- if (line.possibleBpt) {
- var currentLineStr = line.line.toString();
- if (currentLineStr.startsWith(lineStr)) {
- completions.add('${sharedPrefix}${currentLineStr} ');
- completions.add('${sharedPrefix}${currentLineStr}:');
- }
+ var report = await script.isolate.getSourceReport(
+ [Isolate.kPossibleBreakpointsReport], script);
+ Set<int> possibleBpts = getPossibleBreakpointLines(report, script);
+ for (var line in possibleBpts) {
+ var currentLineStr = line.toString();
+ if (currentLineStr.startsWith(lineStr)) {
+ completions.add('${sharedPrefix}${currentLineStr} ');
+ completions.add('${sharedPrefix}${currentLineStr}:');
}
}
return completions;
@@ -416,9 +417,6 @@
// Complete the column.
int lineNum = int.parse(lineStr);
var scriptLine = script.getLine(lineNum);
- if (!scriptLine.possibleBpt) {
- return [];
- }
var sharedPrefix = '${script.name}:${lineStr}:';
List completions = [];
int maxCol = scriptLine.text.trimRight().runes.length;
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index 8c67ebc..d50b092 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -88,10 +88,6 @@
return Future.wait(loads);
}
- Future refreshCoverage() {
- return cls.refreshCoverage();
- }
-
onSampleBufferChange(CpuProfile sampleBuffer) {
stackTraceTreeConfigElement.show = sampleBuffer.sampleCount > 0;
cpuProfileTreeElement.show = sampleBuffer.sampleCount > 0;
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index 6e59887..60e8ee0 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -24,7 +24,6 @@
<library-nav-menu library="{{ cls.library }}"></library-nav-menu>
<class-nav-menu cls="{{ cls }}" last="{{ true }}"></class-nav-menu>
<nav-refresh callback="{{ refreshAllocationProfile }}" label="Refresh Allocation Profile"></nav-refresh>
- <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index cf78a26..06f91e7 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -8,6 +8,7 @@
import 'dart:html';
import 'dart:math';
import 'observatory_element.dart';
+import 'nav_bar.dart';
import 'package:observatory/app.dart';
import 'package:observatory/cli.dart';
import 'package:observatory/debugger.dart';
@@ -1067,28 +1068,6 @@
'Syntax: info <subcommand>\n';
}
-class RefreshCoverageCommand extends DebuggerCommand {
- RefreshCoverageCommand(Debugger debugger) : super(debugger, 'coverage', []);
-
- Future run(List<String> args) {
- Set<Script> scripts = debugger.stackElement.activeScripts();
- List pending = [];
- for (var script in scripts) {
- pending.add(script.refreshCoverage().then((_) {
- debugger.console.print('Refreshed coverage for ${script.name}');
- }));
- }
- return Future.wait(pending);
- }
-
- String helpShort = 'Refresh code coverage information for current frames';
-
- String helpLong =
- 'Refresh code coverage information for current frames.\n'
- '\n'
- 'Syntax: refresh coverage\n\n';
-}
-
class RefreshStackCommand extends DebuggerCommand {
RefreshStackCommand(Debugger debugger) : super(debugger, 'stack', []);
@@ -1106,7 +1085,6 @@
class RefreshCommand extends DebuggerCommand {
RefreshCommand(Debugger debugger) : super(debugger, 'refresh', [
- new RefreshCoverageCommand(debugger),
new RefreshStackCommand(debugger),
]);
@@ -1400,7 +1378,6 @@
if ((breakOnException != iso.exceptionsPauseInfo) &&
(iso.exceptionsPauseInfo != null)) {
breakOnException = iso.exceptionsPauseInfo;
- console.print("Now pausing for exceptions: $breakOnException");
}
_isolate.reload().then((response) {
@@ -1515,6 +1492,25 @@
warnOutOfDate();
}
+ void _reportIsolateError(Isolate isolate) {
+ if (isolate == null) {
+ return;
+ }
+ DartError error = isolate.error;
+ if (error == null) {
+ return;
+ }
+ console.newline();
+ console.printBold('Isolate exited due to an unhandled exception:');
+ console.print(error.message);
+ console.newline();
+ console.printBold("Type 'set break-on-exception Unhandled' to pause the"
+ " isolate when an unhandled exception occurs.");
+ console.newline();
+ console.printBold("You can make this the default by running with "
+ "--pause-isolates-on-unhandled-exceptions");
+ }
+
void _reportPause(ServiceEvent event) {
if (event.kind == ServiceEvent.kPauseStart) {
console.print(
@@ -1524,6 +1520,7 @@
console.print(
"Paused at isolate exit "
"(type 'continue' or [F7] to exit the isolate')");
+ _reportIsolateError(isolate);
} else if (stack['frames'].length > 0) {
Frame frame = stack['frames'][0];
var script = frame.location.script;
@@ -1640,8 +1637,11 @@
case ServiceEvent.kPauseInterrupted:
case ServiceEvent.kPauseException:
if (event.owner == isolate) {
- _refreshStack(event).then((_) {
+ _refreshStack(event).then((_) async {
flushStdio();
+ if (isolate != null) {
+ await isolate.reload();
+ }
_reportPause(event);
});
}
@@ -1896,6 +1896,7 @@
var stackElement = $['stackElement'];
debugger.stackElement = stackElement;
stackElement.debugger = debugger;
+ stackElement.scroller = $['stackDiv'];
debugger.console = $['console'];
debugger.input = $['commandline'];
debugger.input.debugger = debugger;
@@ -1952,7 +1953,8 @@
var splitterDiv = $['splitterDiv'];
var cmdDiv = $['commandDiv'];
- int navbarHeight = navbarDiv.clientHeight;
+ // For now, force navbar height to 40px in the debugger.
+ int navbarHeight = NavBarElement.height;
int splitterHeight = splitterDiv.clientHeight;
int cmdHeight = cmdDiv.clientHeight;
@@ -1960,6 +1962,7 @@
int fixedHeight = navbarHeight + splitterHeight + cmdHeight;
int available = windowHeight - fixedHeight;
int stackHeight = available ~/ 1.6;
+ navbarDiv.style.setProperty('height', '${navbarHeight}px');
stackDiv.style.setProperty('height', '${stackHeight}px');
}
@@ -1987,6 +1990,7 @@
@CustomTag('debugger-stack')
class DebuggerStackElement extends ObservatoryElement {
@published Isolate isolate;
+ @published Element scroller;
@observable bool hasStack = false;
@observable bool hasMessages = false;
@observable bool isSampled = false;
@@ -1996,6 +2000,7 @@
_addFrame(List frameList, Frame frameInfo) {
DebuggerFrameElement frameElement = new Element.tag('debugger-frame');
frameElement.frame = frameInfo;
+ frameElement.scroller = scroller;
if (frameInfo.index == currentFrame) {
frameElement.setCurrent(true);
@@ -2122,15 +2127,6 @@
}
}
- Set<Script> activeScripts() {
- var s = new Set<Script>();
- List frameElements = $['frameList'].children;
- for (var frameElement in frameElements) {
- s.add(frameElement.children[0].script);
- }
- return s;
- }
-
Future doPauseIsolate() {
if (debugger != null) {
return debugger.isolate.pause();
@@ -2153,6 +2149,7 @@
@CustomTag('debugger-frame')
class DebuggerFrameElement extends ObservatoryElement {
@published Frame frame;
+ @published Element scroller;
// Is this the current frame?
bool _current = false;
@@ -2167,17 +2164,14 @@
var frameOuter = $['frameOuter'];
if (_current) {
frameOuter.classes.add('current');
- expanded = true;
- frameOuter.classes.add('shadow');
+ _expand();
scrollIntoView();
} else {
frameOuter.classes.remove('current');
if (_pinned) {
- expanded = true;
- frameOuter.classes.add('shadow');
+ _expand();
} else {
- expanded = false;
- frameOuter.classes.remove('shadow');
+ _unexpand();
}
}
busy = false;
@@ -2190,7 +2184,6 @@
DebuggerFrameElement.created() : super.created();
-
String makeExpandKey(String key) {
return '${frame.function.qualifiedName}/${key}';
}
@@ -2206,11 +2199,87 @@
Script get script => frame.location.script;
+ int _varsTop(varsDiv) {
+ const minTop = 5;
+ if (varsDiv == null) {
+ return minTop;
+ }
+ const navbarHeight = NavBarElement.height;
+ const bottomPad = 6;
+ var parent = varsDiv.parent.getBoundingClientRect();
+ var varsHeight = varsDiv.clientHeight;
+ var maxTop = parent.height - (varsHeight + bottomPad);
+ var adjustedTop = navbarHeight - parent.top;
+ return (max(minTop, min(maxTop, adjustedTop)));
+ }
+
+ void _onScroll(event) {
+ if (!expanded) {
+ return;
+ }
+ var varsDiv = shadowRoot.querySelector('#vars');
+ if (varsDiv == null) {
+ return;
+ }
+ var currentTop = varsDiv.style.top;
+ var newTop = _varsTop(varsDiv);
+ if (currentTop != newTop) {
+ varsDiv.style.top = '${newTop}px';
+ }
+ }
+
+ void _expand() {
+ var frameOuter = $['frameOuter'];
+ expanded = true;
+ frameOuter.classes.add('shadow');
+ _subscribeToScroll();
+ }
+
+ void _unexpand() {
+ var frameOuter = $['frameOuter'];
+ expanded = false;
+ _unsubscribeToScroll();
+ frameOuter.classes.remove('shadow');
+ }
+
+ StreamSubscription _scrollSubscription;
+ StreamSubscription _resizeSubscription;
+
+ void _subscribeToScroll() {
+ if (scroller != null) {
+ if (_scrollSubscription == null) {
+ _scrollSubscription = scroller.onScroll.listen(_onScroll);
+ }
+ if (_resizeSubscription == null) {
+ _resizeSubscription = window.onResize.listen(_onScroll);
+ }
+ }
+ }
+
+ void _unsubscribeToScroll() {
+ if (_scrollSubscription != null) {
+ _scrollSubscription.cancel();
+ _scrollSubscription = null;
+ }
+ if (_resizeSubscription != null) {
+ _resizeSubscription.cancel();
+ _resizeSubscription = null;
+ }
+ }
+
@override
void attached() {
super.attached();
int windowHeight = window.innerHeight;
scriptHeight = '${windowHeight ~/ 1.6}px';
+ if (expanded) {
+ _subscribeToScroll();
+ }
+ }
+
+ void detached() {
+ _unsubscribeToScroll();
+ super.detached();
}
void toggleExpand(var a, var b, var c) {
@@ -2220,13 +2289,10 @@
busy = true;
frame.function.load().then((func) {
_pinned = !_pinned;
- var frameOuter = $['frameOuter'];
if (_pinned) {
- expanded = true;
- frameOuter.classes.add('shadow');
+ _expand();
} else {
- expanded = false;
- frameOuter.classes.remove('shadow');
+ _unexpand();
}
busy = false;
});
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 981f260..20e2e4d 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -238,6 +238,12 @@
flex-basis: 250px;
overflow-x: hidden;
}
+ #vars {
+ position: relative;
+ top: 5px;
+ padding-left:2em;
+ padding-bottom: 5px;
+ }
</style>
<div id="frameOuter" class="frameOuter">
<a on-click="{{ toggleExpand }}">
@@ -263,11 +269,12 @@
location="{{ frame.function.location }}"
currentPos="{{ frame.location.tokenPos }}"
inDebuggerContext="{{ true }}"
+ scroller="{{ scroller }}"
variables="{{ frame.variables }}">
</source-inset>
</div>
<div class="flex-item-vars">
- <div style="padding-left:2em;" class="memberList">
+ <div id="vars" class="memberList">
<template repeat="{{ v in properLocals }}">
{{ v['name']}} :
<any-service-ref ref="{{ v['value'] }}"
diff --git a/runtime/observatory/lib/src/elements/function_view.dart b/runtime/observatory/lib/src/elements/function_view.dart
index 5b0d8ec..58f206b 100644
--- a/runtime/observatory/lib/src/elements/function_view.dart
+++ b/runtime/observatory/lib/src/elements/function_view.dart
@@ -18,8 +18,4 @@
Future refresh() {
return function.reload();
}
-
- Future refreshCoverage() {
- return function.refreshCoverage();
- }
}
diff --git a/runtime/observatory/lib/src/elements/function_view.html b/runtime/observatory/lib/src/elements/function_view.html
index 57e2c8c..a087382 100644
--- a/runtime/observatory/lib/src/elements/function_view.html
+++ b/runtime/observatory/lib/src/elements/function_view.html
@@ -21,7 +21,6 @@
<class-nav-menu cls="{{ function.dartOwner }}"></class-nav-menu>
</template>
<nav-menu link="{{ makeLink('/inspect', function) }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
- <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.dart b/runtime/observatory/lib/src/elements/isolate_view.dart
index fe4fd95..40738a1 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.dart
+++ b/runtime/observatory/lib/src/elements/isolate_view.dart
@@ -33,8 +33,4 @@
await isolate.topFrame.function.load();
}
}
-
- Future refreshCoverage() {
- return isolate.refreshCoverage();
- }
}
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index 915930fc..b090fdd 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -28,7 +28,6 @@
<top-nav-menu></top-nav-menu>
<vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
<isolate-nav-menu isolate="{{ isolate }}" last="{{ true }}"></isolate-nav-menu>
- <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/library_view.dart b/runtime/observatory/lib/src/elements/library_view.dart
index 6b43ae3..3c9a256 100644
--- a/runtime/observatory/lib/src/elements/library_view.dart
+++ b/runtime/observatory/lib/src/elements/library_view.dart
@@ -30,8 +30,4 @@
library.variables.forEach((variable) => loads.add(variable.reload()));
return Future.wait(loads);
}
-
- Future refreshCoverage() {
- return library.refreshCoverage();
- }
}
diff --git a/runtime/observatory/lib/src/elements/library_view.html b/runtime/observatory/lib/src/elements/library_view.html
index d43fe3e..51d2da8 100644
--- a/runtime/observatory/lib/src/elements/library_view.html
+++ b/runtime/observatory/lib/src/elements/library_view.html
@@ -20,7 +20,6 @@
<vm-nav-menu vm="{{ library.isolate.vm }}"></vm-nav-menu>
<isolate-nav-menu isolate="{{ library.isolate }}"></isolate-nav-menu>
<library-nav-menu library="{{ library }}" last="{{ true }}"></library-nav-menu>
- <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/nav_bar.dart b/runtime/observatory/lib/src/elements/nav_bar.dart
index db77700..3999db87 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.dart
+++ b/runtime/observatory/lib/src/elements/nav_bar.dart
@@ -17,6 +17,9 @@
@published bool notifyOnPause = true;
@published bool pad = true;
+ // Desired nav var height in pixels.
+ static const height = 40;
+
NavBarElement.created() : super.created();
}
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 47bbff7..aa3c0a8 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -6,7 +6,9 @@
import 'dart:async';
import 'dart:html';
+import 'dart:math';
import 'observatory_element.dart';
+import 'nav_bar.dart';
import 'service_ref.dart';
import 'package:observatory/service.dart';
import 'package:observatory/utils.dart';
@@ -244,7 +246,7 @@
for (var entry in callSite.entries) {
var r = row();
- r.append(cell(serviceRef(entry.receiverContainer)));
+ r.append(cell(serviceRef(entry.receiver)));
r.append(cell(entry.count.toString()));
r.append(cell(serviceRef(entry.target)));
details.append(r);
@@ -374,16 +376,24 @@
@published bool inDebuggerContext = false;
@published ObservableList variables;
+ @published Element scroller;
+ RefreshButtonElement _refreshButton;
+
int _currentLine;
int _currentCol;
int _startLine;
int _endLine;
+ Map<int, List<ServiceMap>> _rangeMap = {};
+ Set _callSites = new Set<CallSite>();
+ Set _possibleBreakpointLines = new Set<int>();
+
var annotations = [];
var annotationsCursor;
StreamSubscription _scriptChangeSubscription;
Future<StreamSubscription> _debugSubscriptionFuture;
+ StreamSubscription _scrollSubscription;
bool hasLoadedLibraryDeclarations = false;
@@ -402,11 +412,20 @@
super.attached();
_debugSubscriptionFuture =
app.vm.listenEventStream(VM.kDebugStream, _onDebugEvent);
+ if (scroller != null) {
+ _scrollSubscription = scroller.onScroll.listen(_onScroll);
+ } else {
+ _scrollSubscription = window.onScroll.listen(_onScroll);
+ }
}
void detached() {
cancelFutureSubscription(_debugSubscriptionFuture);
_debugSubscriptionFuture = null;
+ if (_scrollSubscription != null) {
+ _scrollSubscription.cancel();
+ _scrollSubscription = null;
+ }
if (_scriptChangeSubscription != null) {
// Don't leak. If only Dart and Javascript exposed weak references...
_scriptChangeSubscription.cancel();
@@ -415,6 +434,17 @@
super.detached();
}
+ void _onScroll(event) {
+ if (_refreshButton == null) {
+ return;
+ }
+ var currentTop = _refreshButton.style.top;
+ var newTop = _refreshButtonTop();
+ if (currentTop != newTop) {
+ _refreshButton.style.top = '${newTop}px';
+ }
+ }
+
void _onDebugEvent(event) {
if (script == null) {
return;
@@ -486,11 +516,55 @@
element.title = "Line did execute";
return element;
}
+ Element hitsCompiled(Element element) {
+ element.classes.add('hitsCompiled');
+ element.title = "Line in compiled function";
+ return element;
+ }
+ Element hitsNotCompiled(Element element) {
+ element.classes.add('hitsNotCompiled');
+ element.title = "Line in uncompiled function";
+ return element;
+ }
Element container;
+ Future _refresh() async {
+ await update();
+ }
+
+ // Build _rangeMap and _callSites from a source report.
+ Future _refreshSourceReport() async {
+ var sourceReport = await script.isolate.getSourceReport(
+ [Isolate.kCallSitesReport, Isolate.kPossibleBreakpointsReport],
+ script, startPos, endPos);
+ _possibleBreakpointLines = getPossibleBreakpointLines(sourceReport, script);
+ _rangeMap.clear();
+ _callSites.clear();
+ for (var range in sourceReport['ranges']) {
+ int startLine = script.tokenToLine(range['startPos']);
+ int endLine = script.tokenToLine(range['endPos']);
+ for (var line = startLine; line <= endLine; line++) {
+ var rangeList = _rangeMap[line];
+ if (rangeList == null) {
+ _rangeMap[line] = [range];
+ } else {
+ rangeList.add(range);
+ }
+ }
+ if (range['compiled']) {
+ var rangeCallSites = range['callSites'];
+ if (rangeCallSites != null) {
+ for (var callSiteMap in rangeCallSites) {
+ _callSites.add(new CallSite.fromMap(callSiteMap, script));
+ }
+ }
+ }
+ }
+ }
+
Task _updateTask;
- void update() {
+ Future update() async {
assert(_updateTask != null);
if (script == null) {
// We may have previously had a script.
@@ -500,13 +574,12 @@
return;
}
if (!script.loaded) {
- script.load().then((_) => update());
- return;
+ await script.load();
}
-
if (_scriptChangeSubscription == null) {
_scriptChangeSubscription = script.changes.listen((_) => update());
}
+ await _refreshSourceReport();
computeAnnotations();
@@ -803,7 +876,7 @@
}
void addCallSiteAnnotations() {
- for (var callSite in script.callSites) {
+ for (var callSite in _callSites) {
annotations.add(new CallSiteAnnotation(callSite));
}
}
@@ -828,10 +901,35 @@
}
}
+ int _refreshButtonTop() {
+ if (_refreshButton == null) {
+ return 5;
+ }
+ const padding = 5;
+ const navbarHeight = NavBarElement.height;
+ var rect = getBoundingClientRect();
+ var buttonHeight = _refreshButton.clientHeight;
+ return min(max(0, navbarHeight - rect.top) + padding,
+ rect.height - (buttonHeight + padding));
+ }
+
+ RefreshButtonElement _newRefreshButton() {
+ var button = new Element.tag('refresh-button');
+ button.style.position = 'absolute';
+ button.style.display = 'inline-block';
+ button.style.top = '${_refreshButtonTop()}px';
+ button.style.right = '5px';
+ button.callback = _refresh;
+ return button;
+ }
+
Element linesTable() {
var table = new DivElement();
table.classes.add("sourceTable");
+ _refreshButton = _newRefreshButton();
+ table.append(_refreshButton);
+
if (_startLine == null || _endLine == null) {
return table;
}
@@ -904,35 +1002,38 @@
Element lineBreakpointElement(ScriptLine line) {
var e = new DivElement();
- var busy = false;
- if (line == null || !line.possibleBpt) {
- e.classes.add("emptyBreakpoint");
+ if (line == null || !_possibleBreakpointLines.contains(line.line)) {
e.classes.add('noCopy');
+ e.classes.add("emptyBreakpoint");
e.text = nbsp;
return e;
}
+
e.text = 'B';
- update() {
+ var busy = false;
+ void update() {
e.classes.clear();
e.classes.add('noCopy');
-
- if (!line.possibleBpt) {
- e.classes.add("emptyBreakpoint");
- e.text = nbsp;
- } else if (busy) {
+ if (busy) {
e.classes.add("busyBreakpoint");
- } else {
- if (line.breakpoints != null) {
- if (line.breakpointResolved) {
- e.classes.add("resolvedBreakpoint");
- } else {
- e.classes.add("unresolvedBreakpoint");
+ } else if (line.breakpoints != null) {
+ bool resolved = false;
+ for (var bpt in line.breakpoints) {
+ if (bpt.resolved) {
+ resolved = true;
+ break;
}
- } else {
- e.classes.add("possibleBreakpoint");
}
+ if (resolved) {
+ e.classes.add("resolvedBreakpoint");
+ } else {
+ e.classes.add("unresolvedBreakpoint");
+ }
+ } else {
+ e.classes.add("possibleBreakpoint");
}
}
+
line.changes.listen((_) => update());
e.onClick.listen((event) {
if (busy) {
@@ -973,17 +1074,51 @@
var lineNumber = line == null ? "..." : line.line;
var e = span("$nbsp${lineNumber.toString().padLeft(lineNumPad,nbsp)}$nbsp");
e.classes.add('noCopy');
-
if (lineNumber == _currentLine) {
hitsCurrent(e);
- } else if ((line == null) || (line.hits == null)) {
- hitsUnknown(e);
- } else if (line.hits == 0) {
- hitsNotExecuted(e);
- } else {
- hitsExecuted(e);
+ return e;
}
-
+ var ranges = _rangeMap[lineNumber];
+ if ((ranges == null) || ranges.isEmpty) {
+ // This line is not code.
+ hitsUnknown(e);
+ return e;
+ }
+ bool compiled = true;
+ bool hasCallInfo = false;
+ bool executed = false;
+ for (var range in ranges) {
+ if (range['compiled']) {
+ for (var callSite in range['callSites']) {
+ var callLine = line.script.tokenToLine(callSite['tokenPos']);
+ if (lineNumber == callLine) {
+ // The call site is on the current line.
+ hasCallInfo = true;
+ for (var cacheEntry in callSite['cacheEntries']) {
+ if (cacheEntry['count'] > 0) {
+ // If any call site on the line has been executed, we
+ // mark the line as executed.
+ executed = true;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ // If any range isn't compiled, show the line as not compiled.
+ // This is necessary so that nested functions appear to be uncompiled.
+ compiled = false;
+ }
+ }
+ if (executed) {
+ hitsExecuted(e);
+ } else if (hasCallInfo) {
+ hitsNotExecuted(e);
+ } else if (compiled) {
+ hitsCompiled(e);
+ } else {
+ hitsNotCompiled(e);
+ }
return e;
}
@@ -1036,6 +1171,26 @@
}
}
+@CustomTag('refresh-button')
+class RefreshButtonElement extends PolymerElement {
+ RefreshButtonElement.created() : super.created();
+
+ @published var callback = null;
+ bool busy = false;
+
+ Future buttonClick(var event, var b, var c) async {
+ if (busy) {
+ return;
+ }
+ busy = true;
+ if (callback != null) {
+ await callback();
+ }
+ busy = false;
+ }
+}
+
+
@CustomTag('source-inset')
class SourceInsetElement extends PolymerElement {
SourceInsetElement.created() : super.created();
@@ -1045,4 +1200,5 @@
@published int currentPos;
@published bool inDebuggerContext = false;
@published ObservableList variables;
+ @published Element scroller;
}
diff --git a/runtime/observatory/lib/src/elements/script_inset.html b/runtime/observatory/lib/src/elements/script_inset.html
index a76ae42..92d2940 100644
--- a/runtime/observatory/lib/src/elements/script_inset.html
+++ b/runtime/observatory/lib/src/elements/script_inset.html
@@ -1,6 +1,19 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="observatory_element.html">
+<polymer-element name="icon-refresh" noscript>
+ <template>
+ <style>
+ svg {
+ fill: currentColor
+ }
+ </style>
+ <svg width="24" height="24">
+ <path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
+ </svg>
+ </template>
+</polymer-element>
+
<polymer-element name="script-inset" extends="observatory-element">
<template>
<style>
@@ -14,6 +27,7 @@
.sourceInset {
}
.sourceTable {
+ position: relative;
background-color: #f5f5f5;
border: 1px solid #ccc;
padding: 10px;
@@ -39,7 +53,7 @@
.currentCol {
background-color: #6cf;
}
- .hitsCurrent, .hitsNone, .hitsNotExecuted, .hitsExecuted {
+ .hitsCurrent, .hitsNone, .hitsNotExecuted, .hitsExecuted, .hitsCompiled, .hitsNotCompiled {
display: table-cell;
vertical-align: top;
font: 400 14px consolas, courier, monospace;
@@ -58,6 +72,13 @@
.hitsExecuted {
background-color: #aea;
}
+ .hitsCompiled {
+ background-color: #e0e0e0;
+ }
+ .hitsNotCompiled {
+ background-color: #f0c5c5;
+ }
+
.noCopy {}
.emptyBreakpoint, .possibleBreakpoint, .busyBreakpoint, .unresolvedBreakpoint, .resolvedBreakpoint {
display: table-cell;
@@ -99,12 +120,40 @@
</template>
</polymer-element>
+<polymer-element name="refresh-button">
+ <template>
+ <style>
+ .refreshButton {
+ color: rgba(0,0,0,.3);
+ }
+ .refreshButton:hover {
+ color: black;
+ }
+ .refreshButtonDisabled {
+ color: white;
+ cursor: wait;
+ }
+ </style>
+ <template if="{{ callback != null }}">
+ <template if="{{ busy }}">
+ <icon-refresh id="refreshIcon" class="refreshButtonDisabled">
+ </icon-refresh>
+ </template>
+ <template if="{{ !busy }}">
+ <a on-click="{{ buttonClick }}">
+ <icon-refresh id="refreshIcon" class="refreshButton"></icon-refresh>
+ </a>
+ </template>
+ </template>
+ </template>
+</polymer-element>
<polymer-element name="source-inset">
<template>
<template if="{{ location != null }}">
<script-inset script="{{ location.script }}"
startPos="{{ location.tokenPos }}"
+ scroller="{{ scroller }}"
endPos="{{ location.endTokenPos }}"
height="{{ height }}"
currentPos="{{ currentPos }}"
diff --git a/runtime/observatory/lib/src/elements/script_view.dart b/runtime/observatory/lib/src/elements/script_view.dart
index ff07a80..c896b8d 100644
--- a/runtime/observatory/lib/src/elements/script_view.dart
+++ b/runtime/observatory/lib/src/elements/script_view.dart
@@ -20,8 +20,4 @@
Future refresh() {
return script.reload();
}
-
- Future refreshCoverage() {
- return script.refreshCoverage();
- }
}
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index 1dc23b4..c65fa49 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -13,7 +13,6 @@
<isolate-nav-menu isolate="{{ script.isolate }}"></isolate-nav-menu>
<library-nav-menu library="{{ script.library }}"></library-nav-menu>
<nav-menu link="{{ makeLink('/inspect', script) }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
- <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
</nav-bar>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index e45cb8d..abc1ea4 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -395,40 +395,6 @@
}
}
-abstract class Coverage {
- // Following getters and functions will be provided by [ServiceObject].
- String get id;
- Isolate get isolate;
-
- Future refreshCoverage() {
- return refreshCallSiteData();
- }
-
- /// Default handler for coverage data.
- void processCallSiteData(List coverageData) {
- coverageData.forEach((scriptCoverage) {
- assert(scriptCoverage['script'] != null);
- scriptCoverage['script']._processCallSites(scriptCoverage['callSites']);
- });
- }
-
- Future refreshCallSiteData() {
- Map params = {};
- if (this is! Isolate) {
- params['targetId'] = id;
- }
- return isolate.invokeRpcNoUpgrade('_getCallSiteData', params).then(
- (ObservableMap map) {
- var coverage = new ServiceObject._fromMap(isolate, map);
- assert(coverage.type == 'CodeCoverage');
- var coverageList = coverage['coverage'];
- assert(coverageList != null);
- processCallSiteData(coverageList);
- return this;
- });
- }
-}
-
abstract class ServiceObjectOwner extends ServiceObject {
/// Creates an empty [ServiceObjectOwner].
ServiceObjectOwner._empty(ServiceObjectOwner owner) : super._empty(owner);
@@ -1135,7 +1101,7 @@
}
/// State for a running isolate.
-class Isolate extends ServiceObjectOwner with Coverage {
+class Isolate extends ServiceObjectOwner {
static const kLoggingStream = '_Logging';
static const kExtensionStream = 'Extension';
@@ -1194,6 +1160,26 @@
});
}
+ static const kCallSitesReport = '_CallSites';
+ static const kPossibleBreakpointsReport = 'PossibleBreakpoints';
+
+ Future<ServiceMap> getSourceReport(List<String> report_kinds,
+ [Script script,
+ int startPos,
+ int endPos]) {
+ var params = { 'reports' : report_kinds };
+ if (script != null) {
+ params['scriptId'] = script.id;
+ }
+ if (startPos != null) {
+ params['tokenPos'] = startPos;
+ }
+ if (endPos != null) {
+ params['endTokenPos'] = endPos;
+ }
+ return invokeRpc('_getSourceReport', params);
+ }
+
/// Fetches and builds the class hierarchy for this isolate. Returns the
/// Object class object.
Future<Class> getClassHierarchy() {
@@ -1536,34 +1522,15 @@
}
}
- Future<ServiceObject> addBreakpoint(
- Script script, int line, [int col]) async {
- // TODO(turnidge): Pass line as an int instead of a string.
- try {
- Map params = {
- 'scriptId': script.id,
- 'line': line.toString(),
- };
- if (col != null) {
- params['column'] = col.toString();
- }
- Breakpoint bpt = await invokeRpc('addBreakpoint', params);
- if (bpt.resolved && script.loaded) {
- SourceLocation loc = bpt.location;
- if (script.tokenToLine(loc.tokenPos) != line) {
- script.getLine(line).possibleBpt = false;
- }
- }
- return bpt;
- } on ServerRpcException catch(e) {
- if (e.code == ServerRpcException.kCannotAddBreakpoint) {
- // Unable to set a breakpoint at the desired line.
- if (script.loaded) {
- script.getLine(line).possibleBpt = false;
- }
- }
- rethrow;
+ Future<ServiceObject> addBreakpoint(Script script, int line, [int col]) {
+ Map params = {
+ 'scriptId': script.id,
+ 'line': line,
+ };
+ if (col != null) {
+ params['column'] = col;
}
+ return invokeRpc('addBreakpoint', params);
}
Future<ServiceObject> addBreakpointByScriptUri(
@@ -2115,7 +2082,7 @@
}
-class Library extends HeapObject with Coverage {
+class Library extends HeapObject {
@observable String uri;
@reflectable final dependencies = new ObservableList<LibraryDependency>();
@reflectable final scripts = new ObservableList<Script>();
@@ -2213,7 +2180,7 @@
bool get empty => accumulated.empty && current.empty;
}
-class Class extends HeapObject with Coverage {
+class Class extends HeapObject {
@observable Library library;
@observable bool isAbstract;
@@ -2592,7 +2559,7 @@
static FunctionKind kUNKNOWN = new FunctionKind._internal('UNKNOWN');
}
-class ServiceFunction extends HeapObject with Coverage {
+class ServiceFunction extends HeapObject {
// owner is a Library, Class, or ServiceFunction.
@observable ServiceObject dartOwner;
@observable Library library;
@@ -2738,21 +2705,21 @@
final Script script;
final int line;
final String text;
- @observable int hits;
- @observable bool possibleBpt = true;
- @observable bool breakpointResolved = false;
@observable Set<Breakpoint> breakpoints;
- bool get isBlank {
- // Compute isBlank on demand.
- if (_isBlank == null) {
- _isBlank = text.trim().isEmpty;
- }
- return _isBlank;
- }
- bool _isBlank;
+ ScriptLine(this.script, this.line, this.text);
- bool get isTrivialLine => !possibleBpt;
+ bool get isBlank {
+ return text.isEmpty || text.trim().isEmpty;
+ }
+
+ bool _isTrivial = null;
+ bool get isTrivial {
+ if (_isTrivial == null) {
+ _isTrivial = _isTrivialLine(text);
+ }
+ return _isTrivial;
+ }
static bool _isTrivialToken(String token) {
if (token == 'else') {
@@ -2789,16 +2756,11 @@
return true;
}
- ScriptLine(this.script, this.line, this.text) {
- possibleBpt = !_isTrivialLine(text);
- }
-
void addBreakpoint(Breakpoint bpt) {
if (breakpoints == null) {
breakpoints = new Set<Breakpoint>();
}
breakpoints.add(bpt);
- breakpointResolved = breakpointResolved || bpt.resolved;
}
void removeBreakpoint(Breakpoint bpt) {
@@ -2806,7 +2768,6 @@
breakpoints.remove(bpt);
if (breakpoints.isEmpty) {
breakpoints = null;
- breakpointResolved = false;
}
}
}
@@ -2850,19 +2811,19 @@
}
class CallSiteEntry {
- final /* Class | Library */ receiverContainer;
+ final /* Class | Library */ receiver;
final int count;
final ServiceFunction target;
- CallSiteEntry(this.receiverContainer, this.count, this.target);
+ CallSiteEntry(this.receiver, this.count, this.target);
factory CallSiteEntry.fromMap(Map entryMap) {
- return new CallSiteEntry(entryMap['receiverContainer'],
+ return new CallSiteEntry(entryMap['receiver'],
entryMap['count'],
entryMap['target']);
}
- String toString() => "CallSiteEntry(${receiverContainer.name}, $count)";
+ String toString() => "CallSiteEntry(${receiver.name}, $count)";
}
/// The location of a local variable reference in a script.
@@ -2873,10 +2834,8 @@
LocalVarLocation(this.line, this.column, this.endColumn);
}
-class Script extends HeapObject with Coverage {
- Set<CallSite> callSites = new Set<CallSite>();
+class Script extends HeapObject {
final lines = new ObservableList<ScriptLine>();
- final _hits = new Map<int, int>();
@observable String uri;
@observable String kind;
@observable int firstTokenPos;
@@ -3021,36 +2980,6 @@
_tokenToCol[tokenOffset] = colNumber;
}
}
-
- for (var line in lines) {
- // Remove possible breakpoints on lines with no tokens.
- if (!lineSet.contains(line.line)) {
- line.possibleBpt = false;
- }
- }
- }
-
- void _processCallSites(List newCallSiteMaps) {
- var mergedCallSites = new Set<CallSite>();
- for (var callSiteMap in newCallSiteMaps) {
- var newSite = new CallSite.fromMap(callSiteMap, this);
- mergedCallSites.add(newSite);
-
- var line = newSite.line;
- var hit = newSite.aggregateCount;
- assert(line >= 1); // Lines start at 1.
- var oldHits = _hits[line];
- if (oldHits != null) {
- hit += oldHits;
- }
- _hits[line] = hit;
- }
-
- mergedCallSites.addAll(callSites);
- callSites = mergedCallSites;
- _applyHitsToLines();
- // Notify any Observers that this Script's state has changed.
- notifyChange(null);
}
void _processSource(String source) {
@@ -3072,18 +3001,10 @@
}
}
- _applyHitsToLines();
// Notify any Observers that this Script's state has changed.
notifyChange(null);
}
- void _applyHitsToLines() {
- for (var line in lines) {
- var hits = _hits[line.line];
- line.hits = hits;
- }
- }
-
void _addBreakpoint(Breakpoint bpt) {
var line;
if (bpt.location.tokenPos != null) {
@@ -3174,7 +3095,7 @@
if (line == lastLine) {
// Only one line.
- if (!getLine(line).isTrivialLine) {
+ if (!getLine(line).isTrivial) {
// TODO(johnmccutchan): end token pos -> column can lie for snapshotted
// code. e.g.:
// io_sink.dart source line 23 ends at column 39
@@ -3190,7 +3111,7 @@
}
// Scan first line.
- if (!getLine(line).isTrivialLine) {
+ if (!getLine(line).isTrivial) {
lineContents = getLine(line).text.substring(column);
r.addAll(scanLineForLocalVariableLocations(pattern,
name,
@@ -3201,7 +3122,7 @@
// Scan middle lines.
while (line < (lastLine - 1)) {
- if (getLine(line).isTrivialLine) {
+ if (getLine(line).isTrivial) {
line++;
continue;
}
@@ -3215,7 +3136,7 @@
}
// Scan last line.
- if (!getLine(line).isTrivialLine) {
+ if (!getLine(line).isTrivial) {
// TODO(johnmccutchan): end token pos -> column can lie for snapshotted
// code. e.g.:
// io_sink.dart source line 23 ends at column 39
@@ -4025,6 +3946,48 @@
}
+// Helper function to extract possible breakpoint locations from a
+// SourceReport for some script.
+Set<int> getPossibleBreakpointLines(ServiceMap report, Script script) {
+ var result = new Set<int>();
+ int scriptIndex;
+ int numScripts = report['scripts'].length;
+ for (scriptIndex = 0; scriptIndex < numScripts; scriptIndex++) {
+ if (report['scripts'][scriptIndex].id == script.id) {
+ break;
+ }
+ }
+ if (scriptIndex == numScripts) {
+ return result;
+ }
+ var ranges = report['ranges'];
+ if (ranges != null) {
+ for (var range in ranges) {
+ if (range['scriptIndex'] != scriptIndex) {
+ continue;
+ }
+ if (range['compiled']) {
+ var possibleBpts = range['possibleBreakpoints'];
+ if (possibleBpts != null) {
+ for (var tokenPos in possibleBpts) {
+ result.add(script.tokenToLine(tokenPos));
+ }
+ }
+ } else {
+ int startLine = script.tokenToLine(range['startPos']);
+ int endLine = script.tokenToLine(range['endPos']);
+ for (int line = startLine; line <= endLine; line++) {
+ if (!script.getLine(line).isTrivial) {
+ result.add(line);
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+
// Returns true if [map] is a service map. i.e. it has the following keys:
// 'id' and a 'type'.
bool _isServiceMap(ObservableMap m) {
diff --git a/runtime/observatory/tests/service/caching_test.dart b/runtime/observatory/tests/service/caching_test.dart
index 8a72447..6194ba6 100644
--- a/runtime/observatory/tests/service/caching_test.dart
+++ b/runtime/observatory/tests/service/caching_test.dart
@@ -13,27 +13,14 @@
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
-script() {
- print("This executed");
-}
-
-hasSomeCoverageData(Script script) {
- for (var line in script.lines) {
- if (line.hits != null) return true;
- }
- return false;
-}
-
var tests = [
(Isolate isolate) async {
Library lib = await isolate.rootLibrary.load();
Script script = await lib.scripts.single.load();
- expect(hasSomeCoverageData(script), isFalse);
- Script script2 = await script.refreshCoverage();
+ Script script2 = await isolate.getObject(script.id);
expect(identical(script, script2), isTrue);
- expect(hasSomeCoverageData(script), isTrue);
},
];
-main(args) => runIsolateTests(args, tests, testeeBefore: script);
+main(args) => runIsolateTests(args, tests);
diff --git a/runtime/observatory/tests/service/coverage_test.dart b/runtime/observatory/tests/service/coverage_test.dart
index 0255687..d1c71eb 100644
--- a/runtime/observatory/tests/service/coverage_test.dart
+++ b/runtime/observatory/tests/service/coverage_test.dart
@@ -69,7 +69,7 @@
expect(coverage['coverage'].length, equals(1));
expect(coverage['coverage'][0]['hits'],
equals([15, 1, 16, 0, 18, 1, 20, 1,
- 24, 1, 25, 1, 27, 0]));
+ 24, 1, 25, 1, 27, 0, 13, 0]));
// Library
coverage = await isolate.invokeRpcNoUpgrade('_getCoverage',
@@ -78,7 +78,7 @@
expect(coverage['coverage'].length, equals(4));
expect(coverage['coverage'][0]['hits'],
equals([15, 1, 16, 0, 18, 1, 20, 1,
- 24, 1, 25, 1, 27, 0]));
+ 24, 1, 25, 1, 27, 0, 13, 0]));
expect(coverage['coverage'][1]['hits'],
equals([33, 1, 34, 1, 105, 2]));
@@ -90,7 +90,7 @@
expect(coverage['coverage'].length, equals(4));
expect(coverage['coverage'][0]['hits'],
equals([15, 1, 16, 0, 18, 1, 20, 1,
- 24, 1, 25, 1, 27, 0]));
+ 24, 1, 25, 1, 27, 0, 13, 0]));
expect(coverage['coverage'][1]['hits'],
equals([33, 1, 34, 1, 105, 2]));
@@ -102,4 +102,6 @@
];
-main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);
+main(args) => runIsolateTests(args, tests,
+ testeeConcurrent: testFunction,
+ trace_service: true);
diff --git a/runtime/observatory/tests/service/debugger_location_test.dart b/runtime/observatory/tests/service/debugger_location_test.dart
index 7825ae6..ab50f4d 100644
--- a/runtime/observatory/tests/service/debugger_location_test.dart
+++ b/runtime/observatory/tests/service/debugger_location_test.dart
@@ -236,9 +236,7 @@
await DebuggerLocation.complete(debugger,
'debugger_location_test.dart:11');
expect(completions.toString(), equals(
- '[debugger_location_test.dart:11 ,'
- ' debugger_location_test.dart:11:,'
- ' debugger_location_test.dart:110 ,'
+ '[debugger_location_test.dart:110 ,'
' debugger_location_test.dart:110:,'
' debugger_location_test.dart:111 ,'
' debugger_location_test.dart:111:,'
diff --git a/runtime/observatory/tests/service/get_allocation_samples_test.dart b/runtime/observatory/tests/service/get_allocation_samples_test.dart
index 698fce5..a21ed9c 100644
--- a/runtime/observatory/tests/service/get_allocation_samples_test.dart
+++ b/runtime/observatory/tests/service/get_allocation_samples_test.dart
@@ -67,7 +67,7 @@
var tree = cpuProfile.loadCodeTree('exclusive');
var node = tree.root;
var expected =
- ['Root', 'test', 'test', '_FunctionImpl.call', 'runIsolateTests'];
+ ['Root', 'test', 'test', '_Closure.call', 'runIsolateTests'];
for (var i = 0; i < expected.length; i++) {
expect(node.profileCode.code.name, equals(expected[i]));
// Depth first traversal.
diff --git a/runtime/observatory/tests/service/get_source_report_test.dart b/runtime/observatory/tests/service/get_source_report_test.dart
index 71345ee..d306bca 100644
--- a/runtime/observatory/tests/service/get_source_report_test.dart
+++ b/runtime/observatory/tests/service/get_source_report_test.dart
@@ -110,7 +110,7 @@
expect(coverage['scripts'].length, greaterThan(1));
// Multiple reports (make sure enum list parameter parsing works).
- params = { 'reports' : ['CallSites', 'Coverage'],
+ params = { 'reports' : ['_CallSites', 'Coverage', 'PossibleBreakpoints'],
'scriptId' : func.location.script.id,
'tokenPos' : func.location.tokenPos,
'endTokenPos' : func.location.endTokenPos };
@@ -120,6 +120,7 @@
var range = coverage['ranges'][0];
expect(range.containsKey('callSites'), isTrue);
expect(range.containsKey('coverage'), isTrue);
+ expect(range.containsKey('possibleBreakpoints'), isTrue);
// missing scriptId with tokenPos.
bool caughtException = false;
diff --git a/runtime/observatory/tests/service/graph_test.dart b/runtime/observatory/tests/service/graph_test.dart
index 3cf8c46..fe31d16 100644
--- a/runtime/observatory/tests/service/graph_test.dart
+++ b/runtime/observatory/tests/service/graph_test.dart
@@ -71,9 +71,15 @@
bVertex.shallowSize +
rVertex.shallowSize));
- const int fixedSizeListCid = 62;
+ Library corelib =
+ isolate.libraries.singleWhere((lib) => lib.uri == 'dart:core');
+ await corelib.load();
+ Class _List =
+ corelib.classes.singleWhere((cls) => cls.vmName.startsWith('_List'));
+ int kArrayCid = _List.vmCid;
+ // startsWith to ignore the private mangling
List<ObjectVertex> lists = new List.from(graph.vertices.where(
- (ObjectVertex obj) => obj.vmCid == fixedSizeListCid));
+ (ObjectVertex obj) => obj.vmCid == kArrayCid));
expect(lists.length >= 2, isTrue);
// Order by decreasing retained size.
lists.sort((u, v) => v.retainedSize - u.retainedSize);
diff --git a/runtime/observatory/tests/service/issue_25465_test.dart b/runtime/observatory/tests/service/issue_25465_test.dart
new file mode 100644
index 0000000..3a739f0
--- /dev/null
+++ b/runtime/observatory/tests/service/issue_25465_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'dart:async';
+
+testMain() {
+ var foo; // line 11
+ foo = 42; // line 12
+ print(foo);
+}
+
+var tests = [
+ hasPausedAtStart,
+
+ // Add breakpoints at line 11 and line 12.
+ (Isolate isolate) async {
+ var rootLib = isolate.rootLibrary;
+ await rootLib.load();
+ var script = rootLib.scripts[0];
+
+ var bpt1 = await isolate.addBreakpoint(script, 11);
+ var bpt2 = await isolate.addBreakpoint(script, 12);
+ expect(await bpt1.location.getLine(), equals(11));
+ expect(await bpt2.location.getLine(), equals(12));
+
+ var stream = await isolate.vm.getEventStream(VM.kDebugStream);
+ Completer completer = new Completer();
+ var subscription;
+ var breakCount = 0;
+ subscription = stream.listen((ServiceEvent event) async {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ breakCount++;
+ print('break count is $breakCount');
+ if (breakCount == 1) {
+ // We are stopped at breakpoint 1.
+ expect(event.breakpoint.number, equals(bpt1.number));
+
+ // Remove both breakpoints
+ var result = await isolate.removeBreakpoint(bpt1);
+ expect(result.type, equals("Success"));
+
+ result = await isolate.removeBreakpoint(bpt2);
+ expect(result.type, equals("Success"));
+
+ isolate.stepOver();
+ } else {
+ // No breakpoint.
+ expect(event.breakpoint, isNull);
+
+ // We expect the next step to take us to line 12.
+ var stack = await isolate.getStack();
+ expect(await stack['frames'][0].location.getLine(), equals(12));
+
+ subscription.cancel();
+ completer.complete(null);
+ }
+ }
+ });
+ isolate.resume();
+ await completer.future;
+ },
+];
+
+main(args) => runIsolateTests(args, tests,
+ testeeConcurrent: testMain,
+ pause_on_start: true);
diff --git a/runtime/observatory/tests/service/pause_on_unhandled_exceptions_test.dart b/runtime/observatory/tests/service/pause_on_unhandled_exceptions_test.dart
new file mode 100644
index 0000000..4a6b2dd
--- /dev/null
+++ b/runtime/observatory/tests/service/pause_on_unhandled_exceptions_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'dart:async';
+
+doThrow() {
+ throw "TheException"; // Line 13.
+ return "end of doThrow";
+}
+
+var tests = [
+ hasStoppedWithUnhandledException,
+ (Isolate isolate) async {
+ var stack = await isolate.getStack();
+ expect(stack['frames'][0].function.name, equals('doThrow'));
+ }
+];
+
+main(args) => runIsolateTests(args,
+ tests,
+ pause_on_unhandled_exceptions: true,
+ testeeConcurrent: doThrow);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 7562cf4..8a572de 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -22,4 +22,7 @@
process_service_test: Pass, Fail # Issue 24344
[ ($noopt || $compiler == precompiler) ]
-*: Skip # Issue 24651
\ No newline at end of file
+*: Skip # Issue 24651
+
+[ $runtime == vm ]
+coverage_test: Pass Slow
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 58de4e6..6e64180 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -26,7 +26,10 @@
Platform.script.toFilePath(),
_TESTEE_MODE_FLAG] {}
- Future<int> launch(bool pause_on_start, bool pause_on_exit, bool trace_service) {
+ Future<int> launch(bool pause_on_start,
+ bool pause_on_exit,
+ bool pause_on_unhandled_exceptions,
+ bool trace_service) {
assert(pause_on_start != null);
assert(pause_on_exit != null);
assert(trace_service != null);
@@ -41,6 +44,9 @@
if (pause_on_exit) {
fullArgs.add('--pause-isolates-on-exit');
}
+ if (pause_on_unhandled_exceptions) {
+ fullArgs.add('--pause-isolates-on-unhandled-exceptions');
+ }
fullArgs.addAll(Platform.executableArguments);
fullArgs.addAll(args);
print('** Launching $dartExecutable ${fullArgs.join(' ')}');
@@ -110,7 +116,8 @@
bool pause_on_start: false,
bool pause_on_exit: false,
bool trace_service: false,
- bool verbose_vm: false}) {
+ bool verbose_vm: false,
+ bool pause_on_unhandled_exceptions: false}) {
assert(!pause_on_start || testeeBefore == null);
if (mainArgs.contains(_TESTEE_MODE_FLAG)) {
if (!pause_on_start) {
@@ -128,7 +135,8 @@
}
} else {
var process = new _TestLauncher();
- process.launch(pause_on_start, pause_on_exit, trace_service).then((port) {
+ process.launch(pause_on_start, pause_on_exit,
+ pause_on_unhandled_exceptions, trace_service).then((port) {
if (mainArgs.contains("--gdb")) {
port = 8181;
}
@@ -157,15 +165,14 @@
}
}
-
-Future<Isolate> hasStoppedAtBreakpoint(Isolate isolate) {
+Future<Isolate> hasPausedFor(Isolate isolate, String kind) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
var subscription;
subscription = stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print('Breakpoint reached');
+ if (event.kind == kind) {
+ print('Paused with $kind');
subscription.cancel();
if (completer != null) {
// Reload to update isolate.pauseEvent.
@@ -178,9 +185,9 @@
// Pause may have happened before we subscribed.
isolate.reload().then((_) {
if ((isolate.pauseEvent != null) &&
- (isolate.pauseEvent.kind == ServiceEvent.kPauseBreakpoint)) {
+ (isolate.pauseEvent.kind == kind)) {
// Already waiting at a breakpoint.
- print('Breakpoint reached');
+ print('Paused with $kind');
subscription.cancel();
if (completer != null) {
completer.complete(isolate);
@@ -193,6 +200,13 @@
return completer.future; // Will complete when breakpoint hit.
}
+Future<Isolate> hasStoppedAtBreakpoint(Isolate isolate) {
+ return hasPausedFor(isolate, ServiceEvent.kPauseBreakpoint);
+}
+
+Future<Isolate> hasStoppedWithUnhandledException(Isolate isolate) {
+ return hasPausedFor(isolate, ServiceEvent.kPauseException);
+}
Future<Isolate> hasPausedAtStart(Isolate isolate) {
// Set up a listener to wait for breakpoint events.
@@ -255,11 +269,13 @@
Frame top = frames[0];
Script script = await top.location.script.load();
- if (script.tokenToLine(top.location.tokenPos) != line) {
+ int actualLine = script.tokenToLine(top.location.tokenPos);
+ if (actualLine != line) {
var sb = new StringBuffer();
- sb.write("Expected to be at line $line, but got stack trace:\n");
+ sb.write("Expected to be at line $line but actually at line $actualLine");
+ sb.write("\nFull stack trace:\n");
for (Frame f in stack['frames']) {
- sb.write(" $f\n");
+ sb.write(" $f [${await f.location.getLine()}]\n");
}
throw sb.toString();
}
@@ -341,7 +357,8 @@
bool pause_on_start: false,
bool pause_on_exit: false,
bool trace_service: false,
- bool verbose_vm: false}) async {
+ bool verbose_vm: false,
+ bool pause_on_unhandled_exceptions: false}) async {
if (mainArgs.contains(_TESTEE_MODE_FLAG)) {
if (!pause_on_start) {
if (testeeBefore != null) {
@@ -360,6 +377,7 @@
var process = new _TestLauncher();
process.launch(pause_on_start,
pause_on_exit,
+ pause_on_unhandled_exceptions,
trace_service).then((port) async {
if (mainArgs.contains("--gdb")) {
port = 8181;
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index f5163a0..ade646c 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -21,6 +21,8 @@
# TODO(koda): Improve support for negative tests.
cc/VerifyImplicit_Crash: Crash, Timeout # Timeout: Issue #24596
cc/VerifyExplicit_Crash: Crash, Timeout # Timeout: Issue #24596
+# It can take some time for all the isolates to shutdown in a Debug build.
+dart/spawn_shutdown_test: Pass, Slow # VM Shutdown test
# The following section refers to the dart vm tests which live under
# runtime/tests/vm/dart.
@@ -31,7 +33,7 @@
cc/Dart2JSCompilerStats: Skip
cc/CorelibCompilerStats: Skip
-[ $arch == simarm || $arch == simarmv5te || $arch == simarm64 || $arch == simmips ]
+[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $arch == simmips ]
cc/Service_Profile: Skip
[ $arch == arm ]
diff --git a/runtime/tools/gyp/runtime-configurations.gypi b/runtime/tools/gyp/runtime-configurations.gypi
index 4f88987..0b053c4 100644
--- a/runtime/tools/gyp/runtime-configurations.gypi
+++ b/runtime/tools/gyp/runtime-configurations.gypi
@@ -92,6 +92,20 @@
},
},
+ 'Dart_simarmv6_Base': {
+ 'abstract': 1,
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386' ],
+ },
+ },
+
+ 'Dart_simarmv5te_Base': {
+ 'abstract': 1,
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386' ],
+ },
+ },
+
'Dart_simmips_Base': {
'abstract': 1,
'xcode_settings': {
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 12f470a..1e6e6ef 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -1798,10 +1798,20 @@
ASSEMBLER_TEST_RUN(IntDiv_supported, test) {
EXPECT(test != NULL);
+#if defined(USING_SIMULATOR)
+ bool orig = TargetCPUFeatures::integer_division_supported();
+ HostCPUFeatures::set_integer_division_supported(true);
if (TargetCPUFeatures::can_divide()) {
typedef int (*Tst)() DART_UNUSED;
EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
+ HostCPUFeatures::set_integer_division_supported(orig);
+#else
+ if (TargetCPUFeatures::can_divide()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
+#endif
}
@@ -1829,10 +1839,20 @@
ASSEMBLER_TEST_RUN(IntDiv_unsupported, test) {
EXPECT(test != NULL);
+#if defined(USING_SIMULATOR)
+ bool orig = TargetCPUFeatures::integer_division_supported();
+ HostCPUFeatures::set_integer_division_supported(false);
if (TargetCPUFeatures::can_divide()) {
typedef int (*Tst)() DART_UNUSED;
EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
+ HostCPUFeatures::set_integer_division_supported(orig);
+#else
+ if (TargetCPUFeatures::can_divide()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
+#endif
}
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 19542b3..2deefa2 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -121,6 +121,36 @@
}
}
+bool LetNode::IsPotentiallyConst() const {
+ for (intptr_t i = 0; i < num_temps(); i++) {
+ if (!initializers_[i]->IsPotentiallyConst()) {
+ return false;
+ }
+ }
+ for (intptr_t i = 0; i < nodes_.length(); i++) {
+ if (!nodes_[i]->IsPotentiallyConst()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+const Instance* LetNode::EvalConstExpr() const {
+ for (intptr_t i = 0; i < num_temps(); i++) {
+ if (initializers_[i]->EvalConstExpr() == NULL) {
+ return NULL;
+ }
+ }
+ const Instance* last = NULL;
+ for (intptr_t i = 0; i < nodes_.length(); i++) {
+ last = nodes_[i]->EvalConstExpr();
+ if (last == NULL) {
+ return NULL;
+ }
+ }
+ return last;
+}
+
void ArrayNode::VisitChildren(AstNodeVisitor* visitor) const {
for (intptr_t i = 0; i < this->length(); i++) {
@@ -329,6 +359,7 @@
case Token::kBIT_AND:
case Token::kSHL:
case Token::kSHR:
+ case Token::kIFNULL:
return this->left()->IsPotentiallyConst() &&
this->right()->IsPotentiallyConst();
default:
@@ -343,7 +374,8 @@
if (left_val == NULL) {
return NULL;
}
- if (!left_val->IsNumber() && !left_val->IsBool() && !left_val->IsString()) {
+ if (!left_val->IsNumber() && !left_val->IsBool() && !left_val->IsString() &&
+ kind_ != Token::kIFNULL) {
return NULL;
}
const Instance* right_val = this->right()->EvalConstExpr();
@@ -388,6 +420,11 @@
return left_val;
}
return NULL;
+ case Token::kIFNULL:
+ if (left_val->IsNull()) {
+ return right_val;
+ }
+ return left_val;
default:
UNREACHABLE();
return NULL;
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 01ae0cf..494d768 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -99,7 +99,8 @@
public:
explicit AstNode(intptr_t token_pos)
: token_pos_(token_pos) {
- ASSERT(Scanner::ValidSourcePosition(token_pos_));
+ ASSERT(!Token::IsClassifying(token_pos_) ||
+ (token_pos_ == ClassifyingTokenPositions::kMethodExtractor));
}
virtual ~AstNode() { }
@@ -327,6 +328,9 @@
LocalVariable* TempAt(intptr_t i) const { return vars_[i]; }
AstNode* InitializerAt(intptr_t i) const { return initializers_[i]; }
+ virtual bool IsPotentiallyConst() const;
+ virtual const Instance* EvalConstExpr() const;
+
LocalVariable* AddInitializer(AstNode* node);
const GrowableArray<AstNode*>& nodes() const { return nodes_; }
diff --git a/runtime/vm/ast_printer_test.cc b/runtime/vm/ast_printer_test.cc
index 872d5bb..9ac8d72 100644
--- a/runtime/vm/ast_printer_test.cc
+++ b/runtime/vm/ast_printer_test.cc
@@ -13,7 +13,7 @@
namespace dart {
TEST_CASE(AstPrinter) {
- const intptr_t kPos = Scanner::kNoSourcePos;
+ const intptr_t kPos = Token::kNoSourcePos;
LocalVariable* v =
new LocalVariable(kPos,
String::ZoneHandle(Symbols::New("wurscht")),
diff --git a/runtime/vm/ast_test.cc b/runtime/vm/ast_test.cc
index 83fea1b..afe4bdb 100644
--- a/runtime/vm/ast_test.cc
+++ b/runtime/vm/ast_test.cc
@@ -13,10 +13,10 @@
namespace dart {
TEST_CASE(Ast) {
- LocalVariable* v = new LocalVariable(Scanner::kNoSourcePos,
+ LocalVariable* v = new LocalVariable(Token::kNoSourcePos,
String::ZoneHandle(Symbols::New("v")),
Type::ZoneHandle(Type::DynamicType()));
- AstNode* ll = new LoadLocalNode(Scanner::kNoSourcePos, v);
+ AstNode* ll = new LoadLocalNode(Token::kNoSourcePos, v);
EXPECT(ll->IsLoadLocalNode());
EXPECT(!ll->IsLiteralNode());
LoadLocalNode* lln = ll->AsLoadLocalNode();
@@ -24,7 +24,7 @@
v->set_index(1);
EXPECT_EQ(1, v->index());
- LocalVariable* p = new LocalVariable(Scanner::kNoSourcePos,
+ LocalVariable* p = new LocalVariable(Token::kNoSourcePos,
String::ZoneHandle(Symbols::New("p")),
Type::ZoneHandle(Type::DynamicType()));
EXPECT(!p->HasIndex());
@@ -32,22 +32,22 @@
EXPECT(p->HasIndex());
EXPECT_EQ(-1, p->index());
- ReturnNode* r = new ReturnNode(Scanner::kNoSourcePos, lln);
+ ReturnNode* r = new ReturnNode(Token::kNoSourcePos, lln);
EXPECT_EQ(lln, r->value());
LiteralNode* l =
- new LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(3)));
+ new LiteralNode(Token::kNoSourcePos, Smi::ZoneHandle(Smi::New(3)));
EXPECT(l->literal().IsSmi());
EXPECT_EQ(Smi::New(3), l->literal().raw());
BinaryOpNode* b =
- new BinaryOpNode(Scanner::kNoSourcePos, Token::kADD, l, lln);
+ new BinaryOpNode(Token::kNoSourcePos, Token::kADD, l, lln);
EXPECT_EQ(Token::kADD, b->kind());
EXPECT_EQ(l, b->left());
EXPECT_EQ(lln, b->right());
UnaryOpNode* u =
- new UnaryOpNode(Scanner::kNoSourcePos, Token::kNEGATE, b);
+ new UnaryOpNode(Token::kNoSourcePos, Token::kNEGATE, b);
EXPECT_EQ(Token::kNEGATE, u->kind());
EXPECT_EQ(b, u->operand());
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index 32ec3f9..8954f0a 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -13,6 +13,9 @@
// Quick access to the current zone.
#define Z (thread()->zone())
+// Quick synthetic token position.
+#define ST(token_pos) Token::ToSynthetic(token_pos)
+
// Nodes that are unreachable from already parsed expressions.
#define FOR_EACH_UNREACHABLE_NODE(V) \
V(AwaitMarker) \
@@ -71,7 +74,7 @@
if (await_tmp == NULL) {
// We need a new temp variable; add it to the function's top scope.
await_tmp = new (Z) LocalVariable(
- Scanner::kNoSourcePos, symbol, Object::dynamic_type());
+ Token::kNoSourcePos, symbol, Object::dynamic_type());
async_temp_scope_->AddVariable(await_tmp);
// After adding it to the top scope, we can look it up from the preamble.
// The following call includes an ASSERT check.
@@ -89,9 +92,11 @@
}
-LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) {
+LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node,
+ intptr_t token_pos) {
LocalVariable* tmp_var = EnsureCurrentTempVar();
- preamble_->Add(new(Z) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node));
+ ASSERT(Token::IsSynthetic(token_pos) || Token::IsNoSource(token_pos));
+ preamble_->Add(new(Z) StoreLocalNode(token_pos, tmp_var, node));
NextTempVar();
return tmp_var;
}
@@ -119,7 +124,7 @@
// :saved_try_ctx_var = :await_saved_try_ctx_var_y;
// :await_temp_var_(X+1) = :result_param;
- const intptr_t token_pos = node->token_pos();
+ const intptr_t token_pos = ST(node->token_pos());
LocalVariable* async_op = GetVariableInScope(
preamble_->scope(), Symbols::AsyncOperation());
LocalVariable* async_then_callback = GetVariableInScope(
@@ -134,7 +139,8 @@
preamble_->scope(), Symbols::AsyncOperationStackTraceParam());
AstNode* transformed_expr = Transform(node->expr());
- LocalVariable* await_temp = AddToPreambleNewTempVar(transformed_expr);
+ LocalVariable* await_temp = AddToPreambleNewTempVar(transformed_expr,
+ ST(node->token_pos()));
AwaitMarkerNode* await_marker =
new (Z) AwaitMarkerNode(async_temp_scope_, node->scope(), token_pos);
@@ -146,23 +152,23 @@
const Function& async_await_helper = Function::ZoneHandle(
Z, async_lib.LookupFunctionAllowPrivate(Symbols::AsyncAwaitHelper()));
ASSERT(!async_await_helper.IsNull());
- ArgumentListNode* async_await_helper_args = new (Z) ArgumentListNode(
- Scanner::kNoSourcePos);
+ ArgumentListNode* async_await_helper_args =
+ new (Z) ArgumentListNode(token_pos);
async_await_helper_args->Add(
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, await_temp));
+ new(Z) LoadLocalNode(token_pos, await_temp));
async_await_helper_args->Add(
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, async_then_callback));
+ new(Z) LoadLocalNode(token_pos, async_then_callback));
async_await_helper_args->Add(
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, async_catch_error_callback));
+ new(Z) LoadLocalNode(token_pos, async_catch_error_callback));
StaticCallNode* await_helper_call = new (Z) StaticCallNode(
node->token_pos(),
async_await_helper,
async_await_helper_args);
preamble_->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos, result_param, await_helper_call));
+ token_pos, result_param, await_helper_call));
- ReturnNode* continuation_return = new(Z) ReturnNode(Scanner::kNoSourcePos);
+ ReturnNode* continuation_return = new(Z) ReturnNode(token_pos);
continuation_return->set_return_type(ReturnNode::kContinuationTarget);
preamble_->Add(continuation_return);
@@ -171,15 +177,15 @@
// saved try context of the outer try block.
if (node->saved_try_ctx() != NULL) {
preamble_->Add(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ token_pos,
node->saved_try_ctx(),
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(token_pos,
node->async_saved_try_ctx())));
if (node->outer_saved_try_ctx() != NULL) {
preamble_->Add(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ token_pos,
node->outer_saved_try_ctx(),
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(token_pos,
node->outer_async_saved_try_ctx())));
}
} else {
@@ -188,34 +194,33 @@
// Load the async_op variable. It is unused, but the observatory uses it
// to determine if a breakpoint is inside an asynchronous function.
- LoadLocalNode* load_async_op = new (Z) LoadLocalNode(
- Scanner::kNoSourcePos, async_op);
+ LoadLocalNode* load_async_op = new (Z) LoadLocalNode(token_pos, async_op);
preamble_->Add(load_async_op);
LoadLocalNode* load_error_param = new (Z) LoadLocalNode(
- Scanner::kNoSourcePos, error_param);
+ token_pos, error_param);
LoadLocalNode* load_stack_trace_param = new (Z) LoadLocalNode(
- Scanner::kNoSourcePos, stack_trace_param);
+ token_pos, stack_trace_param);
SequenceNode* error_ne_null_branch = new (Z) SequenceNode(
- Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+ token_pos, ChainNewScope(preamble_->scope()));
error_ne_null_branch->Add(new (Z) ThrowNode(
- Scanner::kNoSourcePos,
+ token_pos,
load_error_param,
load_stack_trace_param));
preamble_->Add(new (Z) IfNode(
- Scanner::kNoSourcePos,
+ token_pos,
new (Z) ComparisonNode(
- Scanner::kNoSourcePos,
+ token_pos,
Token::kNE,
load_error_param,
- new (Z) LiteralNode(Scanner::kNoSourcePos,
+ new (Z) LiteralNode(token_pos,
Object::null_instance())),
error_ne_null_branch,
NULL));
LocalVariable* result = AddToPreambleNewTempVar(new(Z) LoadLocalNode(
- Scanner::kNoSourcePos, result_param));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ token_pos, result_param), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(token_pos, result);
}
@@ -242,18 +247,18 @@
const Token::Kind compare_logical_op = (logical_op == Token::kAND) ?
Token::kEQ : Token::kNE;
SequenceNode* eval = new (Z) SequenceNode(
- Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+ ST(new_left->token_pos()), ChainNewScope(preamble_->scope()));
SequenceNode* saved_preamble = preamble_;
preamble_ = eval;
result = Transform(right);
preamble_ = saved_preamble;
IfNode* right_body = new(Z) IfNode(
- Scanner::kNoSourcePos,
+ ST(new_left->token_pos()),
new(Z) ComparisonNode(
- Scanner::kNoSourcePos,
+ ST(new_left->token_pos()),
compare_logical_op,
new_left,
- new(Z) LiteralNode(Scanner::kNoSourcePos, Bool::True())),
+ new(Z) LiteralNode(ST(new_left->token_pos()), Bool::True())),
eval,
NULL);
preamble_->Add(right_body);
@@ -280,8 +285,8 @@
new(Z) BinaryOpNode(node->token_pos(),
node->kind(),
new_left,
- new_right));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ new_right), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -295,8 +300,8 @@
node->kind(),
new_left,
new_right,
- node->mask32()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->mask32()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -307,16 +312,17 @@
new(Z) ComparisonNode(node->token_pos(),
node->kind(),
new_left,
- new_right));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ new_right), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
AstNode* new_operand = Transform(node->operand());
LocalVariable* result = AddToPreambleNewTempVar(
- new(Z) UnaryOpNode(node->token_pos(), node->kind(), new_operand));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ new(Z) UnaryOpNode(node->token_pos(), node->kind(), new_operand),
+ ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -325,26 +331,26 @@
void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
AstNode* new_condition = Transform(node->condition());
SequenceNode* new_true = new (Z) SequenceNode(
- Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+ ST(node->true_expr()->token_pos()), ChainNewScope(preamble_->scope()));
SequenceNode* saved_preamble = preamble_;
preamble_ = new_true;
AstNode* new_true_result = Transform(node->true_expr());
SequenceNode* new_false = new (Z) SequenceNode(
- Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+ ST(node->false_expr()->token_pos()), ChainNewScope(preamble_->scope()));
preamble_ = new_false;
AstNode* new_false_result = Transform(node->false_expr());
preamble_ = saved_preamble;
- IfNode* new_if = new(Z) IfNode(Scanner::kNoSourcePos,
+ IfNode* new_if = new(Z) IfNode(ST(node->token_pos()),
new_condition,
new_true,
new_false);
preamble_->Add(new_if);
LocalVariable* result = AddToPreambleNewTempVar(
- new(Z) ConditionalExprNode(Scanner::kNoSourcePos,
+ new(Z) ConditionalExprNode(ST(node->token_pos()),
new_condition,
new_true_result,
- new_false_result));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ new_false_result), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -371,8 +377,8 @@
ArrayNode* new_value = Transform(node->value())->AsArrayNode();
LocalVariable* result = AddToPreambleNewTempVar(
new(Z) StringInterpolateNode(node->token_pos(),
- new_value));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ new_value), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -385,8 +391,8 @@
new(Z) ClosureNode(node->token_pos(),
node->function(),
new_receiver,
- node->scope()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->scope()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -399,8 +405,8 @@
new_receiver,
node->function_name(),
new_args,
- node->is_conditional()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->is_conditional()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -410,8 +416,8 @@
LocalVariable* result = AddToPreambleNewTempVar(
new(Z) StaticCallNode(node->token_pos(),
node->function(),
- new_args));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ new_args), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -422,8 +428,8 @@
new(Z) ConstructorCallNode(node->token_pos(),
node->type_arguments(),
node->constructor(),
- new_args));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ new_args), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -433,8 +439,8 @@
new(Z) InstanceGetterNode(node->token_pos(),
new_receiver,
node->field_name(),
- node->is_conditional()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->is_conditional()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -449,8 +455,8 @@
new_receiver,
node->field_name(),
new_value,
- node->is_conditional()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->is_conditional()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -465,8 +471,9 @@
node->cls(),
node->field_name());
new_getter->set_owner(node->owner());
- LocalVariable* result = AddToPreambleNewTempVar(new_getter);
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ LocalVariable* result =
+ AddToPreambleNewTempVar(new_getter, ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -489,8 +496,9 @@
node->function(),
new_value);
- LocalVariable* result = AddToPreambleNewTempVar(new_setter);
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ LocalVariable* result =
+ AddToPreambleNewTempVar(new_setter, ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -525,8 +533,8 @@
new(Z) LoadIndexedNode(node->token_pos(),
new_array,
new_index,
- node->super_class()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->super_class()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -539,8 +547,8 @@
new_array,
new_index,
new_value,
- node->super_class()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->super_class()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -550,8 +558,8 @@
new(Z) AssignableNode(node->token_pos(),
new_expr,
node->type(),
- node->dst_name()));
- result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+ node->dst_name()), ST(node->token_pos()));
+ result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
}
@@ -565,8 +573,8 @@
async_temp_scope_->AddVariable(node->TempAt(i));
AstNode* new_init_val = Transform(node->InitializerAt(i));
preamble_->Add(new(Z) StoreLocalNode(node->token_pos(),
- node->TempAt(i),
- new_init_val));
+ node->TempAt(i),
+ new_init_val));
}
// Add all expressions but the last to the preamble. We must do
diff --git a/runtime/vm/ast_transformer.h b/runtime/vm/ast_transformer.h
index e9f6791..d8c01d0 100644
--- a/runtime/vm/ast_transformer.h
+++ b/runtime/vm/ast_transformer.h
@@ -51,7 +51,7 @@
private:
LocalVariable* EnsureCurrentTempVar();
- LocalVariable* AddToPreambleNewTempVar(AstNode* node);
+ LocalVariable* AddToPreambleNewTempVar(AstNode* node, intptr_t token_pos);
ArgumentListNode* TransformArguments(ArgumentListNode* node);
AstNode* LazyTransform(const Token::Kind kind,
AstNode* new_left,
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 7596920..f7bd22d 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -339,13 +339,11 @@
SetupNativeResolver();
ClassFinalizer::ProcessPendingClasses();
- Class& cls = Class::Handle(zone);
- // Eagerly compile the function implementation class as it is the super
- // class of signature classes. This allows us to just finalize signature
- // classes without going through the hoops of trying to compile them.
- const Type& type =
- Type::Handle(zone, isolate->object_store()->function_impl_type());
- cls = type.type_class();
+ // Eagerly compile the _Closure class as it is the class of all closure
+ // instances. This allows us to just finalize function types
+ // without going through the hoops of trying to compile their scope class.
+ const Class& cls =
+ Class::Handle(zone, isolate->object_store()->closure_class());
Compiler::CompileClass(cls);
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 8803755..26e4d5d 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -28,9 +28,9 @@
V(Object_instanceOfString, 2) \
V(Object_as, 3) \
V(Function_apply, 2) \
- V(FunctionImpl_equals, 2) \
- V(FunctionImpl_hashCode, 1) \
- V(FunctionImpl_clone, 1) \
+ V(Closure_equals, 2) \
+ V(Closure_hashCode, 1) \
+ V(Closure_clone, 1) \
V(AbstractType_toString, 1) \
V(Identical_comparison, 2) \
V(Integer_bitAndFromInteger, 2) \
diff --git a/runtime/vm/cha.cc b/runtime/vm/cha.cc
index 667d598..ed5255e 100644
--- a/runtime/vm/cha.cc
+++ b/runtime/vm/cha.cc
@@ -49,8 +49,8 @@
bool CHA::IsImplemented(const Class& cls) {
- // Signature classes have different type checking rules.
- ASSERT(!cls.IsSignatureClass());
+ // Function type aliases have different type checking rules.
+ ASSERT(!cls.IsTypedefClass());
// Can't track dependencies for classes on the VM heap since those are
// read-only.
// TODO(fschneider): Enable tracking of CHA dependent code for VM heap
diff --git a/runtime/vm/cha_test.cc b/runtime/vm/cha_test.cc
index a7c998d..7712324 100644
--- a/runtime/vm/cha_test.cc
+++ b/runtime/vm/cha_test.cc
@@ -98,10 +98,9 @@
EXPECT(ContainsCid(cha.leaf_classes(), class_c.id()));
EXPECT(ContainsCid(cha.leaf_classes(), class_d.id()));
- const Class& function_impl_class =
- Class::Handle(Type::Handle(Isolate::Current()->object_store()->
- function_impl_type()).type_class());
- EXPECT(cha.HasSubclasses(function_impl_class.id()));
+ const Class& closure_class =
+ Class::Handle(Isolate::Current()->object_store()->closure_class());
+ EXPECT(!cha.HasSubclasses(closure_class.id()));
}
} // namespace dart
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 8ef3511..67b3683 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -440,7 +440,8 @@
if (!target_type.IsInstantiated()) {
const TypeArguments& type_args = TypeArguments::Handle(type.arguments());
Error& bound_error = Error::Handle();
- target_type ^= target_type.InstantiateFrom(type_args, &bound_error);
+ target_type ^= target_type.InstantiateFrom(
+ type_args, &bound_error, NULL, Heap::kOld);
if (bound_error.IsNull()) {
target_type ^= FinalizeType(cls, target_type, kCanonicalize);
} else {
@@ -457,10 +458,10 @@
}
-void ClassFinalizer::ResolveTypeClass(const Class& cls,
- const AbstractType& type) {
- if (type.IsFinalized() || type.HasResolvedTypeClass()) {
- return;
+RawAbstractType* ClassFinalizer::ResolveTypeClass(const Class& cls,
+ const Type& type) {
+ if (type.IsFinalized()) {
+ return type.raw();
}
if (FLAG_trace_type_finalization) {
THR_Print("Resolve type class of '%s'\n",
@@ -473,55 +474,77 @@
// that the type parameter appeared in a static scope. Leaving the type as
// unresolved is the correct thing to do.
- // Lookup the type class.
- const UnresolvedClass& unresolved_class =
- UnresolvedClass::Handle(type.unresolved_class());
- const Class& type_class =
- Class::Handle(ResolveClass(cls, unresolved_class));
-
- // Replace unresolved class with resolved type class.
- const Type& parameterized_type = Type::Cast(type);
- if (type_class.IsNull()) {
- // The type class could not be resolved. The type is malformed.
- FinalizeMalformedType(
- Error::Handle(), // No previous error.
- Script::Handle(cls.script()),
- parameterized_type,
- "cannot resolve class '%s' from '%s'",
- String::Handle(unresolved_class.Name()).ToCString(),
- String::Handle(cls.Name()).ToCString());
- return;
+ // Lookup the type class if necessary.
+ Class& type_class = Class::Handle();
+ if (type.HasResolvedTypeClass()) {
+ type_class = type.type_class();
+ } else {
+ const UnresolvedClass& unresolved_class =
+ UnresolvedClass::Handle(type.unresolved_class());
+ type_class = ResolveClass(cls, unresolved_class);
+ if (type_class.IsNull()) {
+ // The type class could not be resolved. The type is malformed.
+ FinalizeMalformedType(
+ Error::Handle(), // No previous error.
+ Script::Handle(cls.script()),
+ type,
+ "cannot resolve class '%s' from '%s'",
+ String::Handle(unresolved_class.Name()).ToCString(),
+ String::Handle(cls.Name()).ToCString());
+ return type.raw();
+ }
}
- parameterized_type.set_type_class(type_class);
+ // Promote the Type to a FunctionType in case its type class is a typedef.
+ if (type_class.IsTypedefClass()) {
+ return FunctionType::New(type_class,
+ TypeArguments::Handle(type.arguments()),
+ Function::Handle(type_class.signature_function()),
+ type.token_pos());
+ }
+ // Replace unresolved class with resolved type class.
+ type.set_type_class(type_class);
+ return type.raw();
}
-void ClassFinalizer::ResolveType(const Class& cls, const AbstractType& type) {
+RawAbstractType* ClassFinalizer::ResolveType(const Class& cls,
+ const AbstractType& type) {
if (type.IsResolved()) {
- return;
+ return type.raw();
}
- ASSERT(type.IsType());
if (FLAG_trace_type_finalization) {
THR_Print("Resolve type '%s'\n", String::Handle(type.Name()).ToCString());
}
- ResolveTypeClass(cls, type);
- if (type.IsMalformed()) {
- ASSERT(type.IsResolved());
- return;
+ AbstractType& resolved_type = AbstractType::Handle();
+ if (type.IsType()) {
+ resolved_type = ResolveTypeClass(cls, Type::Cast(type));
+ if (resolved_type.IsMalformed()) {
+ ASSERT(resolved_type.IsResolved());
+ return resolved_type.raw();
+ }
+ } else {
+ ASSERT(type.IsFunctionType());
+ const Function& signature =
+ Function::Handle(FunctionType::Cast(type).signature());
+ ResolveSignature(cls, signature);
+ resolved_type = type.raw();
}
// Mark type as resolved before resolving its type arguments in order to avoid
// repeating resolution of recursive types.
- Type::Cast(type).set_is_resolved();
+ resolved_type.SetIsResolved();
// Resolve type arguments, if any.
- const TypeArguments& arguments = TypeArguments::Handle(type.arguments());
+ const TypeArguments& arguments =
+ TypeArguments::Handle(resolved_type.arguments());
if (!arguments.IsNull()) {
const intptr_t num_arguments = arguments.Length();
AbstractType& type_argument = AbstractType::Handle();
for (intptr_t i = 0; i < num_arguments; i++) {
type_argument = arguments.TypeAt(i);
- ResolveType(cls, type_argument);
+ type_argument = ResolveType(cls, type_argument);
+ arguments.SetTypeAt(i, type_argument);
}
}
+ return resolved_type.raw();
}
@@ -564,7 +587,7 @@
// A non-contractive type can be detected by looking at the queue of types
// pending finalization that are mutually recursive with the checked type.
void ClassFinalizer::CheckRecursiveType(const Class& cls,
- const Type& type,
+ const AbstractType& type,
PendingTypes* pending_types) {
Zone* zone = Thread::Current()->zone();
if (FLAG_trace_type_finalization) {
@@ -620,6 +643,127 @@
}
+// Expand the type arguments of the given type and finalize its full type
+// argument vector. Return the number of type arguments (0 for a raw type).
+intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments(
+ const Class& cls,
+ const AbstractType& type,
+ PendingTypes* pending_types) {
+ Zone* Z = Thread::Current()->zone();
+ // The type class does not need to be finalized in order to finalize the type,
+ // however, it must at least be resolved (this was done as part of resolving
+ // the type itself, a precondition to calling FinalizeType).
+ // Also, the interfaces of the type class must be resolved and the type
+ // parameters of the type class must be finalized.
+ Class& type_class = Class::Handle(Z, type.type_class());
+ if (!type_class.is_type_finalized()) {
+ FinalizeTypeParameters(type_class, pending_types);
+ ResolveUpperBounds(type_class);
+ }
+
+ // The finalized type argument vector needs num_type_arguments types.
+ const intptr_t num_type_arguments = type_class.NumTypeArguments();
+ // The class has num_type_parameters type parameters.
+ const intptr_t num_type_parameters = type_class.NumTypeParameters();
+
+ // Initialize the type argument vector.
+ // Check the number of parsed type arguments, if any.
+ // Specifying no type arguments indicates a raw type, which is not an error.
+ // However, type parameter bounds are checked below, even for a raw type.
+ TypeArguments& arguments = TypeArguments::Handle(Z, type.arguments());
+ if (!arguments.IsNull() && (arguments.Length() != num_type_parameters)) {
+ // Wrong number of type arguments. The type is mapped to the raw type.
+ if (Isolate::Current()->flags().error_on_bad_type()) {
+ const String& type_class_name = String::Handle(Z, type_class.Name());
+ ReportError(cls, type.token_pos(),
+ "wrong number of type arguments for class '%s'",
+ type_class_name.ToCString());
+ }
+ // Make the type raw and continue without reporting any error.
+ // A static warning should have been reported.
+ arguments = TypeArguments::null();
+ type.set_arguments(arguments);
+ }
+
+ // Mark the type as being finalized in order to detect self reference and
+ // postpone bound checking until after all types in the graph of
+ // mutually recursive types are finalized.
+ type.SetIsBeingFinalized();
+ pending_types->Add(type);
+
+ // The full type argument vector consists of the type arguments of the
+ // super types of type_class, which are initialized from the parsed
+ // type arguments, followed by the parsed type arguments.
+ TypeArguments& full_arguments = TypeArguments::Handle(Z);
+ if (num_type_arguments > 0) {
+ // If no type arguments were parsed and if the super types do not prepend
+ // type arguments to the vector, we can leave the vector as null.
+ if (!arguments.IsNull() || (num_type_arguments > num_type_parameters)) {
+ full_arguments = TypeArguments::New(num_type_arguments);
+ // Copy the parsed type arguments at the correct offset in the full type
+ // argument vector.
+ const intptr_t offset = num_type_arguments - num_type_parameters;
+ AbstractType& type_arg =
+ AbstractType::Handle(Z, Type::DynamicType());
+ // Leave the temporary type arguments at indices [0..offset[ as null.
+ for (intptr_t i = 0; i < num_type_parameters; i++) {
+ // If no type parameters were provided, a raw type is desired, so we
+ // create a vector of dynamic.
+ if (!arguments.IsNull()) {
+ type_arg = arguments.TypeAt(i);
+ // The parsed type_arg may or may not be finalized.
+ }
+ full_arguments.SetTypeAt(offset + i, type_arg);
+ }
+ // Replace the compile-time argument vector (of length zero or
+ // num_type_parameters) of this type being finalized with the still
+ // unfinalized run-time argument vector (of length num_type_arguments).
+ // This type being finalized may be recursively reached via bounds
+ // checking or type arguments of its super type.
+ type.set_arguments(full_arguments);
+ // Finalize the current type arguments of the type, which are still the
+ // parsed type arguments.
+ if (!arguments.IsNull()) {
+ for (intptr_t i = 0; i < num_type_parameters; i++) {
+ type_arg = full_arguments.TypeAt(offset + i);
+ ASSERT(!type_arg.IsBeingFinalized());
+ type_arg = FinalizeType(cls, type_arg, kFinalize, pending_types);
+ if (type_arg.IsMalformed()) {
+ // Malformed type arguments are mapped to dynamic.
+ type_arg = Type::DynamicType();
+ }
+ full_arguments.SetTypeAt(offset + i, type_arg);
+ }
+ }
+ if (offset > 0) {
+ TrailPtr trail = new Trail(Z, 4);
+ Error& bound_error = Error::Handle();
+ FinalizeTypeArguments(type_class, full_arguments, offset,
+ &bound_error, pending_types, trail);
+ }
+ if (full_arguments.IsRaw(0, num_type_arguments)) {
+ // The parameterized_type is raw. Set its argument vector to null, which
+ // is more efficient in type tests.
+ full_arguments = TypeArguments::null();
+ }
+ type.set_arguments(full_arguments);
+ } else {
+ ASSERT(full_arguments.IsNull()); // Use null vector for raw type.
+ }
+ }
+
+ // Self referencing types may get finalized indirectly.
+ if (!type.IsFinalized()) {
+ ASSERT(full_arguments.IsNull() ||
+ !full_arguments.IsRaw(0, num_type_arguments));
+ // Mark the type as finalized.
+ type.SetIsFinalized();
+ // Do not yet remove the type from the pending_types array.
+ }
+ return full_arguments.IsNull() ? 0 : full_arguments.Length();
+}
+
+
// Finalize the type argument vector 'arguments' of the type defined by the
// class 'cls' parameterized with the type arguments 'cls_args'.
// The vector 'cls_args' is already initialized as a subvector at the correct
@@ -687,8 +831,8 @@
super_type_arg = super_type_args.TypeAt(i);
if (!super_type_arg.IsTypeRef()) {
if (super_type_arg.IsBeingFinalized()) {
- ASSERT(super_type_arg.IsType());
- CheckRecursiveType(cls, Type::Cast(super_type_arg), pending_types);
+ ASSERT(super_type_arg.IsType() || super_type_arg.IsFunctionType());
+ CheckRecursiveType(cls, super_type_arg, pending_types);
if (FLAG_trace_type_finalization) {
THR_Print("Creating TypeRef '%s': '%s'\n",
String::Handle(super_type_arg.Name()).ToCString(),
@@ -737,7 +881,7 @@
if (super_type_arg.IsTypeRef()) {
super_type_arg = TypeRef::Cast(super_type_arg).type();
}
- Type::Cast(super_type_arg).set_is_being_finalized();
+ Type::Cast(super_type_arg).SetIsBeingFinalized();
pending_types->Add(super_type_arg);
const Class& cls = Class::Handle(super_type_arg.type_class());
FinalizeTypeArguments(
@@ -844,9 +988,10 @@
if (type_arg.IsTypeParameter()) {
const Class& type_arg_cls = Class::Handle(
TypeParameter::Cast(type_arg).parameterized_class());
- const AbstractType& bound = AbstractType::Handle(
+ AbstractType& bound = AbstractType::Handle(
TypeParameter::Cast(type_arg).bound());
- ResolveType(type_arg_cls, bound);
+ bound = ResolveType(type_arg_cls, bound);
+ TypeParameter::Cast(type_arg).set_bound(bound);
}
// This may be called only if type needs to be finalized, therefore
// seems OK to allocate finalized types in old space.
@@ -870,24 +1015,17 @@
}
-void ClassFinalizer::CheckTypeBounds(const Class& cls, const Type& type) {
+void ClassFinalizer::CheckTypeBounds(const Class& cls,
+ const AbstractType& type) {
+ ASSERT(type.IsType() || type.IsFunctionType());
ASSERT(type.IsFinalized());
TypeArguments& arguments = TypeArguments::Handle(type.arguments());
if (arguments.IsNull()) {
return;
}
- Class& owner_class = Class::Handle();
- Class& type_class = Class::Handle(type.type_class());
- if (type_class.IsSignatureClass()) {
- const Function& signature_fun =
- Function::Handle(type_class.signature_function());
- ASSERT(!signature_fun.is_static());
- owner_class = signature_fun.Owner();
- } else {
- owner_class = type_class.raw();
- }
+ const Class& type_class = Class::Handle(type.type_class());
Error& bound_error = Error::Handle();
- CheckTypeArgumentBounds(owner_class, arguments, &bound_error);
+ CheckTypeArgumentBounds(type_class, arguments, &bound_error);
type.set_arguments(arguments);
// If a bound error occurred, mark the type as malbounded.
// The bound error will be ignored in production mode.
@@ -936,22 +1074,23 @@
// encountered here.
ASSERT(!type.IsBeingFinalized());
+ Zone* Z = Thread::Current()->zone();
+ const AbstractType& resolved_type =
+ AbstractType::Handle(Z, ResolveType(cls, type));
// A malformed type gets mapped to a finalized type.
- ResolveType(cls, type);
- if (type.IsMalformed()) {
- ASSERT(type.IsFinalized());
- return type.raw();
+ if (resolved_type.IsMalformed()) {
+ ASSERT(resolved_type.IsFinalized());
+ return resolved_type.raw();
}
- Zone* Z = Thread::Current()->zone();
if (FLAG_trace_type_finalization) {
THR_Print("Finalizing type '%s' for class '%s'\n",
- String::Handle(Z, type.Name()).ToCString(),
+ String::Handle(Z, resolved_type.Name()).ToCString(),
cls.ToCString());
}
- if (type.IsTypeParameter()) {
- const TypeParameter& type_parameter = TypeParameter::Cast(type);
+ if (resolved_type.IsTypeParameter()) {
+ const TypeParameter& type_parameter = TypeParameter::Cast(resolved_type);
const Class& parameterized_class =
Class::Handle(Z, type_parameter.parameterized_class());
ASSERT(!parameterized_class.IsNull());
@@ -966,7 +1105,7 @@
// belongs to a mixin application class.
if (!type_parameter.IsFinalized()) {
type_parameter.set_index(type_parameter.index() + offset);
- type_parameter.set_is_finalized();
+ type_parameter.SetIsFinalized();
} else {
ASSERT(cls.IsMixinApplication());
}
@@ -981,8 +1120,8 @@
return type_parameter.raw();
}
- // At this point, we can only have a parameterized_type.
- const Type& parameterized_type = Type::Cast(type);
+ // At this point, we can only have a Type or a FunctionType.
+ ASSERT(resolved_type.IsType() || resolved_type.IsFunctionType());
// This type is the root type of the type graph if no pending types queue is
// allocated yet.
@@ -991,197 +1130,93 @@
pending_types = new PendingTypes(Z, 4);
}
- // The type class does not need to be finalized in order to finalize the type,
- // however, it must at least be resolved (this was done as part of resolving
- // the type itself, a precondition to calling FinalizeType).
- // Also, the interfaces of the type class must be resolved and the type
- // parameters of the type class must be finalized.
- Class& type_class = Class::Handle(Z, parameterized_type.type_class());
- if (!type_class.is_type_finalized()) {
- FinalizeTypeParameters(type_class, pending_types);
- ResolveUpperBounds(type_class);
- }
-
- // The finalized type argument vector needs num_type_arguments types.
- const intptr_t num_type_arguments = type_class.NumTypeArguments();
- // The type class has num_type_parameters type parameters.
- const intptr_t num_type_parameters = type_class.NumTypeParameters();
-
- // Initialize the type argument vector.
- // Check the number of parsed type arguments, if any.
- // Specifying no type arguments indicates a raw type, which is not an error.
- // However, type parameter bounds are checked below, even for a raw type.
- TypeArguments& arguments =
- TypeArguments::Handle(Z, parameterized_type.arguments());
- if (!arguments.IsNull() && (arguments.Length() != num_type_parameters)) {
- // Wrong number of type arguments. The type is mapped to the raw type.
- if (Isolate::Current()->flags().error_on_bad_type()) {
- const String& type_class_name =
- String::Handle(Z, type_class.Name());
- ReportError(cls, parameterized_type.token_pos(),
- "wrong number of type arguments for class '%s'",
- type_class_name.ToCString());
- }
- // Make the type raw and continue without reporting any error.
- // A static warning should have been reported.
- arguments = TypeArguments::null();
- parameterized_type.set_arguments(arguments);
- }
-
- // Mark the type as being finalized in order to detect self reference and
- // postpone bound checking until after all types in the graph of
- // mutually recursive types are finalized.
- parameterized_type.set_is_being_finalized();
- pending_types->Add(parameterized_type);
-
- // The full type argument vector consists of the type arguments of the
- // super types of type_class, which are initialized from the parsed
- // type arguments, followed by the parsed type arguments.
- TypeArguments& full_arguments = TypeArguments::Handle(Z);
- Error& bound_error = Error::Handle(Z);
- if (num_type_arguments > 0) {
- // If no type arguments were parsed and if the super types do not prepend
- // type arguments to the vector, we can leave the vector as null.
- if (!arguments.IsNull() || (num_type_arguments > num_type_parameters)) {
- full_arguments = TypeArguments::New(num_type_arguments);
- // Copy the parsed type arguments at the correct offset in the full type
- // argument vector.
- const intptr_t offset = num_type_arguments - num_type_parameters;
- AbstractType& type_arg =
- AbstractType::Handle(Z, Type::DynamicType());
- // Leave the temporary type arguments at indices [0..offset[ as null.
- for (intptr_t i = 0; i < num_type_parameters; i++) {
- // If no type parameters were provided, a raw type is desired, so we
- // create a vector of dynamic.
- if (!arguments.IsNull()) {
- type_arg = arguments.TypeAt(i);
- // The parsed type_arg may or may not be finalized.
- }
- full_arguments.SetTypeAt(offset + i, type_arg);
- }
- // Replace the compile-time argument vector (of length zero or
- // num_type_parameters) of this type being finalized with the still
- // unfinalized run-time argument vector (of length num_type_arguments).
- // This type being finalized may be recursively reached via bounds
- // checking or type arguments of its super type.
- parameterized_type.set_arguments(full_arguments);
- // Finalize the current type arguments of the type, which are still the
- // parsed type arguments.
- if (!arguments.IsNull()) {
- for (intptr_t i = 0; i < num_type_parameters; i++) {
- type_arg = full_arguments.TypeAt(offset + i);
- ASSERT(!type_arg.IsBeingFinalized());
- type_arg = FinalizeType(cls, type_arg, kFinalize, pending_types);
- if (type_arg.IsMalformed()) {
- // Malformed type arguments are mapped to dynamic.
- type_arg = Type::DynamicType();
- }
- full_arguments.SetTypeAt(offset + i, type_arg);
- }
- }
- // If the type class is a signature class, the full argument vector
- // must include the argument vector of the super type.
- // If the signature class is a function type alias, it is also the owner
- // of its signature function and no super type is involved.
- // If the signature class is canonical (not an alias), the owner of its
- // signature function may either be an alias or the enclosing class of a
- // local function, in which case the super type of the enclosing class is
- // also considered when filling up the argument vector.
- Class& owner_class = Class::Handle(Z);
- if (type_class.IsSignatureClass()) {
- const Function& signature_fun =
- Function::Handle(Z, type_class.signature_function());
- ASSERT(!signature_fun.is_static());
- owner_class = signature_fun.Owner();
- } else {
- owner_class = type_class.raw();
- }
- if (offset > 0) {
- TrailPtr trail = new Trail(Z, 4);
- FinalizeTypeArguments(owner_class, full_arguments, offset,
- &bound_error, pending_types, trail);
- }
- if (full_arguments.IsRaw(0, num_type_arguments)) {
- // The parameterized_type is raw. Set its argument vector to null, which
- // is more efficient in type tests.
- full_arguments = TypeArguments::null();
- }
- parameterized_type.set_arguments(full_arguments);
- } else {
- ASSERT(full_arguments.IsNull()); // Use null vector for raw type.
- }
- }
-
- // Self referencing types may get finalized indirectly.
- if (!parameterized_type.IsFinalized()) {
- ASSERT(full_arguments.IsNull() ||
- !full_arguments.IsRaw(0, num_type_arguments));
- // Mark the type as finalized.
- parameterized_type.SetIsFinalized();
- // Do not yet remove the type from the pending_types array.
- }
+ const intptr_t num_expanded_type_arguments =
+ ExpandAndFinalizeTypeArguments(cls, resolved_type, pending_types);
// If we are done finalizing a graph of mutually recursive types, check their
// bounds.
if (is_root_type) {
for (intptr_t i = pending_types->length() - 1; i >= 0; i--) {
- CheckTypeBounds(cls, Type::Cast(pending_types->At(i)));
- if (FLAG_trace_type_finalization && type.IsRecursive()) {
+ CheckTypeBounds(cls, pending_types->At(i));
+ if (FLAG_trace_type_finalization && resolved_type.IsRecursive()) {
THR_Print("Done finalizing recursive type '%s': %s\n",
- String::Handle(Z, type.Name()).ToCString(),
- type.ToCString());
+ String::Handle(Z, resolved_type.Name()).ToCString(),
+ resolved_type.ToCString());
}
}
}
- // If the type class is a signature class, we are currently finalizing a
- // signature type, i.e. finalizing the result type and parameter types of the
- // signature function of this signature type.
+ // If the type is a FunctionType, we also need to finalize the types in its
+ // signature, i.e. finalize the result type and parameter types of the
+ // signature function of this function type.
// We do this after marking this type as finalized in order to allow a
// function type to refer to itself via its parameter types and result type.
- if (type_class.IsSignatureClass()) {
- // The class may be created while parsing a function body, after all
- // pending classes have already been finalized.
- FinalizeTypesInClass(type_class);
+ // Note that we do not instantiate these types according to the type
+ // arguments. This will happen on demand when executing a type test.
+ if (resolved_type.IsFunctionType()) {
+ const Function& signature =
+ Function::Handle(Z, FunctionType::Cast(resolved_type).signature());
+ FinalizeSignature(cls, signature);
}
if (FLAG_trace_type_finalization) {
THR_Print("Done finalizing type '%s' with %" Pd " type args: %s\n",
- String::Handle(Z, parameterized_type.Name()).ToCString(),
- parameterized_type.arguments() == TypeArguments::null() ?
- 0 : num_type_arguments,
- parameterized_type.ToCString());
+ String::Handle(Z, resolved_type.Name()).ToCString(),
+ num_expanded_type_arguments,
+ resolved_type.ToCString());
}
if (finalization >= kCanonicalize) {
- if (FLAG_trace_type_finalization && parameterized_type.IsRecursive()) {
- AbstractType& type = Type::Handle(Z);
- type = parameterized_type.Canonicalize();
+ if (FLAG_trace_type_finalization && resolved_type.IsRecursive()) {
+ AbstractType& recursive_type =
+ AbstractType::Handle(Z, resolved_type.Canonicalize());
THR_Print("Done canonicalizing recursive type '%s': %s\n",
- String::Handle(Z, type.Name()).ToCString(),
- type.ToCString());
- return type.raw();
+ String::Handle(Z, recursive_type.Name()).ToCString(),
+ recursive_type.ToCString());
+ return recursive_type.raw();
}
- return parameterized_type.Canonicalize();
+ return resolved_type.Canonicalize();
} else {
- return parameterized_type.raw();
+ return resolved_type.raw();
}
}
-void ClassFinalizer::ResolveAndFinalizeSignature(const Class& cls,
- const Function& function) {
+void ClassFinalizer::ResolveSignature(const Class& cls,
+ const Function& function) {
// Resolve result type.
AbstractType& type = AbstractType::Handle(function.result_type());
// It is not a compile time error if this name does not resolve to a class or
// interface.
+ AbstractType& resolved_type = AbstractType::Handle(ResolveType(cls, type));
+ if (resolved_type.raw() != type.raw()) {
+ function.set_result_type(resolved_type);
+ }
+ // Resolve formal parameter types.
+ const intptr_t num_parameters = function.NumParameters();
+ for (intptr_t i = 0; i < num_parameters; i++) {
+ type = function.ParameterTypeAt(i);
+ resolved_type = ResolveType(cls, type);
+ if (resolved_type.raw() != type.raw()) {
+ function.SetParameterTypeAt(i, resolved_type);
+ }
+ }
+}
+
+
+void ClassFinalizer::FinalizeSignature(const Class& cls,
+ const Function& function) {
+ // Finalize result type.
+ AbstractType& type = AbstractType::Handle(function.result_type());
+ // It is not a compile time error if this name does not resolve to a class or
+ // interface.
AbstractType& finalized_type =
AbstractType::Handle(FinalizeType(cls, type, kCanonicalize));
// The result type may be malformed or malbounded.
- if (type.raw() != finalized_type.raw()) {
+ if (finalized_type.raw() != type.raw()) {
function.set_result_type(finalized_type);
}
- // Resolve formal parameter types.
+ // Finalize formal parameter types.
const intptr_t num_parameters = function.NumParameters();
for (intptr_t i = 0; i < num_parameters; i++) {
type = function.ParameterTypeAt(i);
@@ -1255,7 +1290,8 @@
for (intptr_t i = 0; i < num_type_params; i++) {
type_param ^= type_params.TypeAt(i);
bound = type_param.bound();
- ResolveType(cls, bound);
+ bound = ResolveType(cls, bound);
+ type_param.set_bound(bound);
}
}
@@ -1445,7 +1481,7 @@
Error& error = Error::Handle(Z);
for (intptr_t i = 0; i < num_functions; i++) {
function ^= array.At(i);
- ResolveAndFinalizeSignature(cls, function);
+ FinalizeSignature(cls, function);
name = function.name();
// Report signature conflicts only.
if (Isolate::Current()->flags().error_on_bad_override() &&
@@ -1718,8 +1754,8 @@
FinalizeType(mixin_app_class, param_bound, kCanonicalize);
param.set_bound(param_bound); // In case part of recursive type.
}
- param_bound = param_bound.InstantiateFrom(instantiator,
- &bound_error);
+ param_bound = param_bound.InstantiateFrom(
+ instantiator, &bound_error, NULL, Heap::kOld);
// The instantiator contains only TypeParameter objects and no
// BoundedType objects, so no bound error may occur.
ASSERT(!param_bound.IsBoundedType());
@@ -1947,19 +1983,21 @@
// the BoundedType in another BoundedType.
if (type.IsBoundedType()) {
bounded_type = BoundedType::Cast(type).type();
- bounded_type = bounded_type.InstantiateFrom(instantiator,
- &bound_error);
+ bounded_type = bounded_type.InstantiateFrom(
+ instantiator, &bound_error, NULL, Heap::kOld);
// The instantiator contains only TypeParameter objects and no
// BoundedType objects, so no bound error may occur.
ASSERT(bound_error.IsNull());
upper_bound = BoundedType::Cast(type).bound();
- upper_bound = upper_bound.InstantiateFrom(instantiator, &bound_error);
+ upper_bound = upper_bound.InstantiateFrom(
+ instantiator, &bound_error, NULL, Heap::kOld);
ASSERT(bound_error.IsNull());
type_parameter = BoundedType::Cast(type).type_parameter();
// The type parameter that declared the bound does not change.
type = BoundedType::New(bounded_type, upper_bound, type_parameter);
} else {
- type = type.InstantiateFrom(instantiator, &bound_error);
+ type = type.InstantiateFrom(
+ instantiator, &bound_error, NULL, Heap::kOld);
ASSERT(bound_error.IsNull());
}
}
@@ -2172,12 +2210,23 @@
const intptr_t num_functions = functions.Length();
for (intptr_t i = 0; i < num_functions; i++) {
func ^= functions.At(i);
- if (func.IsGenerativeConstructor()) {
+ if (func.IsFactory() || func.IsGenerativeConstructor()) {
// A mixin class must not have explicit constructors.
if (!func.IsImplicitConstructor()) {
- ReportError(cls, cls.token_pos(),
- "mixin class '%s' must not have constructors\n",
- String::Handle(zone, mixin_cls.Name()).ToCString());
+ const char* ctr_kind = func.IsFactory() ? "factory" : "constructor";
+ const Script& script = Script::Handle(cls.script());
+ const Error& error = Error::Handle(
+ LanguageError::NewFormatted(Error::Handle(),
+ script, func.token_pos(), Report::AtLocation,
+ Report::kError, Heap::kNew,
+ "%s '%s' is illegal in mixin class %s",
+ ctr_kind,
+ String::Handle(func.PrettyName()).ToCString(),
+ String::Handle(zone, mixin_cls.Name()).ToCString()));
+
+ ReportErrors(error, cls, cls.token_pos(),
+ "mixin class '%s' must not have constructors",
+ String::Handle(zone, mixin_cls.Name()).ToCString());
}
continue; // Skip the implicit constructor.
}
@@ -2245,6 +2294,8 @@
// Only resolving rather than finalizing the upper bounds here would result in
// instantiated type parameters of the super type to temporarily have
// unfinalized bounds. It is more efficient to finalize them early.
+ // Finalize bounds even if running in production mode, so that a snapshot
+ // contains them.
FinalizeUpperBounds(cls);
// Finalize super type.
AbstractType& super_type = AbstractType::Handle(cls.super_type());
@@ -2265,10 +2316,13 @@
mixin_type ^= FinalizeType(cls, mixin_type, kCanonicalizeWellFormed);
cls.set_mixin(mixin_type);
}
- if (cls.IsSignatureClass()) {
+ if (cls.IsTypedefClass()) {
+ const Function& signature = Function::Handle(cls.signature_function());
+ FunctionType& type = FunctionType::Handle(signature.SignatureType());
+
// Check for illegal self references.
GrowableArray<intptr_t> visited_aliases;
- if (!IsAliasCycleFree(cls, &visited_aliases)) {
+ if (!IsTypedefCycleFree(cls, type, &visited_aliases)) {
const String& name = String::Handle(cls.Name());
ReportError(cls, cls.token_pos(),
"typedef '%s' illegally refers to itself",
@@ -2276,26 +2330,22 @@
}
cls.set_is_type_finalized();
- // The type parameters of signature classes may have bounds.
- FinalizeUpperBounds(cls);
-
// Resolve and finalize the result and parameter types of the signature
- // function of this signature class.
- const Function& sig_function = Function::Handle(cls.signature_function());
- ResolveAndFinalizeSignature(cls, sig_function);
+ // function of this typedef class.
+ FinalizeSignature(cls, signature); // Does not modify signature type.
+ ASSERT(signature.SignatureType() == type.raw());
- // Resolve and finalize the signature type of this signature class.
- const Type& sig_type = Type::Handle(cls.SignatureType());
- FinalizeType(cls, sig_type, kCanonicalizeWellFormed);
+ // Resolve and finalize the signature type of this typedef.
+ type ^= FinalizeType(cls, type, kCanonicalizeWellFormed);
+ signature.SetSignatureType(type);
- // Add this class to the subclasses of the superclass (_FunctionImpl).
- if (!super_type.IsNull()) {
- ASSERT(!super_type.IsObjectType());
- ASSERT(!super_class.IsNull());
- super_class.AddDirectSubclass(cls);
- }
+ // Closure instances do not refer to this typedef as their class, so there
+ // is no need to add this typedef class to the subclasses of _Closure.
+ ASSERT(super_type.IsNull() || super_type.IsObjectType());
+
return;
}
+
// Finalize interface types (but not necessarily interface classes).
Array& interface_types = Array::Handle(cls.interfaces());
AbstractType& interface_type = AbstractType::Handle();
@@ -2332,9 +2382,6 @@
// Mark as type finalized before resolving type parameter upper bounds
// in order to break cycles.
cls.set_is_type_finalized();
- // Finalize bounds even if running in production mode, so that a snapshot
- // contains them.
- FinalizeUpperBounds(cls);
// Add this class to the direct subclasses of the superclass, unless the
// superclass is Object.
if (!super_type.IsNull() && !super_type.IsObjectType()) {
@@ -2401,9 +2448,9 @@
cls.SetFunctions(functions);
}
// Every class should have at least a constructor, unless it is a top level
- // class or a signature class.
+ // class or a typedef class.
ASSERT(cls.IsTopLevel() ||
- cls.IsSignatureClass() ||
+ cls.IsTypedefClass() ||
(Array::Handle(cls.functions()).Length() > 0));
// Resolve and finalize all member types.
ResolveAndFinalizeMemberTypes(cls);
@@ -2494,82 +2541,74 @@
}
-// Helper function called by IsAliasCycleFree.
-bool ClassFinalizer::IsTypeCycleFree(
- const Class& cls,
- const AbstractType& type,
- GrowableArray<intptr_t>* visited) {
+// Returns false if a function type alias illegally refers to itself.
+bool ClassFinalizer::IsTypedefCycleFree(const Class& cls,
+ const AbstractType& type,
+ GrowableArray<intptr_t>* visited) {
ASSERT(visited != NULL);
- ResolveType(cls, type);
- if (type.IsType() && !type.IsMalformed()) {
- const Class& type_class = Class::Handle(type.type_class());
- if (!type_class.is_type_finalized() &&
- type_class.IsSignatureClass() &&
- !IsAliasCycleFree(type_class, visited)) {
- return false;
- }
- const TypeArguments& type_args = TypeArguments::Handle(type.arguments());
- if (!type_args.IsNull()) {
- AbstractType& type_arg = AbstractType::Handle();
- for (intptr_t i = 0; i < type_args.Length(); i++) {
- type_arg = type_args.TypeAt(i);
- if (!IsTypeCycleFree(cls, type_arg, visited)) {
+ AbstractType& resolved_type = AbstractType::Handle(ResolveType(cls, type));
+ bool checking_typedef = false;
+ if ((resolved_type.IsType() || resolved_type.IsFunctionType()) &&
+ !resolved_type.IsMalformed()) {
+ AbstractType& other_type = AbstractType::Handle();
+ if (resolved_type.IsFunctionType()) {
+ const Class& scope_class = Class::Handle(resolved_type.type_class());
+ if (!scope_class.is_type_finalized() && scope_class.IsTypedefClass()) {
+ checking_typedef = true;
+ const intptr_t scope_class_id = scope_class.id();
+ ASSERT(visited != NULL);
+ for (intptr_t i = 0; i < visited->length(); i++) {
+ if ((*visited)[i] == scope_class_id) {
+ // We have already visited alias 'scope_class'. We found a cycle.
+ return false;
+ }
+ }
+ visited->Add(scope_class_id);
+ }
+ // Check the bounds of this function type.
+ const intptr_t num_type_params = scope_class.NumTypeParameters();
+ TypeParameter& type_param = TypeParameter::Handle();
+ const TypeArguments& type_params =
+ TypeArguments::Handle(scope_class.type_parameters());
+ ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
+ (type_params.Length() == num_type_params));
+ for (intptr_t i = 0; i < num_type_params; i++) {
+ type_param ^= type_params.TypeAt(i);
+ other_type = type_param.bound();
+ if (!IsTypedefCycleFree(cls, other_type, visited)) {
+ return false;
+ }
+ }
+ // Check the result type of the signature of this function type.
+ const Function& function =
+ Function::Handle(FunctionType::Cast(resolved_type).signature());
+ other_type = function.result_type();
+ if (!IsTypedefCycleFree(cls, other_type, visited)) {
+ return false;
+ }
+ // Check the parameter types of the signature of this function type.
+ const intptr_t num_parameters = function.NumParameters();
+ for (intptr_t i = 0; i < num_parameters; i++) {
+ other_type = function.ParameterTypeAt(i);
+ if (!IsTypedefCycleFree(cls, other_type, visited)) {
return false;
}
}
}
- }
- return true;
-}
-
-
-// Returns false if the function type alias illegally refers to itself.
-bool ClassFinalizer::IsAliasCycleFree(const Class& cls,
- GrowableArray<intptr_t>* visited) {
- ASSERT(cls.IsSignatureClass());
- ASSERT(!cls.is_type_finalized());
- ASSERT(visited != NULL);
- const intptr_t cls_index = cls.id();
- for (intptr_t i = 0; i < visited->length(); i++) {
- if ((*visited)[i] == cls_index) {
- // We have already visited alias 'cls'. We found a cycle.
- return false;
+ const TypeArguments& type_args =
+ TypeArguments::Handle(resolved_type.arguments());
+ if (!type_args.IsNull()) {
+ for (intptr_t i = 0; i < type_args.Length(); i++) {
+ other_type = type_args.TypeAt(i);
+ if (!IsTypedefCycleFree(cls, other_type, visited)) {
+ return false;
+ }
+ }
+ }
+ if (checking_typedef) {
+ visited->RemoveLast();
}
}
-
- // Visit the bounds, result type, and parameter types of this signature type.
- visited->Add(cls.id());
- AbstractType& type = AbstractType::Handle();
-
- // Check the bounds of this signature type.
- const intptr_t num_type_params = cls.NumTypeParameters();
- TypeParameter& type_param = TypeParameter::Handle();
- const TypeArguments& type_params =
- TypeArguments::Handle(cls.type_parameters());
- ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
- (type_params.Length() == num_type_params));
- for (intptr_t i = 0; i < num_type_params; i++) {
- type_param ^= type_params.TypeAt(i);
- type = type_param.bound();
- if (!IsTypeCycleFree(cls, type, visited)) {
- return false;
- }
- }
- // Check the result type of the function of this signature type.
- const Function& function = Function::Handle(cls.signature_function());
- type = function.result_type();
- if (!IsTypeCycleFree(cls, type, visited)) {
- return false;
- }
- // Check the formal parameter types of the function of this signature type.
- const intptr_t num_parameters = function.NumParameters();
- for (intptr_t i = 0; i < num_parameters; i++) {
- type = function.ParameterTypeAt(i);
- if (!IsTypeCycleFree(cls, type, visited)) {
- return false;
- }
- }
- visited->RemoveLast();
return true;
}
@@ -2657,8 +2696,16 @@
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
AbstractType& mixin_super_type =
AbstractType::Handle(zone, mixin_app_type.super_type());
- ResolveType(cls, mixin_super_type);
+ mixin_super_type = ResolveType(cls, mixin_super_type);
ASSERT(mixin_super_type.HasResolvedTypeClass()); // Even if malformed.
+ if (mixin_super_type.IsMalformedOrMalbounded()) {
+ ReportError(Error::Handle(zone, mixin_super_type.error()));
+ }
+ if (mixin_super_type.IsDynamicType()) {
+ ReportError(cls, cls.token_pos(),
+ "class '%s' may not extend 'dynamic'",
+ String::Handle(zone, cls.Name()).ToCString());
+ }
// The super type may have a BoundedType as type argument, but cannot be
// a BoundedType itself.
CollectTypeArguments(cls, Type::Cast(mixin_super_type), type_args);
@@ -2673,7 +2720,7 @@
for (intptr_t i = 0; i < depth; i++) {
mixin_type = mixin_app_type.MixinTypeAt(i);
ASSERT(!mixin_type.IsNull());
- ResolveType(cls, mixin_type);
+ mixin_type = ResolveType(cls, mixin_type);
ASSERT(mixin_type.HasResolvedTypeClass()); // Even if malformed.
ASSERT(mixin_type.IsType());
const intptr_t num_super_type_args = type_args.Length();
@@ -2834,7 +2881,7 @@
Class& interface_class = Class::Handle(zone);
// Resolve super type. Failures lead to a longjmp.
- ResolveType(cls, super_type);
+ super_type = ResolveType(cls, super_type);
if (super_type.IsMalformedOrMalbounded()) {
ReportError(Error::Handle(zone, super_type.error()));
}
@@ -2844,7 +2891,7 @@
String::Handle(zone, cls.Name()).ToCString());
}
interface_class = super_type.type_class();
- if (interface_class.IsSignatureClass()) {
+ if (interface_class.IsTypedefClass()) {
ReportError(cls, cls.token_pos(),
"class '%s' may not extend function type alias '%s'",
String::Handle(zone, cls.Name()).ToCString(),
@@ -2914,7 +2961,7 @@
// Resolve interfaces. Failures lead to a longjmp.
for (intptr_t i = 0; i < super_interfaces.Length(); i++) {
interface ^= super_interfaces.At(i);
- ResolveType(cls, interface);
+ interface = ResolveType(cls, interface);
ASSERT(!interface.IsTypeParameter()); // Should be detected by parser.
// A malbounded interface is only reported when involved in a type test.
if (interface.IsMalformed()) {
@@ -2925,7 +2972,7 @@
"'dynamic' may not be used as interface");
}
interface_class = interface.type_class();
- if (interface_class.IsSignatureClass()) {
+ if (interface_class.IsTypedefClass()) {
const String& interface_name = String::Handle(zone,
interface_class.Name());
ReportError(cls, cls.token_pos(),
@@ -3048,7 +3095,7 @@
va_list args) {
LanguageError& error = LanguageError::Handle(
LanguageError::NewFormattedV(
- prev_error, script, type.token_pos(),
+ prev_error, script, type.token_pos(), Report::AtLocation,
Report::kMalformedType, Heap::kOld,
format, args));
if (Isolate::Current()->flags().error_on_bad_type()) {
@@ -3061,7 +3108,7 @@
type.set_arguments(Object::null_type_arguments());
if (!type.IsFinalized()) {
type.SetIsFinalized();
- // Do not canonicalize malformed types, since they may not be resolved.
+ // Do not canonicalize malformed types, since they contain an error field.
} else {
// The only case where the malformed type was already finalized is when its
// type arguments are not within bounds. In that case, we have a prev_error.
@@ -3103,13 +3150,13 @@
void ClassFinalizer::FinalizeMalboundedType(const Error& prev_error,
const Script& script,
- const Type& type,
+ const AbstractType& type,
const char* format, ...) {
va_list args;
va_start(args, format);
LanguageError& error = LanguageError::Handle(
LanguageError::NewFormattedV(
- prev_error, script, type.token_pos(),
+ prev_error, script, type.token_pos(), Report::AtLocation,
Report::kMalboundedType, Heap::kOld,
format, args));
va_end(args);
@@ -3149,7 +3196,8 @@
va_list args;
va_start(args, format);
const Script& script = Script::Handle(cls.script());
- Report::MessageV(Report::kError, script, token_pos, format, args);
+ Report::MessageV(Report::kError,
+ script, token_pos, Report::AtLocation, format, args);
va_end(args);
UNREACHABLE();
}
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index 3aa7c2c..a8c59a2 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -60,7 +60,7 @@
// string and its arguments.
static void FinalizeMalboundedType(const Error& prev_error,
const Script& script,
- const Type& type,
+ const AbstractType& type,
const char* format, ...)
PRINTF_ATTRIBUTE(4, 5);
@@ -89,7 +89,8 @@
#endif // defined(DART_NO_SNAPSHOT).
// Resolve the class of the type, but not the type's type arguments.
- static void ResolveTypeClass(const Class& cls, const AbstractType& type);
+ // May promote the type from Type to FunctionType.
+ static RawAbstractType* ResolveTypeClass(const Class& cls, const Type& type);
// Resolve the type and target of the redirecting factory.
static void ResolveRedirectingFactory(const Class& cls,
@@ -102,17 +103,16 @@
private:
static void AllocateEnumValues(const Class& enum_cls);
static bool IsSuperCycleFree(const Class& cls);
- static bool IsTypeCycleFree(const Class& cls,
- const AbstractType& type,
- GrowableArray<intptr_t>* visited);
- static bool IsAliasCycleFree(const Class& cls,
- GrowableArray<intptr_t>* visited);
+ static bool IsTypedefCycleFree(const Class& cls,
+ const AbstractType& type,
+ GrowableArray<intptr_t>* visited);
static bool IsMixinCycleFree(const Class& cls,
GrowableArray<intptr_t>* visited);
static void CheckForLegalConstClass(const Class& cls);
static RawClass* ResolveClass(const Class& cls,
const UnresolvedClass& unresolved_class);
- static void ResolveType(const Class& cls, const AbstractType& type);
+ static RawAbstractType* ResolveType(const Class& cls,
+ const AbstractType& type);
static void ResolveRedirectingFactoryTarget(
const Class& cls,
const Function& factory,
@@ -134,6 +134,9 @@
GrowableArray<intptr_t>* visited);
static void FinalizeTypeParameters(const Class& cls,
PendingTypes* pending_types = NULL);
+ static intptr_t ExpandAndFinalizeTypeArguments(const Class& cls,
+ const AbstractType& type,
+ PendingTypes* pending_types);
static void FinalizeTypeArguments(const Class& cls,
const TypeArguments& arguments,
intptr_t num_uninitialized_arguments,
@@ -141,16 +144,16 @@
PendingTypes* pending_types,
TrailPtr trail);
static void CheckRecursiveType(const Class& cls,
- const Type& type,
+ const AbstractType& type,
PendingTypes* pending_types);
- static void CheckTypeBounds(const Class& cls, const Type& type);
+ static void CheckTypeBounds(const Class& cls, const AbstractType& type);
static void CheckTypeArgumentBounds(const Class& cls,
const TypeArguments& arguments,
Error* bound_error);
static void ResolveUpperBounds(const Class& cls);
static void FinalizeUpperBounds(const Class& cls);
- static void ResolveAndFinalizeSignature(const Class& cls,
- const Function& function);
+ static void ResolveSignature(const Class& cls, const Function& function);
+ static void FinalizeSignature(const Class& cls, const Function& function);
static void ResolveAndFinalizeMemberTypes(const Class& cls);
static void PrintClassInformation(const Class& cls);
static void CollectInterfaces(
diff --git a/runtime/vm/class_finalizer_test.cc b/runtime/vm/class_finalizer_test.cc
index 828ecac..2c87c9c 100644
--- a/runtime/vm/class_finalizer_test.cc
+++ b/runtime/vm/class_finalizer_test.cc
@@ -14,7 +14,7 @@
const String& class_name = String::Handle(Symbols::New(name));
const Script& script = Script::Handle();
const Class& cls =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
cls.set_interfaces(Object::empty_array());
cls.SetFunctions(Object::empty_array());
cls.SetFields(Object::empty_array());
@@ -96,12 +96,12 @@
const UnresolvedClass& unresolved = UnresolvedClass::Handle(
UnresolvedClass::New(LibraryPrefix::Handle(),
superclass_name,
- Scanner::kNoSourcePos));
+ Token::kNoSourcePos));
const TypeArguments& type_arguments = TypeArguments::Handle();
rhb.set_super_type(Type::Handle(
Type::New(Object::Handle(unresolved.raw()),
type_arguments,
- Scanner::kNoSourcePos)));
+ Token::kNoSourcePos)));
EXPECT(ClassFinalizer::ProcessPendingClasses());
}
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index adc7853..ac4cb24 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/code_descriptors.h"
+#include "vm/compiler.h"
namespace dart {
@@ -15,25 +16,47 @@
(kind == RawPcDescriptors::kOther) ||
(deopt_id != Thread::kNoDeoptId));
- intptr_t merged_kind_try =
- RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
+ // When precompiling, we only use pc descriptors for exceptions.
+ if (Compiler::allow_recompilation() || try_index != -1) {
+ intptr_t merged_kind_try =
+ RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
- PcDescriptors::EncodeInteger(&encoded_data_, merged_kind_try);
- PcDescriptors::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
- PcDescriptors::EncodeInteger(&encoded_data_, deopt_id - prev_deopt_id);
- PcDescriptors::EncodeInteger(&encoded_data_, token_pos - prev_token_pos);
+ PcDescriptors::EncodeInteger(&encoded_data_, merged_kind_try);
+ PcDescriptors::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
+ PcDescriptors::EncodeInteger(&encoded_data_, deopt_id - prev_deopt_id);
+ PcDescriptors::EncodeInteger(&encoded_data_, token_pos - prev_token_pos);
- prev_pc_offset = pc_offset;
- prev_deopt_id = deopt_id;
- prev_token_pos = token_pos;
+ prev_pc_offset = pc_offset;
+ prev_deopt_id = deopt_id;
+ prev_token_pos = token_pos;
+ }
}
RawPcDescriptors* DescriptorList::FinalizePcDescriptors(uword entry_point) {
+ if (encoded_data_.length() == 0) {
+ return Object::empty_descriptors().raw();
+ }
return PcDescriptors::New(&encoded_data_);
}
+
+void CodeSourceMapBuilder::AddEntry(intptr_t pc_offset,
+ intptr_t token_pos) {
+ CodeSourceMap::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
+ CodeSourceMap::EncodeInteger(&encoded_data_, token_pos - prev_token_pos);
+
+ prev_pc_offset = pc_offset;
+ prev_token_pos = token_pos;
+}
+
+
+RawCodeSourceMap* CodeSourceMapBuilder::Finalize() {
+ return CodeSourceMap::New(&encoded_data_);
+}
+
+
void StackmapTableBuilder::AddEntry(intptr_t pc_offset,
BitmapBuilder* bitmap,
intptr_t register_bit_count) {
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index e24e186..11e3437 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -42,6 +42,29 @@
};
+class CodeSourceMapBuilder : public ZoneAllocated {
+ public:
+ explicit CodeSourceMapBuilder(intptr_t initial_capacity = 64)
+ : encoded_data_(initial_capacity),
+ prev_pc_offset(0),
+ prev_token_pos(0) {}
+
+ ~CodeSourceMapBuilder() { }
+
+ void AddEntry(intptr_t pc_offset, intptr_t token_pos);
+
+ RawCodeSourceMap* Finalize();
+
+ private:
+ GrowableArray<uint8_t> encoded_data_;
+
+ intptr_t prev_pc_offset;
+ intptr_t prev_token_pos;
+
+ DISALLOW_COPY_AND_ASSIGN(CodeSourceMapBuilder);
+};
+
+
class StackmapTableBuilder : public ZoneAllocated {
public:
StackmapTableBuilder()
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 2586a97..30cedd4 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -18,7 +18,7 @@
namespace dart {
-static const intptr_t kPos = Scanner::kNoSourcePos;
+static const intptr_t kPos = Token::kNoSourcePos;
CODEGEN_TEST_GENERATE(StackmapCodegen, test) {
@@ -268,4 +268,100 @@
EXPECT(!result.IsError());
}
+
+TEST_CASE(DescriptorList_TokenPositions) {
+ DescriptorList* descriptors = new DescriptorList(64);
+ ASSERT(descriptors != NULL);
+ const intptr_t token_positions[] = {
+ kMinInt32,
+ 5,
+ 13,
+ 13,
+ 13,
+ 13,
+ 31,
+ 23,
+ 23,
+ 23,
+ 33,
+ 33,
+ 5,
+ 5,
+ Token::kMinSourcePos,
+ Token::kMaxSourcePos,
+ };
+ const intptr_t num_token_positions =
+ sizeof(token_positions) / sizeof(token_positions[0]);
+
+ for (intptr_t i = 0; i < num_token_positions; i++) {
+ descriptors->AddDescriptor(RawPcDescriptors::kRuntimeCall, 0, 0,
+ token_positions[i], 0);
+ }
+
+ const PcDescriptors& finalized_descriptors =
+ PcDescriptors::Handle(descriptors->FinalizePcDescriptors(0));
+
+ ASSERT(!finalized_descriptors.IsNull());
+ PcDescriptors::Iterator it(finalized_descriptors,
+ RawPcDescriptors::kRuntimeCall);
+
+ intptr_t i = 0;
+ while (it.MoveNext()) {
+ if (token_positions[i] != it.TokenPos()) {
+ OS::Print("[%" Pd "]: Expected: %" Pd " != %" Pd "\n",
+ i, token_positions[i], it.TokenPos());
+ }
+ EXPECT(token_positions[i] == it.TokenPos());
+ i++;
+ }
+}
+
+
+TEST_CASE(CodeSourceMap_TokenPositions) {
+ const intptr_t token_positions[] = {
+ kMinInt32,
+ 5,
+ 13,
+ 13,
+ 13,
+ 13,
+ 31,
+ 23,
+ 23,
+ 23,
+ 33,
+ 33,
+ 5,
+ 5,
+ Token::kMinSourcePos,
+ Token::kMaxSourcePos,
+ };
+ const intptr_t num_token_positions =
+ sizeof(token_positions) / sizeof(token_positions[0]);
+
+ CodeSourceMapBuilder* builder = new CodeSourceMapBuilder();
+ ASSERT(builder != NULL);
+
+ for (intptr_t i = 0; i < num_token_positions; i++) {
+ builder->AddEntry(i, token_positions[i]);
+ }
+
+ const CodeSourceMap& code_Source_map =
+ CodeSourceMap::Handle(builder->Finalize());
+
+ ASSERT(!code_Source_map.IsNull());
+ CodeSourceMap::Iterator it(code_Source_map);
+
+ uintptr_t i = 0;
+ while (it.MoveNext()) {
+ EXPECT(it.PcOffset() == i);
+ if (token_positions[i] != it.TokenPos()) {
+ OS::Print("[%" Pd "]: Expected: %" Pd " != %" Pd "\n",
+ i, token_positions[i], it.TokenPos());
+ }
+ EXPECT(token_positions[i] == it.TokenPos());
+ i++;
+ }
+}
+
} // namespace dart
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index d7c92d7..d0cdd74e 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -204,7 +204,7 @@
ASSERT(!type.IsNull() && !type.IsInstantiated());
ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
Error& bound_error = Error::Handle();
- type = type.InstantiateFrom(instantiator, &bound_error);
+ type = type.InstantiateFrom(instantiator, &bound_error, NULL, Heap::kOld);
if (!bound_error.IsNull()) {
// Throw a dynamic type error.
const intptr_t location = GetCallerLocation();
@@ -300,7 +300,7 @@
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
- const Type& instance_type = Type::Handle(instance.GetType());
+ const AbstractType& instance_type = AbstractType::Handle(instance.GetType());
ASSERT(instance_type.IsInstantiated());
if (type.IsInstantiated()) {
OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n",
@@ -334,10 +334,10 @@
// This updates the type test cache, an array containing 4-value elements
-// (instance class, instance type arguments, instantiator type arguments and
-// test_result). It can be applied to classes with type arguments in which
-// case it contains just the result of the class subtype test, not including
-// the evaluation of type arguments.
+// (instance class (or function if the instance is a closure), instance type
+// arguments, instantiator type arguments and test_result). It can be applied to
+// classes with type arguments in which case it contains just the result of the
+// class subtype test, not including the evaluation of type arguments.
// This operation is currently very slow (lookup of code is not efficient yet).
static void UpdateTypeTestCache(
const Instance& instance,
@@ -360,11 +360,16 @@
}
return;
}
- TypeArguments& instance_type_arguments =
- TypeArguments::Handle();
const Class& instance_class = Class::Handle(instance.clazz());
-
- if (instance_class.NumTypeArguments() > 0) {
+ Object& instance_class_id_or_function = Object::Handle();
+ if (instance_class.IsClosureClass()) {
+ instance_class_id_or_function = Closure::Cast(instance).function();
+ } else {
+ instance_class_id_or_function = Smi::New(instance_class.id());
+ }
+ TypeArguments& instance_type_arguments = TypeArguments::Handle();
+ if (instance_class.IsClosureClass() ||
+ (instance_class.NumTypeArguments() > 0)) {
instance_type_arguments = instance.GetTypeArguments();
}
@@ -377,20 +382,19 @@
instance_type_arguments.IsCanonical());
ASSERT(instantiator_type_arguments.IsNull() ||
instantiator_type_arguments.IsCanonical());
- intptr_t last_instance_class_id = -1;
- TypeArguments& last_instance_type_arguments =
- TypeArguments::Handle();
- TypeArguments& last_instantiator_type_arguments =
- TypeArguments::Handle();
+ Object& last_instance_class_id_or_function = Object::Handle();
+ TypeArguments& last_instance_type_arguments = TypeArguments::Handle();
+ TypeArguments& last_instantiator_type_arguments = TypeArguments::Handle();
Bool& last_result = Bool::Handle();
for (intptr_t i = 0; i < len; ++i) {
new_cache.GetCheck(
i,
- &last_instance_class_id,
+ &last_instance_class_id_or_function,
&last_instance_type_arguments,
&last_instantiator_type_arguments,
&last_result);
- if ((last_instance_class_id == instance_class.id()) &&
+ if ((last_instance_class_id_or_function.raw() ==
+ instance_class_id_or_function.raw()) &&
(last_instance_type_arguments.raw() == instance_type_arguments.raw()) &&
(last_instantiator_type_arguments.raw() ==
instantiator_type_arguments.raw())) {
@@ -402,7 +406,7 @@
}
}
#endif
- new_cache.AddCheck(instance_class.id(),
+ new_cache.AddCheck(instance_class_id_or_function,
instance_type_arguments,
instantiator_type_arguments,
result);
@@ -415,13 +419,13 @@
ASSERT(bound_error.IsNull()); // Malbounded types are not optimized.
}
OS::PrintErr(" Updated test cache %p ix: %" Pd " with "
- "(cid: %" Pd ", type-args: %p, instantiator: %p, result: %s)\n"
+ "(cid-or-fun: %p, type-args: %p, instantiator: %p, result: %s)\n"
" instance [class: (%p '%s' cid: %" Pd "), type-args: %p %s]\n"
" test-type [class: (%p '%s' cid: %" Pd "), in-type-args: %p %s]\n",
new_cache.raw(),
len,
- instance_class.id(),
+ instance_class_id_or_function.raw(),
instance_type_arguments.raw(),
instantiator_type_arguments.raw(),
result.ToCString(),
@@ -745,15 +749,8 @@
if (getter.IsNull() || getter.IsMethodExtractor()) {
return false;
}
- const Class& cache_class = Class::Handle(receiver_class.IsSignatureClass()
- ? receiver_class.SuperClass()
- : receiver_class.raw());
- ASSERT(
- !receiver_class.IsSignatureClass() ||
- (receiver_class.SuperClass() == Type::Handle(
- Isolate::Current()->object_store()->function_impl_type()).type_class()));
const Function& target_function =
- Function::Handle(cache_class.GetInvocationDispatcher(
+ Function::Handle(receiver_class.GetInvocationDispatcher(
target_name,
arguments_descriptor,
RawFunction::kInvokeFieldDispatcher,
@@ -1223,15 +1220,14 @@
// Arg1: arguments descriptor array.
// Arg2: arguments array.
DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) {
- const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
+ const Closure& receiver = Closure::CheckedHandle(arguments.ArgAt(0));
const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(1));
const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(2));
// For closure the function name is always 'call'. Replace it with the
// name of the closurized function so that exception contains more
// relevant information.
- ASSERT(receiver.IsClosure());
- const Function& function = Function::Handle(Closure::function(receiver));
+ const Function& function = Function::Handle(receiver.function());
const String& original_function_name =
String::Handle(function.QualifiedUserVisibleName());
const Object& result = Object::Handle(
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index bb7008a..bd569fc 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -24,7 +24,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index f9a3f42..f7d741f 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -24,7 +24,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index a9c62f4..a8184bf 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -24,7 +24,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index 78e698b..676a1b0 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -24,7 +24,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index ca98231..7d1f31d 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -24,7 +24,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 70d1ac6..7479506 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -80,7 +80,7 @@
bool Compiler::always_optimize_ = false;
bool Compiler::allow_recompilation_ = true;
-#ifndef DART_PRECOMPILED
+#ifndef DART_PRECOMPILED_RUNTIME
// TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove
// separate helpers functions & `optimizing` args.
@@ -282,14 +282,13 @@
if (cls.is_marked_for_parsing()) {
return Error::null();
}
- // If the class is a signature class there is no need to try and
+ // If the class is a typedef class there is no need to try and
// compile it. Just finalize it directly.
- if (cls.IsSignatureClass()) {
+ if (cls.IsTypedefClass()) {
#if defined(DEBUG)
- const Type& type = Type::Handle(
- Isolate::Current()->object_store()->function_impl_type());
- const Class& type_cls = Class::Handle(type.type_class());
- ASSERT(type_cls.is_finalized());
+ const Class& closure_cls = Class::Handle(
+ Isolate::Current()->object_store()->closure_class());
+ ASSERT(closure_cls.is_finalized());
#endif
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
@@ -1341,8 +1340,7 @@
CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id);
const bool success = helper.Compile(pipeline);
if (!success) {
- if (optimized) {
- ASSERT(!Compiler::always_optimize()); // Optimized is the only code.
+ if (optimized && !Compiler::always_optimize()) {
// Optimizer bailed out. Disable optimizations and never try again.
if (trace_compiler) {
THR_Print("--> disabling optimizations for '%s'\n",
@@ -1359,6 +1357,8 @@
// We got an error during compilation.
error = isolate->object_store()->sticky_error();
isolate->object_store()->clear_sticky_error();
+ ASSERT(error.IsLanguageError() &&
+ LanguageError::Cast(error).kind() != Report::kBailout);
return error.raw();
}
}
@@ -1941,7 +1941,7 @@
}
-#else // DART_PRECOMPILED
+#else // DART_PRECOMPILED_RUNTIME
DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
@@ -2046,6 +2046,6 @@
UNREACHABLE();
}
-#endif // DART_PRECOMPILED
+#endif // DART_PRECOMPILED_RUNTIME
} // namespace dart
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index 491468a..edaea94 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -56,12 +56,16 @@
namespace dart {
-// TODO(zra): Add a target for ARMv6.
#if defined(TARGET_ARCH_ARM_5TE)
DEFINE_FLAG(bool, use_vfp, false, "Use vfp instructions if supported");
DEFINE_FLAG(bool, use_neon, false, "Use neon instructions if supported");
DEFINE_FLAG(bool, use_integer_division, false,
"Use integer division instruction if supported");
+#elif defined(TARGET_ARCH_ARM_6)
+DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
+DEFINE_FLAG(bool, use_neon, false, "Use neon instructions if supported");
+DEFINE_FLAG(bool, use_integer_division, false,
+ "Use integer division instruction if supported");
#else
DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
DEFINE_FLAG(bool, use_neon, true, "Use neon instructions if supported");
@@ -242,6 +246,8 @@
#if defined(TARGET_ARCH_ARM_5TE)
arm_version_ = ARMv5TE;
+#elif defined(TARGET_ARCH_ARM_6)
+ arm_version_ = ARMv6;
#else
arm_version_ = ARMv7;
#endif
diff --git a/runtime/vm/cpuinfo.h b/runtime/vm/cpuinfo.h
index 3ccf2d4..cd1247e 100644
--- a/runtime/vm/cpuinfo.h
+++ b/runtime/vm/cpuinfo.h
@@ -61,7 +61,7 @@
if (HasField(FieldName(kCpuInfoHardware))) {
return ExtractField(kCpuInfoHardware);
} else {
- return "";
+ return strdup("Unknown");
}
}
diff --git a/runtime/vm/cpuinfo_linux.cc b/runtime/vm/cpuinfo_linux.cc
index 0341530..e58bac1 100644
--- a/runtime/vm/cpuinfo_linux.cc
+++ b/runtime/vm/cpuinfo_linux.cc
@@ -28,14 +28,20 @@
fields_[kCpuInfoFeatures] = "flags";
method_ = kCpuInfoCpuId;
CpuId::InitOnce();
-#elif defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
- // TODO(zra): Verify that these field names are correct for arm64.
+#elif defined(HOST_ARCH_ARM)
fields_[kCpuInfoProcessor] = "Processor";
fields_[kCpuInfoModel] = "model name";
fields_[kCpuInfoHardware] = "Hardware";
fields_[kCpuInfoFeatures] = "Features";
method_ = kCpuInfoSystem;
ProcCpuInfo::InitOnce();
+#elif defined(HOST_ARCH_ARM64)
+ fields_[kCpuInfoProcessor] = "Processor";
+ fields_[kCpuInfoModel] = "CPU implementer";
+ fields_[kCpuInfoHardware] = "CPU implementer";
+ fields_[kCpuInfoFeatures] = "Features";
+ method_ = kCpuInfoSystem;
+ ProcCpuInfo::InitOnce();
#elif defined(HOST_ARCH_MIPS)
fields_[kCpuInfoProcessor] = "system type";
fields_[kCpuInfoModel] = "cpu model";
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 796aaca..d316138 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -77,7 +77,6 @@
}
}
-#if 0
#define API_TIMELINE_DURATION \
TimelineDurationScope tds(Thread::Current(), \
Timeline::GetVMApiStream(), \
@@ -87,10 +86,7 @@
TimelineBeginEndScope tbes(Thread::Current(), \
Timeline::GetVMApiStream(), \
CURRENT_FUNC)
-#else
-#define API_TIMELINE_DURATION ASSERT(true)
-#define API_TIMELINE_BEGIN_END ASSERT(true)
-#endif
+
#if defined(DEBUG)
// An object visitor which will iterate over all the function objects in the
@@ -111,7 +107,7 @@
// Verify that the result type of a function is canonical or a
// TypeParameter.
typeHandle_ ^= funcHandle_.result_type();
- ASSERT(typeHandle_.IsNull() ||
+ ASSERT(typeHandle_.IsMalformed() ||
!typeHandle_.IsResolved() ||
typeHandle_.IsTypeParameter() ||
typeHandle_.IsCanonical());
@@ -120,8 +116,9 @@
const intptr_t num_parameters = funcHandle_.NumParameters();
for (intptr_t i = 0; i < num_parameters; i++) {
typeHandle_ = funcHandle_.ParameterTypeAt(i);
- ASSERT(typeHandle_.IsTypeParameter() ||
+ ASSERT(typeHandle_.IsMalformed() ||
!typeHandle_.IsResolved() ||
+ typeHandle_.IsTypeParameter() ||
typeHandle_.IsCanonical());
}
}
@@ -1858,14 +1855,7 @@
DART_EXPORT bool Dart_IsClosure(Dart_Handle object) {
- // We can't use a fast class index check here because there are many
- // different signature classes for closures.
- Thread* thread = Thread::Current();
- CHECK_ISOLATE(thread->isolate());
- ReusableObjectHandleScope reused_obj_handle(thread);
- const Instance& closure_obj =
- Api::UnwrapInstanceHandle(reused_obj_handle, object);
- return (!closure_obj.IsNull() && closure_obj.IsClosure());
+ return Api::ClassId(object) == kClosureCid;
}
@@ -1917,7 +1907,8 @@
if (!obj.IsInstance()) {
RETURN_TYPE_ERROR(Z, instance, Instance);
}
- const Type& type = Type::Handle(Instance::Cast(obj).GetType());
+ const AbstractType& type =
+ AbstractType::Handle(Instance::Cast(obj).GetType());
return Api::NewHandle(T, type.Canonicalize());
}
@@ -3888,7 +3879,7 @@
// Construct name of the constructor to invoke.
const String& constructor_name = Api::UnwrapStringHandle(Z, name);
- const Type& type_obj = Type::Handle(Z, instance.GetType());
+ const AbstractType& type_obj = AbstractType::Handle(Z, instance.GetType());
const Class& cls = Class::Handle(Z, type_obj.type_class());
const String& class_name = String::Handle(Z, cls.Name());
const Array& strings = Array::Handle(Z, Array::New(3));
@@ -5135,7 +5126,7 @@
// Construct the type object, canonicalize it and return.
Type& instantiated_type = Type::Handle(
- Type::New(cls, type_args_obj, Scanner::kNoSourcePos));
+ Type::New(cls, type_args_obj, Token::kNoSourcePos));
instantiated_type ^= ClassFinalizer::FinalizeType(
cls, instantiated_type, ClassFinalizer::kCanonicalize);
return Api::NewHandle(T, instantiated_type.raw());
@@ -5882,7 +5873,7 @@
}
-#if defined(DART_PRECOMPILED)
+#if defined(DART_PRECOMPILED_RUNTIME)
DART_EXPORT Dart_Handle Dart_Precompile(
Dart_QualifiedFunctionName entry_points[],
@@ -5903,7 +5894,7 @@
return 0;
}
-#else // DART_PRECOMPILED
+#else // DART_PRECOMPILED_RUNTIME
DART_EXPORT Dart_Handle Dart_Precompile(
Dart_QualifiedFunctionName entry_points[],
@@ -5977,7 +5968,7 @@
return Api::Success();
}
-#endif // DART_PRECOMPILED
+#endif // DART_PRECOMPILED_RUNTIME
DART_EXPORT bool Dart_IsRunningPrecompiledCode() {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index a2cf1d3..8a40a7a 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -6762,9 +6762,9 @@
TEST_CASE(SetNativeResolver) {
const char* kScriptChars =
"class Test {"
- " static foo() native \"SomeNativeFunction\";"
- " static bar() native \"SomeNativeFunction2\";"
- " static baz() native \"SomeNativeFunction3\";"
+ " static foo() native \"SomeNativeFunction\";\n"
+ " static bar() native \"SomeNativeFunction2\";\n"
+ " static baz() native \"SomeNativeFunction3\";\n"
"}";
Dart_Handle error = Dart_NewApiError("incoming error");
Dart_Handle result;
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index abb3e5d..3a53dcc 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -192,7 +192,12 @@
ASSERT(getter_result.IsNull() || getter_result.IsInstance());
arguments.SetAt(0, getter_result);
- return InvokeClosure(arguments, arguments_descriptor);
+ // This otherwise unnecessary handle is used to prevent clang from
+ // doing tail call elimination, which would make the stack overflow
+ // check above ineffective.
+ Object& result = Object::Handle(InvokeClosure(arguments,
+ arguments_descriptor));
+ return result.raw();
}
cls = cls.SuperClass();
}
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index c533e3b..1b3d84a 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -84,7 +84,7 @@
line_number_(-1),
column_number_(-1) {
ASSERT(!script.IsNull());
- ASSERT(token_pos_ >= 0);
+ ASSERT(Token::IsReal(token_pos_));
}
// Create a latent breakpoint at given url and line number.
@@ -93,8 +93,8 @@
intptr_t requested_column_number)
: script_(Script::null()),
url_(url.raw()),
- token_pos_(Scanner::kNoSourcePos),
- end_token_pos_(Scanner::kNoSourcePos),
+ token_pos_(Token::kNoSourcePos),
+ end_token_pos_(Token::kNoSourcePos),
is_resolved_(false),
next_(NULL),
conditions_(NULL),
@@ -239,7 +239,7 @@
code_(Code::ZoneHandle(code.raw())),
function_(Function::ZoneHandle(code.function())),
token_pos_initialized_(false),
- token_pos_(Scanner::kNoSourcePos),
+ token_pos_(Token::kNoSourcePos),
try_index_(-1),
line_number_(-1),
column_number_(-1),
@@ -566,7 +566,7 @@
intptr_t ActivationFrame::TokenPos() {
if (!token_pos_initialized_) {
token_pos_initialized_ = true;
- token_pos_ = Scanner::kNoSourcePos;
+ token_pos_ = Token::kNoSourcePos;
GetPcDescriptors();
PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind);
uword pc_offset = pc_ - code().EntryPoint();
@@ -592,9 +592,10 @@
intptr_t ActivationFrame::LineNumber() {
// Compute line number lazily since it causes scanning of the script.
- if ((line_number_ < 0) && (TokenPos() >= 0)) {
+ if ((line_number_ < 0) && Token::IsReal(TokenPos())) {
+ const intptr_t token_pos = TokenPos();
const Script& script = Script::Handle(SourceScript());
- script.GetTokenLocation(TokenPos(), &line_number_, NULL);
+ script.GetTokenLocation(token_pos, &line_number_, NULL);
}
return line_number_;
}
@@ -602,10 +603,11 @@
intptr_t ActivationFrame::ColumnNumber() {
// Compute column number lazily since it causes scanning of the script.
- if ((column_number_ < 0) && (TokenPos() >= 0)) {
+ if ((column_number_ < 0) && Token::IsReal(TokenPos())) {
+ const intptr_t token_pos = TokenPos();
const Script& script = Script::Handle(SourceScript());
if (script.HasSource()) {
- script.GetTokenLocation(TokenPos(), &line_number_, &column_number_);
+ script.GetTokenLocation(token_pos, &line_number_, &column_number_);
} else {
column_number_ = -1;
}
@@ -654,7 +656,7 @@
ASSERT(!pc_desc_.IsNull());
intptr_t innermost_begin_pos = 0;
intptr_t activation_token_pos = TokenPos();
- ASSERT(activation_token_pos >= 0);
+ ASSERT(Token::IsReal(activation_token_pos));
GetVarDescriptors();
intptr_t var_desc_len = var_descriptors_.Length();
for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) {
@@ -767,7 +769,7 @@
GetVarDescriptors();
intptr_t activation_token_pos = TokenPos();
- if (activation_token_pos < 0) {
+ if (!Token::IsDebugPause(activation_token_pos)) {
// We don't have a token position for this frame, so can't determine
// which variables are visible.
vars_initialized_ = true;
@@ -1256,6 +1258,7 @@
obj_cache_(NULL),
stack_trace_(NULL),
stepping_fp_(0),
+ skip_next_step_(false),
exc_pause_info_(kNoPauseOnExceptions) {
}
@@ -1626,7 +1629,6 @@
// interested in exception events.
if (ignore_breakpoints_ ||
IsPaused() ||
- (!HasDebugEventHandler()) ||
(exc_pause_info_ == kNoPauseOnExceptions)) {
return;
}
@@ -1675,8 +1677,8 @@
// and:
// - has the lowest token position number which satisfies the above.
//
-// When we consider a column number, we look for the closed token
-// which intersects the desired column. For example:
+// When we consider a column number, we look for the token which
+// intersects the desired column. For example:
//
// 1 2 3
// 12345678901234567890 0
@@ -1740,7 +1742,7 @@
PcDescriptors::Iterator iter(desc, kSafepointKind);
while (iter.MoveNext()) {
const intptr_t pos = iter.TokenPos();
- if ((pos < 0) ||
+ if ((!Token::IsReal(pos)) ||
(pos < requested_token_pos) ||
(pos > last_token_pos)) {
// Token is not in the target range.
@@ -1786,7 +1788,7 @@
PcDescriptors::Iterator iter(desc, kSafepointKind);
while (iter.MoveNext()) {
const intptr_t pos = iter.TokenPos();
- if ((pos < 0) ||
+ if ((!Token::IsReal(pos)) ||
(pos < begin_pos) ||
(pos > end_of_line_pos)) {
// Token is not on same line as best fit.
@@ -1821,13 +1823,13 @@
return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos(),
-1 /* no column */);
}
- return -1;
+ return Token::kNoSourcePos;
}
void Debugger::MakeCodeBreakpointAt(const Function& func,
BreakpointLocation* loc) {
- ASSERT(loc->token_pos_ >= 0);
+ ASSERT(Token::IsReal(loc->token_pos_));
ASSERT((loc != NULL) && loc->IsResolved());
ASSERT(!func.HasOptimizedCode());
Code& code = Code::Handle(func.unoptimized_code());
@@ -2144,7 +2146,7 @@
if (!closure.IsClosure()) {
return NULL;
}
- const Function& func = Function::Handle(Closure::function(closure));
+ const Function& func = Function::Handle(Closure::Cast(closure).function());
const Script& script = Script::Handle(func.script());
BreakpointLocation* bpt_location = SetBreakpoint(script,
func.token_pos(),
@@ -2242,14 +2244,14 @@
script ^= scripts.At(0);
intptr_t first_token_idx, last_token_idx;
script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx);
- if (first_token_idx < 0) {
+ if (!Token::IsReal(first_token_idx)) {
// Script does not contain the given line number.
if (FLAG_verbose_debug) {
OS::Print("Script '%s' does not contain line number %" Pd "\n",
script_url.ToCString(), line_number);
}
return NULL;
- } else if (last_token_idx < 0) {
+ } else if (!Token::IsReal(last_token_idx)) {
// Line does not contain any tokens.
if (FLAG_verbose_debug) {
OS::Print("No executable code at line %" Pd " in '%s'\n",
@@ -2531,7 +2533,8 @@
}
-void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace) {
+void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace,
+ bool skip_next_step) {
stepping_fp_ = 0;
if (resume_action_ == kSingleStep) {
// When single stepping, we need to deoptimize because we might be
@@ -2541,11 +2544,19 @@
// to call an optimized function.
DeoptimizeWorld();
isolate_->set_single_step(true);
+ skip_next_step_ = skip_next_step;
+ if (FLAG_verbose_debug) {
+ OS::Print("HandleSteppingRequest- kSingleStep\n");
+ }
} else if (resume_action_ == kStepOver) {
DeoptimizeWorld();
isolate_->set_single_step(true);
+ skip_next_step_ = skip_next_step;
ASSERT(stack_trace->Length() > 0);
stepping_fp_ = stack_trace->FrameAt(0)->fp();
+ if (FLAG_verbose_debug) {
+ OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_);
+ }
} else if (resume_action_ == kStepOut) {
DeoptimizeWorld();
isolate_->set_single_step(true);
@@ -2557,6 +2568,9 @@
break;
}
}
+ if (FLAG_verbose_debug) {
+ OS::Print("HandleSteppingRequest- kStepOut %" Px "\n", stepping_fp_);
+ }
}
}
@@ -2614,6 +2628,10 @@
if (IsPaused()) {
return Error::null();
}
+ if (skip_next_step_) {
+ skip_next_step_ = false;
+ return Error::null();
+ }
// Check whether we are in a Dart function that the user is
// interested in. If we saved the frame pointer of a stack frame
@@ -2627,7 +2645,7 @@
// There is an "interesting frame" set. Only pause at appropriate
// locations in this frame.
if (stepping_fp_ > frame->fp()) {
- // We are in a callee of the frame we're interested in.
+ // We are i n a callee of the frame we're interested in.
// Ignore this stepping break.
return Error::null();
} else if (frame->fp() > stepping_fp_) {
@@ -2641,15 +2659,14 @@
if (!frame->IsDebuggable()) {
return Error::null();
}
- if (frame->TokenPos() < 0) {
+ if (!Token::IsDebugPause(frame->TokenPos())) {
return Error::null();
}
- // Don't pause for a single step if there is a breakpoint set
- // at this location.
- if (HasActiveBreakpoint(frame->pc())) {
- return Error::null();
- }
+ // If there is an active breakpoint at this pc, then we should have
+ // already bailed out of this function in the skip_next_step_ test
+ // above.
+ ASSERT(!HasActiveBreakpoint(frame->pc()));
if (FLAG_verbose_debug) {
OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n",
@@ -2748,7 +2765,9 @@
ASSERT(stack_trace_ == NULL);
stack_trace_ = stack_trace;
SignalPausedEvent(top_frame, bpt_hit);
- HandleSteppingRequest(stack_trace_);
+ // When we single step from a user breakpoint, our next stepping
+ // point will be at the exact same pc. Skip it.
+ HandleSteppingRequest(stack_trace_, true /* skip next step */);
stack_trace_ = NULL;
if (cbpt->IsInternal()) {
RemoveInternalBreakpoints();
@@ -2886,7 +2905,7 @@
intptr_t bp_pos =
ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos(),
loc->requested_column_number());
- if (bp_pos < 0) {
+ if (!Token::IsDebugPause(bp_pos)) {
if (FLAG_verbose_debug) {
OS::Print("Failed resolving breakpoint for function '%s'\n",
String::Handle(func.name()).ToCString());
@@ -2974,8 +2993,8 @@
ASSERT(line_number >= 0);
intptr_t first_token_pos, last_token_pos;
script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos);
- if ((first_token_pos < 0) ||
- (last_token_pos < 0)) {
+ if (!Token::IsDebugPause(first_token_pos) ||
+ !Token::IsDebugPause(last_token_pos)) {
// Script does not contain the given line number or there are no
// tokens on the line. Drop the breakpoint silently.
Breakpoint* bpt = matched_loc->breakpoints();
@@ -3111,7 +3130,7 @@
pause_event_->breakpoint() == curr_bpt) {
pause_event_->set_breakpoint(NULL);
}
- return;
+ break;
}
prev_bpt = curr_bpt;
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index acb69ec..5696e96 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -651,7 +651,8 @@
// interrupts, etc.
void Pause(DebuggerEvent* event);
- void HandleSteppingRequest(DebuggerStackTrace* stack_trace);
+ void HandleSteppingRequest(DebuggerStackTrace* stack_trace,
+ bool skip_next_step = false);
Isolate* isolate_;
Dart_Port isolate_id_; // A unique ID for the isolate in the debugger.
@@ -690,6 +691,11 @@
// lower on the stack.
uword stepping_fp_;
+ // If we step while at a breakpoint, we would hit the same pc twice.
+ // We use this field to let us skip the next single-step after a
+ // breakpoint.
+ bool skip_next_step_;
+
Dart_ExceptionPauseInfo exc_pause_info_;
static EventHandler* event_handler_;
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 7e1ec45..5241d34 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -652,7 +652,7 @@
// Construct the super type object, canonicalize it and return.
Type& instantiated_type = Type::Handle(
- Type::New(super_cls, super_type_args_array, Scanner::kNoSourcePos));
+ Type::New(super_cls, super_type_args_array, Token::kNoSourcePos));
ASSERT(!instantiated_type.IsNull());
instantiated_type.SetIsFinalized();
return Api::NewHandle(T, instantiated_type.Canonicalize());
@@ -671,7 +671,7 @@
if (!instance.IsClosure()) {
return Api::NewError("%s: parameter 0 is not a closure", CURRENT_FUNC);
}
- const Function& func = Function::Handle(Closure::function(instance));
+ const Function& func = Function::Handle(Closure::Cast(instance).function());
ASSERT(!func.IsNull());
if (name != NULL) {
*name = Api::NewHandle(T, func.QualifiedUserVisibleName());
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index 71a734a..d3f89c7 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -304,6 +304,48 @@
}
}
}
+ } else if (cls.id() == kClosureCid) {
+ // TODO(regis): It would be better to programmatically add these fields to
+ // the VM Closure class. Declaring them in the Dart class _Closure does not
+ // work, because the class is prefinalized and CalculateFieldOffsets is
+ // therefore not called. Resetting the finalization state may be an option.
+ const Closure& closure = Closure::Cast(*object_);
+
+ Smi& offset = Smi::Handle();
+ Object& value = Object::Handle();
+
+ for (intptr_t i = 0; i < field_count_; i++) {
+ offset ^= GetFieldOffset(i);
+ if (offset.Value() == Closure::type_arguments_offset()) {
+ TypeArguments& arguments = TypeArguments::Handle();
+ arguments ^= GetValue(i);
+ closure.SetTypeArguments(arguments);
+ if (FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr(" closure@type_arguments (offset %" Pd ") <- %s\n",
+ offset.Value(),
+ value.ToCString());
+ }
+ } else if (offset.Value() == Closure::function_offset()) {
+ Function& function = Function::Handle();
+ function ^= GetValue(i);
+ closure.set_function(function);
+ if (FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr(" closure@function (offset %" Pd ") <- %s\n",
+ offset.Value(),
+ value.ToCString());
+ }
+ } else {
+ ASSERT(offset.Value() == Closure::context_offset());
+ Context& context = Context::Handle();
+ context ^= GetValue(i);
+ closure.set_context(context);
+ if (FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr(" closure@context (offset %" Pd ") <- %s\n",
+ offset.Value(),
+ value.ToCString());
+ }
+ }
+ }
} else {
const Instance& obj = Instance::Cast(*object_);
@@ -324,8 +366,7 @@
value.ToCString());
}
} else {
- ASSERT(cls.IsSignatureClass() ||
- (offset.Value() == cls.type_arguments_field_offset()));
+ ASSERT(offset.Value() == cls.type_arguments_field_offset());
obj.SetFieldAtOffset(offset.Value(), value);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" null Field @ offset(%" Pd ") <- %s\n",
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index fed89bb..ee62949 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -48,6 +48,9 @@
// Quick access to the locally defined zone() method.
#define Z (zone())
+// Quick synthetic token position.
+#define ST(token_pos) Token::ToSynthetic(token_pos)
+
// TODO(srdjan): Allow compiler to add constants as they are encountered in
// the compilation.
const double kCommonDoubleConstants[] =
@@ -829,20 +832,26 @@
Definition* EffectGraphVisitor::BuildStoreTemp(const LocalVariable& local,
- Value* value) {
+ Value* value,
+ intptr_t token_pos) {
ASSERT(!local.is_captured());
- return new(Z) StoreLocalInstr(local, value);
+ ASSERT(!Token::IsClassifying(token_pos));
+ return new(Z) StoreLocalInstr(local, value, ST(token_pos));
}
-Definition* EffectGraphVisitor::BuildStoreExprTemp(Value* value) {
+Definition* EffectGraphVisitor::BuildStoreExprTemp(Value* value,
+ intptr_t token_pos) {
return BuildStoreTemp(*owner()->parsed_function().expression_temp_var(),
- value);
+ value,
+ token_pos);
}
-Definition* EffectGraphVisitor::BuildLoadExprTemp() {
- return BuildLoadLocal(*owner()->parsed_function().expression_temp_var());
+Definition* EffectGraphVisitor::BuildLoadExprTemp(intptr_t token_pos) {
+ ASSERT(!Token::IsClassifying(token_pos));
+ return BuildLoadLocal(*owner()->parsed_function().expression_temp_var(),
+ token_pos);
}
@@ -850,7 +859,7 @@
Value* value,
intptr_t token_pos) {
if (local.is_captured()) {
- LocalVariable* tmp_var = EnterTempLocalScope(value);
+ LocalVariable* tmp_var = EnterTempLocalScope(value, token_pos);
intptr_t delta =
owner()->context_level() - local.owner()->context_level();
ASSERT(delta >= 0);
@@ -860,7 +869,7 @@
context, Context::parent_offset(), Type::ZoneHandle(Z, Type::null()),
token_pos));
}
- Value* tmp_val = Bind(new(Z) LoadLocalInstr(*tmp_var));
+ Value* tmp_val = Bind(new(Z) LoadLocalInstr(*tmp_var, token_pos));
StoreInstanceFieldInstr* store =
new(Z) StoreInstanceFieldInstr(Context::variable_offset(local.index()),
context,
@@ -868,7 +877,7 @@
kEmitStoreBarrier,
token_pos);
Do(store);
- return ExitTempLocalScope(tmp_var);
+ return ExitTempLocalScope(tmp_var, token_pos);
} else {
return new(Z) StoreLocalInstr(local, value, token_pos);
}
@@ -903,6 +912,7 @@
void EffectGraphVisitor::BuildSaveContext(
const LocalVariable& variable,
intptr_t token_pos) {
+ ASSERT(Token::IsSynthetic(token_pos) || Token::IsNoSource(token_pos));
Value* context = Bind(BuildCurrentContext(token_pos));
Do(BuildStoreLocal(variable, context, token_pos));
}
@@ -1122,7 +1132,7 @@
// statements for which there is no associated source position.
const Function& function = owner()->function();
if (FLAG_support_debugger &&
- (node->token_pos() >= 0) && !function.is_native()) {
+ Token::IsDebugPause(node->token_pos()) && !function.is_native()) {
AddInstruction(new(Z) DebugStepCheckInstr(node->token_pos(),
RawPcDescriptors::kRuntimeCall));
}
@@ -1177,7 +1187,7 @@
if (function.IsAsyncClosure() &&
(node->return_type() == ReturnNode::kRegular)) {
// Temporary store the computed return value.
- Do(BuildStoreExprTemp(return_value));
+ Do(BuildStoreExprTemp(return_value, node->token_pos()));
LocalVariable* rcv_var =
node->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
@@ -1186,7 +1196,7 @@
new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
Value* rcv_value = Bind(BuildLoadLocal(*rcv_var, node->token_pos()));
arguments->Add(PushArgument(rcv_value));
- Value* returned_value = Bind(BuildLoadExprTemp());
+ Value* returned_value = Bind(BuildLoadExprTemp(node->token_pos()));
arguments->Add(PushArgument(returned_value));
InstanceCallInstr* call = new(Z) InstanceCallInstr(
node->token_pos(),
@@ -1199,7 +1209,7 @@
Do(call);
// Rebind the return value for the actual return call to be null.
- return_value = BuildNullValue();
+ return_value = BuildNullValue(node->token_pos());
}
intptr_t current_context_level = owner()->context_level();
@@ -1425,22 +1435,22 @@
right_value,
constant_true,
false)); // No number check.
- for_right.Do(BuildStoreExprTemp(compare));
+ for_right.Do(BuildStoreExprTemp(compare, node->token_pos()));
if (node->kind() == Token::kAND) {
ValueGraphVisitor for_false(owner());
Value* constant_false =
for_false.Bind(new(Z) ConstantInstr(Bool::False()));
- for_false.Do(BuildStoreExprTemp(constant_false));
+ for_false.Do(BuildStoreExprTemp(constant_false, node->token_pos()));
Join(for_test, for_right, for_false);
} else {
ASSERT(node->kind() == Token::kOR);
ValueGraphVisitor for_true(owner());
Value* constant_true = for_true.Bind(new(Z) ConstantInstr(Bool::True()));
- for_true.Do(BuildStoreExprTemp(constant_true));
+ for_true.Do(BuildStoreExprTemp(constant_true, node->token_pos()));
Join(for_test, for_true, for_right);
}
- ReturnDefinition(BuildLoadExprTemp());
+ ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
return;
}
@@ -1502,9 +1512,9 @@
const Class& instantiator_class = Class::Handle(
Z, owner()->function().Owner());
// Since called only when type tested against is not instantiated.
- ASSERT(instantiator_class.NumTypeParameters() > 0);
+ ASSERT(instantiator_class.IsGeneric());
Value* instantiator_type_arguments = NULL;
- Value* instantiator = BuildInstantiator(instantiator_class);
+ Value* instantiator = BuildInstantiator(token_pos);
if (instantiator == NULL) {
// No instantiator when inside factory.
instantiator_type_arguments =
@@ -1527,8 +1537,8 @@
const Class& instantiator_class = Class::Handle(
Z, owner()->function().Owner());
// Since called only when type tested against is not instantiated.
- ASSERT(instantiator_class.NumTypeParameters() > 0);
- instantiator = BuildInstantiator(instantiator_class);
+ ASSERT(instantiator_class.IsGeneric());
+ instantiator = BuildInstantiator(token_pos);
if (instantiator == NULL) {
// No instantiator when inside factory.
instantiator_type_arguments =
@@ -1541,8 +1551,9 @@
}
-Value* EffectGraphVisitor::BuildNullValue() {
- return Bind(new(Z) ConstantInstr(Object::ZoneHandle(Z, Object::null())));
+Value* EffectGraphVisitor::BuildNullValue(intptr_t token_pos) {
+ return Bind(new(Z) ConstantInstr(Object::ZoneHandle(Z, Object::null()),
+ token_pos));
}
@@ -1555,7 +1566,7 @@
// Build the type check computation.
Value* instantiator_type_arguments = NULL;
if (dst_type.IsInstantiated()) {
- instantiator_type_arguments = BuildNullValue();
+ instantiator_type_arguments = BuildNullValue(token_pos);
} else {
BuildTypecheckArguments(token_pos, &instantiator_type_arguments);
}
@@ -1666,7 +1677,7 @@
PushArgumentInstr* push_left = PushArgument(for_left_value.value());
PushArgumentInstr* push_type_args = NULL;
if (type.IsInstantiated()) {
- push_type_args = PushArgument(BuildNullValue());
+ push_type_args = PushArgument(BuildNullValue(node->token_pos()));
} else {
BuildTypecheckPushArguments(node->token_pos(), &push_type_args);
}
@@ -1718,7 +1729,7 @@
PushArgumentInstr* push_left = PushArgument(for_value.value());
PushArgumentInstr* push_type_args = NULL;
if (type.IsInstantiated()) {
- push_type_args = PushArgument(BuildNullValue());
+ push_type_args = PushArgument(BuildNullValue(node->token_pos()));
} else {
BuildTypecheckPushArguments(node->token_pos(), &push_type_args);
}
@@ -1917,15 +1928,17 @@
ValueGraphVisitor for_true(owner());
node->true_expr()->Visit(&for_true);
ASSERT(for_true.is_open());
- for_true.Do(BuildStoreExprTemp(for_true.value()));
+ for_true.Do(BuildStoreExprTemp(for_true.value(),
+ node->true_expr()->token_pos()));
ValueGraphVisitor for_false(owner());
node->false_expr()->Visit(&for_false);
ASSERT(for_false.is_open());
- for_false.Do(BuildStoreExprTemp(for_false.value()));
+ for_false.Do(BuildStoreExprTemp(for_false.value(),
+ node->false_expr()->token_pos()));
Join(for_test, for_true, for_false);
- ReturnDefinition(BuildLoadExprTemp());
+ ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
}
@@ -2273,6 +2286,8 @@
// We need to create a new await state which involves:
// * Increase the jump counter. Sanity check against the list of targets.
// * Save the current context for resuming.
+ ASSERT(Token::IsSynthetic(node->token_pos()) ||
+ Token::IsNoSource(node->token_pos()));
ASSERT(node->async_scope() != NULL);
ASSERT(node->await_scope() != NULL);
LocalVariable* jump_var = node->async_scope()->LookupVariable(
@@ -2288,8 +2303,8 @@
ASSERT(jump_count == owner()->await_joins()->length());
// Store the counter in :await_jump_var.
Value* jump_val = Bind(new(Z) ConstantInstr(
- Smi::ZoneHandle(Z, Smi::New(jump_count))));
- Do(BuildStoreLocal(*jump_var, jump_val));
+ Smi::ZoneHandle(Z, Smi::New(jump_count)), node->token_pos()));
+ Do(BuildStoreLocal(*jump_var, jump_val, node->token_pos()));
// Save the current context for resuming.
BuildSaveContext(*ctx_var, node->token_pos());
}
@@ -2304,7 +2319,8 @@
}
-LocalVariable* EffectGraphVisitor::EnterTempLocalScope(Value* value) {
+LocalVariable* EffectGraphVisitor::EnterTempLocalScope(
+ Value* value, intptr_t token_pos) {
Do(new(Z) PushTempInstr(value));
owner()->AllocateTemp();
@@ -2313,7 +2329,7 @@
char name[64];
OS::SNPrint(name, 64, ":tmp_local%" Pd, index);
LocalVariable* var =
- new(Z) LocalVariable(Scanner::kNoSourcePos,
+ new(Z) LocalVariable(Token::kNoSourcePos,
String::ZoneHandle(Z, Symbols::New(name)),
*value->Type()->ToAbstractType());
var->set_index(index);
@@ -2321,8 +2337,9 @@
}
-Definition* EffectGraphVisitor::ExitTempLocalScope(LocalVariable* var) {
- Value* tmp = Bind(new(Z) LoadLocalInstr(*var));
+Definition* EffectGraphVisitor::ExitTempLocalScope(
+ LocalVariable* var, intptr_t token_pos) {
+ Value* tmp = Bind(new(Z) LoadLocalInstr(*var, token_pos));
owner()->DeallocateTemps(1);
ASSERT(GetCurrentTempLocalIndex() == var->index());
return new(Z) DropTempsInstr(1, tmp);
@@ -2400,13 +2417,14 @@
num_elements);
Value* array_val = Bind(create);
- { LocalVariable* tmp_var = EnterTempLocalScope(array_val);
+ { LocalVariable* tmp_var = EnterTempLocalScope(array_val, node->token_pos());
const intptr_t class_id = kArrayCid;
const intptr_t deopt_id = Thread::kNoDeoptId;
for (int i = 0; i < node->length(); ++i) {
- Value* array = Bind(new(Z) LoadLocalInstr(*tmp_var));
+ Value* array = Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
Value* index =
- Bind(new(Z) ConstantInstr(Smi::ZoneHandle(Z, Smi::New(i))));
+ Bind(new(Z) ConstantInstr(Smi::ZoneHandle(Z, Smi::New(i)),
+ node->token_pos()));
ValueGraphVisitor for_value(owner());
node->ElementAt(i)->Visit(&for_value);
Append(for_value);
@@ -2421,7 +2439,7 @@
index_scale, class_id, deopt_id, node->token_pos());
Do(store);
}
- ReturnDefinition(ExitTempLocalScope(tmp_var));
+ ReturnDefinition(ExitTempLocalScope(tmp_var, node->token_pos()));
}
}
@@ -2500,36 +2518,45 @@
isolate()->AddClosureFunction(function);
}
}
- ZoneGrowableArray<PushArgumentInstr*>* arguments =
- new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
ASSERT(function.context_scope() != ContextScope::null());
// The function type of a closure may have type arguments. In that case,
// pass the type arguments of the instantiator.
- const Class& cls = Class::ZoneHandle(Z, function.signature_class());
- ASSERT(!cls.IsNull());
- const bool requires_type_arguments = cls.NumTypeArguments() > 0;
- Value* type_arguments = NULL;
- if (requires_type_arguments) {
- ASSERT(cls.type_arguments_field_offset() ==
- Closure::type_arguments_offset());
- ASSERT(cls.instance_size() == Closure::InstanceSize());
- const Class& instantiator_class = Class::Handle(
- Z, owner()->function().Owner());
- type_arguments = BuildInstantiatorTypeArguments(node->token_pos(),
- instantiator_class,
- NULL);
- arguments->Add(PushArgument(type_arguments));
- }
+ const Class& closure_class =
+ Class::ZoneHandle(Z, isolate()->object_store()->closure_class());
+ ZoneGrowableArray<PushArgumentInstr*>* no_arguments =
+ new(Z) ZoneGrowableArray<PushArgumentInstr*>(0);
AllocateObjectInstr* alloc = new(Z) AllocateObjectInstr(node->token_pos(),
- cls,
- arguments);
+ closure_class,
+ no_arguments);
alloc->set_closure_function(function);
Value* closure_val = Bind(alloc);
- { LocalVariable* closure_tmp_var = EnterTempLocalScope(closure_val);
+ { LocalVariable* closure_tmp_var = EnterTempLocalScope(closure_val,
+ node->token_pos());
+ // Store type arguments if scope class is generic.
+ const FunctionType& function_type =
+ FunctionType::ZoneHandle(Z, function.SignatureType());
+ const Class& scope_cls = Class::ZoneHandle(Z, function_type.scope_class());
+ if (scope_cls.IsGeneric()) {
+ ASSERT(function.Owner() == scope_cls.raw());
+ Value* closure_tmp_val = Bind(new(Z) LoadLocalInstr(*closure_tmp_var,
+ node->token_pos()));
+ const Class& instantiator_class = Class::Handle(
+ Z, owner()->function().Owner());
+ Value* type_arguments = BuildInstantiatorTypeArguments(node->token_pos(),
+ instantiator_class,
+ NULL);
+ Do(new(Z) StoreInstanceFieldInstr(Closure::type_arguments_offset(),
+ closure_tmp_val,
+ type_arguments,
+ kEmitStoreBarrier,
+ node->token_pos()));
+ }
+
// Store function.
- Value* closure_tmp_val = Bind(new(Z) LoadLocalInstr(*closure_tmp_var));
+ Value* closure_tmp_val =
+ Bind(new(Z) LoadLocalInstr(*closure_tmp_var, node->token_pos()));
Value* func_val =
Bind(new(Z) ConstantInstr(Function::ZoneHandle(Z, function.raw())));
Do(new(Z) StoreInstanceFieldInstr(Closure::function_offset(),
@@ -2543,9 +2570,11 @@
Value* allocated_context =
Bind(new(Z) AllocateContextInstr(node->token_pos(),
kNumContextVariables));
- { LocalVariable* context_tmp_var = EnterTempLocalScope(allocated_context);
+ { LocalVariable* context_tmp_var =
+ EnterTempLocalScope(allocated_context, node->token_pos());
// Store receiver in context.
- Value* context_tmp_val = Bind(new(Z) LoadLocalInstr(*context_tmp_var));
+ Value* context_tmp_val =
+ Bind(new(Z) LoadLocalInstr(*context_tmp_var, node->token_pos()));
ValueGraphVisitor for_receiver(owner());
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
@@ -2556,14 +2585,16 @@
kEmitStoreBarrier,
node->token_pos()));
// Store new context in closure.
- closure_tmp_val = Bind(new(Z) LoadLocalInstr(*closure_tmp_var));
- context_tmp_val = Bind(new(Z) LoadLocalInstr(*context_tmp_var));
+ closure_tmp_val =
+ Bind(new(Z) LoadLocalInstr(*closure_tmp_var, node->token_pos()));
+ context_tmp_val =
+ Bind(new(Z) LoadLocalInstr(*context_tmp_var, node->token_pos()));
Do(new(Z) StoreInstanceFieldInstr(Closure::context_offset(),
closure_tmp_val,
context_tmp_val,
kEmitStoreBarrier,
node->token_pos()));
- Do(ExitTempLocalScope(context_tmp_var));
+ Do(ExitTempLocalScope(context_tmp_var, node->token_pos()));
}
} else {
// Store current context in closure.
@@ -2576,7 +2607,7 @@
kEmitStoreBarrier,
node->token_pos()));
}
- ReturnDefinition(ExitTempLocalScope(closure_tmp_var));
+ ReturnDefinition(ExitTempLocalScope(closure_tmp_var, node->token_pos()));
}
}
@@ -2595,34 +2626,34 @@
void EffectGraphVisitor::BuildInstanceCallConditional(InstanceCallNode* node) {
+ const intptr_t token_pos = node->token_pos();
LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
- LoadLocalNode* load_temp =
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+ LoadLocalNode* load_temp = new(Z) LoadLocalNode(token_pos, temp_var);
LiteralNode* null_constant =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+ new(Z) LiteralNode(ST(token_pos), Object::null_instance());
ComparisonNode* check_is_null =
- new(Z) ComparisonNode(Scanner::kNoSourcePos,
+ new(Z) ComparisonNode(ST(token_pos),
Token::kEQ,
load_temp,
null_constant);
- TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+ TestGraphVisitor for_test(owner(), ST(token_pos));
check_is_null->Visit(&for_test);
EffectGraphVisitor for_true(owner());
EffectGraphVisitor for_false(owner());
StoreLocalNode* store_null =
- new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, null_constant);
+ new(Z) StoreLocalNode(ST(token_pos), temp_var, null_constant);
store_null->Visit(&for_true);
InstanceCallNode* call =
- new(Z) InstanceCallNode(node->token_pos(),
+ new(Z) InstanceCallNode(token_pos,
load_temp,
node->function_name(),
node->arguments());
StoreLocalNode* store_result =
- new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, call);
+ new(Z) StoreLocalNode(ST(token_pos), temp_var, call);
store_result->Visit(&for_false);
Join(for_test, for_true, for_false);
@@ -2634,9 +2665,9 @@
ValueGraphVisitor for_receiver(owner());
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
- Do(BuildStoreExprTemp(for_receiver.value()));
+ Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
BuildInstanceCallConditional(node);
- ReturnDefinition(BuildLoadExprTemp());
+ ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
} else {
EffectGraphVisitor::VisitInstanceCallNode(node);
}
@@ -2648,7 +2679,7 @@
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
if (node->is_conditional()) {
- Do(BuildStoreExprTemp(for_receiver.value()));
+ Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
BuildInstanceCallConditional(node);
} else {
PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
@@ -2730,16 +2761,17 @@
node->closure()->Visit(&for_closure);
Append(for_closure);
- LocalVariable* tmp_var = EnterTempLocalScope(for_closure.value());
+ LocalVariable* tmp_var =
+ EnterTempLocalScope(for_closure.value(), node->token_pos());
ZoneGrowableArray<PushArgumentInstr*>* arguments =
new(Z) ZoneGrowableArray<PushArgumentInstr*>(node->arguments()->length());
- Value* closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var));
+ Value* closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
PushArgumentInstr* push_closure = PushArgument(closure_val);
arguments->Add(push_closure);
BuildPushArguments(*node->arguments(), arguments);
- closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var));
+ closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
LoadFieldInstr* function_load = new(Z) LoadFieldInstr(
closure_val,
Closure::function_offset(),
@@ -2752,11 +2784,11 @@
new(Z) ClosureCallInstr(function_val, node, arguments);
if (result_needed) {
Value* result = Bind(closure_call);
- Do(new(Z) StoreLocalInstr(*tmp_var, result));
+ Do(new(Z) StoreLocalInstr(*tmp_var, result, ST(node->token_pos())));
} else {
Do(closure_call);
}
- ReturnDefinition(ExitTempLocalScope(tmp_var));
+ ReturnDefinition(ExitTempLocalScope(tmp_var, node->token_pos()));
}
@@ -2886,8 +2918,7 @@
}
-Value* EffectGraphVisitor::BuildInstantiator(const Class& instantiator_class) {
- ASSERT(instantiator_class.NumTypeParameters() > 0);
+Value* EffectGraphVisitor::BuildInstantiator(intptr_t token_pos) {
Function& outer_function = Function::Handle(Z, owner()->function().raw());
while (outer_function.IsLocalFunction()) {
outer_function = outer_function.parent_function();
@@ -2898,7 +2929,7 @@
LocalVariable* instantiator = owner()->parsed_function().instantiator();
ASSERT(instantiator != NULL);
- Value* result = Bind(BuildLoadLocal(*instantiator));
+ Value* result = Bind(BuildLoadLocal(*instantiator, token_pos));
return result;
}
@@ -2909,7 +2940,7 @@
intptr_t token_pos,
const Class& instantiator_class,
Value* instantiator) {
- if (instantiator_class.NumTypeParameters() == 0) {
+ if (!instantiator_class.IsGeneric()) {
// The type arguments are compile time constants.
TypeArguments& type_arguments =
TypeArguments::ZoneHandle(Z, TypeArguments::null());
@@ -2934,10 +2965,10 @@
LocalVariable* instantiator_var =
owner()->parsed_function().instantiator();
ASSERT(instantiator_var != NULL);
- return Bind(BuildLoadLocal(*instantiator_var));
+ return Bind(BuildLoadLocal(*instantiator_var, token_pos));
}
if (instantiator == NULL) {
- instantiator = BuildInstantiator(instantiator_class);
+ instantiator = BuildInstantiator(token_pos);
}
// The instantiator is the receiver of the caller, which is not a factory.
// The receiver cannot be null; extract its TypeArguments object.
@@ -2951,7 +2982,7 @@
instantiator,
type_arguments_field_offset,
Type::ZoneHandle(Z, Type::null()), // Not an instance, no type.
- Scanner::kNoSourcePos));
+ token_pos));
}
@@ -2995,11 +3026,12 @@
// tn <- LoadLocal(temp)
Value* allocate = BuildObjectAllocation(node);
- { LocalVariable* tmp_var = EnterTempLocalScope(allocate);
- Value* allocated_tmp = Bind(new(Z) LoadLocalInstr(*tmp_var));
+ { LocalVariable* tmp_var = EnterTempLocalScope(allocate, node->token_pos());
+ Value* allocated_tmp =
+ Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
PushArgumentInstr* push_allocated_value = PushArgument(allocated_tmp);
BuildConstructorCall(node, push_allocated_value);
- ReturnDefinition(ExitTempLocalScope(tmp_var));
+ ReturnDefinition(ExitTempLocalScope(tmp_var, node->token_pos()));
}
}
@@ -3007,33 +3039,32 @@
void EffectGraphVisitor::BuildInstanceGetterConditional(
InstanceGetterNode* node) {
+ const intptr_t token_pos = node->token_pos();
LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
- LoadLocalNode* load_temp =
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+ LoadLocalNode* load_temp = new(Z) LoadLocalNode(token_pos, temp_var);
LiteralNode* null_constant =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+ new(Z) LiteralNode(ST(token_pos), Object::null_instance());
ComparisonNode* check_is_null =
- new(Z) ComparisonNode(Scanner::kNoSourcePos,
+ new(Z) ComparisonNode(ST(token_pos),
Token::kEQ,
load_temp,
null_constant);
- TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+ TestGraphVisitor for_test(owner(), ST(token_pos));
check_is_null->Visit(&for_test);
EffectGraphVisitor for_true(owner());
EffectGraphVisitor for_false(owner());
StoreLocalNode* store_null =
- new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, null_constant);
+ new(Z) StoreLocalNode(ST(token_pos), temp_var, null_constant);
store_null->Visit(&for_true);
- InstanceGetterNode* getter =
- new(Z) InstanceGetterNode(node->token_pos(),
- load_temp,
- node->field_name());
+ InstanceGetterNode* getter = new(Z) InstanceGetterNode(token_pos,
+ load_temp,
+ node->field_name());
StoreLocalNode* store_getter =
- new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, getter);
+ new(Z) StoreLocalNode(ST(token_pos), temp_var, getter);
store_getter->Visit(&for_false);
Join(for_test, for_true, for_false);
@@ -3045,9 +3076,9 @@
ValueGraphVisitor for_receiver(owner());
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
- Do(BuildStoreExprTemp(for_receiver.value()));
+ Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
BuildInstanceGetterConditional(node);
- ReturnDefinition(BuildLoadExprTemp());
+ ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
} else {
EffectGraphVisitor::VisitInstanceGetterNode(node);
}
@@ -3059,7 +3090,7 @@
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
if (node->is_conditional()) {
- Do(BuildStoreExprTemp(for_receiver.value()));
+ Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
BuildInstanceGetterConditional(node);
} else {
PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
@@ -3095,7 +3126,7 @@
Value* value = NULL;
if (result_is_needed) {
- value = Bind(BuildStoreExprTemp(for_value.value()));
+ value = Bind(BuildStoreExprTemp(for_value.value(), node->token_pos()));
} else {
value = for_value.value();
}
@@ -3104,30 +3135,31 @@
void EffectGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) {
+ const intptr_t token_pos = node->token_pos();
if (node->is_conditional()) {
ValueGraphVisitor for_receiver(owner());
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
- Do(BuildStoreExprTemp(for_receiver.value()));
+ Do(BuildStoreExprTemp(for_receiver.value(), token_pos));
LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
LoadLocalNode* load_temp =
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+ new(Z) LoadLocalNode(ST(token_pos), temp_var);
LiteralNode* null_constant =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+ new(Z) LiteralNode(ST(token_pos), Object::null_instance());
ComparisonNode* check_is_null =
- new(Z) ComparisonNode(Scanner::kNoSourcePos,
+ new(Z) ComparisonNode(ST(token_pos),
Token::kEQ,
load_temp,
null_constant);
- TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+ TestGraphVisitor for_test(owner(), ST(token_pos));
check_is_null->Visit(&for_test);
EffectGraphVisitor for_true(owner());
EffectGraphVisitor for_false(owner());
InstanceSetterNode* setter =
- new(Z) InstanceSetterNode(node->token_pos(),
+ new(Z) InstanceSetterNode(token_pos,
load_temp,
node->field_name(),
node->value());
@@ -3141,7 +3173,7 @@
const String& name =
String::ZoneHandle(Z, Field::SetterSymbol(node->field_name()));
const intptr_t kNumArgsChecked = 1; // Do not check value type.
- InstanceCallInstr* call = new(Z) InstanceCallInstr(node->token_pos(),
+ InstanceCallInstr* call = new(Z) InstanceCallInstr(token_pos,
name,
Token::kSET,
arguments,
@@ -3153,40 +3185,41 @@
void ValueGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) {
+ const intptr_t token_pos = node->token_pos();
if (node->is_conditional()) {
ValueGraphVisitor for_receiver(owner());
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
- Do(BuildStoreExprTemp(for_receiver.value()));
+ Do(BuildStoreExprTemp(for_receiver.value(), token_pos));
LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
LoadLocalNode* load_temp =
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+ new(Z) LoadLocalNode(ST(token_pos), temp_var);
LiteralNode* null_constant =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+ new(Z) LiteralNode(ST(token_pos), Object::null_instance());
ComparisonNode* check_is_null =
- new(Z) ComparisonNode(Scanner::kNoSourcePos,
+ new(Z) ComparisonNode(ST(token_pos),
Token::kEQ,
load_temp,
null_constant);
- TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+ TestGraphVisitor for_test(owner(), ST(token_pos));
check_is_null->Visit(&for_test);
ValueGraphVisitor for_true(owner());
null_constant->Visit(&for_true);
- for_true.Do(BuildStoreExprTemp(for_true.value()));
+ for_true.Do(BuildStoreExprTemp(for_true.value(), token_pos));
ValueGraphVisitor for_false(owner());
InstanceSetterNode* setter =
- new(Z) InstanceSetterNode(node->token_pos(),
+ new(Z) InstanceSetterNode(token_pos,
load_temp,
node->field_name(),
node->value());
setter->Visit(&for_false);
- for_false.Do(BuildStoreExprTemp(for_false.value()));
+ for_false.Do(BuildStoreExprTemp(for_false.value(), token_pos));
Join(for_test, for_true, for_false);
- ReturnDefinition(BuildLoadExprTemp());
+ ReturnDefinition(BuildLoadExprTemp(token_pos));
return;
}
ZoneGrowableArray<PushArgumentInstr*>* arguments =
@@ -3195,14 +3228,14 @@
const String& name =
String::ZoneHandle(Z, Field::SetterSymbol(node->field_name()));
const intptr_t kNumArgsChecked = 1; // Do not check value type.
- Do(new(Z) InstanceCallInstr(node->token_pos(),
+ Do(new(Z) InstanceCallInstr(token_pos,
name,
Token::kSET,
arguments,
Object::null_array(),
kNumArgsChecked,
owner()->ic_data_array()));
- ReturnDefinition(BuildLoadExprTemp());
+ ReturnDefinition(BuildLoadExprTemp(token_pos));
}
@@ -3284,6 +3317,7 @@
String::ZoneHandle(Z, Field::SetterSymbol(node->field_name()));
ZoneGrowableArray<PushArgumentInstr*>* arguments =
new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
+ const intptr_t token_pos = node->token_pos();
// A super setter is an instance setter whose setter function is
// resolved at compile time (in the caller instance getter's super class).
// Unlike a static getter, a super getter has a receiver parameter.
@@ -3294,7 +3328,7 @@
if (is_super_setter) {
ASSERT(node->receiver() != NULL);
// Resolve and call noSuchMethod.
- ArgumentListNode* arguments = new(Z) ArgumentListNode(node->token_pos());
+ ArgumentListNode* arguments = new(Z) ArgumentListNode(token_pos);
arguments->Add(node->receiver());
arguments->Add(node->value());
call = BuildStaticNoSuchMethodCall(
@@ -3306,10 +3340,10 @@
true); // Super invocation.
} else {
// Throw a NoSuchMethodError.
- ArgumentListNode* arguments = new(Z) ArgumentListNode(node->token_pos());
+ ArgumentListNode* arguments = new(Z) ArgumentListNode(token_pos);
arguments->Add(node->value());
call = BuildThrowNoSuchMethodError(
- node->token_pos(),
+ token_pos,
node->cls(),
setter_name,
arguments, // Argument is the value passed to the setter.
@@ -3332,13 +3366,13 @@
Append(for_value);
Value* value = NULL;
if (result_is_needed) {
- value = Bind(BuildStoreExprTemp(for_value.value()));
+ value = Bind(BuildStoreExprTemp(for_value.value(), token_pos));
} else {
value = for_value.value();
}
arguments->Add(PushArgument(value));
- call = new(Z) StaticCallInstr(node->token_pos(),
+ call = new(Z) StaticCallInstr(token_pos,
setter_function,
Object::null_array(), // No names.
arguments,
@@ -3346,7 +3380,7 @@
}
if (result_is_needed) {
Do(call);
- ReturnDefinition(BuildLoadExprTemp());
+ ReturnDefinition(BuildLoadExprTemp(token_pos));
} else {
ReturnDefinition(call);
}
@@ -3382,10 +3416,11 @@
}
-LoadLocalInstr* EffectGraphVisitor::BuildLoadThisVar(LocalScope* scope) {
+LoadLocalInstr* EffectGraphVisitor::BuildLoadThisVar(
+ LocalScope* scope, intptr_t token_pos) {
LocalVariable* receiver_var = scope->LookupVariable(Symbols::This(),
true); // Test only.
- return new(Z) LoadLocalInstr(*receiver_var);
+ return new(Z) LoadLocalInstr(*receiver_var, token_pos);
}
@@ -3395,7 +3430,7 @@
intptr_t offset,
const Type& type,
intptr_t class_id) {
- Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+ Value* receiver = Bind(BuildLoadThisVar(node->scope(), node->token_pos()));
LoadFieldInstr* load = new(Z) LoadFieldInstr(receiver,
offset,
type,
@@ -3410,10 +3445,10 @@
NativeBodyNode* node,
intptr_t offset,
StoreBarrierType emit_store_barrier) {
- Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+ Value* receiver = Bind(BuildLoadThisVar(node->scope(), node->token_pos()));
LocalVariable* value_var =
node->scope()->LookupVariable(Symbols::Value(), true);
- Value* value = Bind(new(Z) LoadLocalInstr(*value_var));
+ Value* value = Bind(new(Z) LoadLocalInstr(*value_var, node->token_pos()));
StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
offset,
receiver,
@@ -3427,19 +3462,20 @@
void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) {
const Function& function = owner()->function();
+ const intptr_t token_pos = node->token_pos();
if (!function.IsClosureFunction()) {
MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
switch (kind) {
case MethodRecognizer::kObjectEquals: {
- Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+ Value* receiver = Bind(BuildLoadThisVar(node->scope(), token_pos));
LocalVariable* other_var =
node->scope()->LookupVariable(Symbols::Other(),
true); // Test only.
- Value* other = Bind(new(Z) LoadLocalInstr(*other_var));
+ Value* other = Bind(new(Z) LoadLocalInstr(*other_var, token_pos));
// Receiver is not a number because numbers override equality.
const bool kNoNumberCheck = false;
StrictCompareInstr* compare =
- new(Z) StrictCompareInstr(node->token_pos(),
+ new(Z) StrictCompareInstr(token_pos,
Token::kEQ_STRICT,
receiver,
other,
@@ -3463,11 +3499,11 @@
Smi::ZoneHandle(Z, Smi::New(0))));
Value* load_val = Bind(load);
StrictCompareInstr* compare =
- new(Z) StrictCompareInstr(node->token_pos(),
- Token::kEQ_STRICT,
- load_val,
- zero_val,
- false); // No number check.
+ new(Z) StrictCompareInstr(token_pos,
+ Token::kEQ_STRICT,
+ load_val,
+ zero_val,
+ false); // No number check.
return ReturnDefinition(compare);
}
case MethodRecognizer::kGrowableArrayLength:
@@ -3483,12 +3519,12 @@
case MethodRecognizer::kClassIDgetID: {
LocalVariable* value_var =
node->scope()->LookupVariable(Symbols::Value(), true);
- Value* value = Bind(new(Z) LoadLocalInstr(*value_var));
+ Value* value = Bind(new(Z) LoadLocalInstr(*value_var, token_pos));
LoadClassIdInstr* load = new(Z) LoadClassIdInstr(value);
return ReturnDefinition(load);
}
case MethodRecognizer::kGrowableArrayCapacity: {
- Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+ Value* receiver = Bind(BuildLoadThisVar(node->scope(), token_pos));
LoadFieldInstr* data_load = new(Z) LoadFieldInstr(
receiver,
Array::data_offset(),
@@ -3509,12 +3545,14 @@
LocalVariable* type_args_parameter =
node->scope()->LookupVariable(Symbols::TypeArgumentsParameter(),
true);
- Value* element_type = Bind(new(Z) LoadLocalInstr(*type_args_parameter));
+ Value* element_type =
+ Bind(new(Z) LoadLocalInstr(*type_args_parameter, token_pos));
LocalVariable* length_parameter =
node->scope()->LookupVariable(Symbols::Length(), true);
- Value* length = Bind(new(Z) LoadLocalInstr(*length_parameter));
+ Value* length =
+ Bind(new(Z) LoadLocalInstr(*length_parameter, token_pos));
CreateArrayInstr* create_array =
- new CreateArrayInstr(node->token_pos(), element_type, length);
+ new CreateArrayInstr(token_pos, element_type, length);
return ReturnDefinition(create_array);
}
case MethodRecognizer::kBigint_getDigits: {
@@ -3627,7 +3665,7 @@
!node->value()->AsLoadLocalNode()->local().IsInternal()) ||
node->value()->IsClosureNode()) &&
!node->local().IsInternal() &&
- (node->token_pos() >= 0)) {
+ Token::IsDebugPause(node->token_pos())) {
AddInstruction(new(Z) DebugStepCheckInstr(
node->token_pos(), RawPcDescriptors::kRuntimeCall));
}
@@ -3673,6 +3711,7 @@
void EffectGraphVisitor::VisitStoreInstanceFieldNode(
StoreInstanceFieldNode* node) {
+ const intptr_t token_pos = node->token_pos();
ValueGraphVisitor for_instance(owner());
node->instance()->Visit(&for_instance);
Append(for_instance);
@@ -3691,26 +3730,26 @@
}
if (FLAG_use_field_guards) {
- store_value = Bind(BuildStoreExprTemp(store_value));
+ store_value = Bind(BuildStoreExprTemp(store_value, token_pos));
GuardFieldClassInstr* guard_field_class =
new(Z) GuardFieldClassInstr(store_value,
- node->field(),
- thread()->GetNextDeoptId());
+ node->field(),
+ thread()->GetNextDeoptId());
AddInstruction(guard_field_class);
- store_value = Bind(BuildLoadExprTemp());
+ store_value = Bind(BuildLoadExprTemp(token_pos));
GuardFieldLengthInstr* guard_field_length =
new(Z) GuardFieldLengthInstr(store_value,
node->field(),
thread()->GetNextDeoptId());
AddInstruction(guard_field_length);
- store_value = Bind(BuildLoadExprTemp());
+ store_value = Bind(BuildLoadExprTemp(token_pos));
}
StoreInstanceFieldInstr* store =
new(Z) StoreInstanceFieldInstr(node->field(),
for_instance.value(),
store_value,
kEmitStoreBarrier,
- node->token_pos());
+ token_pos);
// Maybe initializing unboxed store.
store->set_is_potential_unboxed_initialization(true);
ReturnDefinition(store);
@@ -3743,7 +3782,7 @@
Append(for_value);
Value* store_value = NULL;
if (result_is_needed) {
- store_value = Bind(BuildStoreExprTemp(for_value.value()));
+ store_value = Bind(BuildStoreExprTemp(for_value.value(), token_pos));
} else {
store_value = for_value.value();
}
@@ -3752,7 +3791,7 @@
if (result_is_needed) {
Do(store);
- return BuildLoadExprTemp();
+ return BuildLoadExprTemp(token_pos);
} else {
return store;
}
@@ -3835,6 +3874,7 @@
StoreIndexedNode* node,
bool result_is_needed) {
Function* super_function = NULL;
+ const intptr_t token_pos = node->token_pos();
if (node->IsSuperStore()) {
// Resolve the store indexed operator in the super class.
super_function = &Function::ZoneHandle(
@@ -3843,7 +3883,7 @@
if (super_function->IsNull()) {
// Could not resolve super operator. Generate call noSuchMethod() of the
// super class instead.
- ArgumentListNode* arguments = new(Z) ArgumentListNode(node->token_pos());
+ ArgumentListNode* arguments = new(Z) ArgumentListNode(token_pos);
arguments->Add(node->array());
arguments->Add(node->index_expr());
arguments->Add(node->value());
@@ -3857,7 +3897,7 @@
if (result_is_needed) {
Do(call);
// BuildStaticNoSuchMethodCall stores the value in expression_temp.
- return BuildLoadExprTemp();
+ return BuildLoadExprTemp(token_pos);
} else {
return call;
}
@@ -3881,7 +3921,7 @@
Append(for_value);
Value* value = NULL;
if (result_is_needed) {
- value = Bind(BuildStoreExprTemp(for_value.value()));
+ value = Bind(BuildStoreExprTemp(for_value.value(), token_pos));
} else {
value = for_value.value();
}
@@ -3891,14 +3931,14 @@
// Generate static call to super operator []=.
StaticCallInstr* store =
- new(Z) StaticCallInstr(node->token_pos(),
+ new(Z) StaticCallInstr(token_pos,
*super_function,
Object::null_array(),
arguments,
owner()->ic_data_array());
if (result_is_needed) {
Do(store);
- return BuildLoadExprTemp();
+ return BuildLoadExprTemp(token_pos);
} else {
return store;
}
@@ -3908,7 +3948,7 @@
const String& name =
String::ZoneHandle(Z, Symbols::New(Token::Str(Token::kASSIGN_INDEX)));
InstanceCallInstr* store =
- new(Z) InstanceCallInstr(node->token_pos(),
+ new(Z) InstanceCallInstr(token_pos,
name,
Token::kASSIGN_INDEX,
arguments,
@@ -3917,7 +3957,7 @@
owner()->ic_data_array());
if (result_is_needed) {
Do(store);
- return BuildLoadExprTemp();
+ return BuildLoadExprTemp(token_pos);
} else {
return store;
}
@@ -4008,7 +4048,8 @@
Value* allocated_context =
Bind(new(Z) AllocateContextInstr(node->token_pos(),
num_context_variables));
- { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context);
+ { LocalVariable* tmp_var =
+ EnterTempLocalScope(allocated_context, node->token_pos());
if (!is_top_level_sequence || HasContextScope()) {
ASSERT(is_top_level_sequence ||
(nested_block.ContextLevel() ==
@@ -4023,7 +4064,7 @@
node->token_pos()));
}
Do(BuildStoreContext(
- Bind(ExitTempLocalScope(tmp_var)),
+ Bind(ExitTempLocalScope(tmp_var, node->token_pos())),
node->token_pos()));
}
@@ -4041,7 +4082,7 @@
// Create a temporary local describing the original position.
const String& temp_name = Symbols::TempParam();
LocalVariable* temp_local = new(Z) LocalVariable(
- Scanner::kNoSourcePos, // Token index.
+ Token::kNoSourcePos, // Token index.
temp_name,
Object::dynamic_type()); // Type.
temp_local->set_index(param_frame_index);
@@ -4053,14 +4094,16 @@
temp_local->set_is_captured_parameter(true);
// Copy parameter from local frame to current context.
- Value* load = Bind(BuildLoadLocal(*temp_local));
- Do(BuildStoreLocal(parameter, load));
+ Value* load = Bind(BuildLoadLocal(*temp_local, node->token_pos()));
+ Do(BuildStoreLocal(parameter, load, ST(node->token_pos())));
// Write NULL to the source location to detect buggy accesses and
// allow GC of passed value if it gets overwritten by a new value in
// the function.
Value* null_constant = Bind(new(Z) ConstantInstr(
Object::ZoneHandle(Z, Object::null())));
- Do(BuildStoreLocal(*temp_local, null_constant));
+ Do(BuildStoreLocal(*temp_local,
+ null_constant,
+ ST(node->token_pos())));
}
}
}
@@ -4074,15 +4117,15 @@
// basic block. Place this check at the last parameter to ensure parameters
// are in scope in the debugger at method entry.
const int num_params = function.NumParameters();
- intptr_t check_pos = Scanner::kNoSourcePos;
+ intptr_t check_pos = Token::kNoSourcePos;
if (num_params > 0) {
const LocalVariable& parameter = *scope->VariableAt(num_params - 1);
check_pos = parameter.token_pos();
}
- if (check_pos < 0) {
+ if (!Token::IsDebugPause(check_pos)) {
// No parameters or synthetic parameters.
check_pos = node->token_pos();
- ASSERT(check_pos >= 0);
+ ASSERT(Token::IsDebugPause(check_pos));
}
AddInstruction(new(Z) DebugStepCheckInstr(check_pos,
RawPcDescriptors::kRuntimeCall));
@@ -4122,7 +4165,8 @@
NULL,
parameter.type(),
parameter.name())) {
- Value* parameter_value = Bind(BuildLoadLocal(parameter));
+ Value* parameter_value =
+ Bind(BuildLoadLocal(parameter, parameter.token_pos()));
Do(BuildAssertAssignable(parameter.token_pos(),
parameter_value,
parameter.type(),
@@ -4181,7 +4225,7 @@
exit_ = NULL;
LoadLocalNode* load_jump_count =
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, jump_var);
+ new(Z) LoadLocalNode(node->token_pos(), jump_var);
ComparisonNode* check_jump_count;
const intptr_t num_await_states = owner()->await_joins()->length();
@@ -4189,12 +4233,12 @@
Symbols::AwaitContextVar(), false);
for (intptr_t i = 0; i < num_await_states; i++) {
check_jump_count = new(Z) ComparisonNode(
- Scanner::kNoSourcePos,
+ ST(node->token_pos()),
Token::kEQ,
load_jump_count,
new(Z) LiteralNode(
- Scanner::kNoSourcePos, Smi::ZoneHandle(Z, Smi::New(i))));
- TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+ ST(node->token_pos()), Smi::ZoneHandle(Z, Smi::New(i))));
+ TestGraphVisitor for_test(owner(), ST(node->token_pos()));
check_jump_count->Visit(&for_test);
EffectGraphVisitor for_true(owner());
EffectGraphVisitor for_false(owner());
@@ -4206,7 +4250,7 @@
// Restore the saved continuation context, i.e. the context that was
// saved into :await_ctx_var before the closure suspended.
- for_true.BuildRestoreContext(*old_context, Scanner::kNoSourcePos);
+ for_true.BuildRestoreContext(*old_context, ST(node->token_pos()));
// Goto saved join.
for_true.Goto((*owner()->await_joins())[i]);
@@ -4264,7 +4308,7 @@
owner()->set_try_index(try_handler_index);
// Preserve current context into local variable ':saved_try_context_var'.
- BuildSaveContext(node->context_var(), node->token_pos());
+ BuildSaveContext(node->context_var(), ST(node->token_pos()));
EffectGraphVisitor for_try(owner());
node->try_block()->Visit(&for_try);
@@ -4341,11 +4385,11 @@
node->rethrow_clause()->Visit(&for_finally);
if (for_finally.is_open()) {
// Rethrow the exception. Manually build the graph for rethrow.
- Value* exception = for_finally.Bind(
- for_finally.BuildLoadLocal(catch_block->rethrow_exception_var()));
+ Value* exception = for_finally.Bind(for_finally.BuildLoadLocal(
+ catch_block->rethrow_exception_var(), finally_block->token_pos()));
for_finally.PushArgument(exception);
- Value* stacktrace = for_finally.Bind(
- for_finally.BuildLoadLocal(catch_block->rethrow_stacktrace_var()));
+ Value* stacktrace = for_finally.Bind(for_finally.BuildLoadLocal(
+ catch_block->rethrow_stacktrace_var(), finally_block->token_pos()));
for_finally.PushArgument(stacktrace);
for_finally.AddInstruction(
new(Z) ReThrowInstr(catch_block->token_pos(), catch_handler_index));
@@ -4420,7 +4464,7 @@
ZoneGrowableArray<PushArgumentInstr*>* arguments =
new(Z) ZoneGrowableArray<PushArgumentInstr*>();
// Object receiver, actually a class literal of the unresolved method's owner.
- Type& type = Type::ZoneHandle(
+ AbstractType& type = Type::ZoneHandle(
Z,
Type::New(function_class,
TypeArguments::Handle(Z, TypeArguments::null()),
@@ -4621,6 +4665,7 @@
Report::MessageF(Report::kBailout,
Script::Handle(function.script()),
function.token_pos(),
+ Report::AtLocation,
"FlowGraphBuilder Bailout: %s %s",
String::Handle(function.name()).ToCString(),
reason);
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 94c9444..2c2d14d 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -303,16 +303,18 @@
void AddReturnExit(intptr_t token_pos, Value* value);
protected:
- Definition* BuildStoreTemp(const LocalVariable& local, Value* value);
- Definition* BuildStoreExprTemp(Value* value);
- Definition* BuildLoadExprTemp();
+ Definition* BuildStoreTemp(const LocalVariable& local,
+ Value* value,
+ intptr_t token_pos);
+ Definition* BuildStoreExprTemp(Value* value, intptr_t token_pos);
+ Definition* BuildLoadExprTemp(intptr_t token_pos);
Definition* BuildStoreLocal(const LocalVariable& local,
Value* value,
- intptr_t token_pos = Scanner::kNoSourcePos);
+ intptr_t token_pos);
Definition* BuildLoadLocal(const LocalVariable& local,
- intptr_t token_pos = Scanner::kNoSourcePos);
- LoadLocalInstr* BuildLoadThisVar(LocalScope* scope);
+ intptr_t token_pos);
+ LoadLocalInstr* BuildLoadThisVar(LocalScope* scope, intptr_t token_pos);
LoadFieldInstr* BuildNativeGetter(
NativeBodyNode* node,
MethodRecognizer::Kind kind,
@@ -341,7 +343,7 @@
PushArgumentInstr** push_instantiator_type_arguments);
void BuildTypecheckArguments(intptr_t token_pos,
Value** instantiator_type_arguments);
- Value* BuildInstantiator(const Class& instantiator_class);
+ Value* BuildInstantiator(intptr_t token_pos);
Value* BuildInstantiatorTypeArguments(intptr_t token_pos,
const Class& instantiator_class,
Value* instantiator);
@@ -428,7 +430,7 @@
void BuildClosureCall(ClosureCallNode* node, bool result_needed);
- Value* BuildNullValue();
+ Value* BuildNullValue(intptr_t token_pos);
// Returns true if the run-time type check can be eliminated.
bool CanSkipTypeCheck(intptr_t token_pos,
@@ -438,8 +440,8 @@
// Helpers for allocating and deallocating temporary locals on top of the
// expression stack.
- LocalVariable* EnterTempLocalScope(Value* value);
- Definition* ExitTempLocalScope(LocalVariable* var);
+ LocalVariable* EnterTempLocalScope(Value* value, intptr_t token_pos);
+ Definition* ExitTempLocalScope(LocalVariable* var, intptr_t token_pos);
void BuildLetTempExpressions(LetNode* node);
diff --git a/runtime/vm/flow_graph_builder_test.cc b/runtime/vm/flow_graph_builder_test.cc
index 91a13b2..2213d0b 100644
--- a/runtime/vm/flow_graph_builder_test.cc
+++ b/runtime/vm/flow_graph_builder_test.cc
@@ -95,6 +95,26 @@
DUMP_ASSERT(count > 0);
}
+ // Expect to find an instance call at |line| and |column|.
+ void InstanceCallAt(const char* needle,
+ intptr_t line,
+ intptr_t column = -1) {
+ ZoneGrowableArray<Instruction*>* instructions =
+ FindInstructionsAt(line, column);
+ intptr_t count = 0;
+ for (intptr_t i = 0; i < instructions->length(); i++) {
+ Instruction* instr = instructions->At(i);
+ EXPECT(instr != NULL);
+ if (instr->IsInstanceCall()) {
+ const char* haystack = instr->ToCString();
+ if (strstr(haystack, needle) != NULL) {
+ count++;
+ }
+ }
+ }
+ DUMP_ASSERT(count > 0);
+ }
+
// Expect to find at least one static call at |line| and |column|. The
// static call will have |needle| in its |ToCString| representation.
void StaticCallAt(const char* needle,
@@ -146,9 +166,26 @@
}
}
+ // Fails if any of the IR nodes has a token position of Token::kNoSourcePos.
+ void EnsureSourcePositions() {
+ for (intptr_t i = 0; i < blocks_->length(); i++) {
+ BlockEntryInstr* entry = (*blocks_)[i];
+ DUMP_ASSERT(entry->token_pos() != Token::kNoSourcePos);
+ for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
+ Instruction* instr = it.Current();
+ DUMP_ASSERT(instr->token_pos() != Token::kNoSourcePos);
+ }
+ }
+ }
+
private:
void DumpInstruction(Instruction* instr) {
- const intptr_t token_pos = instr->token_pos();
+ intptr_t token_pos = instr->token_pos();
+ bool synthetic = false;
+ if (Token::IsSynthetic(token_pos)) {
+ synthetic = true;
+ token_pos = Token::FromSynthetic(token_pos);
+ }
if (token_pos < 0) {
const char* token_pos_string =
ClassifyingTokenPositions::ToCString(token_pos);
@@ -161,10 +198,17 @@
&token_line,
&token_column,
NULL);
- THR_Print(" %02d:%02d -- %s\n",
- static_cast<int>(token_line),
- static_cast<int>(token_column),
- instr->ToCString());
+ if (synthetic) {
+ THR_Print(" *%02d:%02d -- %s\n",
+ static_cast<int>(token_line),
+ static_cast<int>(token_column),
+ instr->ToCString());
+ } else {
+ THR_Print(" %02d:%02d -- %s\n",
+ static_cast<int>(token_line),
+ static_cast<int>(token_column),
+ instr->ToCString());
+ }
}
Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) {
@@ -185,6 +229,9 @@
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
Instruction* instr = it.Current();
intptr_t token_pos = instr->token_pos();
+ if (Token::IsSynthetic(token_pos)) {
+ token_pos = Token::FromSynthetic(token_pos);
+ }
if (token_pos < 0) {
continue;
}
@@ -267,6 +314,8 @@
spt.InstanceCallAt(4, 13, Token::kADD);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 3);
spt.FuzzyInstructionMatchAt("Return", 5, 3);
+
+ spt.EnsureSourcePositions();
}
@@ -294,6 +343,8 @@
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3);
spt.FuzzyInstructionMatchAt("Return", 7, 3);
+
+ spt.EnsureSourcePositions();
}
@@ -323,6 +374,8 @@
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3);
spt.FuzzyInstructionMatchAt("Return", 7, 3);
+
+ spt.EnsureSourcePositions();
}
@@ -370,6 +423,8 @@
spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3);
spt.FuzzyInstructionMatchAt("Return", 10, 3);
+
+ spt.EnsureSourcePositions();
}
@@ -408,6 +463,8 @@
spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3);
spt.FuzzyInstructionMatchAt("Return", 10, 3);
+
+ spt.EnsureSourcePositions();
}
@@ -445,6 +502,8 @@
spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
spt.FuzzyInstructionMatchAt("Return", 6, 1);
+
+ spt.EnsureSourcePositions();
}
@@ -487,6 +546,8 @@
spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
spt.FuzzyInstructionMatchAt("Return", 6, 1);
+
+ spt.EnsureSourcePositions();
}
@@ -535,6 +596,8 @@
spt.FuzzyInstructionMatchAt("LoadLocal(z", 9, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3);
spt.FuzzyInstructionMatchAt("Return", 9, 3);
+
+ spt.EnsureSourcePositions();
}
@@ -563,6 +626,8 @@
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 12);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 5);
spt.FuzzyInstructionMatchAt("Return", 7, 5);
+
+ spt.EnsureSourcePositions();
}
@@ -607,6 +672,8 @@
spt.FuzzyInstructionMatchAt("Constant(#5", 7, 21); // '5'
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 14);
spt.FuzzyInstructionMatchAt("Return", 7, 14);
+
+ spt.EnsureSourcePositions();
}
@@ -657,6 +724,82 @@
spt.FuzzyInstructionMatchAt("Constant(#99", 10, 12); // '9'
spt.FuzzyInstructionMatchAt("Return", 10, 5); // 'r'
+
+ spt.EnsureSourcePositions();
+}
+
+
+TEST_CASE(SourcePosition_InstanceFields) {
+ const char* kScript =
+ "class A {\n"
+ " var x;\n"
+ " var y;\n"
+ "}\n"
+ "main() {\n"
+ " var z = new A();\n"
+ " z.x = 99;\n"
+ " z.y = z.x;\n"
+ " return z.y;\n"
+ "}\n";
+
+ SourcePositionTest spt(thread, kScript);
+ spt.BuildGraphFor("main");
+ spt.FuzzyInstructionMatchAt("AllocateObject(A)", 6, 15); // 'A'
+ spt.FuzzyInstructionMatchAt("StaticCall", 6, 15); // 'A'
+ spt.FuzzyInstructionMatchAt("StoreLocal(z", 6, 9); // '='
+ spt.InstanceCallAt("set:x", 7, 5); // 'x'
+ spt.InstanceCallAt("get:x", 8, 11); // 'x'
+ spt.InstanceCallAt("set:y", 8, 5); // 'y'
+
+ spt.InstanceCallAt("get:y", 9, 12); // 'y'
+ spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3);
+ spt.FuzzyInstructionMatchAt("Return", 9, 3);
+
+ spt.EnsureSourcePositions();
+}
+
+
+TEST_CASE(SourcePosition_Async) {
+ const char* kScript =
+ "import 'dart:async';\n"
+ "var x = 5;\n"
+ "var y = 5;\n"
+ "foo(Future f1, Future f2) async {\n"
+ " await f1;\n"
+ " await f2;\n"
+ " return 55;\n"
+ "}\n"
+ "main() {\n"
+ " foo(new Future.value(33));\n"
+ "}\n";
+
+ SourcePositionTest spt(thread, kScript);
+ spt.BuildGraphFor("foo");
+ spt.EnsureSourcePositions();
+ spt.Dump();
+}
+
+
+static bool SyntheticRoundTripTest(intptr_t token_pos) {
+ return Token::FromSynthetic(Token::ToSynthetic(token_pos)) == token_pos;
+}
+
+
+UNIT_TEST_CASE(SourcePosition_SyntheticTokens) {
+ EXPECT(Token::kNoSourcePos == -1);
+ EXPECT(Token::kMinSourcePos == 0);
+ EXPECT(Token::kMaxSourcePos > 0);
+
+ EXPECT(!Token::IsSynthetic(0));
+ EXPECT(Token::IsSynthetic(Token::ToSynthetic(0)));
+ EXPECT(Token::IsSynthetic(Token::ToSynthetic(9)));
+ EXPECT(!Token::IsSynthetic(Token::FromSynthetic(-1)));
+ EXPECT(!Token::IsSynthetic(ClassifyingTokenPositions::kPrivate));
+ EXPECT(!Token::IsSynthetic(ClassifyingTokenPositions::kLast));
+
+ EXPECT(SyntheticRoundTripTest(0));
+ EXPECT(SyntheticRoundTripTest(Token::kMaxSourcePos));
+ EXPECT(SyntheticRoundTripTest(Token::kMinSourcePos));
}
} // namespace dart
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 1f02942..eabcbf1 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -627,6 +627,7 @@
Report::MessageF(Report::kBailout,
Script::Handle(function.script()),
function.token_pos(),
+ Report::AtLocation,
"FlowGraphCompiler Bailout: %s %s",
String::Handle(function.name()).ToCString(),
reason);
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index abd8b65..429631f 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -273,7 +273,7 @@
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+ ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
const Register kInstanceReg = R0;
Error& bound_error = Error::Handle(zone());
const Type& int_type = Type::Handle(zone(), Type::IntType());
@@ -286,15 +286,15 @@
} else {
__ b(is_not_instance_lbl, EQ);
}
- const intptr_t num_type_args = type_class.NumTypeArguments();
- const intptr_t num_type_params = type_class.NumTypeParameters();
- const intptr_t from_index = num_type_args - num_type_params;
- const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(zone(), type.arguments());
- const bool is_raw_type = type_arguments.IsNull() ||
- type_arguments.IsRaw(from_index, num_type_params);
- // Signature class is an instantiated parameterized type.
- if (!type_class.IsSignatureClass()) {
+ // A function type test requires checking the function signature.
+ if (!type.IsFunctionType()) {
+ const intptr_t num_type_args = type_class.NumTypeArguments();
+ const intptr_t num_type_params = type_class.NumTypeParameters();
+ const intptr_t from_index = num_type_args - num_type_params;
+ const TypeArguments& type_arguments =
+ TypeArguments::ZoneHandle(zone(), type.arguments());
+ const bool is_raw_type = type_arguments.IsNull() ||
+ type_arguments.IsRaw(from_index, num_type_params);
if (is_raw_type) {
const Register kClassIdReg = R2;
// dynamic type argument, check only classes.
@@ -362,6 +362,10 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
+ if (type.IsFunctionType()) {
+ // Fallthrough.
+ return true;
+ }
const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
@@ -392,12 +396,10 @@
__ b(is_not_instance_lbl);
return false;
}
- if (type.IsFunctionType()) {
+ if (type.IsDartFunctionType()) {
// Check if instance is a closure.
- __ LoadClassById(R3, kClassIdReg);
- __ ldr(R3, FieldAddress(R3, Class::signature_function_offset()));
- __ CompareObject(R3, Object::null_object());
- __ b(is_instance_lbl, NE);
+ __ CompareImmediate(kClassIdReg, kClosureCid);
+ __ b(is_instance_lbl, EQ);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
@@ -505,7 +507,7 @@
__ Bind(&fall_through);
return type_test_cache.raw();
}
- if (type.IsType()) {
+ if (type.IsType() || type.IsFunctionType()) {
const Register kInstanceReg = R0;
const Register kTypeArgumentsReg = R1;
__ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi?
@@ -547,10 +549,10 @@
}
if (type.IsInstantiated()) {
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- // A class equality check is only applicable with a dst type of a
- // non-parameterized class, non-signature class, or with a raw dst type of
+ // A class equality check is only applicable with a dst type (not a
+ // function type) of a non-parameterized class or with a raw dst type of
// a parameterized class.
- if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+ if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
type,
is_instance_lbl,
@@ -673,7 +675,7 @@
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
ASSERT(!dst_type.IsNull());
ASSERT(dst_type.IsFinalized());
// Assignable check is skipped in FlowGraphBuilder, not here.
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 359c89c..977010a 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -265,7 +265,7 @@
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+ ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
const Register kInstanceReg = R0;
Error& bound_error = Error::Handle(zone());
const Type& int_type = Type::Handle(zone(), Type::IntType());
@@ -278,15 +278,15 @@
} else {
__ b(is_not_instance_lbl, EQ);
}
- const intptr_t num_type_args = type_class.NumTypeArguments();
- const intptr_t num_type_params = type_class.NumTypeParameters();
- const intptr_t from_index = num_type_args - num_type_params;
- const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(zone(), type.arguments());
- const bool is_raw_type = type_arguments.IsNull() ||
- type_arguments.IsRaw(from_index, num_type_params);
- // Signature class is an instantiated parameterized type.
- if (!type_class.IsSignatureClass()) {
+ // A function type test requires checking the function signature.
+ if (!type.IsFunctionType()) {
+ const intptr_t num_type_args = type_class.NumTypeArguments();
+ const intptr_t num_type_params = type_class.NumTypeParameters();
+ const intptr_t from_index = num_type_args - num_type_params;
+ const TypeArguments& type_arguments =
+ TypeArguments::ZoneHandle(zone(), type.arguments());
+ const bool is_raw_type = type_arguments.IsNull() ||
+ type_arguments.IsRaw(from_index, num_type_params);
if (is_raw_type) {
const Register kClassIdReg = R2;
// dynamic type argument, check only classes.
@@ -354,6 +354,10 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
+ if (type.IsFunctionType()) {
+ // Fallthrough.
+ return true;
+ }
const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
@@ -384,12 +388,10 @@
__ b(is_not_instance_lbl);
return false;
}
- if (type.IsFunctionType()) {
+ if (type.IsDartFunctionType()) {
// Check if instance is a closure.
- __ LoadClassById(R3, kClassIdReg);
- __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset());
- __ CompareObject(R3, Object::null_object());
- __ b(is_instance_lbl, NE);
+ __ CompareImmediate(kClassIdReg, kClosureCid);
+ __ b(is_instance_lbl, EQ);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
@@ -497,7 +499,7 @@
__ Bind(&fall_through);
return type_test_cache.raw();
}
- if (type.IsType()) {
+ if (type.IsType() || type.IsFunctionType()) {
const Register kInstanceReg = R0;
const Register kTypeArgumentsReg = R1;
__ tsti(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
@@ -539,10 +541,10 @@
}
if (type.IsInstantiated()) {
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- // A class equality check is only applicable with a dst type of a
- // non-parameterized class, non-signature class, or with a raw dst type of
+ // A class equality check is only applicable with a dst type (not a
+ // function type) of a non-parameterized class or with a raw dst type of
// a parameterized class.
- if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+ if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
type,
is_instance_lbl,
@@ -665,7 +667,7 @@
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
ASSERT(!dst_type.IsNull());
ASSERT(dst_type.IsFinalized());
// Assignable check is skipped in FlowGraphBuilder, not here.
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index b2272fe9..3a2ee04 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -277,7 +277,7 @@
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+ ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
const Register kInstanceReg = EAX;
Error& bound_error = Error::Handle(zone());
const Type& int_type = Type::Handle(zone(), Type::IntType());
@@ -290,15 +290,15 @@
} else {
__ j(ZERO, is_not_instance_lbl);
}
- const intptr_t num_type_args = type_class.NumTypeArguments();
- const intptr_t num_type_params = type_class.NumTypeParameters();
- const intptr_t from_index = num_type_args - num_type_params;
- const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(zone(), type.arguments());
- const bool is_raw_type = type_arguments.IsNull() ||
- type_arguments.IsRaw(from_index, num_type_params);
- // Signature class is an instantiated parameterized type.
- if (!type_class.IsSignatureClass()) {
+ // A function type test requires checking the function signature.
+ if (!type.IsFunctionType()) {
+ const intptr_t num_type_args = type_class.NumTypeArguments();
+ const intptr_t num_type_params = type_class.NumTypeParameters();
+ const intptr_t from_index = num_type_args - num_type_params;
+ const TypeArguments& type_arguments =
+ TypeArguments::ZoneHandle(zone(), type.arguments());
+ const bool is_raw_type = type_arguments.IsNull() ||
+ type_arguments.IsRaw(from_index, num_type_params);
if (is_raw_type) {
const Register kClassIdReg = ECX;
// dynamic type argument, check only classes.
@@ -365,6 +365,10 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
+ if (type.IsFunctionType()) {
+ // Fallthrough.
+ return true;
+ }
const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
@@ -395,14 +399,10 @@
__ jmp(is_not_instance_lbl);
return false;
}
- if (type.IsFunctionType()) {
+ if (type.IsDartFunctionType()) {
// Check if instance is a closure.
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ LoadClassById(EDI, kClassIdReg);
- __ movl(EDI, FieldAddress(EDI, Class::signature_function_offset()));
- __ cmpl(EDI, raw_null);
- __ j(NOT_EQUAL, is_instance_lbl);
+ __ cmpl(kClassIdReg, Immediate(kClosureCid));
+ __ j(EQUAL, is_instance_lbl);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
@@ -513,7 +513,7 @@
__ Bind(&fall_through);
return type_test_cache.raw();
}
- if (type.IsType()) {
+ if (type.IsType() || type.IsFunctionType()) {
const Register kInstanceReg = EAX;
const Register kTypeArgumentsReg = EDX;
__ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
@@ -555,10 +555,10 @@
}
if (type.IsInstantiated()) {
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- // A class equality check is only applicable with a dst type of a
- // non-parameterized class, non-signature class, or with a raw dst type of
+ // A class equality check is only applicable with a dst type (not a
+ // function type) of a non-parameterized class or with a raw dst type of
// a parameterized class.
- if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+ if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
type,
is_instance_lbl,
@@ -684,7 +684,7 @@
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
ASSERT(!dst_type.IsNull());
ASSERT(dst_type.IsFinalized());
// Assignable check is skipped in FlowGraphBuilder, not here.
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index f98bb67..a6fef0b 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -265,7 +265,7 @@
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+ ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
const Register kInstanceReg = A0;
Error& bound_error = Error::Handle(zone());
const Type& int_type = Type::Handle(zone(), Type::IntType());
@@ -278,15 +278,15 @@
} else {
__ beq(CMPRES1, ZR, is_not_instance_lbl);
}
- const intptr_t num_type_args = type_class.NumTypeArguments();
- const intptr_t num_type_params = type_class.NumTypeParameters();
- const intptr_t from_index = num_type_args - num_type_params;
- const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(zone(), type.arguments());
- const bool is_raw_type = type_arguments.IsNull() ||
- type_arguments.IsRaw(from_index, num_type_params);
- // Signature class is an instantiated parameterized type.
- if (!type_class.IsSignatureClass()) {
+ // A function type test requires checking the function signature.
+ if (!type.IsFunctionType()) {
+ const intptr_t num_type_args = type_class.NumTypeArguments();
+ const intptr_t num_type_params = type_class.NumTypeParameters();
+ const intptr_t from_index = num_type_args - num_type_params;
+ const TypeArguments& type_arguments =
+ TypeArguments::ZoneHandle(zone(), type.arguments());
+ const bool is_raw_type = type_arguments.IsNull() ||
+ type_arguments.IsRaw(from_index, num_type_params);
if (is_raw_type) {
const Register kClassIdReg = T0;
// dynamic type argument, check only classes.
@@ -353,6 +353,10 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
+ if (type.IsFunctionType()) {
+ // Fallthrough.
+ return true;
+ }
const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
@@ -382,11 +386,9 @@
__ b(is_not_instance_lbl);
return false;
}
- if (type.IsFunctionType()) {
+ if (type.IsDartFunctionType()) {
// Check if instance is a closure.
- __ LoadClassById(T1, kClassIdReg);
- __ lw(T1, FieldAddress(T1, Class::signature_function_offset()));
- __ BranchNotEqual(T1, Object::null_object(), is_instance_lbl);
+ __ BranchEqual(kClassIdReg, Immediate(kClosureCid), is_instance_lbl);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
@@ -493,7 +495,7 @@
__ Bind(&fall_through);
return type_test_cache.raw();
}
- if (type.IsType()) {
+ if (type.IsType() || type.IsFunctionType()) {
const Register kInstanceReg = A0;
const Register kTypeArgumentsReg = A1;
__ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask));
@@ -535,10 +537,10 @@
}
if (type.IsInstantiated()) {
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- // A class equality check is only applicable with a dst type of a
- // non-parameterized class, non-signature class, or with a raw dst type of
+ // A class equality check is only applicable with a dst type (not a
+ // function type) of a non-parameterized class or with a raw dst type of
// a parameterized class.
- if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+ if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
type,
is_instance_lbl,
@@ -667,7 +669,7 @@
const String& dst_name,
LocationSummary* locs) {
__ Comment("AssertAssignable");
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
ASSERT(!dst_type.IsNull());
ASSERT(dst_type.IsFinalized());
// Assignable check is skipped in FlowGraphBuilder, not here.
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index e54b1eb..4662afb 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -274,7 +274,7 @@
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+ ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
const Register kInstanceReg = RAX;
Error& bound_error = Error::Handle(zone());
const Type& int_type = Type::Handle(zone(), Type::IntType());
@@ -287,15 +287,15 @@
} else {
__ j(ZERO, is_not_instance_lbl);
}
- const intptr_t num_type_args = type_class.NumTypeArguments();
- const intptr_t num_type_params = type_class.NumTypeParameters();
- const intptr_t from_index = num_type_args - num_type_params;
- const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(zone(), type.arguments());
- const bool is_raw_type = type_arguments.IsNull() ||
- type_arguments.IsRaw(from_index, num_type_params);
- // Signature class is an instantiated parameterized type.
- if (!type_class.IsSignatureClass()) {
+ // A function type test requires checking the function signature.
+ if (!type.IsFunctionType()) {
+ const intptr_t num_type_args = type_class.NumTypeArguments();
+ const intptr_t num_type_params = type_class.NumTypeParameters();
+ const intptr_t from_index = num_type_args - num_type_params;
+ const TypeArguments& type_arguments =
+ TypeArguments::ZoneHandle(zone(), type.arguments());
+ const bool is_raw_type = type_arguments.IsNull() ||
+ type_arguments.IsRaw(from_index, num_type_params);
if (is_raw_type) {
const Register kClassIdReg = R10;
// dynamic type argument, check only classes.
@@ -362,6 +362,10 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
+ if (type.IsFunctionType()) {
+ // Fallthrough.
+ return true;
+ }
const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
@@ -392,12 +396,10 @@
__ jmp(is_not_instance_lbl);
return false;
}
- if (type.IsFunctionType()) {
+ if (type.IsDartFunctionType()) {
// Check if instance is a closure.
- __ LoadClassById(R13, kClassIdReg);
- __ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
- __ CompareObject(R13, Object::null_object());
- __ j(NOT_EQUAL, is_instance_lbl);
+ __ cmpq(kClassIdReg, Immediate(kClosureCid));
+ __ j(EQUAL, is_instance_lbl);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
@@ -507,7 +509,7 @@
__ Bind(&fall_through);
return type_test_cache.raw();
}
- if (type.IsType()) {
+ if (type.IsType() || type.IsFunctionType()) {
const Register kInstanceReg = RAX;
const Register kTypeArgumentsReg = RDX;
__ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
@@ -549,10 +551,10 @@
}
if (type.IsInstantiated()) {
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
- // A class equality check is only applicable with a dst type of a
- // non-parameterized class, non-signature class, or with a raw dst type of
+ // A class equality check is only applicable with a dst type (not a
+ // function type) of a non-parameterized class or with a raw dst type of
// a parameterized class.
- if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+ if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
type,
is_instance_lbl,
@@ -676,7 +678,7 @@
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
ASSERT(!dst_type.IsNull());
ASSERT(dst_type.IsFinalized());
// Assignable check is skipped in FlowGraphBuilder, not here.
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index bc5d7bc..1b39f97 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -687,213 +687,236 @@
// Save and clear deopt id.
const intptr_t prev_deopt_id = thread()->deopt_id();
thread()->set_deopt_id(0);
- // Install bailout jump.
- LongJumpScope jump;
- if (setjmp(*jump.Set()) == 0) {
- // Parse the callee function.
- bool in_cache;
- ParsedFunction* parsed_function;
- {
- CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer);
- parsed_function = GetParsedFunction(function, &in_cache);
- }
+ Error& error = Error::Handle();
+ {
+ // Install bailout jump.
+ LongJumpScope jump;
+ if (setjmp(*jump.Set()) == 0) {
+ // Parse the callee function.
+ bool in_cache;
+ ParsedFunction* parsed_function;
+ {
+ CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer);
+ parsed_function = GetParsedFunction(function, &in_cache);
+ }
- // Load IC data for the callee.
- ZoneGrowableArray<const ICData*>* ic_data_array =
- new(Z) ZoneGrowableArray<const ICData*>();
- const bool clone_descriptors = Compiler::IsBackgroundCompilation();
- function.RestoreICDataMap(ic_data_array, clone_descriptors);
+ // Load IC data for the callee.
+ ZoneGrowableArray<const ICData*>* ic_data_array =
+ new(Z) ZoneGrowableArray<const ICData*>();
+ const bool clone_descriptors = Compiler::IsBackgroundCompilation();
+ function.RestoreICDataMap(ic_data_array, clone_descriptors);
- // Build the callee graph.
- InlineExitCollector* exit_collector =
- new(Z) InlineExitCollector(caller_graph_, call);
- FlowGraphBuilder builder(*parsed_function,
- *ic_data_array,
- exit_collector,
- Compiler::kNoOSRDeoptId);
- builder.SetInitialBlockId(caller_graph_->max_block_id());
- FlowGraph* callee_graph;
- {
- CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer);
- callee_graph = builder.BuildGraph();
- }
+ // Build the callee graph.
+ InlineExitCollector* exit_collector =
+ new(Z) InlineExitCollector(caller_graph_, call);
+ FlowGraphBuilder builder(*parsed_function,
+ *ic_data_array,
+ exit_collector,
+ Compiler::kNoOSRDeoptId);
+ builder.SetInitialBlockId(caller_graph_->max_block_id());
+ FlowGraph* callee_graph;
+ {
+ CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer);
+ callee_graph = builder.BuildGraph();
+ }
- // The parameter stubs are a copy of the actual arguments providing
- // concrete information about the values, for example constant values,
- // without linking between the caller and callee graphs.
- // TODO(zerny): Put more information in the stubs, eg, type information.
- ZoneGrowableArray<Definition*>* param_stubs =
- new(Z) ZoneGrowableArray<Definition*>(
- function.NumParameters());
+ // The parameter stubs are a copy of the actual arguments providing
+ // concrete information about the values, for example constant values,
+ // without linking between the caller and callee graphs.
+ // TODO(zerny): Put more information in the stubs, eg, type information.
+ ZoneGrowableArray<Definition*>* param_stubs =
+ new(Z) ZoneGrowableArray<Definition*>(
+ function.NumParameters());
- // Create a parameter stub for each fixed positional parameter.
- for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) {
- param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph));
- }
+ // Create a parameter stub for each fixed positional parameter.
+ for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) {
+ param_stubs->Add(CreateParameterStub(i, (*arguments)[i],
+ callee_graph));
+ }
- // If the callee has optional parameters, rebuild the argument and stub
- // arrays so that actual arguments are in one-to-one with the formal
- // parameters.
- if (function.HasOptionalParameters()) {
- TRACE_INLINING(THR_Print(" adjusting for optional parameters\n"));
- if (!AdjustForOptionalParameters(*parsed_function,
- argument_names,
- arguments,
- param_stubs,
- callee_graph)) {
- function.set_is_inlinable(false);
- TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n"));
- PRINT_INLINING_TREE("Optional arg mismatch",
+ // If the callee has optional parameters, rebuild the argument and stub
+ // arrays so that actual arguments are in one-to-one with the formal
+ // parameters.
+ if (function.HasOptionalParameters()) {
+ TRACE_INLINING(THR_Print(" adjusting for optional parameters\n"));
+ if (!AdjustForOptionalParameters(*parsed_function,
+ argument_names,
+ arguments,
+ param_stubs,
+ callee_graph)) {
+ function.set_is_inlinable(false);
+ TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n"));
+ PRINT_INLINING_TREE("Optional arg mismatch",
+ &call_data->caller, &function, call_data->call);
+ return false;
+ }
+ }
+
+ // After treating optional parameters the actual/formal count must
+ // match.
+ ASSERT(arguments->length() == function.NumParameters());
+ ASSERT(param_stubs->length() == callee_graph->parameter_count());
+
+ // Update try-index of the callee graph.
+ BlockEntryInstr* call_block = call_data->call->GetBlock();
+ if (call_block->InsideTryBlock()) {
+ intptr_t try_index = call_block->try_index();
+ for (BlockIterator it = callee_graph->reverse_postorder_iterator();
+ !it.Done(); it.Advance()) {
+ BlockEntryInstr* block = it.Current();
+ block->set_try_index(try_index);
+ }
+ }
+
+ BlockScheduler block_scheduler(callee_graph);
+ block_scheduler.AssignEdgeWeights();
+
+ {
+ CSTAT_TIMER_SCOPE(thread(), graphinliner_ssa_timer);
+ // Compute SSA on the callee graph, catching bailouts.
+ callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(),
+ param_stubs);
+ DEBUG_ASSERT(callee_graph->VerifyUseLists());
+ }
+
+ {
+ CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
+ // TODO(fschneider): Improve suppression of speculative inlining.
+ // Deopt-ids overlap between caller and callee.
+ FlowGraphOptimizer optimizer(callee_graph,
+ inliner_->use_speculative_inlining_,
+ inliner_->inlining_black_list_);
+ if (Compiler::always_optimize()) {
+ optimizer.PopulateWithICData();
+
+ optimizer.ApplyClassIds();
+ DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+ FlowGraphTypePropagator::Propagate(callee_graph);
+ DEBUG_ASSERT(callee_graph->VerifyUseLists());
+ }
+ optimizer.ApplyICData();
+ DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+ // Optimize (a << b) & c patterns, merge instructions. Must occur
+ // before 'SelectRepresentations' which inserts conversion nodes.
+ optimizer.TryOptimizePatterns();
+ DEBUG_ASSERT(callee_graph->VerifyUseLists());
+ }
+
+ if (FLAG_trace_inlining &&
+ (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
+ THR_Print("Callee graph for inlining %s\n",
+ function.ToFullyQualifiedCString());
+ FlowGraphPrinter printer(*callee_graph);
+ printer.PrintBlocks();
+ }
+
+ // Collect information about the call site and caller graph.
+ // TODO(zerny): Do this after CP and dead code elimination.
+ intptr_t constants_count = 0;
+ for (intptr_t i = 0; i < param_stubs->length(); ++i) {
+ if ((*param_stubs)[i]->IsConstant()) ++constants_count;
+ }
+
+ FlowGraphInliner::CollectGraphInfo(callee_graph);
+ const intptr_t size = function.optimized_instruction_count();
+ const intptr_t call_site_count = function.optimized_call_site_count();
+
+ function.set_optimized_instruction_count(size);
+ function.set_optimized_call_site_count(call_site_count);
+
+ // Use heuristics do decide if this call should be inlined.
+ if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
+ // If size is larger than all thresholds, don't consider it again.
+ if ((size > FLAG_inlining_size_threshold) &&
+ (call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
+ (size > FLAG_inlining_constant_arguments_min_size_threshold) &&
+ (size > FLAG_inlining_constant_arguments_max_size_threshold)) {
+ function.set_is_inlinable(false);
+ }
+ thread()->set_deopt_id(prev_deopt_id);
+ TRACE_INLINING(THR_Print(" Bailout: heuristics with "
+ "code size: %" Pd ", "
+ "call sites: %" Pd ", "
+ "const args: %" Pd "\n",
+ size,
+ call_site_count,
+ constants_count));
+ PRINT_INLINING_TREE("Heuristic fail",
&call_data->caller, &function, call_data->call);
return false;
}
- }
- // After treating optional parameters the actual/formal count must match.
- ASSERT(arguments->length() == function.NumParameters());
- ASSERT(param_stubs->length() == callee_graph->parameter_count());
+ // Inline dispatcher methods regardless of the current depth.
+ const intptr_t depth =
+ (function.IsInvokeFieldDispatcher() ||
+ function.IsNoSuchMethodDispatcher()) ? 0 : inlining_depth_;
+ collected_call_sites_->FindCallSites(callee_graph, depth,
+ &inlined_info_);
- // Update try-index of the callee graph.
- BlockEntryInstr* call_block = call_data->call->GetBlock();
- if (call_block->InsideTryBlock()) {
- intptr_t try_index = call_block->try_index();
- for (BlockIterator it = callee_graph->reverse_postorder_iterator();
- !it.Done(); it.Advance()) {
- BlockEntryInstr* block = it.Current();
- block->set_try_index(try_index);
+ // Add the function to the cache.
+ if (!in_cache) {
+ function_cache_.Add(parsed_function);
}
- }
- BlockScheduler block_scheduler(callee_graph);
- block_scheduler.AssignEdgeWeights();
-
- {
- CSTAT_TIMER_SCOPE(thread(), graphinliner_ssa_timer);
- // Compute SSA on the callee graph, catching bailouts.
- callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(),
- param_stubs);
- DEBUG_ASSERT(callee_graph->VerifyUseLists());
- }
-
- {
- CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
- // TODO(fschneider): Improve suppression of speculative inlining.
- // Deopt-ids overlap between caller and callee.
- FlowGraphOptimizer optimizer(callee_graph,
- inliner_->use_speculative_inlining_,
- inliner_->inlining_black_list_);
- if (Compiler::always_optimize()) {
- optimizer.PopulateWithICData();
-
- optimizer.ApplyClassIds();
- DEBUG_ASSERT(callee_graph->VerifyUseLists());
-
- FlowGraphTypePropagator::Propagate(callee_graph);
- DEBUG_ASSERT(callee_graph->VerifyUseLists());
- }
- optimizer.ApplyICData();
- DEBUG_ASSERT(callee_graph->VerifyUseLists());
-
- // Optimize (a << b) & c patterns, merge instructions. Must occur before
- // 'SelectRepresentations' which inserts conversion nodes.
- optimizer.TryOptimizePatterns();
- DEBUG_ASSERT(callee_graph->VerifyUseLists());
- }
-
- if (FLAG_trace_inlining &&
- (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
- THR_Print("Callee graph for inlining %s\n",
- function.ToFullyQualifiedCString());
- FlowGraphPrinter printer(*callee_graph);
- printer.PrintBlocks();
- }
-
- // Collect information about the call site and caller graph.
- // TODO(zerny): Do this after CP and dead code elimination.
- intptr_t constants_count = 0;
- for (intptr_t i = 0; i < param_stubs->length(); ++i) {
- if ((*param_stubs)[i]->IsConstant()) ++constants_count;
- }
-
- FlowGraphInliner::CollectGraphInfo(callee_graph);
- const intptr_t size = function.optimized_instruction_count();
- const intptr_t call_site_count = function.optimized_call_site_count();
-
- function.set_optimized_instruction_count(size);
- function.set_optimized_call_site_count(call_site_count);
-
- // Use heuristics do decide if this call should be inlined.
- if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
- // If size is larger than all thresholds, don't consider it again.
- if ((size > FLAG_inlining_size_threshold) &&
- (call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
- (size > FLAG_inlining_constant_arguments_min_size_threshold) &&
- (size > FLAG_inlining_constant_arguments_max_size_threshold)) {
- function.set_is_inlinable(false);
+ // Build succeeded so we restore the bailout jump.
+ inlined_ = true;
+ inlined_size_ += size;
+ if (is_recursive_call) {
+ inlined_recursive_call_ = true;
}
thread()->set_deopt_id(prev_deopt_id);
- TRACE_INLINING(THR_Print(" Bailout: heuristics with "
- "code size: %" Pd ", "
- "call sites: %" Pd ", "
- "const args: %" Pd "\n",
- size,
- call_site_count,
- constants_count));
- PRINT_INLINING_TREE("Heuristic fail",
- &call_data->caller, &function, call_data->call);
- return false;
+
+ call_data->callee_graph = callee_graph;
+ call_data->parameter_stubs = param_stubs;
+ call_data->exit_collector = exit_collector;
+
+ // When inlined, we add the guarded fields of the callee to the caller's
+ // list of guarded fields.
+ for (intptr_t i = 0;
+ i < callee_graph->guarded_fields()->length();
+ ++i) {
+ FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(),
+ (*callee_graph->guarded_fields())[i]);
+ }
+ // When inlined, we add the deferred prefixes of the callee to the
+ // caller's list of deferred prefixes.
+ caller_graph()->AddToDeferredPrefixes(
+ callee_graph->deferred_prefixes());
+
+ FlowGraphInliner::SetInliningId(callee_graph,
+ inliner_->NextInlineId(callee_graph->function(),
+ call_data->caller_inlining_id_));
+ TRACE_INLINING(THR_Print(" Success\n"));
+ PRINT_INLINING_TREE(NULL,
+ &call_data->caller, &function, call);
+ return true;
+ } else {
+ error = isolate()->object_store()->sticky_error();
+ isolate()->object_store()->clear_sticky_error();
+ ASSERT(error.IsLanguageError());
+
+ if (LanguageError::Cast(error).kind() == Report::kBailout) {
+ thread()->set_deopt_id(prev_deopt_id);
+ TRACE_INLINING(THR_Print(" Bailout: %s\n",
+ error.ToErrorCString()));
+ PRINT_INLINING_TREE("Bailout",
+ &call_data->caller, &function, call);
+ return false;
+ } else {
+ // Fall through to exit long jump scope.
+ }
}
-
- // Inline dispatcher methods regardless of the current depth.
- const intptr_t depth =
- (function.IsInvokeFieldDispatcher() ||
- function.IsNoSuchMethodDispatcher()) ? 0 : inlining_depth_;
- collected_call_sites_->FindCallSites(callee_graph, depth, &inlined_info_);
-
- // Add the function to the cache.
- if (!in_cache) {
- function_cache_.Add(parsed_function);
- }
-
- // Build succeeded so we restore the bailout jump.
- inlined_ = true;
- inlined_size_ += size;
- if (is_recursive_call) {
- inlined_recursive_call_ = true;
- }
- thread()->set_deopt_id(prev_deopt_id);
-
- call_data->callee_graph = callee_graph;
- call_data->parameter_stubs = param_stubs;
- call_data->exit_collector = exit_collector;
-
- // When inlined, we add the guarded fields of the callee to the caller's
- // list of guarded fields.
- for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) {
- FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(),
- (*callee_graph->guarded_fields())[i]);
- }
- // When inlined, we add the deferred prefixes of the callee to the
- // caller's list of deferred prefixes.
- caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes());
-
- FlowGraphInliner::SetInliningId(callee_graph,
- inliner_->NextInlineId(callee_graph->function(),
- call_data->caller_inlining_id_));
- TRACE_INLINING(THR_Print(" Success\n"));
- PRINT_INLINING_TREE(NULL,
- &call_data->caller, &function, call);
- return true;
- } else {
- Error& error = Error::Handle();
- error = isolate()->object_store()->sticky_error();
- isolate()->object_store()->clear_sticky_error();
- thread()->set_deopt_id(prev_deopt_id);
- TRACE_INLINING(THR_Print(" Bailout: %s\n", error.ToErrorCString()));
- PRINT_INLINING_TREE("Bailout",
- &call_data->caller, &function, call);
- return false;
}
+
+ // Propagate a compile-time error. Only in precompilation do we attempt to
+ // inline functions that have never been compiled before; when JITing we
+ // should only see compile-time errors in unoptimized compilation.
+ ASSERT(Compiler::always_optimize());
+ Thread::Current()->long_jump_base()->Jump(1, error);
+ UNREACHABLE();
+ return false;
}
void PrintInlinedInfo(const Function& top) {
@@ -1105,14 +1128,13 @@
call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject();
if ((alloc != NULL) && !alloc->closure_function().IsNull()) {
target ^= alloc->closure_function().raw();
- ASSERT(target.signature_class() == alloc->cls().raw());
+ ASSERT(alloc->cls().IsClosureClass());
}
ConstantInstr* constant =
call->ArgumentAt(0)->OriginalDefinition()->AsConstant();
if ((constant != NULL) &&
- constant->value().IsInstance() &&
- Instance::Cast(constant->value()).IsClosure()) {
- target ^= Closure::function(Instance::Cast(constant->value()));
+ constant->value().IsClosure()) {
+ target ^= Closure::Cast(constant->value()).function();
}
if (target.IsNull()) {
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index c36bf53..ecc3350 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -225,14 +225,6 @@
// finalized yet.
return false;
}
- // Do not run the optimization below if in background compilation since
- // resolution of method extractor functions may create new signature
- // classes.
- // TODO(regis): Remove test for background compilation once signature
- // classes are not generated any longer.
- if (!thread()->IsMutatorThread()) {
- return false;
- }
const Array& args_desc_array = Array::Handle(Z,
ArgumentsDescriptor::New(call->ArgumentCount(),
call->argument_names()));
@@ -284,12 +276,7 @@
}
// Check if getter or setter in function's class and class is currently leaf.
- // Do not run the optimization below if in background compilation since
- // resolution of getter functions may create new signature classes.
- // TODO(regis): Remove test for background compilation once signature classes
- // are not generated any longer.
- if (thread()->IsMutatorThread() &&
- FLAG_guess_icdata_cid &&
+ if (FLAG_guess_icdata_cid &&
((call->token_kind() == Token::kGET) ||
(call->token_kind() == Token::kSET))) {
const Class& owner_class = Class::Handle(Z, function().Owner());
@@ -3904,7 +3891,8 @@
ZoneGrowableArray<intptr_t>* results) const {
ASSERT(results->is_empty());
ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only.
- if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
+ if (type.IsFunctionType() || type.IsDartFunctionType() ||
+ !type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
return Bool::null();
}
const Class& type_class = Class::Handle(Z, type.type_class());
@@ -3959,9 +3947,9 @@
ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
// Requires CHA.
if (!type.IsInstantiated()) return false;
+ // Function types have different type checking rules.
+ if (type.IsFunctionType()) return false;
const Class& type_class = Class::Handle(type.type_class());
- // Signature classes have different type checking rules.
- if (type_class.IsSignatureClass()) return false;
// Could be an interface check?
if (CHA::IsImplemented(type_class)) return false;
// Check if there are subclasses.
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 7ea528a..85371e0 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -489,15 +489,15 @@
cid_ = kDynamicCid;
} else if (type_->IsVoidType()) {
cid_ = kNullCid;
+ } else if (type_->IsFunctionType() || type_->IsDartFunctionType()) {
+ cid_ = kClosureCid;
} else if (type_->HasResolvedTypeClass()) {
const Class& type_class = Class::Handle(type_->type_class());
Thread* thread = Thread::Current();
CHA* cha = thread->cha();
- // Don't infer a cid from an abstract type for signature classes since
- // there can be multiple compatible classes with different cids.
- if (!type_class.IsSignatureClass() &&
- !CHA::IsImplemented(type_class) &&
- !CHA::HasSubclasses(type_class)) {
+ // Don't infer a cid from an abstract type since there can be multiple
+ // compatible classes with different cids.
+ if (!CHA::IsImplemented(type_class) && !CHA::HasSubclasses(type_class)) {
if (type_class.IsPrivate()) {
// Type of a private class cannot change through later loaded libs.
cid_ = type_class.id();
@@ -978,10 +978,11 @@
CompileType AllocateObjectInstr::ComputeType() const {
if (!closure_function().IsNull()) {
- ASSERT(cls().raw() == closure_function().signature_class());
+ ASSERT(cls().id() == kClosureCid);
return CompileType(CompileType::kNonNullable,
- cls().id(),
- &Type::ZoneHandle(cls().SignatureType()));
+ kClosureCid,
+ &FunctionType::ZoneHandle(
+ closure_function().SignatureType()));
}
// TODO(vegorov): Incorporate type arguments into the returned type.
return CompileType::FromCid(cls().id());
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index f5eef18..9b1e89c 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -27,6 +27,11 @@
const intptr_t kSmiMax = (static_cast<intptr_t>(1) << kSmiBits) - 1;
const intptr_t kSmiMin = -(static_cast<intptr_t>(1) << kSmiBits);
+// Hard coded from above but for 32-bit architectures.
+const intptr_t kSmiBits32 = kBitsPerInt32 - 2;
+const intptr_t kSmiMax32 = (static_cast<intptr_t>(1) << kSmiBits32) - 1;
+const intptr_t kSmiMin32 = -(static_cast<intptr_t>(1) << kSmiBits32);
+
#define kPosInfinity bit_cast<double>(DART_UINT64_C(0x7ff0000000000000))
#define kNegInfinity bit_cast<double>(DART_UINT64_C(0xfff0000000000000))
diff --git a/runtime/vm/hash_table.h b/runtime/vm/hash_table.h
index 592cf07..2334bbc 100644
--- a/runtime/vm/hash_table.h
+++ b/runtime/vm/hash_table.h
@@ -435,6 +435,13 @@
return table.Release().raw();
}
+ template<typename Table>
+ static RawArray* New(const Array& array) {
+ Table table(array.raw());
+ table.Initialize();
+ return table.Release().raw();
+ }
+
// Clears 'to' and inserts all elements from 'from', in iteration order.
// The tables must have the same user payload size.
template<typename From, typename To>
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 15635bc..12663f3 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2734,7 +2734,7 @@
if (!compiler->is_optimizing()) {
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
GetDeoptId(),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
}
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -2760,7 +2760,7 @@
// code that matches backwards from the end of the pattern.
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
GetDeoptId(),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
}
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -3689,6 +3689,7 @@
Report::MessageF(Report::kError,
Script::Handle(function().script()),
function().token_pos(),
+ Report::AtLocation,
"native function '%s' (%" Pd " arguments) cannot be found",
native_name().ToCString(),
function().NumParameters());
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 0a40848..60e25a9 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -38,47 +38,6 @@
class RangeBoundary;
class UnboxIntegerInstr;
-// These token positions are used to classify instructions that can't be
-// directly tied to an actual source position.
-#define CLASSIFYING_TOKEN_POSITIONS(V) \
- V(Private, -2) \
- V(Box, -3) \
- V(ParallelMove, -4) \
- V(TempMove, -5) \
- V(Constant, -6) \
- V(PushArgument, -7) \
- V(ControlFlow, -8) \
- V(Context, -9)
-
-// COMPILE_ASSERT that all CLASSIFYING_TOKEN_POSITIONS are less than
-// Scanner::kNoSourcePos.
-#define SANITY_CHECK_VALUES(name, value) \
- COMPILE_ASSERT(value < Scanner::kNoSourcePos);
- CLASSIFYING_TOKEN_POSITIONS(SANITY_CHECK_VALUES);
-#undef SANITY_CHECK_VALUES
-
-class ClassifyingTokenPositions : public AllStatic {
- public:
-#define DEFINE_VALUES(name, value) \
- static const intptr_t k##name = value;
- CLASSIFYING_TOKEN_POSITIONS(DEFINE_VALUES);
-#undef DEFINE_VALUES
-
- static const char* ToCString(intptr_t token_pos) {
- ASSERT(token_pos < 0);
- switch (token_pos) {
- case Scanner::kNoSourcePos: return "NoSource";
-#define DEFINE_CASE(name, value) \
- case value: return #name;
- CLASSIFYING_TOKEN_POSITIONS(DEFINE_CASE);
-#undef DEFINE_CASE
- default:
- UNIMPLEMENTED();
- return NULL;
- }
- }
-};
-
// CompileType describes type of the value produced by the definition.
//
// It captures the following properties:
@@ -668,7 +627,7 @@
const ICData* GetICData(
const ZoneGrowableArray<const ICData*>& ic_data_array) const;
- virtual intptr_t token_pos() const { return Scanner::kNoSourcePos; }
+ virtual intptr_t token_pos() const { return Token::kNoSourcePos; }
virtual intptr_t InputCount() const = 0;
virtual Value* InputAt(intptr_t i) const = 0;
@@ -3312,7 +3271,7 @@
class LoadLocalInstr : public TemplateDefinition<0, NoThrow> {
public:
LoadLocalInstr(const LocalVariable& local,
- intptr_t token_pos = Scanner::kNoSourcePos)
+ intptr_t token_pos)
: local_(local), is_last_(false), token_pos_(token_pos) { }
DECLARE_INSTRUCTION(LoadLocal)
@@ -3428,7 +3387,7 @@
public:
StoreLocalInstr(const LocalVariable& local,
Value* value,
- intptr_t token_pos = Scanner::kNoSourcePos)
+ intptr_t token_pos)
: local_(local), is_dead_(false), is_last_(false), token_pos_(token_pos) {
SetInputAt(0, value);
}
@@ -3757,7 +3716,7 @@
public:
StoreStaticFieldInstr(const Field& field,
Value* value,
- intptr_t token_pos = Scanner::kNoSourcePos)
+ intptr_t token_pos)
: field_(field),
token_pos_(token_pos) {
ASSERT(field.IsZoneHandle());
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 9120195..c585771 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1834,7 +1834,7 @@
locs->live_registers()->Remove(Location::RegisterLocation(result_));
compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateCall(Token::kNoSourcePos, // No token position.
stub_entry,
RawPcDescriptors::kOther,
locs);
@@ -6651,7 +6651,7 @@
// may be inserted before this instruction.
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
GetDeoptId(),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
}
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -6854,7 +6854,7 @@
const Register result = locs()->out(0).reg();
__ PushObject(Object::null_object());
__ Push(typed_data);
- compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateRuntimeCall(Token::kNoSourcePos, // No token position.
deopt_id(),
kGrowRegExpStackRuntimeEntry,
1,
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 05ce132..18d82cd 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -1686,7 +1686,7 @@
locs->live_registers()->Remove(Location::RegisterLocation(result_));
compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateCall(Token::kNoSourcePos, // No token position.
stub_entry,
RawPcDescriptors::kOther,
locs);
@@ -5414,7 +5414,7 @@
// may be inserted before this instruction.
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
GetDeoptId(),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
}
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -5616,7 +5616,7 @@
const Register result = locs()->out(0).reg();
__ PushObject(Object::null_object());
__ Push(typed_data);
- compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateRuntimeCall(Token::kNoSourcePos, // No token position.
deopt_id(),
kGrowRegExpStackRuntimeEntry,
1,
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 0c2f782..3ceb83c 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1675,7 +1675,7 @@
locs->live_registers()->Remove(Location::RegisterLocation(result_));
compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateCall(Token::kNoSourcePos, // No token position.
stub_entry,
RawPcDescriptors::kOther,
locs);
@@ -6551,7 +6551,7 @@
// may be inserted before this instruction.
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
GetDeoptId(),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
}
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -6862,7 +6862,7 @@
const Register result = locs()->out(0).reg();
__ PushObject(Object::null_object());
__ pushl(typed_data);
- compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateRuntimeCall(Token::kNoSourcePos, // No token position.
deopt_id(),
kGrowRegExpStackRuntimeEntry,
1,
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index e403445..ebdd48b 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1859,7 +1859,7 @@
locs->live_registers()->Remove(Location::RegisterLocation(result_));
compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateCall(Token::kNoSourcePos, // No token position.
stub_entry,
RawPcDescriptors::kOther,
locs);
@@ -5389,7 +5389,7 @@
// may be inserted before this instruction.
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
GetDeoptId(),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
}
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -5591,7 +5591,7 @@
__ LoadObject(TMP, Object::null_object());
__ sw(TMP, Address(SP, 1 * kWordSize));
__ sw(typed_data, Address(SP, 0 * kWordSize));
- compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateRuntimeCall(Token::kNoSourcePos, // No token position.
deopt_id(),
kGrowRegExpStackRuntimeEntry,
1,
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 7ca52de..8c164fc 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1685,7 +1685,7 @@
locs->live_registers()->Remove(Location::RegisterLocation(result_));
compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateCall(Token::kNoSourcePos, // No token position.
stub_entry,
RawPcDescriptors::kOther,
locs);
@@ -6192,7 +6192,7 @@
// may be inserted before this instruction.
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
GetDeoptId(),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
}
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -6444,7 +6444,7 @@
const Register result = locs()->out(0).reg();
__ PushObject(Object::null_object());
__ pushq(typed_data);
- compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position.
+ compiler->GenerateRuntimeCall(Token::kNoSourcePos, // No token position.
deopt_id(),
kGrowRegExpStackRuntimeEntry,
1,
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index c3356b3..748c8c4 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -68,19 +68,19 @@
ASSERT(!func.IsNull()); \
func.set_is_intrinsic(true);
- // Set up all core lib functions that can be intrisified.
+ // Set up all core lib functions that can be intrinsified.
lib = Library::CoreLibrary();
ASSERT(!lib.IsNull());
CORE_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
CORE_INTEGER_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
GRAPH_CORE_INTRINSICS_LIST(SETUP_FUNCTION);
- // Set up all math lib functions that can be intrisified.
+ // Set up all math lib functions that can be intrinsified.
lib = Library::MathLibrary();
ASSERT(!lib.IsNull());
MATH_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
- // Set up all dart:typed_data lib functions that can be intrisified.
+ // Set up all dart:typed_data lib functions that can be intrinsified.
lib = Library::TypedDataLibrary();
ASSERT(!lib.IsNull());
TYPED_DATA_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
@@ -304,7 +304,7 @@
new LoadFieldInstr(new Value(array),
length_offset,
Type::ZoneHandle(Type::SmiType()),
- Scanner::kNoSourcePos));
+ Token::kNoSourcePos));
builder->AddInstruction(
new CheckArrayBoundInstr(new Value(length),
new Value(index),
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index bb3121f..1b49169 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -1537,12 +1537,10 @@
Label fall_through;
__ ldr(R0, Address(SP, 0 * kWordSize));
__ LoadClassIdMayBeSmi(R1, R0);
+ __ CompareImmediate(R1, kClosureCid);
+ __ b(&fall_through, EQ); // Instance is a closure.
__ LoadClassById(R2, R1);
-
// R2: class of instance (R0).
- __ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
- __ CompareObject(R3, Object::null_object());
- __ b(&fall_through, NE);
__ ldrh(R3, FieldAddress(R2, Class::num_type_arguments_offset()));
__ CompareImmediate(R3, 0);
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 265d5d4..3c28ec1 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -1614,11 +1614,10 @@
Label fall_through;
__ ldr(R0, Address(SP, 0 * kWordSize));
__ LoadClassIdMayBeSmi(R1, R0);
+ __ CompareImmediate(R1, kClosureCid);
+ __ b(&fall_through, EQ); // Instance is a closure.
__ LoadClassById(R2, R1);
// R2: class of instance (R0).
- __ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
- __ CompareObject(R3, Object::null_object());
- __ b(&fall_through, NE);
__ ldr(R3, FieldAddress(R2, Class::num_type_arguments_offset()), kHalfword);
__ CompareImmediate(R3, 0);
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 61620c8..9f4c622 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -1680,19 +1680,16 @@
Label fall_through;
__ movl(EAX, Address(ESP, + 1 * kWordSize));
__ LoadClassIdMayBeSmi(EDI, EAX);
+ __ cmpl(EDI, Immediate(kClosureCid));
+ __ j(EQUAL, &fall_through, Assembler::kNearJump); // Instance is a closure.
__ LoadClassById(EBX, EDI);
// EBX: class of instance (EAX).
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ movl(EDI, FieldAddress(EBX, Class::signature_function_offset()));
- __ cmpl(EDI, raw_null);
- __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
__ movzxw(EDI, FieldAddress(EBX, Class::num_type_arguments_offset()));
__ cmpl(EDI, Immediate(0));
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
__ movl(EAX, FieldAddress(EBX, Class::canonical_types_offset()));
- __ cmpl(EAX, raw_null);
+ __ CompareObject(EAX, Object::null_object());
__ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set.
__ ret();
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 2be1114..1e289cc 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -1646,12 +1646,10 @@
Label fall_through;
__ lw(T0, Address(SP, 0 * kWordSize));
__ LoadClassIdMayBeSmi(T1, T0);
+ __ BranchEqual(T1, Immediate(kClosureCid), &fall_through);
__ LoadClassById(T2, T1);
// T2: class of instance (T0).
- __ lw(T1, FieldAddress(T2, Class::signature_function_offset()));
- __ BranchNotEqual(T1, Object::null_object(), &fall_through);
-
__ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
__ BranchNotEqual(T1, Immediate(0), &fall_through);
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index e3f2ca4..d9eb08b 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -1536,11 +1536,11 @@
__ LoadClassIdMayBeSmi(RCX, RAX);
// RCX: untagged cid of instance (RAX).
+ __ cmpq(RCX, Immediate(kClosureCid));
+ __ j(EQUAL, &fall_through, Assembler::kNearJump); // Instance is a closure.
+
__ LoadClassById(RDI, RCX);
// RDI: class of instance (RAX).
- __ movq(RCX, FieldAddress(RDI, Class::signature_function_offset()));
- __ CompareObject(RCX, Object::null_object());
- __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
__ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
__ cmpq(RCX, Immediate(0));
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 5c764df..a62ac0e 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -58,6 +58,9 @@
"Pause isolates before starting.");
DEFINE_FLAG(bool, pause_isolates_on_exit, false,
"Pause isolates exiting.");
+DEFINE_FLAG(bool, pause_isolates_on_unhandled_exceptions, false,
+ "Pause isolates on unhandled exceptions.");
+
DEFINE_FLAG(bool, break_at_isolate_spawn, false,
"Insert a one-time breakpoint at the entrypoint for all spawned "
"isolates");
@@ -1070,6 +1073,9 @@
if (!ServiceIsolate::IsServiceIsolate(this)) {
message_handler()->set_pause_on_start(FLAG_pause_isolates_on_start);
message_handler()->set_pause_on_exit(FLAG_pause_isolates_on_exit);
+ if (FLAG_pause_isolates_on_unhandled_exceptions) {
+ debugger()->SetExceptionPauseInfo(kPauseOnUnhandledExceptions);
+ }
}
IsolateSpawnState* state = spawn_state();
if (state != NULL) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 8e84d00..56cf82e 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -718,6 +718,7 @@
RawCode* ic_miss_code_;
ClassTable class_table_;
bool single_step_;
+ bool skip_step_; // skip the next single step.
ThreadRegistry* thread_registry_;
Dart_MessageNotifyCallback message_notify_callback_;
diff --git a/runtime/vm/log.cc b/runtime/vm/log.cc
index d576beb..b7f6589 100644
--- a/runtime/vm/log.cc
+++ b/runtime/vm/log.cc
@@ -13,7 +13,8 @@
DEFINE_FLAG(charp, isolate_log_filter, NULL,
"Log isolates whose name include the filter. "
- "Default: service isolate log messages are suppressed.");
+ "Default: service isolate log messages are suppressed "
+ "(specify 'vm-service' to log them).");
Log::Log(LogPrinter printer)
: printer_(printer),
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 7f4bbec..6f2d172 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -72,6 +72,7 @@
false, // Not native.
cls,
0)); // No token position.
+ function.set_result_type(Type::Handle(Type::DynamicType()));
function.set_is_debuggable(false);
function.set_is_visible(false);
function.AttachCode(code);
diff --git a/runtime/vm/message.cc b/runtime/vm/message.cc
index 54f40b4..195b2c6 100644
--- a/runtime/vm/message.cc
+++ b/runtime/vm/message.cc
@@ -203,9 +203,9 @@
// TODO(johnmccutchan): Move port -> handler map out of Dart and into the
// VM, that way we can lookup the handler without invoking Dart code.
msg_handler = DartLibraryCalls::LookupHandler(current->dest_port());
- if (msg_handler.IsInstance() && Instance::Cast(msg_handler).IsClosure()) {
+ if (msg_handler.IsClosure()) {
// Grab function from closure.
- msg_handler = Closure::function(Instance::Cast(msg_handler));
+ msg_handler = Closure::Cast(msg_handler).function();
}
if (msg_handler.IsFunction()) {
const Function& function = Function::Cast(msg_handler);
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 4d0a348..ddc649b 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -334,18 +334,8 @@
String& name = String::Handle(Z);
while (it.HasNext()) {
cls = it.GetNextClass();
- if (cls.IsSignatureClass()) {
- if (!cls.IsCanonicalSignatureClass()) {
- // This is a typedef. Add it to the list of class names.
- name = cls.UserVisibleName();
- names.Add(name);
- } else {
- // Skip canonical signature classes. These are not named.
- }
- } else {
- name = cls.UserVisibleName();
- names.Add(name);
- }
+ name = cls.UserVisibleName();
+ names.Add(name);
}
return Api::NewHandle(T, Array::MakeArray(names));
}
@@ -362,7 +352,7 @@
ASSERT(ClassFinalizer::AllClassesFinalized());
- RawFunction* rf = Closure::function(closure_obj);
+ RawFunction* rf = Closure::Cast(closure_obj).function();
return Api::NewHandle(T, rf);
}
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 3fb2f74..0655a69 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -107,7 +107,7 @@
// Retrieve the receiver from the context.
const Object& closure = Object::Handle(ArgAt(0));
const Context& context =
- Context::Handle(Closure::context(Instance::Cast(closure)));
+ Context::Handle(Closure::Cast(closure).context());
return context.At(0);
}
return ArgAt(NumHiddenArgs(function_bits));
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 730d560..df6fde0 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -141,6 +141,8 @@
RawClass* Object::instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::object_pool_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+RawClass* Object::code_source_map_class_ =
+ reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::stackmap_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::var_descriptors_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
@@ -613,6 +615,9 @@
cls = Class::New<PcDescriptors>();
pc_descriptors_class_ = cls.raw();
+ cls = Class::New<CodeSourceMap>();
+ code_source_map_class_ = cls.raw();
+
cls = Class::New<Stackmap>();
stackmap_class_ = cls.raw();
@@ -945,6 +950,7 @@
SET_CLASS_NAME(code, Code);
SET_CLASS_NAME(instructions, Instructions);
SET_CLASS_NAME(object_pool, ObjectPool);
+ SET_CLASS_NAME(code_source_map, CodeSourceMap);
SET_CLASS_NAME(pc_descriptors, PcDescriptors);
SET_CLASS_NAME(stackmap, Stackmap);
SET_CLASS_NAME(var_descriptors, LocalVarDescriptors);
@@ -1122,6 +1128,8 @@
// Setup type class early in the process.
const Class& type_cls = Class::Handle(zone, Class::New<Type>());
+ const Class& function_type_cls = Class::Handle(zone,
+ Class::New<FunctionType>());
const Class& type_ref_cls = Class::Handle(zone, Class::New<TypeRef>());
const Class& type_parameter_cls = Class::Handle(zone,
Class::New<TypeParameter>());
@@ -1176,7 +1184,7 @@
// could expect. Use with caution.
type ^= Type::New(Object::Handle(zone, cls.raw()),
TypeArguments::Handle(zone),
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
type.SetIsFinalized();
type ^= type.Canonicalize();
object_store->set_array_type(type);
@@ -1284,6 +1292,9 @@
RegisterPrivateClass(type_cls, Symbols::Type(), core_lib);
pending_classes.Add(type_cls);
+ RegisterPrivateClass(function_type_cls, Symbols::FunctionType(), core_lib);
+ pending_classes.Add(function_type_cls);
+
RegisterPrivateClass(type_ref_cls, Symbols::TypeRef(), core_lib);
pending_classes.Add(type_ref_cls);
@@ -1321,15 +1332,14 @@
RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
pending_classes.Add(cls);
- // Abstract super class for all signature classes.
- cls = Class::New<Instance>(kIllegalCid);
- cls.set_num_type_arguments(0);
+ // Class that represents the Dart class _Closure and C++ class Closure.
+ cls = Class::New<Closure>();
+ cls.set_type_arguments_field_offset(Closure::type_arguments_offset());
+ cls.set_num_type_arguments(0); // Although a closure has type_arguments_.
cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- RegisterPrivateClass(cls, Symbols::FunctionImpl(), core_lib);
+ RegisterPrivateClass(cls, Symbols::_Closure(), core_lib);
pending_classes.Add(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_function_impl_type(type);
+ object_store->set_closure_class(cls);
cls = Class::New<WeakProperty>();
object_store->set_weak_property_class(cls);
@@ -1606,6 +1616,7 @@
cls = Class::New<LibraryPrefix>();
cls = Class::New<Type>();
+ cls = Class::New<FunctionType>();
cls = Class::New<TypeRef>();
cls = Class::New<TypeParameter>();
cls = Class::New<BoundedType>();
@@ -1660,6 +1671,9 @@
cls = Class::New<Double>();
object_store->set_double_class(cls);
+ cls = Class::New<Closure>();
+ object_store->set_closure_class(cls);
+
cls = Class::New<Bigint>();
object_store->set_bigint_class(cls);
@@ -1953,41 +1967,11 @@
}
-RawType* Class::SignatureType() const {
- ASSERT(IsSignatureClass());
- Zone* zone = Thread::Current()->zone();
- const Function& function = Function::Handle(zone, signature_function());
- ASSERT(!function.IsNull());
- if (function.signature_class() != raw()) {
- // This class is a function type alias. Return the canonical signature type.
- const Class& canonical_signature_class =
- Class::Handle(zone, function.signature_class());
- return canonical_signature_class.SignatureType();
- }
- const Type& signature_type = Type::Handle(zone, CanonicalType());
- if (!signature_type.IsNull()) {
- return signature_type.raw();
- }
- // A signature class extends class Instance and is parameterized in the same
- // way as the owner class of its non-static signature function.
- // It is not type parameterized if its signature function is static.
- // See Class::NewSignatureClass() for the setup of its type parameters.
- // During type finalization, the type arguments of the super class of the
- // owner class of its signature function will be prepended to the type
- // argument vector. Therefore, we only need to set the type arguments
- // matching the type parameters here.
- const TypeArguments& signature_type_arguments =
- TypeArguments::Handle(zone, type_parameters());
- // Return the still unfinalized signature type.
- return Type::New(*this, signature_type_arguments, token_pos());
-}
-
-
RawAbstractType* Class::RareType() const {
const Type& type = Type::Handle(Type::New(
*this,
Object::null_type_arguments(),
- Scanner::kNoSourcePos));
+ Token::kNoSourcePos));
return ClassFinalizer::FinalizeType(*this,
type,
ClassFinalizer::kCanonicalize);
@@ -1999,7 +1983,7 @@
const Type& type = Type::Handle(Type::New(
*this,
args,
- Scanner::kNoSourcePos));
+ Token::kNoSourcePos));
return ClassFinalizer::FinalizeType(*this,
type,
ClassFinalizer::kCanonicalize);
@@ -2037,7 +2021,7 @@
result.set_num_type_arguments(0);
result.set_num_own_type_arguments(0);
result.set_num_native_fields(0);
- result.set_token_pos(Scanner::kNoSourcePos);
+ result.set_token_pos(Token::kNoSourcePos);
result.InitEmptyFields();
Isolate::Current()->RegisterClass(result);
return result.raw();
@@ -2049,6 +2033,7 @@
Report::MessageF(Report::kError,
Script::Handle(cls.script()),
cls.token_pos(),
+ Report::AtLocation,
"too many type parameters declared in class '%s' or in its "
"super classes",
String::Handle(cls.Name()).ToCString());
@@ -2180,6 +2165,8 @@
set.Insert(func);
}
StorePointer(&raw_ptr()->functions_hash_table_, set.Release().raw());
+ } else {
+ StorePointer(&raw_ptr()->functions_hash_table_, Array::null());
}
}
@@ -2457,14 +2444,6 @@
cls = raw();
intptr_t num_type_args = 0;
do {
- if (cls.IsSignatureClass()) {
- Function& signature_fun = Function::Handle(zone);
- signature_fun ^= cls.signature_function();
- if (!signature_fun.is_static() &&
- !signature_fun.HasInstantiatedSignature()) {
- cls = signature_fun.Owner();
- }
- }
// Calling NumOwnTypeArguments() on a mixin application class will setup the
// type parameters if not already done.
num_type_args += cls.NumOwnTypeArguments();
@@ -2474,8 +2453,12 @@
break;
}
sup_type = cls.super_type();
- ClassFinalizer::ResolveTypeClass(cls, sup_type);
+ // A BoundedType, TypeRef, or FunctionType can appear as type argument of
+ // sup_type, but not as sup_type itself.
+ ASSERT(sup_type.IsType());
+ sup_type = ClassFinalizer::ResolveTypeClass(cls, Type::Cast(sup_type));
cls = sup_type.type_class();
+ ASSERT(!cls.IsTypedefClass());
} while (true);
set_num_type_arguments(num_type_args);
return num_type_args;
@@ -2527,6 +2510,7 @@
void Class::CalculateFieldOffsets() const {
+ ASSERT(id() != kClosureCid); // Class _Closure is prefinalized.
Array& flds = Array::Handle(fields());
const Class& super = Class::Handle(SuperClass());
intptr_t offset = 0;
@@ -2694,7 +2678,7 @@
false, // Not external.
false, // Not native.
owner,
- 0)); // token_pos
+ ClassifyingTokenPositions::kMethodExtractor)); // token_pos
// Initialize signature: receiver is a single fixed parameter.
const intptr_t kNumParameters = 1;
@@ -2740,9 +2724,7 @@
void Class::Finalize() const {
ASSERT(Thread::Current()->IsMutatorThread());
- // Even if all regular classes are prefinalized (precompilation), signature
- // classes may be added later when we encounter local functions.
- ASSERT(IsSignatureClass() || !Isolate::Current()->all_classes_finalized());
+ ASSERT(!Isolate::Current()->all_classes_finalized());
ASSERT(!is_finalized());
// Prefinalized classes have a VM internal representation and no Dart fields.
// Their instance size is precomputed and field offsets are known.
@@ -2898,6 +2880,7 @@
*error, // No previous error.
Script::Handle(patch.script()),
func.token_pos(),
+ Report::AtLocation,
Report::kError,
Heap::kNew,
"signature mismatch: '%s'", member_name.ToCString());
@@ -2943,6 +2926,7 @@
*error, // No previous error.
Script::Handle(patch.script()),
field.token_pos(),
+ Report::AtLocation,
Report::kError,
Heap::kNew,
"duplicate field: %s", member_name.ToCString());
@@ -3107,7 +3091,7 @@
result.set_num_type_arguments(kUnknownNumTypeArguments);
result.set_num_own_type_arguments(kUnknownNumTypeArguments);
result.set_num_native_fields(0);
- result.set_token_pos(Scanner::kNoSourcePos);
+ result.set_token_pos(Token::kNoSourcePos);
result.InitEmptyFields();
Isolate::Current()->RegisterClass(result);
return result.raw();
@@ -3125,79 +3109,12 @@
}
-RawClass* Class::NewSignatureClass(const String& name,
- const Function& signature_function,
- const Script& script,
- intptr_t token_pos) {
- const Class& result = Class::Handle(New(name, script, token_pos));
- // Instances of a signature class can only be closures.
- result.set_instance_size(Closure::InstanceSize());
- result.set_next_field_offset(Closure::NextFieldOffset());
- // Signature classes extend the _FunctionImpl class.
- result.set_super_type(Type::Handle(
- Isolate::Current()->object_store()->function_impl_type()));
- result.set_is_synthesized_class();
- result.set_type_arguments_field_offset(Closure::type_arguments_offset());
- if (!signature_function.IsNull()) {
- result.PatchSignatureFunction(signature_function);
- }
- return result.raw();
-}
-
-
-void Class::PatchSignatureFunction(const Function& signature_function) const {
- ASSERT(!signature_function.IsNull());
- set_signature_function(signature_function);
- const Class& owner_class = Class::Handle(signature_function.Owner());
- ASSERT(!owner_class.IsNull());
- // A signature class extends class Instance and is either not parameterized or
- // parameterized with exactly the same list of type parameters as the owner
- // class of its function.
- // In case of a function type alias, the function owner is the alias class,
- // which is also the signature class. The signature class is therefore
- // parameterized according to the alias class declaration, even if the
- // function type is not generic.
- // Otherwise, if the function is static or if its signature type is
- // non-generic, i.e. it does not depend on any type parameter of the owner
- // class, then the signature class is not parameterized, although the owner
- // class may be.
- if (owner_class.raw() == raw()) {
- // This signature class is an alias, which cannot be the canonical
- // signature class for this signature function.
- ASSERT(!IsCanonicalSignatureClass());
- // Do not modify the declared type parameters of the alias, even if unused.
- } else {
- // Copy the type parameters only for an instance function type that is not
- // instantiated, i.e. that depends on the type parameters of the owner
- // class.
- // TODO(regis): Verify that it is not a problem for the copied type
- // parameters to refer to the owner class rather than to the signature
- // class. In other words, uninstantiated function types should only get
- // instantiated by the owner class as instantiator and never by the
- // signature class itself.
- TypeArguments& type_parameters = TypeArguments::Handle();
- if (!signature_function.is_static() &&
- (owner_class.NumTypeParameters() > 0) &&
- !signature_function.HasInstantiatedSignature()) {
- type_parameters = owner_class.type_parameters();
- }
- set_type_parameters(type_parameters);
- if (signature_function.signature_class() == Object::null()) {
- // Make this signature class the canonical signature class.
- signature_function.set_signature_class(*this);
- ASSERT(IsCanonicalSignatureClass());
- }
- }
- set_is_prefinalized();
-}
-
-
RawClass* Class::NewNativeWrapper(const Library& library,
const String& name,
int field_count) {
Class& cls = Class::Handle(library.LookupClass(name));
if (cls.IsNull()) {
- cls = New(name, Script::Handle(), Scanner::kNoSourcePos);
+ cls = New(name, Script::Handle(), Token::kNoSourcePos);
cls.SetFields(Object::empty_array());
cls.SetFunctions(Object::empty_array());
// Set super class to Object.
@@ -3289,12 +3206,8 @@
RawString* Class::GeneratePrettyName() const {
- if (!IsCanonicalSignatureClass()) {
- const String& name = String::Handle(Name());
- return String::IdentifierPrettyName(name);
- } else {
- return Name();
- }
+ const String& name = String::Handle(Name());
+ return String::IdentifierPrettyName(name);
}
@@ -3343,6 +3256,8 @@
return Symbols::Instructions().raw();
case kObjectPoolCid:
return Symbols::ObjectPool().raw();
+ case kCodeSourceMapCid:
+ return Symbols::CodeSourceMap().raw();
case kPcDescriptorsCid:
return Symbols::PcDescriptors().raw();
case kStackmapCid:
@@ -3432,12 +3347,8 @@
case kExternalTypedDataFloat64ArrayCid:
return Symbols::Float64List().raw();
default:
- if (!IsCanonicalSignatureClass()) {
- const String& name = String::Handle(Name());
- return String::IdentifierPrettyName(name);
- } else {
- return Name();
- }
+ const String& name = String::Handle(Name());
+ return String::IdentifierPrettyName(name);
}
UNREACHABLE();
}
@@ -3449,14 +3360,14 @@
void Class::set_token_pos(intptr_t token_pos) const {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
}
intptr_t Class::ComputeEndTokenPos() const {
// Return the begin token for synthetic classes.
- if (IsSignatureClass() || IsMixinApplication() || IsTopLevel()) {
+ if (IsMixinApplication() || IsTopLevel()) {
return token_pos();
}
const Script& scr = Script::Handle(script());
@@ -3639,7 +3550,7 @@
RawType* Class::CanonicalType() const {
- if (!IsGeneric()) {
+ if (!IsGeneric() && !IsClosureClass()) {
return reinterpret_cast<RawType*>(raw_ptr()->canonical_types_);
}
Array& types = Array::Handle();
@@ -3653,7 +3564,7 @@
void Class::SetCanonicalType(const Type& type) const {
ASSERT(type.IsCanonical());
- if (!IsGeneric()) {
+ if (!IsGeneric() && !IsClosureClass()) {
ASSERT((canonical_types() == Object::null()) ||
(canonical_types() == type.raw())); // Set during own finalization.
set_canonical_types(type);
@@ -3667,7 +3578,7 @@
}
-intptr_t Class::FindCanonicalTypeIndex(const Type& needle) const {
+intptr_t Class::FindCanonicalTypeIndex(const AbstractType& needle) const {
Thread* thread = Thread::Current();
if (EnsureIsFinalized(thread) != Error::null()) {
return -1;
@@ -3697,8 +3608,8 @@
}
-RawType* Class::CanonicalTypeFromIndex(intptr_t idx) const {
- Type& type = Type::Handle();
+RawAbstractType* Class::CanonicalTypeFromIndex(intptr_t idx) const {
+ AbstractType& type = AbstractType::Handle();
if (idx == 0) {
type = CanonicalType();
if (!type.IsNull()) {
@@ -3745,12 +3656,6 @@
}
-bool Class::IsCanonicalSignatureClass() const {
- const Function& function = Function::Handle(signature_function());
- return (!function.IsNull() && (function.signature_class() == raw()));
-}
-
-
// If test_kind == kIsSubtypeOf, checks if type S is a subtype of type T.
// If test_kind == kIsMoreSpecificThan, checks if S is more specific than T.
// Type S is specified by this class parameterized with 'type_arguments', and
@@ -3823,25 +3728,8 @@
bound_error,
space);
}
- const bool other_is_function_class = other.IsFunctionClass();
- if (other.IsSignatureClass() || other_is_function_class) {
- const Function& other_fun = Function::Handle(zone,
- other.signature_function());
- if (thsi.IsSignatureClass()) {
- if (other_is_function_class) {
- return true;
- }
- // Check for two function types.
- const Function& fun =
- Function::Handle(zone, thsi.signature_function());
- return fun.TypeTest(test_kind,
- type_arguments,
- other_fun,
- other_type_arguments,
- bound_error,
- space);
- }
- // Check if type S has a call() method of function type T.
+ if (other.IsFunctionClass()) {
+ // Check if type S has a call() method.
Function& function =
Function::Handle(zone, thsi.LookupDynamicFunction(Symbols::Call()));
if (function.IsNull()) {
@@ -3853,15 +3741,7 @@
}
}
if (!function.IsNull()) {
- if (other_is_function_class ||
- function.TypeTest(test_kind,
- type_arguments,
- other_fun,
- other_type_arguments,
- bound_error,
- space)) {
- return true;
- }
+ return true;
}
}
// Check for 'direct super type' specified in the implements clause
@@ -4385,7 +4265,7 @@
void UnresolvedClass::set_token_pos(intptr_t token_pos) const {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
}
@@ -4901,7 +4781,8 @@
}
// Cache lookup failed. Instantiate the type arguments.
TypeArguments& result = TypeArguments::Handle();
- result = InstantiateFrom(instantiator_type_arguments, bound_error);
+ result = InstantiateFrom(
+ instantiator_type_arguments, bound_error, NULL, Heap::kOld);
if ((bound_error != NULL) && !bound_error->IsNull()) {
return result.raw();
}
@@ -5493,33 +5374,67 @@
}
-RawClass* Function::signature_class() const {
+RawFunctionType* Function::SignatureType() const {
+ FunctionType& type = FunctionType::Handle();
+ const Object& obj = Object::Handle(raw_ptr()->data_);
if (IsSignatureFunction()) {
- const Object& obj = Object::Handle(raw_ptr()->data_);
- ASSERT(obj.IsNull() || obj.IsClass());
- return (obj.IsNull()) ? Class::null() : Class::Cast(obj).raw();
- }
- if (IsClosureFunction()) {
- const Object& obj = Object::Handle(raw_ptr()->data_);
+ ASSERT(obj.IsNull() || obj.IsFunctionType());
+ type = obj.IsNull() ? FunctionType::null() : FunctionType::Cast(obj).raw();
+ } else {
+ ASSERT(IsClosureFunction());
ASSERT(!obj.IsNull());
- return ClosureData::Cast(obj).signature_class();
+ type = ClosureData::Cast(obj).signature_type();
}
- return Class::null();
+ if (type.IsNull()) {
+ // A function type is parameterized in the same way as the owner class of
+ // its non-static signature function.
+ // It is not type parameterized if its signature function is static.
+ // During type finalization, the type arguments of the super class of the
+ // owner class of its signature function will be prepended to the type
+ // argument vector. Therefore, we only need to set the type arguments
+ // matching the type parameters here.
+ // In case of a function type alias, the function owner is the alias class,
+ // i.e. the typedef. The signature type is therefore parameterized according
+ // to the alias class declaration, even if the function type is not generic.
+ // Otherwise, if the function is static or if its signature type is
+ // non-generic, i.e. it does not depend on any type parameter of the owner
+ // class, then the signature type is not parameterized, although the owner
+ // class may be. In this case, the scope class of the function type is reset
+ // to _Closure class as well as the owner of the signature function.
+ Class& scope_class = Class::Handle(Owner());
+ if (!scope_class.IsTypedefClass() &&
+ (is_static() ||
+ !scope_class.IsGeneric() ||
+ HasInstantiatedSignature())) {
+ scope_class = Isolate::Current()->object_store()->closure_class();
+ if (IsSignatureFunction()) {
+ set_owner(scope_class);
+ set_token_pos(Token::kNoSourcePos);
+ }
+ }
+ const TypeArguments& signature_type_arguments =
+ TypeArguments::Handle(scope_class.type_parameters());
+ // Return the still unfinalized signature type.
+ type = FunctionType::New(scope_class,
+ signature_type_arguments,
+ *this,
+ token_pos());
+
+ SetSignatureType(type);
+ }
+ return type.raw();
}
-void Function::set_signature_class(const Class& value) const {
+void Function::SetSignatureType(const FunctionType& value) const {
if (IsSignatureFunction()) {
set_data(value);
- return;
- }
- if (IsClosureFunction()) {
+ } else {
+ ASSERT(IsClosureFunction());
const Object& obj = Object::Handle(raw_ptr()->data_);
ASSERT(!obj.IsNull());
- ClosureData::Cast(obj).set_signature_class(value);
- return;
+ ClosureData::Cast(obj).set_signature_type(value);
}
- UNREACHABLE();
}
@@ -5640,7 +5555,7 @@
// This field is heavily overloaded:
// eval function: Script expression source
-// signature function: Class signature class
+// signature function: Function type
// method extractor: Function extracted closure function
// noSuchMethod dispatcher: Array arguments descriptor
// invoke-field dispatcher: Array arguments descriptor
@@ -5787,7 +5702,7 @@
void Function::set_token_pos(intptr_t token_pos) const {
- ASSERT(token_pos >= 0);
+ ASSERT(!Token::IsClassifying(token_pos) || IsMethodExtractor());
StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
}
@@ -6169,6 +6084,7 @@
*bound_error, // A bound error if non null.
Script::Handle(other.script()),
other.token_pos(),
+ Report::AtLocation,
Report::kError,
Heap::kNew,
"signature type '%s' of function '%s' is not a subtype of signature "
@@ -6505,6 +6421,25 @@
}
+RawFunction* Function::NewSignatureFunction(const Class& owner,
+ intptr_t token_pos) {
+ const Function& result = Function::Handle(Function::New(
+ Symbols::AnonymousSignature(),
+ RawFunction::kSignatureFunction,
+ /* is_static = */ false,
+ /* is_const = */ false,
+ /* is_abstract = */ false,
+ /* is_external = */ false,
+ /* is_native = */ false,
+ owner, // Same as function type scope class.
+ token_pos));
+ result.set_is_reflectable(false);
+ result.set_is_visible(false);
+ result.set_is_debuggable(false);
+ return result.raw();
+}
+
+
RawFunction* Function::NewEvalFunction(const Class& owner,
const Script& script,
bool is_static) {
@@ -6583,35 +6518,12 @@
param_name = ParameterNameAt(has_receiver - kClosure + i);
closure_function.SetParameterNameAt(i, param_name);
}
-
- // Lookup or create a new signature class for the closure function in the
- // library of the owner class.
- const Class& owner_class = Class::Handle(Owner());
- ASSERT(!owner_class.IsNull() && (Owner() == closure_function.Owner()));
- const Library& library = Library::Handle(owner_class.library());
- ASSERT(!library.IsNull());
- const String& signature = String::Handle(closure_function.Signature());
- Class& signature_class = Class::ZoneHandle(
- library.LookupLocalClass(signature));
- if (signature_class.IsNull()) {
- const Script& script = Script::Handle(this->script());
- signature_class = Class::NewSignatureClass(signature,
- closure_function,
- script,
- closure_function.token_pos());
- library.AddClass(signature_class);
- } else {
- closure_function.set_signature_class(signature_class);
- }
- // Finalize types in signature class here, so that the
- // signature type is not computed twice.
- ClassFinalizer::FinalizeTypesInClass(signature_class);
- const Type& signature_type = Type::Handle(signature_class.SignatureType());
+ const FunctionType& signature_type =
+ FunctionType::Handle(closure_function.SignatureType());
if (!signature_type.IsFinalized()) {
ClassFinalizer::FinalizeType(
- signature_class, signature_type, ClassFinalizer::kCanonicalize);
+ Class::Handle(Owner()), signature_type, ClassFinalizer::kCanonicalize);
}
- ASSERT(closure_function.signature_class() == signature_class.raw());
set_implicit_closure_function(closure_function);
ASSERT(closure_function.IsImplicitClosureFunction());
return closure_function.raw();
@@ -6716,9 +6628,6 @@
Context::Handle(zone, object_store->empty_context());
Instance& closure =
Instance::Handle(zone, Closure::New(*this, context, Heap::kOld));
- const char* error_str = NULL;
- closure ^= closure.CheckAndCanonicalize(&error_str);
- ASSERT(!closure.IsNull());
set_implicit_static_closure(closure);
}
return implicit_static_closure();
@@ -6727,11 +6636,12 @@
RawInstance* Function::ImplicitInstanceClosure(const Instance& receiver) const {
ASSERT(IsImplicitClosureFunction());
- const Class& cls = Class::Handle(signature_class());
+ const FunctionType& signature_type = FunctionType::Handle(SignatureType());
+ const Class& cls = Class::Handle(signature_type.type_class());
const Context& context = Context::Handle(Context::New(1));
context.SetAt(0, receiver);
const Instance& result = Instance::Handle(Closure::New(*this, context));
- if (cls.NumTypeArguments() > 0) {
+ if (cls.IsGeneric()) {
const TypeArguments& type_arguments =
TypeArguments::Handle(receiver.GetTypeArguments());
result.SetTypeArguments(type_arguments);
@@ -6748,18 +6658,17 @@
GrowableHandlePtrArray<const String> pieces(zone, 4);
String& name = String::Handle(zone);
if (!instantiate && !is_static() && (name_visibility == kInternalName)) {
- // Prefix the signature with its signature class and type parameters, if any
+ // Prefix the signature with its scope class and type parameters, if any
// (e.g. "Map<K, V>(K) => bool"). In case of a function type alias, the
- // signature class name is the alias name.
+ // scope class name is the alias name.
// The signature of static functions cannot be type parameterized.
- const Class& function_class = Class::Handle(zone, Owner());
- ASSERT(!function_class.IsNull());
- const TypeArguments& type_parameters = TypeArguments::Handle(
- zone, function_class.type_parameters());
- if (!type_parameters.IsNull()) {
- const String& function_class_name =
- String::Handle(zone, function_class.Name());
- pieces.Add(function_class_name);
+ const Class& scope_class = Class::Handle(zone, Owner());
+ ASSERT(!scope_class.IsNull());
+ if (scope_class.IsGeneric()) {
+ const TypeArguments& type_parameters = TypeArguments::Handle(
+ zone, scope_class.type_parameters());
+ const String& scope_class_name = String::Handle(zone, scope_class.Name());
+ pieces.Add(scope_class_name);
const intptr_t num_type_parameters = type_parameters.Length();
pieces.Add(Symbols::LAngleBracket());
TypeParameter& type_parameter = TypeParameter::Handle(zone);
@@ -7271,8 +7180,8 @@
}
-void ClosureData::set_signature_class(const Class& value) const {
- StorePointer(&raw_ptr()->signature_class_, value.raw());
+void ClosureData::set_signature_type(const FunctionType& value) const {
+ StorePointer(&raw_ptr()->signature_type_, value.raw());
}
@@ -8547,7 +8456,10 @@
cur_token_kind_(Token::kILLEGAL),
cur_token_obj_index_(-1),
stream_type_(stream_type) {
- SetCurrentPosition(token_pos);
+ ASSERT(token_pos != Token::kNoSourcePos);
+ if (token_pos >= 0) {
+ SetCurrentPosition(token_pos);
+ }
}
@@ -9239,7 +9151,8 @@
const String& url = String::Handle(lib.url());
Report::MessageF(Report::kError,
Script::Handle(lib.LookupScript(url)),
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
+ Report::AtLocation,
"too many imports in library '%s'",
url.ToCString());
UNREACHABLE();
@@ -10155,9 +10068,17 @@
}
-void Library::InitResolvedNamesCache(intptr_t size) const {
- const Array& cache = Array::Handle(HashTables::New<ResolvedNamesMap>(size));
- StorePointer(&raw_ptr()->resolved_names_, cache.raw());
+void Library::InitResolvedNamesCache(intptr_t size,
+ SnapshotReader* reader) const {
+ if (reader == NULL) {
+ StorePointer(&raw_ptr()->resolved_names_,
+ HashTables::New<ResolvedNamesMap>(size));
+ } else {
+ intptr_t len = ResolvedNamesMap::ArrayLengthForNumOccupied(size);
+ *reader->ArrayHandle() ^= reader->NewArray(len);
+ StorePointer(&raw_ptr()->resolved_names_,
+ HashTables::New<ResolvedNamesMap>(*reader->ArrayHandle()));
+ }
}
@@ -10512,8 +10433,7 @@
Class& klass = Class::Handle();
while (class_iter.HasNext()) {
klass = class_iter.GetNextClass();
- if (!klass.IsCanonicalSignatureClass() &&
- !klass.IsMixinApplication()) {
+ if (!klass.IsMixinApplication()) {
jsarr.AddValue(klass);
}
}
@@ -11246,15 +11166,15 @@
}
-// Encode integer in SLEB128 format.
-void PcDescriptors::EncodeInteger(GrowableArray<uint8_t>* data,
- intptr_t value) {
+// Encode integer |value| in SLEB128 format and store into |data|.
+static void EncodeSLEB128(GrowableArray<uint8_t>* data,
+ intptr_t value) {
bool is_last_part = false;
while (!is_last_part) {
- intptr_t part = value & 0x7f;
+ uint8_t part = value & 0x7f;
value >>= 7;
if ((value == 0 && (part & 0x40) == 0) ||
- (value == -1 && (part & 0x40) != 0)) {
+ (value == static_cast<intptr_t>(-1) && (part & 0x40) != 0)) {
is_last_part = true;
} else {
part |= 0x80;
@@ -11264,24 +11184,39 @@
}
+// Decode integer in SLEB128 format from |data| and update |byte_index|.
+static intptr_t DecodeSLEB128(const uint8_t* data,
+ const intptr_t data_length,
+ intptr_t* byte_index) {
+ ASSERT(*byte_index < data_length);
+ uword shift = 0;
+ intptr_t value = 0;
+ uint8_t part = 0;
+ do {
+ part = data[(*byte_index)++];
+ value |= static_cast<intptr_t>(part & 0x7f) << shift;
+ shift += 7;
+ } while ((part & 0x80) != 0);
+
+ if ((shift < (sizeof(value) * 8)) && ((part & 0x40) != 0)) {
+ value |= static_cast<intptr_t>(-1) << shift;
+ }
+ return value;
+}
+
+
+// Encode integer in SLEB128 format.
+void PcDescriptors::EncodeInteger(GrowableArray<uint8_t>* data,
+ intptr_t value) {
+ return EncodeSLEB128(data, value);
+}
+
+
// Decode SLEB128 encoded integer. Update byte_index to the next integer.
intptr_t PcDescriptors::DecodeInteger(intptr_t* byte_index) const {
NoSafepointScope no_safepoint;
const uint8_t* data = raw_ptr()->data();
- ASSERT(*byte_index < Length());
- uword shift = 0;
- intptr_t value = 0;
- intptr_t part = 0;
- do {
- part = data[(*byte_index)++];
- value |= (part & 0x7f) << shift;
- shift += 7;
- } while ((part & 0x80) != 0);
-
- if (shift < sizeof(value) * 8 && (part & 0x40) != 0) {
- value |= -(1 << shift);
- }
- return value;
+ return DecodeSLEB128(data, Length(), byte_index);
}
@@ -11583,6 +11518,114 @@
}
+intptr_t CodeSourceMap::Length() const {
+ return raw_ptr()->length_;
+}
+
+
+void CodeSourceMap::SetLength(intptr_t value) const {
+ StoreNonPointer(&raw_ptr()->length_, value);
+}
+
+
+void CodeSourceMap::CopyData(GrowableArray<uint8_t>* delta_encoded_data) {
+ NoSafepointScope no_safepoint;
+ uint8_t* data = UnsafeMutableNonPointer(&raw_ptr()->data()[0]);
+ for (intptr_t i = 0; i < delta_encoded_data->length(); ++i) {
+ data[i] = (*delta_encoded_data)[i];
+ }
+}
+
+
+RawCodeSourceMap* CodeSourceMap::New(GrowableArray<uint8_t>* data) {
+ ASSERT(Object::code_source_map_class() != Class::null());
+ Thread* thread = Thread::Current();
+ CodeSourceMap& result = CodeSourceMap::Handle(thread->zone());
+ {
+ uword size = CodeSourceMap::InstanceSize(data->length());
+ RawObject* raw = Object::Allocate(CodeSourceMap::kClassId,
+ size,
+ Heap::kOld);
+ NoSafepointScope no_safepoint;
+ result ^= raw;
+ result.SetLength(data->length());
+ result.CopyData(data);
+ }
+ return result.raw();
+}
+
+
+RawCodeSourceMap* CodeSourceMap::New(intptr_t length) {
+ ASSERT(Object::code_source_map_class() != Class::null());
+ Thread* thread = Thread::Current();
+ CodeSourceMap& result = CodeSourceMap::Handle(thread->zone());
+ {
+ uword size = CodeSourceMap::InstanceSize(length);
+ RawObject* raw = Object::Allocate(CodeSourceMap::kClassId,
+ size,
+ Heap::kOld);
+ NoSafepointScope no_safepoint;
+ result ^= raw;
+ result.SetLength(length);
+ }
+ return result.raw();
+}
+
+
+void CodeSourceMap::PrintJSONImpl(JSONStream* stream, bool ref) const {
+ Object::PrintJSONImpl(stream, ref);
+}
+
+
+const char* CodeSourceMap::ToCString() const {
+ // "*" in a printf format specifier tells it to read the field width from
+ // the printf argument list.
+#define FORMAT "%#-*" Px "\t%" Pd "\n"
+ if (Length() == 0) {
+ return "empty CodeSourceMap\n";
+ }
+ // 4 bits per hex digit.
+ const int addr_width = kBitsPerWord / 4;
+ // First compute the buffer size required.
+ intptr_t len = 1; // Trailing '\0'.
+ {
+ Iterator iter(*this);
+ while (iter.MoveNext()) {
+ len += OS::SNPrint(NULL, 0, FORMAT, addr_width,
+ iter.PcOffset(),
+ iter.TokenPos());
+ }
+ }
+ // Allocate the buffer.
+ char* buffer = Thread::Current()->zone()->Alloc<char>(len);
+ // Layout the fields in the buffer.
+ intptr_t index = 0;
+ Iterator iter(*this);
+ while (iter.MoveNext()) {
+ index += OS::SNPrint((buffer + index), (len - index), FORMAT, addr_width,
+ iter.PcOffset(),
+ iter.TokenPos());
+ }
+ return buffer;
+#undef FORMAT
+}
+
+
+// Encode integer in SLEB128 format.
+void CodeSourceMap::EncodeInteger(GrowableArray<uint8_t>* data,
+ intptr_t value) {
+ return EncodeSLEB128(data, value);
+}
+
+
+// Decode SLEB128 encoded integer. Update byte_index to the next integer.
+intptr_t CodeSourceMap::DecodeInteger(intptr_t* byte_index) const {
+ NoSafepointScope no_safepoint;
+ const uint8_t* data = raw_ptr()->data();
+ return DecodeSLEB128(data, Length(), byte_index);
+}
+
+
bool Stackmap::GetBit(intptr_t bit_index) const {
ASSERT(InRange(bit_index));
int byte_index = bit_index >> kBitsPerByteLog2;
@@ -14379,7 +14422,7 @@
void SubtypeTestCache::AddCheck(
- intptr_t instance_class_id,
+ const Object& instance_class_id_or_function,
const TypeArguments& instance_type_arguments,
const TypeArguments& instantiator_type_arguments,
const Bool& test_result) const {
@@ -14389,24 +14432,24 @@
data = Array::Grow(data, new_len);
set_cache(data);
intptr_t data_pos = old_num * kTestEntryLength;
- data.SetAt(data_pos + kInstanceClassId,
- Smi::Handle(Smi::New(instance_class_id)));
+ data.SetAt(data_pos + kInstanceClassIdOrFunction,
+ instance_class_id_or_function);
data.SetAt(data_pos + kInstanceTypeArguments, instance_type_arguments);
data.SetAt(data_pos + kInstantiatorTypeArguments,
- instantiator_type_arguments);
+ instantiator_type_arguments);
data.SetAt(data_pos + kTestResult, test_result);
}
void SubtypeTestCache::GetCheck(intptr_t ix,
- intptr_t* instance_class_id,
+ Object* instance_class_id_or_function,
TypeArguments* instance_type_arguments,
TypeArguments* instantiator_type_arguments,
Bool* test_result) const {
Array& data = Array::Handle(cache());
intptr_t data_pos = ix * kTestEntryLength;
- *instance_class_id =
- Smi::Value(Smi::RawCast(data.At(data_pos + kInstanceClassId)));
+ *instance_class_id_or_function =
+ data.At(data_pos + kInstanceClassIdOrFunction);
*instance_type_arguments ^= data.At(data_pos + kInstanceTypeArguments);
*instantiator_type_arguments ^=
data.At(data_pos + kInstantiatorTypeArguments);
@@ -14503,6 +14546,7 @@
RawLanguageError* LanguageError::NewFormattedV(const Error& prev_error,
const Script& script,
intptr_t token_pos,
+ bool report_after_token,
Report::Kind kind,
Heap::Space space,
const char* format,
@@ -14519,6 +14563,7 @@
result.set_previous_error(prev_error);
result.set_script(script);
result.set_token_pos(token_pos);
+ result.set_report_after_token(report_after_token);
result.set_kind(kind);
result.set_message(String::Handle(
String::NewFormattedV(format, args, space)));
@@ -14529,13 +14574,15 @@
RawLanguageError* LanguageError::NewFormatted(const Error& prev_error,
const Script& script,
intptr_t token_pos,
+ bool report_after_token,
Report::Kind kind,
Heap::Space space,
const char* format, ...) {
va_list args;
va_start(args, format);
RawLanguageError* result = LanguageError::NewFormattedV(
- prev_error, script, token_pos, kind, space, format, args);
+ prev_error, script, token_pos, report_after_token,
+ kind, space, format, args);
NoSafepointScope no_safepoint;
va_end(args);
return result;
@@ -14571,11 +14618,16 @@
void LanguageError::set_token_pos(intptr_t token_pos) const {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
}
+void LanguageError::set_report_after_token(bool value) {
+ StoreNonPointer(&raw_ptr()->report_after_token_, value);
+}
+
+
void LanguageError::set_kind(uint8_t value) const {
StoreNonPointer(&raw_ptr()->kind_, value);
}
@@ -14599,6 +14651,7 @@
Report::PrependSnippet(kind(),
Script::Handle(script()),
token_pos(),
+ report_after_token(),
String::Handle(message())));
// Prepend previous error message.
const Error& prev_error = Error::Handle(previous_error());
@@ -14955,11 +15008,32 @@
}
-RawType* Instance::GetType() const {
+RawAbstractType* Instance::GetType() const {
if (IsNull()) {
return Type::NullType();
}
const Class& cls = Class::Handle(clazz());
+ if (cls.IsClosureClass()) {
+ const Function& signature =
+ Function::Handle(Closure::Cast(*this).function());
+ FunctionType& type = FunctionType::Handle(signature.SignatureType());
+ if (type.scope_class() == cls.raw()) {
+ // Type is not parameterized.
+ if (!type.IsCanonical()) {
+ type ^= type.Canonicalize();
+ signature.SetSignatureType(type);
+ }
+ return type.raw();
+ }
+ const Class& scope_cls = Class::Handle(type.scope_class());
+ ASSERT(scope_cls.NumTypeArguments() > 0);
+ TypeArguments& type_arguments = TypeArguments::Handle(GetTypeArguments());
+ type = FunctionType::New(
+ scope_cls, type_arguments, signature, Token::kNoSourcePos);
+ type.SetIsFinalized();
+ type ^= type.Canonicalize();
+ return type.raw();
+ }
Type& type = Type::Handle();
if (!cls.IsGeneric()) {
type = cls.CanonicalType();
@@ -14969,7 +15043,7 @@
if (cls.NumTypeArguments() > 0) {
type_arguments = GetTypeArguments();
}
- type = Type::New(cls, type_arguments, Scanner::kNoSourcePos);
+ type = Type::New(cls, type_arguments, Token::kNoSourcePos);
type.SetIsFinalized();
type ^= type.Canonicalize();
}
@@ -15008,6 +15082,47 @@
}
Zone* zone = Thread::Current()->zone();
const Class& cls = Class::Handle(zone, clazz());
+ if (cls.IsClosureClass()) {
+ if (other.IsObjectType() || other.IsDartFunctionType()) {
+ return true;
+ }
+ Function& other_signature = Function::Handle(zone);
+ TypeArguments& other_type_arguments = TypeArguments::Handle(zone);
+ // Note that we may encounter a bound error in checked mode.
+ if (!other.IsInstantiated()) {
+ const AbstractType& instantiated_other = AbstractType::Handle(
+ zone, other.InstantiateFrom(other_instantiator, bound_error));
+ if ((bound_error != NULL) && !bound_error->IsNull()) {
+ ASSERT(Isolate::Current()->flags().type_checks());
+ return false;
+ }
+ if (instantiated_other.IsDynamicType() ||
+ instantiated_other.IsObjectType() ||
+ instantiated_other.IsDartFunctionType()) {
+ return true;
+ }
+ if (!instantiated_other.IsFunctionType()) {
+ return false;
+ }
+ other_signature = FunctionType::Cast(instantiated_other).signature();
+ other_type_arguments = instantiated_other.arguments();
+ } else {
+ if (!other.IsFunctionType()) {
+ return false;
+ }
+ other_signature = FunctionType::Cast(other).signature();
+ other_type_arguments = other.arguments();
+ }
+ const Function& signature =
+ Function::Handle(zone, Closure::Cast(*this).function());
+ const TypeArguments& type_arguments =
+ TypeArguments::Handle(zone, GetTypeArguments());
+ return signature.IsSubtypeOf(type_arguments,
+ other_signature,
+ other_type_arguments,
+ bound_error,
+ Heap::kOld);
+ }
TypeArguments& type_arguments = TypeArguments::Handle(zone);
if (cls.NumTypeArguments() > 0) {
type_arguments = GetTypeArguments();
@@ -15025,20 +15140,54 @@
}
Class& other_class = Class::Handle(zone);
TypeArguments& other_type_arguments = TypeArguments::Handle(zone);
+ AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw());
// Note that we may encounter a bound error in checked mode.
if (!other.IsInstantiated()) {
- const AbstractType& instantiated_other = AbstractType::Handle(
- zone, other.InstantiateFrom(other_instantiator, bound_error));
+ instantiated_other = other.InstantiateFrom(other_instantiator, bound_error);
if ((bound_error != NULL) && !bound_error->IsNull()) {
ASSERT(Isolate::Current()->flags().type_checks());
return false;
}
- other_class = instantiated_other.type_class();
- other_type_arguments = instantiated_other.arguments();
- } else {
- other_class = other.type_class();
- other_type_arguments = other.arguments();
+ if (instantiated_other.IsTypeRef()) {
+ instantiated_other = TypeRef::Cast(instantiated_other).type();
+ }
+ if (instantiated_other.IsDynamicType()) {
+ return true;
+ }
}
+ other_type_arguments = instantiated_other.arguments();
+ const bool other_is_dart_function = instantiated_other.IsDartFunctionType();
+ if (other_is_dart_function || instantiated_other.IsFunctionType()) {
+ // Check if this instance understands a call() method of a compatible type.
+ Function& call =
+ Function::Handle(zone, cls.LookupDynamicFunction(Symbols::Call()));
+ if (call.IsNull()) {
+ // Walk up the super_class chain.
+ Class& super_cls = Class::Handle(zone, cls.SuperClass());
+ while (!super_cls.IsNull() && call.IsNull()) {
+ call = super_cls.LookupDynamicFunction(Symbols::Call());
+ super_cls = super_cls.SuperClass();
+ }
+ }
+ if (!call.IsNull()) {
+ if (other_is_dart_function) {
+ return true;
+ }
+ const Function& other_signature = Function::Handle(
+ zone, FunctionType::Cast(instantiated_other).signature());
+ if (call.IsSubtypeOf(type_arguments,
+ other_signature,
+ other_type_arguments,
+ bound_error,
+ Heap::kOld)) {
+ return true;
+ }
+ }
+ }
+ if (!instantiated_other.IsType()) {
+ return false;
+ }
+ other_class = instantiated_other.type_class();
return cls.IsSubtypeOf(type_arguments, other_class, other_type_arguments,
bound_error, Heap::kOld);
}
@@ -15104,17 +15253,11 @@
}
-bool Instance::IsClosure() const {
- const Class& cls = Class::Handle(clazz());
- return cls.IsSignatureClass();
-}
-
-
bool Instance::IsCallable(Function* function) const {
Class& cls = Class::Handle(clazz());
- if (cls.IsSignatureClass()) {
+ if (cls.IsClosureClass()) {
if (function != NULL) {
- *function = Closure::function(*this);
+ *function = Closure::Cast(*this).function();
}
return true;
}
@@ -15219,7 +15362,7 @@
return "Instance";
} else {
if (IsClosure()) {
- return Closure::ToCString(*this);
+ return Closure::Cast(*this).ToCString();
}
const Class& cls = Class::Handle(clazz());
TypeArguments& type_arguments = TypeArguments::Handle();
@@ -15228,7 +15371,7 @@
type_arguments = GetTypeArguments();
}
const Type& type =
- Type::Handle(Type::New(cls, type_arguments, Scanner::kNoSourcePos));
+ Type::Handle(Type::New(cls, type_arguments, Token::kNoSourcePos));
const String& type_name = String::Handle(type.UserVisibleName());
return OS::SCreate(Thread::Current()->zone(),
"Instance of '%s'", type_name.ToCString());
@@ -15304,9 +15447,9 @@
jsobj.AddServiceId(*this);
if (IsClosure()) {
jsobj.AddProperty("closureFunction",
- Function::Handle(Closure::function(*this)));
+ Function::Handle(Closure::Cast(*this).function()));
jsobj.AddProperty("closureContext",
- Context::Handle(Closure::context(*this)));
+ Context::Handle(Closure::Cast(*this).context()));
}
if (ref) {
return;
@@ -15328,6 +15471,12 @@
}
+void AbstractType::SetIsResolved() const {
+ // AbstractType is an abstract class.
+ UNREACHABLE();
+}
+
+
bool AbstractType::HasResolvedTypeClass() const {
// AbstractType is an abstract class.
UNREACHABLE();
@@ -15356,6 +15505,11 @@
}
+void AbstractType::set_arguments(const TypeArguments& value) const {
+ // AbstractType is an abstract class.
+ UNREACHABLE();
+}
+
intptr_t AbstractType::token_pos() const {
// AbstractType is an abstract class.
UNREACHABLE();
@@ -15377,6 +15531,12 @@
}
+void AbstractType::SetIsFinalized() const {
+ // AbstractType is an abstract class.
+ UNREACHABLE();
+}
+
+
bool AbstractType::IsBeingFinalized() const {
// AbstractType is an abstract class.
UNREACHABLE();
@@ -15384,6 +15544,12 @@
}
+void AbstractType::SetIsBeingFinalized() const {
+ // AbstractType is an abstract class.
+ UNREACHABLE();
+}
+
+
bool AbstractType::IsMalformed() const {
// AbstractType is an abstract class.
UNREACHABLE();
@@ -15538,8 +15704,29 @@
String& class_name = String::Handle(zone);
intptr_t first_type_param_index;
intptr_t num_type_params; // Number of type parameters to print.
- if (HasResolvedTypeClass()) {
- const Class& cls = Class::Handle(zone, type_class());
+ Class& cls = Class::Handle(zone);
+ if (IsFunctionType()) {
+ cls = type_class();
+ if (!cls.IsTypedefClass()) {
+ const Function& signature_function = Function::Handle(
+ zone, FunctionType::Cast(*this).signature());
+ if (!IsFinalized() || IsBeingFinalized() || IsMalformed()) {
+ return signature_function.UserVisibleSignature();
+ }
+ return signature_function.InstantiatedSignatureFrom(args,
+ name_visibility);
+ }
+ class_name = cls.Name(); // Typedef name.
+ // We may be reporting an error about a malformed function type. In that
+ // case, avoid instantiating the signature, since it may cause divergence.
+ if (!IsFinalized() || IsBeingFinalized() || IsMalformed()) {
+ return class_name.raw();
+ }
+ // Print the name of a typedef as a regular, possibly parameterized, class.
+ } else if (HasResolvedTypeClass()) {
+ cls = type_class();
+ }
+ if (!cls.IsNull()) {
if (IsResolved() || !cls.IsMixinApplication()) {
// Do not print the full vector, but only the declared type parameters.
num_type_params = cls.NumTypeParameters();
@@ -15577,29 +15764,8 @@
first_type_param_index = num_args - num_type_params;
}
}
- if (cls.IsSignatureClass()) {
- // We may be reporting an error about a malformed function type. In that
- // case, avoid instantiating the signature, since it may cause divergence.
- if (!IsFinalized() || IsBeingFinalized() || IsMalformed()) {
- return class_name.raw();
- }
- // To avoid divergence, print the name of a typedef (non-canonical
- // signature class) as a regular, possibly parameterized, class.
- if (cls.IsCanonicalSignatureClass()) {
- const Function& signature_function = Function::Handle(
- zone, cls.signature_function());
- // Signature classes have no super type, however, they take as many
- // type arguments as the owner class of their signature function (if it
- // is non static and generic, see Class::NumTypeArguments()). Therefore,
- // first_type_param_index may be greater than 0 here.
- return signature_function.InstantiatedSignatureFrom(args,
- name_visibility);
- }
- }
} else {
- const UnresolvedClass& cls =
- UnresolvedClass::Handle(zone, unresolved_class());
- class_name = cls.Name();
+ class_name = UnresolvedClass::Handle(zone, unresolved_class()).Name();
num_type_params = num_args;
first_type_param_index = 0;
}
@@ -15691,7 +15857,7 @@
}
-bool AbstractType::IsFunctionType() const {
+bool AbstractType::IsDartFunctionType() const {
return HasResolvedTypeClass() &&
(type_class() == Type::Handle(Type::Function()).type_class());
}
@@ -15729,6 +15895,9 @@
}
return false;
}
+ if (other.IsObjectType() || other.IsDynamicType()) {
+ return true;
+ }
if (IsBoundedType() || other.IsBoundedType()) {
if (Equals(other)) {
return true;
@@ -15740,6 +15909,7 @@
}
return false; // TODO(regis): We should return "maybe after instantiation".
}
+ Zone* zone = Thread::Current()->zone();
// Type parameters cannot be handled by Class::TypeTest().
// When comparing two uninstantiated function types, one returning type
// parameter K, the other returning type parameter V, we cannot assume that K
@@ -15748,7 +15918,7 @@
// The same rule applies when checking the upper bound of a still
// uninstantiated type at compile time. Returning false will defer the test
// to run time.
- // There are however some cases can be decided at compile time.
+ // There are however some cases that can be decided at compile time.
// For example, with class A<K, V extends K>, new A<T, T> called from within
// a class B<T> will never require a run time bound check, even if T is
// uninstantiated at compile time.
@@ -15760,7 +15930,7 @@
return true;
}
}
- const AbstractType& bound = AbstractType::Handle(type_param.bound());
+ const AbstractType& bound = AbstractType::Handle(zone, type_param.bound());
// We may be checking bounds at finalization time and can encounter
// a still unfinalized bound. Finalizing the bound here may lead to cycles.
if (!bound.IsFinalized()) {
@@ -15774,13 +15944,59 @@
if (other.IsTypeParameter()) {
return false; // TODO(regis): We should return "maybe after instantiation".
}
- const Class& cls = Class::Handle(type_class());
- return cls.TypeTest(test_kind,
- TypeArguments::Handle(arguments()),
- Class::Handle(other.type_class()),
- TypeArguments::Handle(other.arguments()),
- bound_error,
- space);
+ const Class& type_cls = Class::Handle(zone, type_class());
+ // Function types cannot be handled by Class::TypeTest().
+ const bool other_is_dart_function_type = other.IsDartFunctionType();
+ if (other_is_dart_function_type || other.IsFunctionType()) {
+ if (IsFunctionType()) {
+ if (other_is_dart_function_type) {
+ return true;
+ }
+ const Function& other_fun =
+ Function::Handle(zone, FunctionType::Cast(other).signature());
+ // Check for two function types.
+ const Function& fun =
+ Function::Handle(zone, FunctionType::Cast(*this).signature());
+ return fun.TypeTest(test_kind,
+ TypeArguments::Handle(zone, arguments()),
+ other_fun,
+ TypeArguments::Handle(zone, other.arguments()),
+ bound_error,
+ space);
+ }
+ // Check if type S has a call() method of function type T.
+ Function& function =
+ Function::Handle(zone, type_cls.LookupDynamicFunction(Symbols::Call()));
+ if (function.IsNull()) {
+ // Walk up the super_class chain.
+ Class& cls = Class::Handle(zone, type_cls.SuperClass());
+ while (!cls.IsNull() && function.IsNull()) {
+ function = cls.LookupDynamicFunction(Symbols::Call());
+ cls = cls.SuperClass();
+ }
+ }
+ if (!function.IsNull()) {
+ if (other_is_dart_function_type ||
+ function.TypeTest(test_kind,
+ TypeArguments::Handle(zone, arguments()),
+ Function::Handle(
+ zone, FunctionType::Cast(other).signature()),
+ TypeArguments::Handle(zone, other.arguments()),
+ bound_error,
+ space)) {
+ return true;
+ }
+ }
+ }
+ if (IsFunctionType()) {
+ return false;
+ }
+ return type_cls.TypeTest(test_kind,
+ TypeArguments::Handle(zone, arguments()),
+ Class::Handle(zone, other.type_class()),
+ TypeArguments::Handle(zone, other.arguments()),
+ bound_error,
+ space);
}
@@ -15890,7 +16106,7 @@
const TypeArguments& no_type_arguments = TypeArguments::Handle();
type ^= Type::New(Object::Handle(type_class.raw()),
no_type_arguments,
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
type.SetIsFinalized();
type ^= type.Canonicalize();
}
@@ -15910,14 +16126,7 @@
}
-void Type::ResetIsFinalized() const {
- ASSERT(IsFinalized());
- set_type_state(RawType::kBeingFinalized);
- SetIsFinalized();
-}
-
-
-void Type::set_is_being_finalized() const {
+void Type::SetIsBeingFinalized() const {
ASSERT(IsResolved() && !IsFinalized() && !IsBeingFinalized());
set_type_state(RawType::kBeingFinalized);
}
@@ -15962,8 +16171,10 @@
}
-void Type::set_is_resolved() const {
+void Type::SetIsResolved() const {
ASSERT(!IsResolved());
+ // A Typedef is a FunctionType, not a type.
+ ASSERT(!Class::Handle(type_class()).IsTypedefClass());
set_type_state(RawType::kResolved);
}
@@ -16001,11 +16212,6 @@
}
-RawTypeArguments* Type::arguments() const {
- return raw_ptr()->arguments_;
-}
-
-
bool Type::IsInstantiated(TrailPtr trail) const {
if (raw_ptr()->type_state_ == RawType::kFinalizedInstantiated) {
return true;
@@ -16021,7 +16227,6 @@
intptr_t len = num_type_args; // Check the full vector of type args.
ASSERT(num_type_args > 0);
// This type is not instantiated if it refers to type parameters.
- // This IsInstantiated() call may be invoked on an unresolved signature type.
// Although this type may still be unresolved, the type parameters it may
// refer to are resolved by definition. We can therefore return the correct
// result even for an unresolved type. We just need to look at all type
@@ -16068,7 +16273,8 @@
// This uninstantiated type is not modified, as it can be instantiated
// with different instantiators. Allocate a new instantiated version of it.
- instantiated_type = Type::New(cls, TypeArguments::Handle(zone), token_pos());
+ instantiated_type =
+ Type::New(cls, TypeArguments::Handle(zone), token_pos(), space);
TypeArguments& type_arguments = TypeArguments::Handle(zone, arguments());
ASSERT(type_arguments.Length() == cls.NumTypeArguments());
if (type_arguments.IsRecursive()) {
@@ -16082,7 +16288,7 @@
if (IsFinalized()) {
instantiated_type.SetIsFinalized();
} else {
- instantiated_type.set_is_resolved();
+ instantiated_type.SetIsResolved();
}
// Canonicalization is not part of instantiation.
return instantiated_type.raw();
@@ -16184,9 +16390,9 @@
ASSERT(!IsBeingFinalized()); // Cloning must occur prior to finalization.
TypeArguments& type_args = TypeArguments::Handle(arguments());
type_args = type_args.CloneUnfinalized();
- const Class& type_cls = Class::Handle(type_class());
- const Type& clone = Type::Handle(Type::New(type_cls, type_args, token_pos()));
- clone.set_is_resolved();
+ const Type& clone = Type::Handle(
+ Type::New(Class::Handle(type_class()), type_args, token_pos()));
+ clone.SetIsResolved();
return clone.raw();
}
@@ -16228,13 +16434,14 @@
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
- Type& type = Type::Handle(zone);
+ AbstractType& type = Type::Handle(zone);
const Class& cls = Class::Handle(zone, type_class());
+ ASSERT(!cls.IsTypedefClass()); // This type should be a FunctionType.
if (cls.raw() == Object::dynamic_class() && (isolate != Dart::vm_isolate())) {
return Object::dynamic_type().raw();
}
// Fast canonical lookup/registry for simple types.
- if (!cls.IsGeneric()) {
+ if (!cls.IsGeneric() && !cls.IsClosureClass()) {
type = cls.CanonicalType();
if (type.IsNull()) {
ASSERT(!cls.raw()->IsVMHeapObject() || (isolate == Dart::vm_isolate()));
@@ -16319,36 +16526,6 @@
canonical_types = new_canonical_types.raw();
}
canonical_types.SetAt(index, *this);
- if ((index == 1) && cls.IsCanonicalSignatureClass()) {
- canonical_types.SetAt(0, *this); // Also set canonical signature type at 0.
-#ifdef DEBUG
- // Verify that the first canonical type is the signature type by checking
- // that the type argument vector of the canonical type ends with the
- // uninstantiated type parameters of the signature class. Note that these
- // type parameters may be bounded if the super class of the owner class
- // declares bounds.
- // The signature type is finalized during class finalization, before the
- // optimizer may canonicalize instantiated function types of the same
- // signature class.
- // Although the signature class extends class Instance, the type arguments
- // of the super class of the owner class of its signature function will be
- // prepended to the type argument vector during class finalization.
- const TypeArguments& type_params =
- TypeArguments::Handle(zone, cls.type_parameters());
- const intptr_t num_type_params = cls.NumTypeParameters();
- const intptr_t num_type_args = cls.NumTypeArguments();
- AbstractType& type_arg = AbstractType::Handle(zone);
- TypeParameter& type_param = TypeParameter::Handle(zone);
- for (intptr_t i = 0; i < num_type_params; i++) {
- type_arg = type_args.TypeAt(num_type_args - num_type_params + i);
- while (type_arg.IsBoundedType()) {
- type_arg = BoundedType::Cast(type_arg).type();
- }
- type_param ^= type_params.TypeAt(i);
- ASSERT(type_arg.Equals(type_param));
- }
-#endif
- }
ASSERT(IsOld());
ASSERT(type_args.IsNull() || type_args.IsOld());
SetCanonical();
@@ -16399,7 +16576,7 @@
void Type::set_token_pos(intptr_t token_pos) const {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
}
@@ -16465,6 +16642,552 @@
}
+void FunctionType::SetIsFinalized() const {
+ ASSERT(!IsFinalized());
+ if (IsInstantiated()) {
+ set_type_state(RawFunctionType::kFinalizedInstantiated);
+ } else {
+ set_type_state(RawFunctionType::kFinalizedUninstantiated);
+ }
+}
+
+
+void FunctionType::ResetIsFinalized() const {
+ ASSERT(IsFinalized());
+ set_type_state(RawFunctionType::kBeingFinalized);
+ SetIsFinalized();
+}
+
+
+void FunctionType::SetIsBeingFinalized() const {
+ ASSERT(IsResolved() && !IsFinalized() && !IsBeingFinalized());
+ set_type_state(RawFunctionType::kBeingFinalized);
+}
+
+
+bool FunctionType::IsMalformed() const {
+ if (raw_ptr()->error_ == LanguageError::null()) {
+ return false;
+ }
+ const LanguageError& type_error = LanguageError::Handle(error());
+ return type_error.kind() == Report::kMalformedType;
+}
+
+
+bool FunctionType::IsMalbounded() const {
+ if (!Isolate::Current()->flags().type_checks()) {
+ return false;
+ }
+ if (raw_ptr()->error_ == LanguageError::null()) {
+ return false;
+ }
+ const LanguageError& type_error = LanguageError::Handle(error());
+ return type_error.kind() == Report::kMalboundedType;
+}
+
+
+bool FunctionType::IsMalformedOrMalbounded() const {
+ if (raw_ptr()->error_ == LanguageError::null()) {
+ return false;
+ }
+ const LanguageError& type_error = LanguageError::Handle(error());
+ if (type_error.kind() == Report::kMalformedType) {
+ return true;
+ }
+ ASSERT(type_error.kind() == Report::kMalboundedType);
+ return Isolate::Current()->flags().type_checks();
+}
+
+
+void FunctionType::set_error(const LanguageError& value) const {
+ StorePointer(&raw_ptr()->error_, value.raw());
+}
+
+
+void FunctionType::SetIsResolved() const {
+ ASSERT(!IsResolved());
+ set_type_state(RawFunctionType::kResolved);
+}
+
+
+bool FunctionType::IsInstantiated(TrailPtr trail) const {
+ if (raw_ptr()->type_state_ == RawFunctionType::kFinalizedInstantiated) {
+ return true;
+ }
+ if (raw_ptr()->type_state_ == RawFunctionType::kFinalizedUninstantiated) {
+ return false;
+ }
+ if (arguments() == TypeArguments::null()) {
+ return true;
+ }
+ const Class& scope_cls = Class::Handle(scope_class());
+ if (!scope_cls.IsGeneric()) {
+ ASSERT(scope_cls.IsClosureClass() || scope_cls.IsTypedefClass());
+ ASSERT(arguments() == TypeArguments::null());
+ return true;
+ }
+ const TypeArguments& type_arguments = TypeArguments::Handle(arguments());
+ const intptr_t num_type_args = scope_cls.NumTypeArguments();
+ const intptr_t num_type_params = scope_cls.NumTypeParameters();
+ // The vector may be longer than necessary. An empty vector is handled above.
+ ASSERT(type_arguments.Length() >= num_type_args);
+ return
+ (num_type_params == 0) ||
+ type_arguments.IsSubvectorInstantiated(num_type_args - num_type_params,
+ num_type_params);
+}
+
+
+RawAbstractType* FunctionType::InstantiateFrom(
+ const TypeArguments& instantiator_type_arguments,
+ Error* bound_error,
+ TrailPtr trail,
+ Heap::Space space) const {
+ Zone* zone = Thread::Current()->zone();
+ ASSERT(IsFinalized() || IsBeingFinalized());
+ ASSERT(!IsInstantiated());
+ ASSERT(!IsMalformed()); // FunctionType cannot be malformed.
+ // Instantiating this type with its own type arguments as instantiator can
+ // occur during finalization and bounds checking. Return the type unchanged.
+ if (arguments() == instantiator_type_arguments.raw()) {
+ return raw();
+ }
+ // If this type is recursive, we may already be instantiating it.
+ FunctionType& instantiated_type = FunctionType::Handle(zone);
+ instantiated_type ^= OnlyBuddyInTrail(trail);
+ if (!instantiated_type.IsNull()) {
+ ASSERT(IsRecursive());
+ return instantiated_type.raw();
+ }
+ // Note that the scope class has to be resolved at this time, but not
+ // necessarily finalized yet. We may be checking bounds at compile time or
+ // finalizing the type argument vector of a recursive type.
+ const Class& cls = Class::Handle(zone, scope_class());
+
+ // This uninstantiated type is not modified, as it can be instantiated
+ // with different instantiators. Allocate a new instantiated version of it.
+ instantiated_type =
+ FunctionType::New(cls,
+ TypeArguments::Handle(zone),
+ Function::Handle(zone, signature()),
+ token_pos(),
+ space);
+ TypeArguments& type_arguments = TypeArguments::Handle(zone, arguments());
+ ASSERT(type_arguments.Length() == cls.NumTypeArguments());
+ if (type_arguments.IsRecursive()) {
+ AddOnlyBuddyToTrail(&trail, instantiated_type);
+ }
+ type_arguments = type_arguments.InstantiateFrom(instantiator_type_arguments,
+ bound_error,
+ trail,
+ space);
+ instantiated_type.set_arguments(type_arguments);
+ if (IsFinalized()) {
+ instantiated_type.SetIsFinalized();
+ } else {
+ instantiated_type.SetIsResolved();
+ }
+ // Canonicalization is not part of instantiation.
+ return instantiated_type.raw();
+}
+
+
+bool FunctionType::IsEquivalent(const Instance& other, TrailPtr trail) const {
+ ASSERT(!IsNull());
+ if (raw() == other.raw()) {
+ return true;
+ }
+ if (!other.IsFunctionType()) {
+ return false;
+ }
+ const FunctionType& other_type = FunctionType::Cast(other);
+ ASSERT(IsResolved() && other_type.IsResolved());
+ if (IsMalformed() || other_type.IsMalformed()) {
+ return false;
+ }
+ if (scope_class() != other_type.scope_class()) {
+ return false;
+ }
+ if ((arguments() == other_type.arguments()) &&
+ (signature() == other_type.signature())) {
+ return true;
+ }
+ if (!IsFinalized() || !other_type.IsFinalized()) {
+ return false;
+ }
+
+ // We do not instantiate the types of the signature. This happens on demand
+ // at runtime during a type test.
+ // Therefore, equal function types must have equal type arguments.
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+ const TypeArguments& other_type_args = TypeArguments::Handle(
+ zone, other_type.arguments());
+ if (!type_args.Equals(other_type_args)) {
+ return false;
+ }
+
+ // Type arguments are equal.
+ // Equal function types must have equal signature types and equal optional
+ // named arguments.
+ if (signature() == other_type.signature()) {
+ return true;
+ }
+ const Function& sig_fun = Function::Handle(zone, signature());
+ const Function& other_sig_fun = Function::Handle(
+ zone, other_type.signature());
+
+ // Compare number of function parameters.
+ const intptr_t num_fixed_params = sig_fun.num_fixed_parameters();
+ const intptr_t other_num_fixed_params = other_sig_fun.num_fixed_parameters();
+ if (num_fixed_params != other_num_fixed_params) {
+ return false;
+ }
+ const intptr_t num_opt_pos_params = sig_fun.NumOptionalPositionalParameters();
+ const intptr_t other_num_opt_pos_params =
+ other_sig_fun.NumOptionalPositionalParameters();
+ if (num_opt_pos_params != other_num_opt_pos_params) {
+ return false;
+ }
+ const intptr_t num_opt_named_params = sig_fun.NumOptionalNamedParameters();
+ const intptr_t other_num_opt_named_params =
+ other_sig_fun.NumOptionalNamedParameters();
+ if (num_opt_named_params != other_num_opt_named_params) {
+ return false;
+ }
+ const intptr_t num_ignored_params = sig_fun.NumImplicitParameters();
+ const intptr_t other_num_ignored_params =
+ other_sig_fun.NumImplicitParameters();
+ if (num_ignored_params != other_num_ignored_params) {
+ return false;
+ }
+ AbstractType& param_type = Type::Handle(zone);
+ AbstractType& other_param_type = Type::Handle(zone);
+ // Check the result type.
+ param_type = sig_fun.result_type();
+ other_param_type = other_sig_fun.result_type();
+ if (!param_type.Equals(other_param_type)) {
+ return false;
+ }
+ // Check the types of all parameters.
+ const intptr_t num_params = sig_fun.NumParameters();
+ ASSERT(other_sig_fun.NumParameters() == num_params);
+ for (intptr_t i = 0; i < num_params; i++) {
+ param_type = sig_fun.ParameterTypeAt(i);
+ other_param_type = other_sig_fun.ParameterTypeAt(i);
+ if (!param_type.Equals(other_param_type)) {
+ return false;
+ }
+ }
+ // Check the names and types of optional named parameters.
+ if (num_opt_named_params == 0) {
+ return true;
+ }
+ for (intptr_t i = num_fixed_params; i < num_params; i++) {
+ if (sig_fun.ParameterNameAt(i) != other_sig_fun.ParameterNameAt(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool FunctionType::IsRecursive() const {
+ return TypeArguments::Handle(arguments()).IsRecursive();
+}
+
+
+RawAbstractType* FunctionType::CloneUnfinalized() const {
+ ASSERT(IsResolved());
+ if (IsFinalized()) {
+ return raw();
+ }
+ ASSERT(!IsMalformed()); // Malformed types are finalized.
+ ASSERT(!IsBeingFinalized()); // Cloning must occur prior to finalization.
+ TypeArguments& type_args = TypeArguments::Handle(arguments());
+ type_args = type_args.CloneUnfinalized();
+ const FunctionType& clone = FunctionType::Handle(
+ FunctionType::New(Class::Handle(scope_class()),
+ type_args,
+ Function::Handle(signature()),
+ token_pos()));
+ clone.SetIsResolved();
+ return clone.raw();
+}
+
+
+RawAbstractType* FunctionType::CloneUninstantiated(const Class& new_owner,
+ TrailPtr trail) const {
+ ASSERT(IsFinalized());
+ ASSERT(!IsMalformed());
+ if (IsInstantiated()) {
+ return raw();
+ }
+ // We may recursively encounter a type already being cloned, because we clone
+ // the upper bounds of its uninstantiated type arguments in the same pass.
+ FunctionType& clone = FunctionType::Handle();
+ clone ^= OnlyBuddyInTrail(trail);
+ if (!clone.IsNull()) {
+ return clone.raw();
+ }
+ clone = FunctionType::New(Class::Handle(scope_class()),
+ TypeArguments::Handle(),
+ Function::Handle(signature()),
+ token_pos());
+ TypeArguments& type_args = TypeArguments::Handle(arguments());
+ // Upper bounds of uninstantiated type arguments may form a cycle.
+ if (type_args.IsRecursive() || !type_args.IsInstantiated()) {
+ AddOnlyBuddyToTrail(&trail, clone);
+ }
+ type_args = type_args.CloneUninstantiated(new_owner, trail);
+ clone.set_arguments(type_args);
+ clone.SetIsFinalized();
+ return clone.raw();
+}
+
+
+RawAbstractType* FunctionType::Canonicalize(TrailPtr trail) const {
+ ASSERT(IsFinalized());
+ if (IsCanonical() || IsMalformed()) {
+ ASSERT(IsMalformed() || TypeArguments::Handle(arguments()).IsOld());
+ return this->raw();
+ }
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ AbstractType& type = Type::Handle(zone);
+ const Class& scope_cls = Class::Handle(zone, type_class());
+ Array& canonical_types = Array::Handle(zone);
+ canonical_types ^= scope_cls.canonical_types();
+ if (canonical_types.IsNull()) {
+ canonical_types = empty_array().raw();
+ }
+ intptr_t length = canonical_types.Length();
+ // Linear search to see whether this type is already present in the
+ // list of canonicalized types.
+ // TODO(asiva): Try to re-factor this lookup code to make sharing
+ // easy between the 4 versions of this loop.
+ intptr_t index = 1; // Slot 0 is reserved for CanonicalType().
+ while (index < length) {
+ type ^= canonical_types.At(index);
+ if (type.IsNull()) {
+ break;
+ }
+ ASSERT(type.IsFinalized());
+ if (this->Equals(type)) {
+ ASSERT(type.IsCanonical());
+ return type.raw();
+ }
+ index++;
+ }
+ // The type was not found in the table. It is not canonical yet.
+
+ // Canonicalize the type arguments.
+ TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+ // In case the type is first canonicalized at runtime, its type argument
+ // vector may be longer than necessary. This is not an issue.
+ ASSERT(type_args.IsNull() ||
+ (type_args.Length() >= scope_cls.NumTypeArguments()));
+ type_args = type_args.Canonicalize(trail);
+ set_arguments(type_args);
+
+ // Replace the actual function by a signature function.
+ const Function& fun = Function::Handle(zone, signature());
+ if (!fun.IsSignatureFunction()) {
+ Function& sig_fun =
+ Function::Handle(zone,
+ Function::NewSignatureFunction(scope_cls,
+ Token::kNoSourcePos));
+ type = fun.result_type();
+ type = type.Canonicalize(trail);
+ sig_fun.set_result_type(type);
+ const intptr_t num_params = fun.NumParameters();
+ sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters());
+ sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(),
+ fun.HasOptionalPositionalParameters());
+ sig_fun.set_parameter_types(Array::Handle(Array::New(num_params,
+ Heap::kOld)));
+ for (intptr_t i = 0; i < num_params; i++) {
+ type = fun.ParameterTypeAt(i);
+ type = type.Canonicalize(trail);
+ sig_fun.SetParameterTypeAt(i, type);
+ }
+ sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
+ set_signature(sig_fun);
+ }
+
+ // Canonicalizing the type arguments and the signature may have changed the
+ // index, may have grown the table, or may even have canonicalized this type.
+ canonical_types ^= scope_cls.canonical_types();
+ if (canonical_types.IsNull()) {
+ canonical_types = empty_array().raw();
+ }
+ length = canonical_types.Length();
+ while (index < length) {
+ type ^= canonical_types.At(index);
+ if (type.IsNull()) {
+ break;
+ }
+ ASSERT(type.IsFinalized());
+ if (this->Equals(type)) {
+ ASSERT(type.IsCanonical());
+ return type.raw();
+ }
+ index++;
+ }
+
+ // The type needs to be added to the list. Grow the list if it is full.
+ if (index >= length) {
+ ASSERT((index == length) || ((index == 1) && (length == 0)));
+ const intptr_t new_length = (length > 64) ?
+ (length + 64) :
+ ((length == 0) ? 2 : (length * 2));
+ const Array& new_canonical_types = Array::Handle(
+ zone, Array::Grow(canonical_types, new_length, Heap::kOld));
+ scope_cls.set_canonical_types(new_canonical_types);
+ canonical_types = new_canonical_types.raw();
+ }
+ canonical_types.SetAt(index, *this);
+ ASSERT(IsOld());
+ ASSERT(type_args.IsNull() || type_args.IsOld());
+ SetCanonical();
+ return this->raw();
+}
+
+
+intptr_t FunctionType::Hash() const {
+ ASSERT(IsFinalized());
+ uint32_t result = 1;
+ if (IsMalformed()) return result;
+ result = CombineHashes(result, Class::Handle(scope_class()).id());
+ result = CombineHashes(result, TypeArguments::Handle(arguments()).Hash());
+ const Function& sig_fun = Function::Handle(signature());
+ AbstractType& type = AbstractType::Handle(sig_fun.result_type());
+ result = CombineHashes(result, type.Hash());
+ result = CombineHashes(result, sig_fun.NumOptionalPositionalParameters());
+ const intptr_t num_params = sig_fun.NumParameters();
+ for (intptr_t i = 0; i < num_params; i++) {
+ type = sig_fun.ParameterTypeAt(i);
+ result = CombineHashes(result, type.Hash());
+ }
+ if (sig_fun.NumOptionalNamedParameters() > 0) {
+ String& param_name = String::Handle();
+ for (intptr_t i = sig_fun.num_fixed_parameters(); i < num_params; i++) {
+ param_name = sig_fun.ParameterNameAt(i);
+ result = CombineHashes(result, param_name.Hash());
+ }
+ }
+ return FinalizeHash(result);
+}
+
+
+void FunctionType::set_scope_class(const Class& value) const {
+ ASSERT(!value.IsNull());
+ StorePointer(&raw_ptr()->scope_class_, value.raw());
+}
+
+
+void FunctionType::set_arguments(const TypeArguments& value) const {
+ StorePointer(&raw_ptr()->arguments_, value.raw());
+}
+
+
+void FunctionType::set_signature(const Function& value) const {
+ StorePointer(&raw_ptr()->signature_, value.raw());
+}
+
+
+RawFunctionType* FunctionType::New(Heap::Space space) {
+ RawObject* raw = Object::Allocate(FunctionType::kClassId,
+ FunctionType::InstanceSize(),
+ space);
+ return reinterpret_cast<RawFunctionType*>(raw);
+}
+
+
+RawFunctionType* FunctionType::New(const Class& clazz,
+ const TypeArguments& arguments,
+ const Function& signature,
+ intptr_t token_pos,
+ Heap::Space space) {
+ const FunctionType& result = FunctionType::Handle(FunctionType::New(space));
+ result.set_scope_class(clazz);
+ result.set_arguments(arguments);
+ result.set_signature(signature);
+ result.set_token_pos(token_pos);
+ result.StoreNonPointer(&result.raw_ptr()->type_state_,
+ RawFunctionType::kAllocated);
+ return result.raw();
+}
+
+
+void FunctionType::set_token_pos(intptr_t token_pos) const {
+ ASSERT(!Token::IsClassifying(token_pos));
+ StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
+}
+
+
+void FunctionType::set_type_state(int8_t state) const {
+ ASSERT((state >= RawFunctionType::kAllocated) &&
+ (state <= RawFunctionType::kFinalizedUninstantiated));
+ StoreNonPointer(&raw_ptr()->type_state_, state);
+}
+
+
+const char* FunctionType::ToCString() const {
+ const char* unresolved = IsResolved() ? "" : "Unresolved ";
+ const Class& scope_cls = Class::Handle(scope_class());
+ const TypeArguments& type_arguments = TypeArguments::Handle(arguments());
+ const Function& signature_function = Function::Handle(signature());
+ const String& signature_string = String::Handle(
+ signature_function.InstantiatedSignatureFrom(type_arguments,
+ kInternalName));
+ if (scope_cls.IsClosureClass()) {
+ ASSERT(arguments() == TypeArguments::null());
+ return OS::SCreate(
+ Thread::Current()->zone(),
+ "%sFunctionType: %s", unresolved, signature_string.ToCString());
+ }
+ const char* class_name = String::Handle(scope_cls.Name()).ToCString();
+ const char* args_cstr =
+ type_arguments.IsNull() ? "null" : type_arguments.ToCString();
+ return OS::SCreate(
+ Thread::Current()->zone(),
+ "%s FunctionType: %s (scope_cls: %s, args: %s)",
+ unresolved,
+ signature_string.ToCString(),
+ class_name,
+ args_cstr);
+}
+
+
+void FunctionType::PrintJSONImpl(JSONStream* stream, bool ref) const {
+ JSONObject jsobj(stream);
+ PrintSharedInstanceJSON(&jsobj, ref);
+ jsobj.AddProperty("kind", "FunctionType");
+ if (IsCanonical()) {
+ const Class& scope_cls = Class::Handle(scope_class());
+ intptr_t id = scope_cls.FindCanonicalTypeIndex(*this);
+ ASSERT(id >= 0);
+ intptr_t cid = scope_cls.id();
+ jsobj.AddFixedServiceId("classes/%" Pd "/types/%" Pd "", cid, id);
+ jsobj.AddProperty("scopeClass", scope_cls);
+ } else {
+ jsobj.AddServiceId(*this);
+ }
+ const String& user_name = String::Handle(PrettyName());
+ const String& vm_name = String::Handle(Name());
+ AddNameProperties(&jsobj, user_name, vm_name);
+ if (ref) {
+ return;
+ }
+ const TypeArguments& typeArgs = TypeArguments::Handle(arguments());
+ if (!typeArgs.IsNull()) {
+ jsobj.AddProperty("typeArguments", typeArgs);
+ }
+}
+
+
bool TypeRef::IsInstantiated(TrailPtr trail) const {
if (TestAndAddToTrail(&trail)) {
return true;
@@ -16528,7 +17251,7 @@
void TypeRef::set_type(const AbstractType& value) const {
- ASSERT(value.HasResolvedTypeClass());
+ ASSERT(value.IsFunctionType() || value.HasResolvedTypeClass());
ASSERT(!value.IsTypeRef());
StorePointer(&raw_ptr()->type_, value.raw());
}
@@ -16640,7 +17363,7 @@
}
-void TypeParameter::set_is_finalized() const {
+void TypeParameter::SetIsFinalized() const {
ASSERT(!IsFinalized());
set_type_state(RawTypeParameter::kFinalizedUninstantiated);
}
@@ -16747,6 +17470,7 @@
*bound_error,
script,
token_pos(),
+ Report::AtLocation,
Report::kMalboundedType,
Heap::kNew,
"type parameter '%s' of class '%s' must extend bound '%s', "
@@ -16789,7 +17513,7 @@
String::Handle(name()),
upper_bound,
token_pos()));
- clone.set_is_finalized();
+ clone.SetIsFinalized();
return clone.raw();
}
@@ -16830,7 +17554,7 @@
void TypeParameter::set_token_pos(intptr_t token_pos) const {
- ASSERT(Scanner::ValidSourcePosition(token_pos));
+ ASSERT(!Token::IsClassifying(token_pos));
StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
}
@@ -21466,8 +22190,8 @@
}
-const char* Closure::ToCString(const Instance& closure) {
- const Function& fun = Function::Handle(Closure::function(closure));
+const char* Closure::ToCString() const {
+ const Function& fun = Function::Handle(function());
const bool is_implicit_closure = fun.IsImplicitClosureFunction();
const char* fun_sig = String::Handle(fun.UserVisibleSignature()).ToCString();
const char* from = is_implicit_closure ? " from " : "";
@@ -21477,23 +22201,36 @@
}
-RawInstance* Closure::New(const Function& function,
- const Context& context,
- Heap::Space space) {
- const Class& cls = Class::Handle(function.signature_class());
- ASSERT(cls.instance_size() == Closure::InstanceSize());
- Instance& result = Instance::Handle();
+void Closure::PrintJSONImpl(JSONStream* stream, bool ref) const {
+ Instance::PrintJSONImpl(stream, ref);
+}
+
+
+RawClosure* Closure::New(const Function& function,
+ const Context& context,
+ Heap::Space space) {
+ Closure& result = Closure::Handle();
{
- RawObject* raw = Object::Allocate(cls.id(), Closure::InstanceSize(), space);
+ RawObject* raw = Object::Allocate(Closure::kClassId,
+ Closure::InstanceSize(),
+ space);
NoSafepointScope no_safepoint;
result ^= raw;
+ result.StorePointer(&result.raw_ptr()->function_, function.raw());
+ result.StorePointer(&result.raw_ptr()->context_, context.raw());
}
- Closure::set_function(result, function);
- Closure::set_context(result, context);
return result.raw();
}
+RawClosure* Closure::New() {
+ RawObject* raw = Object::Allocate(Closure::kClassId,
+ Closure::InstanceSize(),
+ Heap::kOld);
+ return reinterpret_cast<RawClosure*>(raw);
+}
+
+
intptr_t Stacktrace::Length() const {
const Array& code_array = Array::Handle(raw_ptr()->code_array_);
return code_array.Length();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index d67b06a..5ce318c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -507,6 +507,7 @@
static RawClass* instructions_class() { return instructions_class_; }
static RawClass* object_pool_class() { return object_pool_class_; }
static RawClass* pc_descriptors_class() { return pc_descriptors_class_; }
+ static RawClass* code_source_map_class() { return code_source_map_class_; }
static RawClass* stackmap_class() { return stackmap_class_; }
static RawClass* var_descriptors_class() { return var_descriptors_class_; }
static RawClass* exception_handlers_class() {
@@ -768,6 +769,7 @@
static RawClass* instructions_class_; // Class of the Instructions vm object.
static RawClass* object_pool_class_; // Class of the ObjectPool vm object.
static RawClass* pc_descriptors_class_; // Class of PcDescriptors vm object.
+ static RawClass* code_source_map_class_; // Class of CodeSourceMap vm object.
static RawClass* stackmap_class_; // Class of Stackmap vm object.
static RawClass* var_descriptors_class_; // Class of LocalVarDescriptors.
static RawClass* exception_handlers_class_; // Class of ExceptionHandlers.
@@ -941,26 +943,11 @@
intptr_t ComputeEndTokenPos() const;
- // This class represents the signature class of a closure function if
- // signature_function() is not null.
- // The associated function may be a closure function (with code) or a
- // signature function (without code) solely describing the result type and
- // parameter types of the signature.
+ // This class represents a typedef if the signature function is not null.
RawFunction* signature_function() const {
return raw_ptr()->signature_function_;
}
- static intptr_t signature_function_offset() {
- return OFFSET_OF(RawClass, signature_function_);
- }
-
- // Return the signature type of this signature class.
- // For example, if this class represents a signature of the form
- // 'F<T, R>(T, [b: B, c: C]) => R', then its signature type is a parameterized
- // type with this class as the type class and type parameters 'T' and 'R'
- // as its type argument vector.
- // SignatureType is used as the type of formal parameters representing a
- // function.
- RawType* SignatureType() const;
+ void set_signature_function(const Function& value) const;
// Return the Type with type parameters declared by this class filled in with
// dynamic and type parameters declared in superclasses filled in as declared
@@ -1004,6 +991,7 @@
// not overlapping with the type arguments of the super class of this class.
intptr_t NumOwnTypeArguments() const;
+ // Return true if this class declares type parameters.
bool IsGeneric() const;
// If this class is parameterized, each instance has a type_arguments field.
@@ -1094,22 +1082,23 @@
// Check if this class represents the 'Function' class.
bool IsFunctionClass() const;
- // Check if this class represents a signature class.
- bool IsSignatureClass() const {
+ // Check if this class represents the 'Closure' class.
+ bool IsClosureClass() const { return id() == kClosureCid; }
+ static bool IsClosureClass(RawClass* cls) {
+ NoSafepointScope no_safepoint;
+ return cls->ptr()->id_ == kClosureCid;
+ }
+
+ // Check if this class represents a typedef class.
+ bool IsTypedefClass() const {
return signature_function() != Object::null();
}
- static bool IsSignatureClass(RawClass* cls) {
- return cls->ptr()->signature_function_ != Object::null();
- }
+
static bool IsInFullSnapshot(RawClass* cls) {
NoSafepointScope no_safepoint;
return cls->ptr()->library_->ptr()->is_in_fullsnapshot_;
}
- // Check if this class represents a canonical signature class, i.e. not an
- // alias as defined in a typedef.
- bool IsCanonicalSignatureClass() const;
-
// Check the subtype relationship.
bool IsSubtypeOf(const TypeArguments& type_arguments,
const Class& other,
@@ -1184,8 +1173,8 @@
void InsertCanonicalConstant(intptr_t index, const Instance& constant) const;
- intptr_t FindCanonicalTypeIndex(const Type& needle) const;
- RawType* CanonicalTypeFromIndex(intptr_t idx) const;
+ intptr_t FindCanonicalTypeIndex(const AbstractType& needle) const;
+ RawAbstractType* CanonicalTypeFromIndex(intptr_t idx) const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawClass));
@@ -1334,21 +1323,6 @@
// Allocate the raw ExternalTypedData classes.
static RawClass* NewExternalTypedDataClass(intptr_t class_id);
- // Allocate a class representing a function signature described by
- // signature_function, which must be a closure function or a signature
- // function.
- // The class may be type parameterized unless the signature_function is in a
- // static scope. In that case, the type parameters are copied from the owner
- // class of signature_function.
- // A null signature function may be passed in and patched later. See below.
- static RawClass* NewSignatureClass(const String& name,
- const Function& signature_function,
- const Script& script,
- intptr_t token_pos);
-
- // Patch the signature function of a signature class allocated without it.
- void PatchSignatureFunction(const Function& signature_function) const;
-
// Register code that has used CHA for optimization.
// TODO(srdjan): Also register kind of CHA optimization (e.g.: leaf class,
// leaf method, ...).
@@ -1409,8 +1383,6 @@
void set_user_name(const String& value) const;
RawString* GeneratePrettyName() const;
RawString* GenerateUserVisibleName() const;
- void set_signature_function(const Function& value) const;
- void set_signature_type(const AbstractType& value) const;
void set_state_bits(intptr_t bits) const;
void set_constants(const Array& value) const;
@@ -1483,6 +1455,7 @@
friend class Instance;
friend class Object;
friend class Type;
+ friend class FunctionType;
friend class Intrinsifier;
friend class Precompiler;
};
@@ -2108,6 +2081,17 @@
RawString* GetSource() const;
+ // Return the type of this function's signature. It may not be canonical yet.
+ // For example, if this function has a signature of the form
+ // '(T, [b: B, c: C]) => R', where 'T' and 'R' are type parameters of the
+ // owner class of this function, then its signature type is a parameterized
+ // FunctionType with uninstantiated type arguments 'T' and 'R' as elements of
+ // its type argument vector.
+ RawFunctionType* SignatureType() const;
+
+ // Update the signature type (with a canonical version).
+ void SetSignatureType(const FunctionType& value) const;
+
// Build a string of the form 'C<T, R>(T, {b: B, c: C}) => R' representing the
// internal signature of the given function. In this example, T and R are
// type parameters of class C, the owner of the function.
@@ -2124,9 +2108,10 @@
// Build a string of the form '(T, {b: B, c: C}) => R' representing the
// user visible signature of the given function. In this example, T and R are
- // type parameters of class C, the owner of the function.
+ // type parameters of class C, the owner of the function, also called the
+ // scope class of the function type.
// Implicit parameters are hidden, as well as the prefix denoting the
- // signature class and its type parameters.
+ // scope class and its type parameters.
RawString* UserVisibleSignature() const {
const bool instantiate = false;
return BuildSignature(
@@ -2219,10 +2204,6 @@
// Enclosing function of this local function.
RawFunction* parent_function() const;
- // Signature class of this closure function or signature function.
- RawClass* signature_class() const;
- void set_signature_class(const Class& value) const;
-
void set_extracted_method_closure(const Function& function) const;
RawFunction* extracted_method_closure() const;
@@ -2494,6 +2475,14 @@
space);
}
+ // Check the subtype or 'more specific' relationship.
+ bool TypeTest(TypeTestKind test_kind,
+ const TypeArguments& type_arguments,
+ const Function& other,
+ const TypeArguments& other_type_arguments,
+ Error* bound_error,
+ Heap::Space space) const;
+
// Returns true if this function represents an explicit getter function.
bool IsGetterFunction() const {
return kind() == RawFunction::kGetterFunction;
@@ -2557,6 +2546,11 @@
bool IsSignatureFunction() const {
return kind() == RawFunction::kSignatureFunction;
}
+ static bool IsSignatureFunction(RawFunction* function) {
+ NoSafepointScope no_safepoint;
+ return KindBits::decode(function->ptr()->kind_tag_) ==
+ RawFunction::kSignatureFunction;
+ }
bool IsAsyncFunction() const {
return modifier() == RawFunction::kAsync;
@@ -2612,14 +2606,16 @@
const Object& owner,
intptr_t token_pos);
- // Allocates a new Function object representing a closure function, as well as
- // a new associated Class object representing the signature class of the
- // function.
- // The function and the class share the same given name.
+ // Allocates a new Function object representing a closure function.
static RawFunction* NewClosureFunction(const String& name,
const Function& parent,
intptr_t token_pos);
+ // Allocates a new Function object representing a signature function.
+ // The owner is the scope class of the function type.
+ static RawFunction* NewSignatureFunction(const Class& owner,
+ intptr_t token_pos);
+
static RawFunction* NewEvalFunction(const Class& owner,
const Script& script,
bool is_static);
@@ -2775,14 +2771,6 @@
NameVisibility name_visibility,
const TypeArguments& instantiator) const;
- // Check the subtype or 'more specific' relationship.
- bool TypeTest(TypeTestKind test_kind,
- const TypeArguments& type_arguments,
- const Function& other,
- const TypeArguments& other_type_arguments,
- Error* bound_error,
- Heap::Space space) const;
-
// Checks the type of the formal parameter at the given position for
// subtyping or 'more specific' relationship between the type of this function
// and the type of the other function.
@@ -2819,9 +2807,9 @@
RawFunction* parent_function() const { return raw_ptr()->parent_function_; }
void set_parent_function(const Function& value) const;
- // Signature class of this closure function or signature function.
- RawClass* signature_class() const { return raw_ptr()->signature_class_; }
- void set_signature_class(const Class& value) const;
+ // Signature type of this closure function.
+ RawFunctionType* signature_type() const { return raw_ptr()->signature_type_; }
+ void set_signature_type(const FunctionType& value) const;
RawInstance* implicit_static_closure() const {
return raw_ptr()->closure_;
@@ -3601,7 +3589,8 @@
void InitClassDictionary() const;
RawArray* resolved_names() const { return raw_ptr()->resolved_names_; }
- void InitResolvedNamesCache(intptr_t size) const;
+ void InitResolvedNamesCache(intptr_t size,
+ SnapshotReader* reader = NULL) const;
void GrowResolvedNamesCache() const;
bool LookupResolvedNamesCache(const String& name, Object* obj) const;
void AddToResolvedNamesCache(const String& name, const Object& obj) const;
@@ -3986,6 +3975,77 @@
};
+class CodeSourceMap : public Object {
+ public:
+ static const intptr_t kBytesPerElement = 1;
+ static const intptr_t kMaxElements = kMaxInt32 / kBytesPerElement;
+
+ static intptr_t InstanceSize() {
+ ASSERT(sizeof(RawCodeSourceMap) ==
+ OFFSET_OF_RETURNED_VALUE(RawCodeSourceMap, data));
+ return 0;
+ }
+ static intptr_t InstanceSize(intptr_t len) {
+ ASSERT(0 <= len && len <= kMaxElements);
+ return RoundedAllocationSize(sizeof(RawCodeSourceMap) + len);
+ }
+
+ static RawCodeSourceMap* New(GrowableArray<uint8_t>* delta_encoded_data);
+
+ void PrintToJSONObject(JSONObject* jsobj, bool ref) const;
+
+ // Encode integer in SLEB128 format.
+ static void EncodeInteger(GrowableArray<uint8_t>* data, intptr_t value);
+
+ // Decode SLEB128 encoded integer. Update byte_index to the next integer.
+ intptr_t DecodeInteger(intptr_t* byte_index) const;
+
+ class Iterator : ValueObject {
+ public:
+ explicit Iterator(const CodeSourceMap& code_source_map)
+ : code_source_map_(code_source_map),
+ byte_index_(0),
+ cur_pc_offset_(0),
+ cur_token_pos_(0) {
+ }
+
+ bool MoveNext() {
+ // Moves to the next record.
+ while (byte_index_ < code_source_map_.Length()) {
+ cur_pc_offset_ += code_source_map_.DecodeInteger(&byte_index_);
+ cur_token_pos_ += code_source_map_.DecodeInteger(&byte_index_);
+
+ return true;
+ }
+ return false;
+ }
+
+ uword PcOffset() const { return cur_pc_offset_; }
+ intptr_t TokenPos() const { return cur_token_pos_; }
+
+ private:
+ friend class CodeSourceMap;
+
+ const CodeSourceMap& code_source_map_;
+ intptr_t byte_index_;
+
+ intptr_t cur_pc_offset_;
+ intptr_t cur_token_pos_;
+ };
+
+ private:
+ static RawCodeSourceMap* New(intptr_t length);
+
+ intptr_t Length() const;
+ void SetLength(intptr_t value) const;
+ void CopyData(GrowableArray<uint8_t>* data);
+
+ FINAL_HEAP_OBJECT_IMPLEMENTATION(CodeSourceMap, Object);
+ friend class Class;
+ friend class Object;
+};
+
+
class Stackmap : public Object {
public:
static const intptr_t kNoMaximum = -1;
@@ -4216,6 +4276,15 @@
StorePointer(&raw_ptr()->pc_descriptors_, descriptors.raw());
}
+ RawCodeSourceMap* code_source_map() const {
+ return raw_ptr()->code_source_map_;
+ }
+
+ void set_code_source_map(const CodeSourceMap& code_source_map) const {
+ ASSERT(code_source_map.IsOld());
+ StorePointer(&raw_ptr()->code_source_map_, code_source_map.raw());
+ }
+
// Array of DeoptInfo objects.
RawArray* deopt_info_array() const {
return raw_ptr()->deopt_info_array_;
@@ -4726,7 +4795,7 @@
class SubtypeTestCache : public Object {
public:
enum Entries {
- kInstanceClassId = 0,
+ kInstanceClassIdOrFunction = 0,
kInstanceTypeArguments = 1,
kInstantiatorTypeArguments = 2,
kTestResult = 3,
@@ -4734,12 +4803,12 @@
};
intptr_t NumberOfChecks() const;
- void AddCheck(intptr_t class_id,
+ void AddCheck(const Object& instance_class_id_or_function,
const TypeArguments& instance_type_arguments,
const TypeArguments& instantiator_type_arguments,
const Bool& test_result) const;
void GetCheck(intptr_t ix,
- intptr_t* class_id,
+ Object* instance_class_id_or_function,
TypeArguments* instance_type_arguments,
TypeArguments* instantiator_type_arguments,
Bool* test_result) const;
@@ -4817,14 +4886,16 @@
static RawLanguageError* NewFormatted(const Error& prev_error,
const Script& script,
intptr_t token_pos,
+ bool report_after_token,
Report::Kind kind,
Heap::Space space,
const char* format, ...)
- PRINTF_ATTRIBUTE(6, 7);
+ PRINTF_ATTRIBUTE(7, 8);
static RawLanguageError* NewFormattedV(const Error& prev_error,
const Script& script,
intptr_t token_pos,
+ bool report_after_token,
Report::Kind kind,
Heap::Space space,
const char* format, va_list args);
@@ -4847,6 +4918,9 @@
intptr_t token_pos() const { return raw_ptr()->token_pos_; }
void set_token_pos(intptr_t value) const;
+ bool report_after_token() const { return raw_ptr()->report_after_token_; }
+ void set_report_after_token(bool value);
+
void set_kind(uint8_t value) const;
RawString* message() const { return raw_ptr()->message_; }
@@ -4957,7 +5031,7 @@
StorePointer(FieldAddr(field), value.raw());
}
- RawType* GetType() const;
+ RawAbstractType* GetType() const;
virtual RawTypeArguments* GetTypeArguments() const;
virtual void SetTypeArguments(const TypeArguments& value) const;
@@ -4984,9 +5058,6 @@
void SetNativeField(int index, intptr_t value) const;
- // Returns true if the instance is a closure object.
- bool IsClosure() const;
-
// If the instance is a callable object, i.e. a closure or the instance of a
// class implementing a 'call' method, return true and set the function
// (if not NULL) to call.
@@ -5113,17 +5184,21 @@
class AbstractType : public Instance {
public:
virtual bool IsFinalized() const;
+ virtual void SetIsFinalized() const;
virtual bool IsBeingFinalized() const;
+ virtual void SetIsBeingFinalized() const;
virtual bool IsMalformed() const;
virtual bool IsMalbounded() const;
virtual bool IsMalformedOrMalbounded() const;
virtual RawLanguageError* error() const;
virtual void set_error(const LanguageError& value) const;
virtual bool IsResolved() const;
+ virtual void SetIsResolved() const;
virtual bool HasResolvedTypeClass() const;
virtual RawClass* type_class() const;
virtual RawUnresolvedClass* unresolved_class() const;
virtual RawTypeArguments* arguments() const;
+ virtual void set_arguments(const TypeArguments& value) const;
virtual intptr_t token_pos() const;
virtual bool IsInstantiated(TrailPtr trail = NULL) const;
virtual bool CanonicalizeEquals(const Instance& other) const {
@@ -5238,8 +5313,8 @@
// Check if this type represents the 'String' type.
bool IsStringType() const;
- // Check if this type represents the 'Function' type.
- bool IsFunctionType() const;
+ // Check if this type represents the Dart 'Function' type.
+ bool IsDartFunctionType() const;
// Check the subtype relationship.
bool IsSubtypeOf(const AbstractType& other,
@@ -5291,12 +5366,11 @@
(raw_ptr()->type_state_ == RawType::kFinalizedInstantiated) ||
(raw_ptr()->type_state_ == RawType::kFinalizedUninstantiated);
}
- void SetIsFinalized() const;
- void ResetIsFinalized() const; // Ignore current state and set again.
+ virtual void SetIsFinalized() const;
virtual bool IsBeingFinalized() const {
return raw_ptr()->type_state_ == RawType::kBeingFinalized;
}
- void set_is_being_finalized() const;
+ virtual void SetIsBeingFinalized() const;
virtual bool IsMalformed() const;
virtual bool IsMalbounded() const;
virtual bool IsMalformedOrMalbounded() const;
@@ -5305,13 +5379,13 @@
virtual bool IsResolved() const {
return raw_ptr()->type_state_ >= RawType::kResolved;
}
- void set_is_resolved() const;
+ virtual void SetIsResolved() const;
virtual bool HasResolvedTypeClass() const; // Own type class resolved.
virtual RawClass* type_class() const;
void set_type_class(const Object& value) const;
virtual RawUnresolvedClass* unresolved_class() const;
- virtual RawTypeArguments* arguments() const;
- void set_arguments(const TypeArguments& value) const;
+ virtual RawTypeArguments* arguments() const { return raw_ptr()->arguments_; }
+ virtual void set_arguments(const TypeArguments& value) const;
virtual intptr_t token_pos() const { return raw_ptr()->token_pos_; }
virtual bool IsInstantiated(TrailPtr trail = NULL) const;
virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
@@ -5401,6 +5475,104 @@
};
+// TODO(regis): FunctionType is very similar to Type. Instead of a separate
+// class FunctionType, we could consider an object of class Type as representing
+// a function type if it has a non-null function (signature) field.
+// In order to save space, we could reuse the error_ field? A malformed or
+// malbounded function type would lose its function reference, but the error
+// string would contain relevant info.
+
+// A FunctionType describes the signature of a function, i.e. the result type
+// and formal parameter types of the function, as well as the names of optional
+// named formal parameters.
+// If these types refer to type parameters of a class in scope, the function
+// type is generic. A generic function type may be instantiated by a type
+// argument vector.
+// Therefore, a FunctionType consists of a scope class, a type argument vector,
+// and a signature.
+// The scope class is either a generic class (or generic typedef) declaring the
+// type parameters referred to by the signature, or class _Closure in the
+// non-generic case (including the non-generic typedef case).
+// The type arguments specify an instantiation of the generic signature (null in
+// the non-generic case).
+// The signature is a reference to an actual closure function (kClosureFunction)
+// or to a signature function (kSignatureFunction).
+// Since typedefs cannot refer to themselves, directly or indirectly, a
+// FunctionType cannot be recursive. Only individual formal parameter types can.
+class FunctionType : public AbstractType {
+ public:
+ virtual bool IsFinalized() const {
+ return
+ (raw_ptr()->type_state_ == RawFunctionType::kFinalizedInstantiated) ||
+ (raw_ptr()->type_state_ == RawFunctionType::kFinalizedUninstantiated);
+ }
+ virtual void SetIsFinalized() const;
+ void ResetIsFinalized() const; // Ignore current state and set again.
+ virtual bool IsBeingFinalized() const {
+ return raw_ptr()->type_state_ == RawFunctionType::kBeingFinalized;
+ }
+ virtual void SetIsBeingFinalized() const;
+ virtual bool IsMalformed() const;
+ virtual bool IsMalbounded() const;
+ virtual bool IsMalformedOrMalbounded() const;
+ virtual RawLanguageError* error() const { return raw_ptr()->error_; }
+ virtual void set_error(const LanguageError& value) const;
+ virtual bool IsResolved() const {
+ return raw_ptr()->type_state_ >= RawFunctionType::kResolved;
+ }
+ virtual void SetIsResolved() const;
+ // The scope class of a FunctionType is always resolved. It has no actual
+ // type class. Returning false is important for the type testers to work, e.g.
+ // IsDynamicType(), IsBoolType(), etc...
+ virtual bool HasResolvedTypeClass() const { return false; }
+ // Return scope_class from virtual type_class() to factorize finalization
+ // with Type, also a parameterized type.
+ virtual RawClass* type_class() const { return scope_class(); }
+ RawClass* scope_class() const { return raw_ptr()->scope_class_; }
+ void set_scope_class(const Class& value) const;
+ virtual RawTypeArguments* arguments() const { return raw_ptr()->arguments_; }
+ virtual void set_arguments(const TypeArguments& value) const;
+ RawFunction* signature() const { return raw_ptr()->signature_; }
+ virtual intptr_t token_pos() const { return raw_ptr()->token_pos_; }
+ virtual bool IsInstantiated(TrailPtr trail = NULL) const;
+ virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
+ virtual bool IsRecursive() const;
+ virtual RawAbstractType* InstantiateFrom(
+ const TypeArguments& instantiator_type_arguments,
+ Error* malformed_error,
+ TrailPtr trail = NULL,
+ Heap::Space space = Heap::kNew) const;
+ virtual RawAbstractType* CloneUnfinalized() const;
+ virtual RawAbstractType* CloneUninstantiated(
+ const Class& new_owner,
+ TrailPtr trail = NULL) const;
+ virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+
+ virtual intptr_t Hash() const;
+
+ static intptr_t InstanceSize() {
+ return RoundedAllocationSize(sizeof(RawFunctionType));
+ }
+
+ static RawFunctionType* New(const Class& scope_class,
+ const TypeArguments& arguments,
+ const Function& signature,
+ intptr_t token_pos,
+ Heap::Space space = Heap::kOld);
+
+ private:
+ void set_signature(const Function& value) const;
+ void set_token_pos(intptr_t token_pos) const;
+ void set_type_state(int8_t state) const;
+
+ static RawFunctionType* New(Heap::Space space = Heap::kOld);
+
+ FINAL_HEAP_OBJECT_IMPLEMENTATION(FunctionType, AbstractType);
+ friend class Class;
+ friend class TypeArguments;
+};
+
+
// A TypeRef is used to break cycles in the representation of recursive types.
// Its only field is the recursive AbstractType it refers to.
// Note that the cycle always involves type arguments.
@@ -5422,7 +5594,10 @@
return AbstractType::Handle(type()).IsMalformedOrMalbounded();
}
virtual bool IsResolved() const { return true; }
- virtual bool HasResolvedTypeClass() const { return true; }
+ virtual bool HasResolvedTypeClass() const {
+ // Returns false if the ref type is a function type.
+ return AbstractType::Handle(type()).HasResolvedTypeClass();
+ }
RawAbstractType* type() const { return raw_ptr()->type_; }
void set_type(const AbstractType& value) const;
virtual RawClass* type_class() const {
@@ -5491,7 +5666,7 @@
ASSERT(raw_ptr()->type_state_ != RawTypeParameter::kFinalizedInstantiated);
return raw_ptr()->type_state_ == RawTypeParameter::kFinalizedUninstantiated;
}
- void set_is_finalized() const;
+ virtual void SetIsFinalized() const;
virtual bool IsBeingFinalized() const { return false; }
virtual bool IsMalformed() const { return false; }
virtual bool IsMalbounded() const { return false; }
@@ -7667,86 +7842,45 @@
};
-class Closure : public AllStatic {
+class Closure : public Instance {
public:
- static RawFunction* function(const Instance& closure) {
- return *FunctionAddr(closure);
+ RawFunction* function() const { return raw_ptr()->function_; }
+ void set_function(const Function& function) const {
+ // TODO(regis): Only used from deferred_objects.cc. Remove once fixed.
+ StorePointer(&raw_ptr()->function_, function.raw());
}
- static intptr_t function_offset() {
- return static_cast<intptr_t>(kFunctionOffset * kWordSize);
- }
+ static intptr_t function_offset() { return OFFSET_OF(RawClosure, function_); }
- static RawContext* context(const Instance& closure) {
- return *ContextAddr(closure);
+ RawContext* context() const { return raw_ptr()->context_; }
+ void set_context(const Context& context) const {
+ // TODO(regis): Only used from deferred_objects.cc. Remove once fixed.
+ StorePointer(&raw_ptr()->context_, context.raw());
}
- static intptr_t context_offset() {
- return static_cast<intptr_t>(kContextOffset * kWordSize);
- }
+ static intptr_t context_offset() { return OFFSET_OF(RawClosure, context_); }
- static RawTypeArguments* GetTypeArguments(const Instance& closure) {
- return *TypeArgumentsAddr(closure);
- }
- static void SetTypeArguments(const Instance& closure,
- const TypeArguments& value) {
- ASSERT(value.IsNull() || value.IsCanonical());
- closure.StorePointer(TypeArgumentsAddr(closure), value.raw());
- }
static intptr_t type_arguments_offset() {
- return static_cast<intptr_t>(kTypeArgumentsOffset * kWordSize);
+ return OFFSET_OF(RawClosure, type_arguments_);
}
- static const char* ToCString(const Instance& closure);
-
static intptr_t InstanceSize() {
- intptr_t size = sizeof(RawInstance) + (kNumFields * kWordSize);
- ASSERT(size == Object::RoundedAllocationSize(size));
- return size;
+ return RoundedAllocationSize(sizeof(RawClosure));
}
- static RawInstance* New(const Function& function,
- const Context& context,
- Heap::Space space = Heap::kNew);
+ // Returns true if all elements are OK for canonicalization.
+ virtual bool CheckAndCanonicalizeFields(const char** error_str) const {
+ // None of the fields of a closure are instances.
+ return true;
+ }
+
+ static RawClosure* New(const Function& function,
+ const Context& context,
+ Heap::Space space = Heap::kNew);
private:
- static const int kTypeArgumentsOffset = 1;
- static const int kFunctionOffset = 2;
- static const int kContextOffset = 3;
- static const int kNumFields = 3;
+ static RawClosure* New();
- static RawTypeArguments** TypeArgumentsAddr(const Instance& obj) {
- ASSERT(obj.IsClosure());
- return reinterpret_cast<RawTypeArguments**>(
- reinterpret_cast<intptr_t>(obj.raw_ptr()) + type_arguments_offset());
- }
- static RawFunction** FunctionAddr(const Instance& obj) {
- ASSERT(obj.IsClosure());
- return reinterpret_cast<RawFunction**>(
- reinterpret_cast<intptr_t>(obj.raw_ptr()) + function_offset());
- }
- static RawContext** ContextAddr(const Instance& obj) {
- ASSERT(obj.IsClosure());
- return reinterpret_cast<RawContext**>(
- reinterpret_cast<intptr_t>(obj.raw_ptr()) + context_offset());
- }
- static void set_function(const Instance& closure,
- const Function& value) {
- closure.StorePointer(FunctionAddr(closure), value.raw());
- }
- static void set_context(const Instance& closure,
- const Context& value) {
- closure.StorePointer(ContextAddr(closure), value.raw());
- }
- static intptr_t NextFieldOffset() {
- // Indicates this class cannot be extended by dart code.
- return -kWordSize;
- }
- static RawFunction* GetFunction(RawObject* obj) {
- return *(reinterpret_cast<RawFunction**>(
- reinterpret_cast<intptr_t>(obj->ptr()) + function_offset()));
- }
-
+ FINAL_HEAP_OBJECT_IMPLEMENTATION(Closure, Instance);
friend class Class;
- friend class SnapshotWriter;
};
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 624e1fe..c5a6be6 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -20,7 +20,7 @@
null_class_(Class::null()),
null_type_(Type::null()),
function_type_(Type::null()),
- function_impl_type_(Type::null()),
+ closure_class_(Class::null()),
number_type_(Type::null()),
int_type_(Type::null()),
integer_implementation_class_(Class::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index db57663..2b68902 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -67,9 +67,9 @@
function_type_ = value.raw();
}
- RawType* function_impl_type() const { return function_impl_type_; }
- void set_function_impl_type(const Type& value) {
- function_impl_type_ = value.raw();
+ RawClass* closure_class() const { return closure_class_; }
+ void set_closure_class(const Class& value) {
+ closure_class_ = value.raw();
}
RawType* number_type() const { return number_type_; }
@@ -504,7 +504,7 @@
RawClass* null_class_;
RawType* null_type_;
RawType* function_type_;
- RawType* function_impl_type_;
+ RawClass* closure_class_;
RawType* number_type_;
RawType* int_type_;
RawClass* integer_implementation_class_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 422121e..9f31fee 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -29,7 +29,7 @@
static RawClass* CreateDummyClass(const String& class_name,
const Script& script) {
const Class& cls = Class::Handle(
- Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::New(class_name, script, Token::kNoSourcePos));
cls.set_is_synthesized_class(); // Dummy class for testing.
return cls.raw();
}
@@ -2537,17 +2537,17 @@
const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
const String& a = String::ZoneHandle(Symbols::New("a"));
LocalVariable* var_a =
- new LocalVariable(Scanner::kNoSourcePos, a, dynamic_type);
+ new LocalVariable(Token::kNoSourcePos, a, dynamic_type);
parent_scope->AddVariable(var_a);
const String& b = String::ZoneHandle(Symbols::New("b"));
LocalVariable* var_b =
- new LocalVariable(Scanner::kNoSourcePos, b, dynamic_type);
+ new LocalVariable(Token::kNoSourcePos, b, dynamic_type);
local_scope->AddVariable(var_b);
const String& c = String::ZoneHandle(Symbols::New("c"));
LocalVariable* var_c =
- new LocalVariable(Scanner::kNoSourcePos, c, dynamic_type);
+ new LocalVariable(Token::kNoSourcePos, c, dynamic_type);
parent_scope->AddVariable(var_c);
bool test_only = false; // Please, insert alias.
@@ -2630,18 +2630,13 @@
Function& function = Function::Handle();
const String& function_name = String::Handle(Symbols::New("foo"));
function = Function::NewClosureFunction(function_name, parent, 0);
- const Class& signature_class = Class::Handle(
- Class::NewSignatureClass(function_name, function, script, 0));
- const Instance& closure = Instance::Handle(Closure::New(function, context));
+ const Closure& closure = Closure::Handle(Closure::New(function, context));
const Class& closure_class = Class::Handle(closure.clazz());
- EXPECT(closure_class.IsSignatureClass());
- EXPECT(closure_class.IsCanonicalSignatureClass());
- EXPECT_EQ(closure_class.raw(), signature_class.raw());
- const Function& signature_function =
- Function::Handle(signature_class.signature_function());
- EXPECT_EQ(signature_function.raw(), function.raw());
- const Context& closure_context = Context::Handle(Closure::context(closure));
- EXPECT_EQ(closure_context.raw(), closure_context.raw());
+ EXPECT_EQ(closure_class.id(), kClosureCid);
+ const Function& closure_function = Function::Handle(closure.function());
+ EXPECT_EQ(closure_function.raw(), function.raw());
+ const Context& closure_context = Context::Handle(closure.context());
+ EXPECT_EQ(closure_context.raw(), context.raw());
}
@@ -3092,16 +3087,18 @@
SubtypeTestCache& cache = SubtypeTestCache::Handle(SubtypeTestCache::New());
EXPECT(!cache.IsNull());
EXPECT_EQ(0, cache.NumberOfChecks());
+ const Object& class_id_or_fun = Object::Handle(Smi::New(empty_class.id()));
const TypeArguments& targ_0 = TypeArguments::Handle(TypeArguments::New(2));
const TypeArguments& targ_1 = TypeArguments::Handle(TypeArguments::New(3));
- cache.AddCheck(empty_class.id(), targ_0, targ_1, Bool::True());
+ cache.AddCheck(class_id_or_fun, targ_0, targ_1, Bool::True());
EXPECT_EQ(1, cache.NumberOfChecks());
- intptr_t test_class_id = -1;
+ Object& test_class_id_or_fun = Object::Handle();
TypeArguments& test_targ_0 = TypeArguments::Handle();
TypeArguments& test_targ_1 = TypeArguments::Handle();
Bool& test_result = Bool::Handle();
- cache.GetCheck(0, &test_class_id, &test_targ_0, &test_targ_1, &test_result);
- EXPECT_EQ(empty_class.id(), test_class_id);
+ cache.GetCheck(
+ 0, &test_class_id_or_fun, &test_targ_0, &test_targ_1, &test_result);
+ EXPECT_EQ(class_id_or_fun.raw(), test_class_id_or_fun.raw());
EXPECT_EQ(targ_0.raw(), test_targ_0.raw());
EXPECT_EQ(targ_1.raw(), test_targ_1.raw());
EXPECT_EQ(Bool::True().raw(), test_result.raw());
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 47cb001..5440dfb 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -5,7 +5,7 @@
#include "vm/parser.h"
#include "vm/flags.h"
-#ifndef DART_PRECOMPILED
+#ifndef DART_PRECOMPILED_RUNTIME
#include "lib/invocation_mirror.h"
#include "platform/utils.h"
@@ -66,6 +66,8 @@
#define I (isolate())
#define Z (zone())
+// Quick synthetic token position.
+#define ST(token_pos) Token::ToSynthetic(token_pos)
#if defined(DEBUG)
class TraceParser : public ValueObject {
@@ -125,6 +127,27 @@
};
+class RecursionChecker : public ValueObject {
+ public:
+ explicit RecursionChecker(Parser* p) : parser_(p) {
+ parser_->recursion_counter_++;
+ // No need to check the stack unless the parser is in an unusually deep
+ // recurive state. Thus, we omit the more expensive stack checks in
+ // the common case.
+ const int kMaxUncheckedDepth = 100; // Somewhat arbitrary.
+ if (parser_->recursion_counter_ > kMaxUncheckedDepth) {
+ parser_->CheckStack();
+ }
+ }
+ ~RecursionChecker() {
+ parser_->recursion_counter_--;
+ }
+
+ private:
+ Parser* parser_;
+};
+
+
static RawTypeArguments* NewTypeArguments(
const GrowableArray<AbstractType*>& objs) {
const TypeArguments& a =
@@ -239,7 +262,7 @@
struct CatchParamDesc {
CatchParamDesc()
- : token_pos(Scanner::kNoSourcePos), type(NULL), name(NULL), var(NULL) { }
+ : token_pos(Token::kNoSourcePos), type(NULL), name(NULL), var(NULL) { }
intptr_t token_pos;
const AbstractType* type;
const String* name;
@@ -347,7 +370,8 @@
last_used_try_index_(0),
unregister_pending_function_(false),
async_temp_scope_(NULL),
- trace_indent_(0) {
+ trace_indent_(0),
+ recursion_counter_(0) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!library.IsNull());
}
@@ -381,7 +405,8 @@
last_used_try_index_(0),
unregister_pending_function_(false),
async_temp_scope_(NULL),
- trace_indent_(0) {
+ trace_indent_(0),
+ recursion_counter_(0) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!current_function().IsNull());
EnsureExpressionTemp();
@@ -449,6 +474,7 @@
void Parser::SetPosition(intptr_t position) {
tokens_iterator_.SetCurrentPosition(position);
token_kind_ = Token::kILLEGAL;
+ prev_token_pos_ = position;
}
@@ -518,7 +544,7 @@
struct ParamDesc {
ParamDesc()
: type(NULL),
- name_pos(Scanner::kNoSourcePos),
+ name_pos(Token::kNoSourcePos),
name(NULL),
default_value(NULL),
metadata(NULL),
@@ -623,10 +649,10 @@
has_factory = false;
has_operator = false;
has_native = false;
- metadata_pos = Scanner::kNoSourcePos;
+ metadata_pos = Token::kNoSourcePos;
operator_token = Token::kILLEGAL;
type = NULL;
- name_pos = Scanner::kNoSourcePos;
+ name_pos = Token::kNoSourcePos;
name = NULL;
redirect_name = NULL;
dict_name = NULL;
@@ -970,7 +996,7 @@
if (!func.IsImplicitConstructor()) {
parser.SkipFunctionPreamble();
}
- node_sequence = parser.ParseFunc(func);
+ node_sequence = parser.ParseFunc(func, false);
break;
case RawFunction::kImplicitGetter:
ASSERT(!func.is_static());
@@ -1311,7 +1337,7 @@
LoadInstanceFieldNode* load_field =
new LoadInstanceFieldNode(ident_pos, load_receiver, field);
- ReturnNode* return_node = new ReturnNode(Scanner::kNoSourcePos, load_field);
+ ReturnNode* return_node = new ReturnNode(ST(ident_pos), load_field);
current_block_->statements->Add(return_node);
return CloseBlock();
}
@@ -1355,7 +1381,7 @@
StoreInstanceFieldNode* store_field =
new StoreInstanceFieldNode(ident_pos, receiver, field, value);
current_block_->statements->Add(store_field);
- current_block_->statements->Add(new ReturnNode(Scanner::kNoSourcePos));
+ current_block_->statements->Add(new ReturnNode(ST(ident_pos)));
return CloseBlock();
}
@@ -1483,7 +1509,7 @@
ParamList params;
const intptr_t ident_pos = func.token_pos();
- ASSERT(func.token_pos() == 0);
+ ASSERT(func.token_pos() == ClassifyingTokenPositions::kMethodExtractor);
ASSERT(current_class().raw() == func.Owner());
params.AddReceiver(ReceiverType(current_class()), ident_pos);
ASSERT(func.num_fixed_parameters() == 1); // Receiver.
@@ -1503,7 +1529,7 @@
load_receiver,
NULL);
- ReturnNode* return_node = new ReturnNode(Scanner::kNoSourcePos, closure);
+ ReturnNode* return_node = new ReturnNode(ident_pos, closure);
current_block_->statements->Add(return_node);
return CloseBlock();
}
@@ -1624,14 +1650,14 @@
ArgumentListNode* no_args = new ArgumentListNode(token_pos);
LoadLocalNode* receiver = new LoadLocalNode(token_pos, scope->VariableAt(0));
- const Class& function_impl = Class::Handle(Type::Handle(
- Isolate::Current()->object_store()->function_impl_type()).type_class());
+ const Class& closure_cls = Class::Handle(
+ Isolate::Current()->object_store()->closure_class());
const Class& owner = Class::Handle(Z, func.Owner());
ASSERT(!owner.IsNull());
const String& name = String::Handle(Z, func.name());
AstNode* function_object = NULL;
- if (owner.raw() == function_impl.raw() && name.Equals(Symbols::Call())) {
+ if (owner.raw() == closure_cls.raw() && name.Equals(Symbols::Call())) {
function_object = receiver;
} else {
const String& getter_name = String::ZoneHandle(Z,
@@ -1658,7 +1684,7 @@
args->set_names(names);
AstNode* result = NULL;
- if (owner.raw() == function_impl.raw() && name.Equals(Symbols::Call())) {
+ if (owner.raw() == closure_cls.raw() && name.Equals(Symbols::Call())) {
result = new ClosureCallNode(token_pos, function_object, args);
} else {
result = BuildClosureCall(token_pos, function_object, args);
@@ -1735,7 +1761,8 @@
if (!is_match) {
const Error& error = Error::Handle(
LanguageError::NewFormatted(Error::Handle(),
- script_, opening_pos, Report::kWarning, Heap::kNew,
+ script_, opening_pos, Report::AtLocation,
+ Report::kWarning, Heap::kNew,
"unbalanced '%s' opens here", Token::Str(opening_token)));
ReportErrors(error, script_, token_pos,
"unbalanced '%s'", Token::Str(token));
@@ -1879,55 +1906,22 @@
ParseFormalParameterList(no_explicit_default_values, false, &func_params);
// In top-level and mixin functions, the source may be in a different
- // script than the script of the current class.
- Object& sig_func_owner = Object::Handle(Z, current_class().raw());
- if (current_class().script() != script_.raw()) {
- sig_func_owner = PatchClass::New(current_class(), script_);
- }
-
- // The field 'is_static' has no meaning for signature functions.
+ // script than the script of the current class. However, we never reparse
+ // signature functions (except typedef signature functions), therefore
+ // we do not need to keep the correct script via a patch class. Use the
+ // actual current class as owner of the signature function.
const Function& signature_function = Function::Handle(Z,
- Function::New(*parameter.name,
- RawFunction::kSignatureFunction,
- /* is_static = */ false,
- /* is_const = */ false,
- /* is_abstract = */ false,
- /* is_external = */ false,
- /* is_native = */ false,
- sig_func_owner,
- parameter.name_pos));
+ Function::NewSignatureFunction(current_class(),
+ Token::kNoSourcePos));
signature_function.set_result_type(result_type);
- signature_function.set_is_debuggable(false);
AddFormalParamsToFunction(&func_params, signature_function);
- const String& signature =
- String::Handle(Z, signature_function.Signature());
- // Lookup the signature class, i.e. the class whose name is the signature.
- // We only lookup in the current library, but not in its imports, and only
- // create a new canonical signature class if it does not exist yet.
- Class& signature_class =
- Class::ZoneHandle(Z, library_.LookupLocalClass(signature));
- if (signature_class.IsNull()) {
- signature_class = Class::NewSignatureClass(signature,
- signature_function,
- script_,
- parameter.name_pos);
- // Record the function signature class in the current library, unless
- // we are currently skipping a formal parameter list, in which case
- // the signature class could remain unfinalized.
- if (!params->skipped) {
- library_.AddClass(signature_class);
- }
- } else {
- signature_function.set_signature_class(signature_class);
- }
- ASSERT(signature_function.signature_class() == signature_class.raw());
+ FunctionType& signature_type =
+ FunctionType::ZoneHandle(Z, signature_function.SignatureType());
if (!is_top_level_) {
- // Finalize types in signature class here, so that the
- // signature type is not computed twice.
- ClassFinalizer::FinalizeTypesInClass(signature_class);
+ signature_type ^= ClassFinalizer::FinalizeType(
+ current_class(), signature_type, ClassFinalizer::kCanonicalize);
+ signature_function.SetSignatureType(signature_type);
}
- const Type& signature_type =
- Type::ZoneHandle(Z, signature_class.SignatureType());
ASSERT(is_top_level_ || signature_type.IsFinalized());
// A signature type itself cannot be malformed or malbounded, only its
// signature function's result type or parameter types may be.
@@ -2312,9 +2306,10 @@
// parameterized class, make sure that the receiver is captured as
// instantiator.
if (current_block_->scope->function_level() > 0) {
- const Class& signature_class = Class::Handle(Z,
- implicit_closure_function.signature_class());
- if (signature_class.NumTypeParameters() > 0) {
+ const FunctionType& signature_type = FunctionType::Handle(Z,
+ implicit_closure_function.SignatureType());
+ const Class& scope_class = Class::Handle(Z, signature_type.type_class());
+ if (scope_class.IsGeneric()) {
CaptureInstantiator();
}
}
@@ -2877,7 +2872,7 @@
OpenFunctionBlock(func);
LocalVariable* receiver = new LocalVariable(
- Scanner::kNoSourcePos, Symbols::This(), *ReceiverType(current_class()));
+ Token::kNoSourcePos, Symbols::This(), *ReceiverType(current_class()));
current_block_->scope->InsertParameterAt(0, receiver);
// Parse expressions of instance fields that have an explicit
@@ -2920,20 +2915,20 @@
// Prepare user-defined arguments to be forwarded to super call.
// The first user-defined argument is at position 1.
- forwarding_args = new ArgumentListNode(Scanner::kNoSourcePos);
+ forwarding_args = new ArgumentListNode(ST(ctor_pos));
for (int i = 1; i < func.NumParameters(); i++) {
LocalVariable* param = new LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
String::ZoneHandle(Z, func.ParameterNameAt(i)),
Object::dynamic_type());
current_block_->scope->InsertParameterAt(i, param);
- forwarding_args->Add(new LoadLocalNode(Scanner::kNoSourcePos, param));
+ forwarding_args->Add(new LoadLocalNode(ST(ctor_pos), param));
}
}
AstNode* super_call = GenerateSuperConstructorCall(
current_class(),
- Scanner::kNoSourcePos,
+ ctor_pos,
receiver,
forwarding_args);
if (super_call != NULL) {
@@ -2942,7 +2937,7 @@
CheckFieldsInitialized(current_class());
// Empty constructor body.
- current_block_->statements->Add(new ReturnNode(Scanner::kNoSourcePos));
+ current_block_->statements->Add(new ReturnNode(ST(ctor_pos)));
SequenceNode* statements = CloseBlock();
return statements;
}
@@ -3142,7 +3137,7 @@
// Parser is at the opening parenthesis of the formal parameter
// declaration of the function or constructor.
// Parse the formal parameters and code.
-SequenceNode* Parser::ParseFunc(const Function& func) {
+SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) {
TRACE_PARSER("ParseFunc");
Function& saved_innermost_function =
Function::Handle(Z, innermost_function().raw());
@@ -3319,7 +3314,7 @@
BoolScope allow_await(&this->await_is_keyword_,
func.IsAsyncOrGenerator() || func.is_generated_body());
- intptr_t end_token_pos = Scanner::kNoSourcePos;
+ intptr_t end_token_pos = Token::kNoSourcePos;
if (CurrentToken() == Token::kLBRACE) {
ConsumeToken();
if (String::Handle(Z, func.name()).Equals(Symbols::EqualOperator())) {
@@ -3349,6 +3344,9 @@
ASSERT(expr != NULL);
current_block_->statements->Add(new ReturnNode(expr_pos, expr));
end_token_pos = TokenPos();
+ if (check_semicolon) {
+ ExpectSemicolon();
+ }
} else if (IsSymbol(Symbols::Native())) {
if (String::Handle(Z, func.name()).Equals(
Symbols::EqualOperator())) {
@@ -3409,24 +3407,24 @@
void Parser::AddEqualityNullCheck() {
AstNode* argument =
- new LoadLocalNode(Scanner::kNoSourcePos,
+ new LoadLocalNode(Token::kNoSourcePos,
current_block_->scope->parent()->VariableAt(1));
LiteralNode* null_operand =
- new LiteralNode(Scanner::kNoSourcePos, Instance::ZoneHandle(Z));
+ new LiteralNode(Token::kNoSourcePos, Instance::ZoneHandle(Z));
ComparisonNode* check_arg =
- new ComparisonNode(Scanner::kNoSourcePos,
+ new ComparisonNode(Token::kNoSourcePos,
Token::kEQ_STRICT,
argument,
null_operand);
ComparisonNode* result =
- new ComparisonNode(Scanner::kNoSourcePos,
+ new ComparisonNode(Token::kNoSourcePos,
Token::kEQ_STRICT,
- LoadReceiver(Scanner::kNoSourcePos),
+ LoadReceiver(Token::kNoSourcePos),
null_operand);
- SequenceNode* arg_is_null = new SequenceNode(Scanner::kNoSourcePos,
+ SequenceNode* arg_is_null = new SequenceNode(Token::kNoSourcePos,
current_block_->scope);
- arg_is_null->Add(new ReturnNode(Scanner::kNoSourcePos, result));
- IfNode* if_arg_null = new IfNode(Scanner::kNoSourcePos,
+ arg_is_null->Add(new ReturnNode(Token::kNoSourcePos, result));
+ IfNode* if_arg_null = new IfNode(Token::kNoSourcePos,
check_arg,
arg_is_null,
NULL);
@@ -4114,7 +4112,8 @@
member.has_var = true;
// The member type is the 'dynamic' type.
member.type = &Object::dynamic_type();
- } else if (CurrentToken() == Token::kFACTORY) {
+ } else if ((CurrentToken() == Token::kFACTORY) &&
+ (LookaheadToken(1) != Token::kLPAREN)) {
ConsumeToken();
if (member.has_static) {
ReportError("factory method cannot be explicitly marked static");
@@ -4380,10 +4379,6 @@
// Preserve and reuse the original type parameters and bounds since the
// ones defined in the patch class will not be finalized.
orig_type_parameters = cls.type_parameters();
- // A patch class must be given the same name as the class it is patching,
- // otherwise the generic signature classes it defines will not match the
- // patched generic signature classes. Therefore, new signature classes
- // will be introduced and the original ones will not get finalized.
cls = Class::New(class_name, script_, declaration_pos);
cls.set_library(library_);
} else {
@@ -4967,15 +4962,15 @@
"'%s' is already defined", alias_name->ToCString());
}
- // Create the function type alias signature class. It will be linked to its
+ // Create the function type alias scope class. It will be linked to its
// signature function after it has been parsed. The type parameters, in order
- // to be properly finalized, need to be associated to this signature class as
+ // to be properly finalized, need to be associated to this scope class as
// they are parsed.
const Class& function_type_alias = Class::Handle(Z,
- Class::NewSignatureClass(*alias_name,
- Function::Handle(Z),
- script_,
- declaration_pos));
+ Class::New(*alias_name, script_, declaration_pos));
+ function_type_alias.set_is_synthesized_class();
+ function_type_alias.set_is_abstract();
+ function_type_alias.set_is_prefinalized();
library_.AddClass(function_type_alias);
set_current_class(function_type_alias);
// Parse the type parameters of the function type.
@@ -5000,52 +4995,21 @@
const bool no_explicit_default_values = false;
ParseFormalParameterList(no_explicit_default_values, false, &func_params);
ExpectSemicolon();
- // The field 'is_static' has no meaning for signature functions.
- Function& signature_function = Function::Handle(Z,
- Function::New(*alias_name,
- RawFunction::kSignatureFunction,
- /* is_static = */ false,
- /* is_const = */ false,
- /* is_abstract = */ false,
- /* is_external = */ false,
- /* is_native = */ false,
- function_type_alias,
- alias_name_pos));
+ Function& signature_function =
+ Function::Handle(Z, Function::NewSignatureFunction(function_type_alias,
+ alias_name_pos));
signature_function.set_result_type(result_type);
- signature_function.set_is_debuggable(false);
AddFormalParamsToFunction(&func_params, signature_function);
- // Patch the signature function in the signature class.
- function_type_alias.PatchSignatureFunction(signature_function);
+ // Set the signature function in the function type alias class.
+ function_type_alias.set_signature_function(signature_function);
- const String& signature = String::Handle(Z,
- signature_function.Signature());
if (FLAG_trace_parser) {
OS::Print("TopLevel parsing function type alias '%s'\n",
- signature.ToCString());
+ String::Handle(Z, signature_function.Signature()).ToCString());
}
- // Lookup the signature class, i.e. the class whose name is the signature.
- // We only lookup in the current library, but not in its imports, and only
- // create a new canonical signature class if it does not exist yet.
- Class& signature_class =
- Class::ZoneHandle(Z, library_.LookupLocalClass(signature));
- if (signature_class.IsNull()) {
- signature_class = Class::NewSignatureClass(signature,
- signature_function,
- script_,
- alias_name_pos);
- // Record the function signature class in the current library.
- library_.AddClass(signature_class);
- } else {
- // Forget the just created signature function and use the existing one.
- signature_function = signature_class.signature_function();
- function_type_alias.PatchSignatureFunction(signature_function);
- }
- ASSERT(signature_function.signature_class() == signature_class.raw());
-
// The alias should not be marked as finalized yet, since it needs to be
// checked in the class finalizer for illegal self references.
- ASSERT(!function_type_alias.IsCanonicalSignatureClass());
ASSERT(!function_type_alias.is_finalized());
pending_classes.Add(function_type_alias, Heap::kOld);
if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
@@ -5073,7 +5037,7 @@
intptr_t Parser::SkipMetadata() {
if (CurrentToken() != Token::kAT) {
- return Scanner::kNoSourcePos;
+ return Token::kNoSourcePos;
}
intptr_t metadata_pos = TokenPos();
while (CurrentToken() == Token::kAT) {
@@ -5832,7 +5796,7 @@
CheckToken(Token::kAS, "'as' expected");
}
String& prefix = String::Handle(Z);
- intptr_t prefix_pos = Scanner::kNoSourcePos;
+ intptr_t prefix_pos = Token::kNoSourcePos;
if (is_import && (CurrentToken() == Token::kAS)) {
ConsumeToken();
prefix_pos = TokenPos();
@@ -6107,6 +6071,18 @@
}
+void Parser::CheckStack() {
+ volatile uword c_stack_pos = Isolate::GetCurrentStackPointer();
+ volatile uword c_stack_base = OSThread::Current()->stack_base();
+ volatile uword c_stack_limit =
+ c_stack_base - OSThread::GetSpecifiedStackSize();
+ // Note: during early initialization the stack_base() can return 0.
+ if ((c_stack_base > 0) && (c_stack_pos < c_stack_limit)) {
+ ReportError("stack overflow while parsing");
+ }
+}
+
+
void Parser::ChainNewBlock(LocalScope* outer_scope) {
Block* block = new(Z) Block(
current_block_,
@@ -6188,10 +6164,10 @@
// Add the exception and stack trace parameters to the scope.
CatchParamDesc exception_param;
CatchParamDesc stack_trace_param;
- exception_param.token_pos = Scanner::kNoSourcePos;
+ exception_param.token_pos = Token::kNoSourcePos;
exception_param.type = &Object::dynamic_type();
exception_param.name = &Symbols::ExceptionParameter();
- stack_trace_param.token_pos = Scanner::kNoSourcePos;
+ stack_trace_param.token_pos = Token::kNoSourcePos;
stack_trace_param.type = &Object::dynamic_type();
stack_trace_param.name = &Symbols::StackTraceParameter();
@@ -6211,9 +6187,9 @@
// Generate code to load the exception object (:exception_var) into
// the exception variable specified in this block.
current_block_->statements->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
exception_param.var,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
+ new(Z) LoadLocalNode(Token::kNoSourcePos, exception_var)));
}
LocalVariable* stack_trace_var =
@@ -6224,9 +6200,9 @@
// to load the stack trace object (:stack_trace_var) into the stack
// trace variable specified in this block.
current_block_->statements->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
stack_trace_param.var,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
+ new(Z) LoadLocalNode(Token::kNoSourcePos, stack_trace_var)));
}
LocalVariable* saved_exception_var = try_scope->LocalLookupVariable(
Symbols::SavedExceptionVar());
@@ -6245,15 +6221,15 @@
current_block_->scope->LookupVariable(Symbols::Controller(), false);
ASSERT(controller != NULL);
ArgumentListNode* args =
- new(Z) ArgumentListNode(Scanner::kNoSourcePos);
- args->Add(new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_param.var));
- args->Add(new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_param.var));
+ new(Z) ArgumentListNode(Token::kNoSourcePos);
+ args->Add(new(Z) LoadLocalNode(Token::kNoSourcePos, exception_param.var));
+ args->Add(new(Z) LoadLocalNode(Token::kNoSourcePos, stack_trace_param.var));
current_block_->statements->Add(
new(Z) InstanceCallNode(try_end_pos,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, controller),
+ new(Z) LoadLocalNode(Token::kNoSourcePos, controller),
Symbols::AddError(),
args));
- ReturnNode* return_node = new(Z) ReturnNode(Scanner::kNoSourcePos);
+ ReturnNode* return_node = new(Z) ReturnNode(Token::kNoSourcePos);
AddNodeForFinallyInlining(return_node);
current_block_->statements->Add(return_node);
AstNode* catch_block = CloseBlock();
@@ -6278,10 +6254,10 @@
do {
OpenBlock();
ArgumentListNode* no_args =
- new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+ new(Z) ArgumentListNode(Token::kNoSourcePos);
current_block_->statements->Add(
new(Z) InstanceCallNode(try_end_pos,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, controller),
+ new(Z) LoadLocalNode(Token::kNoSourcePos, controller),
Symbols::Close(),
no_args));
@@ -6289,7 +6265,7 @@
AwaitMarkerNode* await_marker =
new(Z) AwaitMarkerNode(async_temp_scope_,
current_block_->scope,
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
current_block_->statements->Add(await_marker);
ReturnNode* continuation_ret = new(Z) ReturnNode(try_end_pos);
continuation_ret->set_return_type(ReturnNode::kContinuationTarget);
@@ -6320,7 +6296,7 @@
handler_types.Add(Object::dynamic_type());
CatchClauseNode* catch_clause = new(Z) CatchClauseNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
catch_handler_list,
Array::ZoneHandle(Z, Array::MakeArray(handler_types)),
context_var,
@@ -6334,7 +6310,7 @@
const intptr_t try_index = try_statement->try_index();
AstNode* try_catch_node =
- new(Z) TryCatchNode(Scanner::kNoSourcePos,
+ new(Z) TryCatchNode(Token::kNoSourcePos,
body,
context_var,
catch_clause,
@@ -6359,10 +6335,10 @@
OpenBlock(); // Catch block.
CatchParamDesc exception_param;
CatchParamDesc stack_trace_param;
- exception_param.token_pos = Scanner::kNoSourcePos;
+ exception_param.token_pos = Token::kNoSourcePos;
exception_param.type = &Object::dynamic_type();
exception_param.name = &Symbols::ExceptionParameter();
- stack_trace_param.token_pos = Scanner::kNoSourcePos;
+ stack_trace_param.token_pos = Token::kNoSourcePos;
stack_trace_param.type = &Object::dynamic_type();
stack_trace_param.name = &Symbols::StackTraceParameter();
@@ -6380,9 +6356,9 @@
// the exception variable specified in this block.
ASSERT(exception_var != NULL);
current_block_->statements->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
exception_param.var,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
+ new(Z) LoadLocalNode(Token::kNoSourcePos, exception_var)));
}
LocalVariable* stack_trace_var =
@@ -6393,9 +6369,9 @@
// trace variable specified in this block.
ASSERT(stack_trace_var != NULL);
current_block_->statements->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
stack_trace_param.var,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
+ new(Z) LoadLocalNode(Token::kNoSourcePos, stack_trace_var)));
}
LocalVariable* saved_exception_var = try_scope->LocalLookupVariable(
Symbols::SavedExceptionVar());
@@ -6413,17 +6389,17 @@
Symbols::AsyncCompleter(), false);
ASSERT(async_completer != NULL);
ArgumentListNode* completer_args =
- new (Z) ArgumentListNode(Scanner::kNoSourcePos);
+ new (Z) ArgumentListNode(Token::kNoSourcePos);
completer_args->Add(
- new (Z) LoadLocalNode(Scanner::kNoSourcePos, exception_param.var));
+ new (Z) LoadLocalNode(Token::kNoSourcePos, exception_param.var));
completer_args->Add(
- new (Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_param.var));
+ new (Z) LoadLocalNode(Token::kNoSourcePos, stack_trace_param.var));
current_block_->statements->Add(new (Z) InstanceCallNode(
TokenPos(),
- new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_completer),
+ new (Z) LoadLocalNode(Token::kNoSourcePos, async_completer),
Symbols::CompleterCompleteError(),
completer_args));
- ReturnNode* return_node = new (Z) ReturnNode(Scanner::kNoSourcePos);
+ ReturnNode* return_node = new (Z) ReturnNode(Token::kNoSourcePos);
// Behavior like a continuation return, i.e,. don't call a completer.
return_node->set_return_type(ReturnNode::kContinuation);
current_block_->statements->Add(return_node);
@@ -6440,7 +6416,7 @@
const intptr_t try_index = try_statement->try_index();
CatchClauseNode* catch_clause = new (Z) CatchClauseNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
catch_handler_list,
Array::ZoneHandle(Z, Array::MakeArray(handler_types)),
context_var,
@@ -6451,7 +6427,7 @@
CatchClauseNode::kInvalidTryIndex,
true);
AstNode* try_catch_node = new (Z) TryCatchNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
try_block,
context_var,
catch_clause,
@@ -6551,19 +6527,12 @@
// Add the parameters to the newly created closure.
AddFormalParamsToFunction(&closure_params, body);
- // Create and set the signature class of the closure.
- const String& sig = String::Handle(Z, body.Signature());
- Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
- if (sig_cls.IsNull()) {
- sig_cls = Class::NewSignatureClass(sig, body, script_, body.token_pos());
- library_.AddClass(sig_cls);
- }
- body.set_signature_class(sig_cls);
- // Finalize types in signature class here, so that the
- // signature type is not computed twice.
- ClassFinalizer::FinalizeTypesInClass(sig_cls);
- const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
- ASSERT(sig_type.IsFinalized());
+ // Finalize function type.
+ FunctionType& signature_type =
+ FunctionType::Handle(Z, body.SignatureType());
+ signature_type ^= ClassFinalizer::FinalizeType(
+ current_class(), signature_type, ClassFinalizer::kCanonicalize);
+ body.SetSignatureType(signature_type);
ASSERT(AbstractType::Handle(Z, body.result_type()).IsResolved());
ASSERT(body.NumParameters() == closure_params.parameters->length());
}
@@ -6589,9 +6558,9 @@
LocalVariable* jump_var =
current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
LiteralNode* init_value =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+ new(Z) LiteralNode(Token::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
current_block_->statements->Add(
- new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+ new(Z) StoreLocalNode(Token::kNoSourcePos, jump_var, init_value));
// return new SyncIterable(body_closure);
const Class& iterable_class =
@@ -6605,17 +6574,17 @@
const String& closure_name = String::Handle(Z, closure.name());
ASSERT(closure_name.IsSymbol());
- ArgumentListNode* arguments = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+ ArgumentListNode* arguments = new(Z) ArgumentListNode(Token::kNoSourcePos);
ClosureNode* closure_obj = new(Z) ClosureNode(
- Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
+ Token::kNoSourcePos, closure, NULL, closure_body->scope());
arguments->Add(closure_obj);
ConstructorCallNode* new_iterable =
- new(Z) ConstructorCallNode(Scanner::kNoSourcePos,
+ new(Z) ConstructorCallNode(Token::kNoSourcePos,
TypeArguments::ZoneHandle(Z),
iterable_constructor,
arguments);
ReturnNode* return_node =
- new (Z) ReturnNode(Scanner::kNoSourcePos, new_iterable);
+ new (Z) ReturnNode(Token::kNoSourcePos, new_iterable);
current_block_->statements->Add(return_node);
return CloseBlock();
}
@@ -6688,20 +6657,12 @@
// Add the parameters to the newly created closure.
AddFormalParamsToFunction(&closure_params, closure);
- // Create and set the signature class of the closure.
- const String& sig = String::Handle(Z, closure.Signature());
- Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
- if (sig_cls.IsNull()) {
- sig_cls =
- Class::NewSignatureClass(sig, closure, script_, closure.token_pos());
- library_.AddClass(sig_cls);
- }
- closure.set_signature_class(sig_cls);
- // Finalize types in signature class here, so that the
- // signature type is not computed twice.
- ClassFinalizer::FinalizeTypesInClass(sig_cls);
- const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
- ASSERT(sig_type.IsFinalized());
+ // Finalize function type.
+ FunctionType& signature_type =
+ FunctionType::Handle(Z, closure.SignatureType());
+ signature_type ^= ClassFinalizer::FinalizeType(
+ current_class(), signature_type, ClassFinalizer::kCanonicalize);
+ closure.SetSignatureType(signature_type);
ASSERT(AbstractType::Handle(Z, closure.result_type()).IsResolved());
ASSERT(closure.NumParameters() == closure_params.parameters->length());
}
@@ -6717,10 +6678,10 @@
// var :await_jump_var;
// var :await_ctx_var;
LocalVariable* await_jump_var = new (Z) LocalVariable(
- Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), Object::dynamic_type());
+ Token::kNoSourcePos, Symbols::AwaitJumpVar(), Object::dynamic_type());
current_block_->scope->AddVariable(await_jump_var);
LocalVariable* await_ctx_var = new (Z) LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
Symbols::AwaitContextVar(),
Object::dynamic_type());
current_block_->scope->AddVariable(await_ctx_var);
@@ -6734,20 +6695,20 @@
// var :async_catch_error_callback;
// var :async_completer;
LocalVariable* async_op_var = new(Z) LocalVariable(
- Scanner::kNoSourcePos, Symbols::AsyncOperation(), Object::dynamic_type());
+ Token::kNoSourcePos, Symbols::AsyncOperation(), Object::dynamic_type());
current_block_->scope->AddVariable(async_op_var);
LocalVariable* async_then_callback_var = new(Z) LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
Symbols::AsyncThenCallback(),
Object::dynamic_type());
current_block_->scope->AddVariable(async_then_callback_var);
LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
Symbols::AsyncCatchErrorCallback(),
Object::dynamic_type());
current_block_->scope->AddVariable(async_catch_error_callback_var);
LocalVariable* async_completer = new(Z) LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
Symbols::AsyncCompleter(),
Object::dynamic_type());
current_block_->scope->AddVariable(async_completer);
@@ -6766,18 +6727,18 @@
// These variables are used to store the async generator closure containing
// the body of the async* function. They are used by the await operator.
LocalVariable* controller_var = new(Z) LocalVariable(
- Scanner::kNoSourcePos, Symbols::Controller(), Object::dynamic_type());
+ Token::kNoSourcePos, Symbols::Controller(), Object::dynamic_type());
current_block_->scope->AddVariable(controller_var);
LocalVariable* async_op_var = new(Z) LocalVariable(
- Scanner::kNoSourcePos, Symbols::AsyncOperation(), Object::dynamic_type());
+ Token::kNoSourcePos, Symbols::AsyncOperation(), Object::dynamic_type());
current_block_->scope->AddVariable(async_op_var);
LocalVariable* async_then_callback_var = new(Z) LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
Symbols::AsyncThenCallback(),
Object::dynamic_type());
current_block_->scope->AddVariable(async_then_callback_var);
LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
Symbols::AsyncCatchErrorCallback(),
Object::dynamic_type());
current_block_->scope->AddVariable(async_catch_error_callback_var);
@@ -6823,20 +6784,12 @@
// Add the parameters to the newly created closure.
AddFormalParamsToFunction(&closure_params, closure);
- // Create and set the signature class of the closure.
- const String& sig = String::Handle(Z, closure.Signature());
- Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
- if (sig_cls.IsNull()) {
- sig_cls =
- Class::NewSignatureClass(sig, closure, script_, closure.token_pos());
- library_.AddClass(sig_cls);
- }
- closure.set_signature_class(sig_cls);
- // Finalize types in signature class here, so that the
- // signature type is not computed twice.
- ClassFinalizer::FinalizeTypesInClass(sig_cls);
- const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
- ASSERT(sig_type.IsFinalized());
+ // Finalize function type.
+ FunctionType& signature_type =
+ FunctionType::Handle(Z, closure.SignatureType());
+ signature_type ^= ClassFinalizer::FinalizeType(
+ current_class(), signature_type, ClassFinalizer::kCanonicalize);
+ closure.SetSignatureType(signature_type);
ASSERT(AbstractType::Handle(Z, closure.result_type()).IsResolved());
ASSERT(closure.NumParameters() == closure_params.parameters->length());
}
@@ -6904,18 +6857,18 @@
LocalVariable* jump_var =
current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
LiteralNode* init_value =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+ new(Z) LiteralNode(Token::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
current_block_->statements->Add(
- new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+ new(Z) StoreLocalNode(Token::kNoSourcePos, jump_var, init_value));
// Add to AST:
// :async_op = <closure>; (containing the original body)
LocalVariable* async_op_var =
current_block_->scope->LookupVariable(Symbols::AsyncOperation(), false);
ClosureNode* closure_obj = new(Z) ClosureNode(
- Scanner::kNoSourcePos, closure_func, NULL, closure_body->scope());
+ Token::kNoSourcePos, closure_func, NULL, closure_body->scope());
StoreLocalNode* store_async_op = new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
async_op_var,
closure_obj);
@@ -6927,18 +6880,18 @@
Symbols::AsyncThenWrapperHelper()));
ASSERT(!async_then_wrapper_helper.IsNull());
ArgumentListNode* async_then_wrapper_helper_args = new (Z) ArgumentListNode(
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
async_then_wrapper_helper_args->Add(
- new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+ new (Z) LoadLocalNode(Token::kNoSourcePos, async_op_var));
StaticCallNode* then_wrapper_call = new (Z) StaticCallNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
async_then_wrapper_helper,
async_then_wrapper_helper_args);
LocalVariable* async_then_callback_var =
current_block_->scope->LookupVariable(
Symbols::AsyncThenCallback(), false);
StoreLocalNode* store_async_then_callback = new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
async_then_callback_var,
then_wrapper_call);
@@ -6951,43 +6904,43 @@
Symbols::AsyncErrorWrapperHelper()));
ASSERT(!async_error_wrapper_helper.IsNull());
ArgumentListNode* async_error_wrapper_helper_args = new (Z) ArgumentListNode(
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
async_error_wrapper_helper_args->Add(
- new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+ new (Z) LoadLocalNode(Token::kNoSourcePos, async_op_var));
StaticCallNode* error_wrapper_call = new (Z) StaticCallNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
async_error_wrapper_helper,
async_error_wrapper_helper_args);
LocalVariable* async_catch_error_callback_var =
current_block_->scope->LookupVariable(
Symbols::AsyncCatchErrorCallback(), false);
StoreLocalNode* store_async_catch_error_callback = new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
async_catch_error_callback_var,
error_wrapper_call);
current_block_->statements->Add(store_async_catch_error_callback);
// :controller = new _AsyncStarStreamController(body_closure);
- ArgumentListNode* arguments = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
- arguments->Add(new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+ ArgumentListNode* arguments = new(Z) ArgumentListNode(Token::kNoSourcePos);
+ arguments->Add(new (Z) LoadLocalNode(Token::kNoSourcePos, async_op_var));
ConstructorCallNode* controller_constructor_call =
- new(Z) ConstructorCallNode(Scanner::kNoSourcePos,
+ new(Z) ConstructorCallNode(Token::kNoSourcePos,
TypeArguments::ZoneHandle(Z),
controller_constructor,
arguments);
LocalVariable* controller_var =
current_block_->scope->LookupVariable(Symbols::Controller(), false);
StoreLocalNode* store_controller =
- new(Z) StoreLocalNode(Scanner::kNoSourcePos,
+ new(Z) StoreLocalNode(Token::kNoSourcePos,
controller_var,
controller_constructor_call);
current_block_->statements->Add(store_controller);
// return :controller.stream;
- ReturnNode* return_node = new(Z) ReturnNode(Scanner::kNoSourcePos,
- new(Z) InstanceGetterNode(Scanner::kNoSourcePos,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos,
+ ReturnNode* return_node = new(Z) ReturnNode(Token::kNoSourcePos,
+ new(Z) InstanceGetterNode(Token::kNoSourcePos,
+ new(Z) LoadLocalNode(Token::kNoSourcePos,
controller_var),
Symbols::Stream()));
current_block_->statements->Add(return_node);
@@ -7081,17 +7034,18 @@
LocalVariable* async_completer = current_block_->scope->LookupVariable(
Symbols::AsyncCompleter(), false);
+ const intptr_t token_pos = ST(closure_body->token_pos());
// Add to AST:
// :async_completer = new Completer.sync();
ArgumentListNode* empty_args =
- new (Z) ArgumentListNode(Scanner::kNoSourcePos);
+ new (Z) ArgumentListNode(token_pos);
ConstructorCallNode* completer_constructor_node = new (Z) ConstructorCallNode(
- Scanner::kNoSourcePos,
+ token_pos,
TypeArguments::ZoneHandle(Z),
completer_constructor,
empty_args);
StoreLocalNode* store_completer = new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ token_pos,
async_completer,
completer_constructor_node);
current_block_->statements->Add(store_completer);
@@ -7100,18 +7054,19 @@
LocalVariable* jump_var =
current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
LiteralNode* init_value =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+ new(Z) LiteralNode(token_pos,
+ Smi::ZoneHandle(Smi::New(-1)));
current_block_->statements->Add(
- new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+ new(Z) StoreLocalNode(token_pos, jump_var, init_value));
// Add to AST:
// :async_op = <closure>; (containing the original body)
LocalVariable* async_op_var = current_block_->scope->LookupVariable(
Symbols::AsyncOperation(), false);
ClosureNode* cn = new(Z) ClosureNode(
- Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
+ token_pos, closure, NULL, closure_body->scope());
StoreLocalNode* store_async_op = new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ token_pos,
async_op_var,
cn);
current_block_->statements->Add(store_async_op);
@@ -7123,18 +7078,18 @@
Symbols::AsyncThenWrapperHelper()));
ASSERT(!async_then_wrapper_helper.IsNull());
ArgumentListNode* async_then_wrapper_helper_args = new (Z) ArgumentListNode(
- Scanner::kNoSourcePos);
+ token_pos);
async_then_wrapper_helper_args->Add(
- new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+ new (Z) LoadLocalNode(token_pos, async_op_var));
StaticCallNode* then_wrapper_call = new (Z) StaticCallNode(
- Scanner::kNoSourcePos,
+ token_pos,
async_then_wrapper_helper,
async_then_wrapper_helper_args);
LocalVariable* async_then_callback_var =
current_block_->scope->LookupVariable(
Symbols::AsyncThenCallback(), false);
StoreLocalNode* store_async_then_callback = new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ token_pos,
async_then_callback_var,
then_wrapper_call);
@@ -7147,18 +7102,18 @@
Symbols::AsyncErrorWrapperHelper()));
ASSERT(!async_error_wrapper_helper.IsNull());
ArgumentListNode* async_error_wrapper_helper_args = new (Z) ArgumentListNode(
- Scanner::kNoSourcePos);
+ token_pos);
async_error_wrapper_helper_args->Add(
- new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+ new (Z) LoadLocalNode(token_pos, async_op_var));
StaticCallNode* error_wrapper_call = new (Z) StaticCallNode(
- Scanner::kNoSourcePos,
+ token_pos,
async_error_wrapper_helper,
async_error_wrapper_helper_args);
LocalVariable* async_catch_error_callback_var =
current_block_->scope->LookupVariable(
Symbols::AsyncCatchErrorCallback(), false);
StoreLocalNode* store_async_catch_error_callback = new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ token_pos,
async_catch_error_callback_var,
error_wrapper_call);
@@ -7166,22 +7121,22 @@
// Add to AST:
// new Future.microtask(:async_op);
- ArgumentListNode* arguments = new (Z) ArgumentListNode(Scanner::kNoSourcePos);
+ ArgumentListNode* arguments = new (Z) ArgumentListNode(token_pos);
arguments->Add(new (Z) LoadLocalNode(
- Scanner::kNoSourcePos, async_op_var));
+ token_pos, async_op_var));
ConstructorCallNode* future_node = new (Z) ConstructorCallNode(
- Scanner::kNoSourcePos, TypeArguments::ZoneHandle(Z), constructor,
+ token_pos, TypeArguments::ZoneHandle(Z), constructor,
arguments);
current_block_->statements->Add(future_node);
// Add to AST:
// return :async_completer.future;
ReturnNode* return_node = new (Z) ReturnNode(
- Scanner::kNoSourcePos,
+ token_pos,
new (Z) InstanceGetterNode(
- Scanner::kNoSourcePos,
+ token_pos,
new (Z) LoadLocalNode(
- Scanner::kNoSourcePos,
+ token_pos,
async_completer),
Symbols::CompleterFuture()));
current_block_->statements->Add(return_node);
@@ -7231,7 +7186,8 @@
if (!Utils::IsInt(16, params->num_fixed_parameters) ||
!Utils::IsInt(16, params->num_optional_parameters)) {
const Script& script = Script::Handle(Class::Handle(func.Owner()).script());
- Report::MessageF(Report::kError, script, func.token_pos(),
+ Report::MessageF(Report::kError,
+ script, func.token_pos(), Report::AtLocation,
"too many formal parameters");
}
func.set_num_fixed_parameters(params->num_fixed_parameters);
@@ -7513,7 +7469,7 @@
result_type = Type::DynamicType();
const intptr_t function_pos = TokenPos();
- intptr_t metadata_pos = Scanner::kNoSourcePos;
+ intptr_t metadata_pos = Token::kNoSourcePos;
if (is_literal) {
ASSERT(CurrentToken() == Token::kLPAREN);
function_name = &Symbols::AnonymousClosure();
@@ -7553,7 +7509,6 @@
// Note that we cannot share the same closure function between the closurized
// and non-closurized versions of the same parent function.
Function& function = Function::ZoneHandle(Z);
- bool is_new_closure = false;
// TODO(hausner): There could be two different closures at the given
// function_pos, one enclosed in a closurized function and one enclosed in the
// non-closurized version of this same function.
@@ -7562,7 +7517,6 @@
// The function will be registered in the lookup table by the
// EffectGraphVisitor::VisitClosureNode when the newly allocated closure
// function has been properly setup.
- is_new_closure = true;
function = Function::NewClosureFunction(*function_name,
innermost_function(),
function_pos);
@@ -7577,17 +7531,19 @@
// passed as a function argument, or returned as a function result.
LocalVariable* function_variable = NULL;
- Type& function_type = Type::ZoneHandle(Z);
+ FunctionType& function_type = FunctionType::ZoneHandle(Z);
if (variable_name != NULL) {
// Since the function type depends on the signature of the closure function,
// it cannot be determined before the formal parameter list of the closure
// function is parsed. Therefore, we set the function type to a new
- // parameterized type to be patched after the actual type is known.
- // We temporarily use the class of the Function interface.
- const Class& unknown_signature_class = Class::Handle(Z,
- Type::Handle(Z, Type::Function()).type_class());
- function_type = Type::New(unknown_signature_class,
- TypeArguments::Handle(Z), function_pos);
+ // function type to be patched after the actual type is known.
+ // We temporarily use the Closure class as scope class.
+ const Class& unknown_scope_class = Class::Handle(Z,
+ I->object_store()->closure_class());
+ function_type = FunctionType::New(unknown_scope_class,
+ TypeArguments::Handle(Z),
+ function,
+ function_pos);
function_type.SetIsFinalized(); // No finalization needed.
// Add the function variable to the scope before parsing the function in
@@ -7611,52 +7567,28 @@
}
// Parse the local function.
- SequenceNode* statements = Parser::ParseFunc(function);
+ SequenceNode* statements = Parser::ParseFunc(function, !is_literal);
INC_STAT(thread(), num_functions_parsed, 1);
// Now that the local function has formal parameters, lookup the signature
- // class in the current library (but not in its imports) and only create a new
- // canonical signature class if it does not exist yet.
- const String& signature = String::Handle(Z, function.Signature());
- Class& signature_class = Class::ZoneHandle(Z);
- if (!is_new_closure) {
- signature_class = function.signature_class();
- }
- if (signature_class.IsNull()) {
- signature_class = library_.LookupLocalClass(signature);
- }
- if (signature_class.IsNull()) {
- // If we don't have a signature class yet, this must be a closure we
- // have not parsed before.
- ASSERT(is_new_closure);
- signature_class = Class::NewSignatureClass(signature,
- function,
- script_,
- function.token_pos());
- // Record the function signature class in the current library.
- library_.AddClass(signature_class);
- } else if (is_new_closure) {
- function.set_signature_class(signature_class);
- }
- ASSERT(function.signature_class() == signature_class.raw());
+ FunctionType& signature_type =
+ FunctionType::ZoneHandle(Z, function.SignatureType());
+ signature_type ^= ClassFinalizer::FinalizeType(
+ current_class(), signature_type, ClassFinalizer::kCanonicalize);
+ function.SetSignatureType(signature_type);
// Local functions are registered in the enclosing class, but
// ignored during class finalization. The enclosing class has
// already been finalized.
ASSERT(current_class().is_finalized());
+ ASSERT(signature_type.IsFinalized());
// Make sure that the instantiator is captured.
- if ((signature_class.NumTypeParameters() > 0) &&
- (current_block_->scope->function_level() > 0)) {
+ if ((current_block_->scope->function_level() > 0) &&
+ Class::Handle(signature_type.type_class()).IsGeneric()) {
CaptureInstantiator();
}
- // Finalize types in signature class here, so that the
- // signature type is not computed twice.
- ClassFinalizer::FinalizeTypesInClass(signature_class);
- const Type& signature_type = Type::Handle(Z, signature_class.SignatureType());
- ASSERT(signature_type.IsFinalized());
-
// A signature type itself cannot be malformed or malbounded, only its
// signature function's result type or parameter types may be.
ASSERT(!signature_type.IsMalformed());
@@ -7664,9 +7596,11 @@
if (variable_name != NULL) {
// Patch the function type of the variable now that the signature is known.
- function_type.set_type_class(signature_class);
+ function_type.set_scope_class(
+ Class::Handle(Z, signature_type.scope_class()));
function_type.set_arguments(
TypeArguments::Handle(Z, signature_type.arguments()));
+ ASSERT(function_type.signature() == function.raw());
// The function type was initially marked as instantiated, but it may
// actually be uninstantiated.
@@ -8052,6 +7986,7 @@
TRACE_PARSER("ParseStatementSequence");
const bool dead_code_allowed = true;
bool abrupt_completing_seen = false;
+ RecursionChecker rc(this);
while (CurrentToken() != Token::kRBRACE) {
const intptr_t statement_pos = TokenPos();
AstNode* statement = ParseStatement();
@@ -8091,6 +8026,7 @@
ParseStatementSequence();
ExpectToken(Token::kRBRACE);
} else {
+ RecursionChecker rc(this);
AstNode* statement = ParseStatement();
if (statement != NULL) {
current_block_->statements->Add(statement);
@@ -8514,11 +8450,11 @@
const Function& print_fn = Function::ZoneHandle(
Z, lib.LookupFunctionAllowPrivate(Symbols::print()));
ASSERT(!print_fn.IsNull());
- ArgumentListNode* one_arg = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+ ArgumentListNode* one_arg = new(Z) ArgumentListNode(Token::kNoSourcePos);
String& msg = String::ZoneHandle(Symbols::NewFormatted("%s", str));
- one_arg->Add(new(Z) LiteralNode(Scanner::kNoSourcePos, msg));
+ one_arg->Add(new(Z) LiteralNode(Token::kNoSourcePos, msg));
AstNode* print_call =
- new(Z) StaticCallNode(Scanner::kNoSourcePos, print_fn, one_arg);
+ new(Z) StaticCallNode(Token::kNoSourcePos, print_fn, one_arg);
return print_call;
}
@@ -8723,9 +8659,9 @@
if (outer_saved_try_ctx != NULL) {
catch_block->Add(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
outer_saved_try_ctx,
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(Token::kNoSourcePos,
outer_async_saved_try_ctx)));
}
@@ -8757,17 +8693,17 @@
do {
OpenBlock();
ArgumentListNode* no_args =
- new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+ new(Z) ArgumentListNode(Token::kNoSourcePos);
current_block_->statements->Add(
- new(Z) InstanceCallNode(Scanner::kNoSourcePos,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_var),
+ new(Z) InstanceCallNode(Token::kNoSourcePos,
+ new(Z) LoadLocalNode(Token::kNoSourcePos, iterator_var),
Symbols::Cancel(),
no_args));
finally_clause = CloseBlock();
AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
if (node_to_inline != NULL) {
InlinedFinallyNode* node =
- new(Z) InlinedFinallyNode(Scanner::kNoSourcePos,
+ new(Z) InlinedFinallyNode(Token::kNoSourcePos,
finally_clause,
context_var,
outer_try_index);
@@ -8823,7 +8759,7 @@
ReportError("Loop variable cannot be 'const'");
}
const String* loop_var_name = NULL;
- intptr_t loop_var_pos = Scanner::kNoSourcePos;
+ intptr_t loop_var_pos = Token::kNoSourcePos;
bool new_loop_var = false;
AbstractType& loop_var_type = AbstractType::ZoneHandle(Z);
if (LookaheadToken(1) == Token::kIN) {
@@ -9124,16 +9060,16 @@
ASSERT(saved_exception_var != NULL);
ASSERT(exception_var != NULL);
statements->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
saved_exception_var,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
+ new(Z) LoadLocalNode(Token::kNoSourcePos, exception_var)));
ASSERT(saved_stack_trace_var != NULL);
ASSERT(stack_trace_var != NULL);
statements->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
saved_stack_trace_var,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
+ new(Z) LoadLocalNode(Token::kNoSourcePos, stack_trace_var)));
}
@@ -9168,9 +9104,9 @@
try_stack_->try_index());
current_block_->statements->Add(
new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
saved_try_ctx,
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(Token::kNoSourcePos,
async_saved_try_ctx)));
}
}
@@ -9441,9 +9377,9 @@
try_block->try_index());
async_code->Add(
new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
saved_try_ctx,
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(Token::kNoSourcePos,
async_saved_try_ctx)));
}
}
@@ -9470,16 +9406,16 @@
Symbols::AsyncSavedTryCtxVarPrefix().ToCString(),
last_used_try_index_ - 1));
LocalVariable* async_saved_try_ctx = new (Z) LocalVariable(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
async_saved_try_ctx_name,
Object::dynamic_type());
ASSERT(async_temp_scope_ != NULL);
async_temp_scope_->AddVariable(async_saved_try_ctx);
ASSERT(saved_try_context != NULL);
current_block_->statements->Add(new(Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
async_saved_try_ctx,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context)));
+ new(Z) LoadLocalNode(Token::kNoSourcePos, saved_try_context)));
}
@@ -9808,9 +9744,9 @@
ASSERT(iterator_param != NULL);
// Generate :iterator.current = expr;
AstNode* iterator =
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_param);
+ new(Z) LoadLocalNode(Token::kNoSourcePos, iterator_param);
AstNode* store_current =
- new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+ new(Z) InstanceSetterNode(Token::kNoSourcePos,
iterator,
String::ZoneHandle(Symbols::Current().raw()),
expr);
@@ -9818,7 +9754,7 @@
if (is_yield_each) {
// Generate :iterator.isYieldEach = true;
AstNode* set_is_yield_each =
- new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+ new(Z) InstanceSetterNode(Token::kNoSourcePos,
iterator,
String::ZoneHandle(Symbols::IsYieldEach().raw()),
new(Z) LiteralNode(TokenPos(), Bool::True()));
@@ -9827,7 +9763,7 @@
AwaitMarkerNode* await_marker =
new(Z) AwaitMarkerNode(async_temp_scope_,
current_block_->scope,
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
yield->AddNode(await_marker);
// Return true to indicate that a value has been generated.
ReturnNode* return_true = new(Z) ReturnNode(yield_pos,
@@ -9848,15 +9784,15 @@
&outer_async_saved_try_ctx);
if (saved_try_ctx != NULL) {
yield->AddNode(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
saved_try_ctx,
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(Token::kNoSourcePos,
async_saved_try_ctx)));
if (outer_saved_try_ctx != NULL) {
yield->AddNode(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
outer_saved_try_ctx,
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(Token::kNoSourcePos,
outer_async_saved_try_ctx)));
}
} else {
@@ -9874,7 +9810,7 @@
add_args->Add(expr);
AstNode* add_call =
new(Z) InstanceCallNode(yield_pos,
- new(Z) LoadLocalNode(Scanner::kNoSourcePos, controller_var),
+ new(Z) LoadLocalNode(Token::kNoSourcePos, controller_var),
is_yield_each ? Symbols::AddStream() : Symbols::add(),
add_args);
@@ -9886,18 +9822,18 @@
// restore saved_try_context
SequenceNode* true_branch =
- new(Z) SequenceNode(Scanner::kNoSourcePos, NULL);
+ new(Z) SequenceNode(Token::kNoSourcePos, NULL);
AstNode* return_from_generator = new(Z) ReturnNode(yield_pos);
true_branch->Add(return_from_generator);
AddNodeForFinallyInlining(return_from_generator);
AstNode* if_is_cancelled =
- new(Z) IfNode(Scanner::kNoSourcePos, add_call, true_branch, NULL);
+ new(Z) IfNode(Token::kNoSourcePos, add_call, true_branch, NULL);
yield->AddNode(if_is_cancelled);
AwaitMarkerNode* await_marker =
new(Z) AwaitMarkerNode(async_temp_scope_,
current_block_->scope,
- Scanner::kNoSourcePos);
+ Token::kNoSourcePos);
yield->AddNode(await_marker);
ReturnNode* continuation_return = new(Z) ReturnNode(yield_pos);
continuation_return->set_return_type(ReturnNode::kContinuationTarget);
@@ -9916,15 +9852,15 @@
&outer_async_saved_try_ctx);
if (saved_try_ctx != NULL) {
yield->AddNode(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
saved_try_ctx,
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(Token::kNoSourcePos,
async_saved_try_ctx)));
if (outer_saved_try_ctx != NULL) {
yield->AddNode(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos,
+ Token::kNoSourcePos,
outer_saved_try_ctx,
- new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+ new (Z) LoadLocalNode(Token::kNoSourcePos,
outer_async_saved_try_ctx)));
}
} else {
@@ -9938,7 +9874,7 @@
AstNode* Parser::ParseStatement() {
TRACE_PARSER("ParseStatement");
AstNode* statement = NULL;
- intptr_t label_pos = Scanner::kNoSourcePos;
+ intptr_t label_pos = Token::kNoSourcePos;
String* label_name = NULL;
if (IsIdentifier()) {
if (LookaheadToken(1) == Token::kCOLON) {
@@ -10098,7 +10034,19 @@
void Parser::ReportError(intptr_t token_pos, const char* format, ...) const {
va_list args;
va_start(args, format);
- Report::MessageV(Report::kError, script_, token_pos, format, args);
+ Report::MessageV(Report::kError,
+ script_, token_pos, Report::AtLocation, format, args);
+ va_end(args);
+ UNREACHABLE();
+}
+
+
+void Parser::ReportErrorBefore(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ Report::MessageV(Report::kError,
+ script_, PrevTokenPos(), Report::AfterLocation,
+ format, args);
va_end(args);
UNREACHABLE();
}
@@ -10107,7 +10055,8 @@
void Parser::ReportError(const char* format, ...) const {
va_list args;
va_start(args, format);
- Report::MessageV(Report::kError, script_, TokenPos(), format, args);
+ Report::MessageV(Report::kError,
+ script_, TokenPos(), Report::AtLocation, format, args);
va_end(args);
UNREACHABLE();
}
@@ -10116,7 +10065,8 @@
void Parser::ReportWarning(intptr_t token_pos, const char* format, ...) const {
va_list args;
va_start(args, format);
- Report::MessageV(Report::kWarning, script_, token_pos, format, args);
+ Report::MessageV(Report::kWarning,
+ script_, token_pos, Report::AtLocation, format, args);
va_end(args);
}
@@ -10124,7 +10074,8 @@
void Parser::ReportWarning(const char* format, ...) const {
va_list args;
va_start(args, format);
- Report::MessageV(Report::kWarning, script_, TokenPos(), format, args);
+ Report::MessageV(Report::kWarning,
+ script_, TokenPos(), Report::AtLocation, format, args);
va_end(args);
}
@@ -10150,7 +10101,7 @@
void Parser::ExpectSemicolon() {
if (CurrentToken() != Token::kSEMICOLON) {
- ReportError("semicolon expected");
+ ReportErrorBefore("semicolon expected");
}
ConsumeToken();
}
@@ -10282,8 +10233,8 @@
func->is_external() && !func->is_static()) {
arguments->Add(LoadReceiver(func->token_pos()));
} else {
- Type& type = Type::ZoneHandle(Z,
- Type::New(cls, TypeArguments::Handle(Z), call_pos, Heap::kOld));
+ AbstractType& type = AbstractType::ZoneHandle(Z);
+ type ^= Type::New(cls, TypeArguments::Handle(Z), call_pos, Heap::kOld);
type ^= ClassFinalizer::FinalizeType(
current_class(), type, ClassFinalizer::kCanonicalize);
arguments->Add(new(Z) LiteralNode(call_pos, type));
@@ -10510,9 +10461,22 @@
}
if (binary_op == Token::kIFNULL) {
// Handle a ?? b.
+ if ((lhs->EvalConstExpr() != NULL) && (rhs->EvalConstExpr() != NULL)) {
+ Instance& expr_value = Instance::ZoneHandle(Z);
+ if (!GetCachedConstant(op_pos, &expr_value)) {
+ expr_value = EvaluateConstExpr(lhs->token_pos(), lhs).raw();
+ if (expr_value.IsNull()) {
+ expr_value = EvaluateConstExpr(rhs->token_pos(), rhs).raw();
+ }
+ CacheConstantValue(op_pos, expr_value);
+ }
+ return new(Z) LiteralNode(op_pos, expr_value);
+ }
+
LetNode* result = new(Z) LetNode(op_pos);
LocalVariable* left_temp = result->AddInitializer(lhs);
- const intptr_t no_pos = Scanner::kNoSourcePos;
+ left_temp->set_is_final();
+ const intptr_t no_pos = Token::kNoSourcePos;
LiteralNode* null_operand =
new(Z) LiteralNode(no_pos, Object::null_instance());
LoadLocalNode* load_left_temp = new(Z) LoadLocalNode(no_pos, left_temp);
@@ -10814,6 +10778,8 @@
Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
const intptr_t expr_pos = TokenPos();
+ RecursionChecker rc(this);
+
if (CurrentToken() == Token::kTHROW) {
if (require_compiletime_const) {
ReportError("'throw expr' is not a valid compile-time constant");
@@ -11861,16 +11827,15 @@
const AbstractType* Parser::ReceiverType(const Class& cls) {
ASSERT(!cls.IsNull());
+ ASSERT(!cls.IsTypedefClass());
+ // Note that if cls is _Closure, the returned type will be _Closure,
+ // and not the signature type.
Type& type = Type::ZoneHandle(Z, cls.CanonicalType());
if (!type.IsNull()) {
return &type;
}
- if (cls.IsSignatureClass()) {
- type = cls.SignatureType();
- } else {
- type = Type::New(cls,
- TypeArguments::Handle(Z, cls.type_parameters()), cls.token_pos());
- }
+ type = Type::New(cls,
+ TypeArguments::Handle(Z, cls.type_parameters()), cls.token_pos());
if (cls.is_type_finalized()) {
type ^= ClassFinalizer::FinalizeType(
cls, type, ClassFinalizer::kCanonicalizeWellFormed);
@@ -11887,7 +11852,7 @@
!current_function().IsInFactoryScope()) {
return false;
}
- return current_class().NumTypeParameters() > 0;
+ return current_class().IsGeneric();
}
// We cache computed compile-time constants in a map so we can look them
@@ -12447,7 +12412,7 @@
bool consume_unresolved_prefix) {
LibraryPrefix& prefix = LibraryPrefix::Handle(Z);
return ParseType(finalization, allow_deferred_type,
- consume_unresolved_prefix, &prefix);
+ consume_unresolved_prefix, &prefix);
}
// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
@@ -13132,19 +13097,12 @@
closure.set_result_type(Object::dynamic_type());
AddFormalParamsToFunction(¶ms, closure);
- // Create and set the signature class of the closure.
- const String& sig = String::Handle(Z, closure.Signature());
- Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
- if (sig_cls.IsNull()) {
- sig_cls = Class::NewSignatureClass(sig, closure, script_, token_pos);
- library_.AddClass(sig_cls);
- }
- closure.set_signature_class(sig_cls);
- // Finalize types in signature class here, so that the
- // signature type is not computed twice.
- ClassFinalizer::FinalizeTypesInClass(sig_cls);
- const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
- ASSERT(sig_type.IsFinalized());
+ // Finalize function type.
+ FunctionType& signature_type =
+ FunctionType::Handle(Z, closure.SignatureType());
+ signature_type ^= ClassFinalizer::FinalizeType(
+ current_class(), signature_type, ClassFinalizer::kCanonicalize);
+ closure.SetSignatureType(signature_type);
// Finalization would be premature when top-level parsing.
ASSERT(!is_top_level_);
return closure.raw();
@@ -14318,7 +14276,7 @@
} // namespace dart
-#else // DART_PRECOMPILED
+#else // DART_PRECOMPILED_RUNTIME
namespace dart {
@@ -14402,4 +14360,4 @@
} // namespace dart
-#endif // DART_PRECOMPILED
+#endif // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 1be0f50..9d9e503 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -36,6 +36,7 @@
struct ParamList;
struct QualIdent;
class TopLevel;
+class RecursionChecker;
// The class ParsedFunction holds the result of parsing a function.
class ParsedFunction : public ZoneAllocated {
@@ -294,6 +295,7 @@
}
intptr_t TokenPos() const { return tokens_iterator_.CurrentPosition(); }
+ intptr_t PrevTokenPos() const { return prev_token_pos_; }
Token::Kind CurrentToken() {
if (token_kind_ == Token::kILLEGAL) {
@@ -316,6 +318,7 @@
void ConsumeToken() {
// Reset cache and advance the token.
+ prev_token_pos_ = tokens_iterator_.CurrentPosition();
token_kind_ = Token::kILLEGAL;
tokens_iterator_.Advance();
INC_STAT(thread(), num_tokens_consumed, 1);
@@ -363,6 +366,9 @@
const Function& constructor,
const TypeArguments& type_arguments);
+ // Report error if parsed code is too deeply nested; avoid stack overflow.
+ void CheckStack();
+
// Report already formatted error.
static void ReportError(const Error& error);
@@ -374,6 +380,8 @@
// Report error message at location of current token in current script.
void ReportError(const char* msg, ...) const PRINTF_ATTRIBUTE(2, 3);
+ void ReportErrorBefore(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+
// Report error message at given location in current script.
void ReportError(intptr_t token_pos,
const char* msg, ...) const PRINTF_ATTRIBUTE(3, 4);
@@ -533,7 +541,7 @@
void AddFormalParamsToScope(const ParamList* params, LocalScope* scope);
SequenceNode* ParseConstructor(const Function& func);
- SequenceNode* ParseFunc(const Function& func);
+ SequenceNode* ParseFunc(const Function& func, bool check_semicolon);
void ParseNativeFunctionBlock(const ParamList* params, const Function& func);
@@ -833,6 +841,7 @@
Script& script_;
TokenStream::Iterator tokens_iterator_;
Token::Kind token_kind_; // Cached token kind for current token.
+ intptr_t prev_token_pos_;
Block* current_block_;
// is_top_level_ is true if parsing the "top level" of a compilation unit,
@@ -889,6 +898,9 @@
// Indentation of parser trace.
intptr_t trace_indent_;
+ intptr_t recursion_counter_;
+ friend class RecursionChecker;
+
DISALLOW_COPY_AND_ASSIGN(Parser);
};
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index e7450b7..a5e6f2e 100644
--- a/runtime/vm/parser_test.cc
+++ b/runtime/vm/parser_test.cc
@@ -270,7 +270,7 @@
" name=:current_context_var\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -309,7 +309,7 @@
" name=:current_context_var\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -325,7 +325,7 @@
" 3 StackVar scope=2 begin=18 end=38 name=c\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -368,7 +368,7 @@
" name=:current_context_var\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -384,7 +384,7 @@
" 3 StackVar scope=2 begin=30 end=52 name=bb\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -397,7 +397,7 @@
" 2 StackVar scope=2 begin=18 end=62 name=aa\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -450,7 +450,7 @@
" name=:current_context_var\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -495,7 +495,7 @@
" name=:current_context_var\n"
// Closure call saves current context.
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -536,7 +536,7 @@
" 0 ContextVar level=0 begin=50 end=62 name=x\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
@@ -551,7 +551,7 @@
" 4 ContextVar level=1 begin=22 end=47 name=i\n"
" 5 StackVar scope=4 begin=32 end=47 name=d\n"
- "_FunctionImpl.call\n"
+ "_Closure.call\n"
" 0 StackVar scope=1 begin=0 end=4 name=this\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 97f90c3..2131faf 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -63,6 +63,7 @@
class_count_(0),
selector_count_(0),
dropped_function_count_(0),
+ dropped_field_count_(0),
libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())),
pending_functions_(
GrowableObjectArray::Handle(Z, GrowableObjectArray::New())),
@@ -111,6 +112,7 @@
}
DropUncompiledFunctions();
+ DropFields();
// TODO(rmacnak): DropEmptyClasses();
@@ -120,14 +122,18 @@
if (FLAG_trace_precompiler) {
THR_Print("Precompiled %" Pd " functions, %" Pd " dynamic types,"
- " %" Pd " dynamic selectors.\n Dropped %" Pd " functions.\n",
+ " %" Pd " dynamic selectors.\n Dropped %" Pd " functions, %" Pd
+ " fields.\n",
function_count_,
class_count_,
selector_count_,
- dropped_function_count_);
+ dropped_function_count_,
+ dropped_field_count_);
}
I->set_compilation_allowed(false);
+ I->object_store()->set_compile_time_constants(Array::null_array());
+ I->object_store()->set_unique_dynamic_targets(Array::null_array());
}
@@ -154,6 +160,7 @@
static const intptr_t kExternallyAllocatedCids[] = {
kBoolCid,
kNullCid,
+ kClosureCid,
kSmiCid,
kMintCid,
@@ -201,6 +208,7 @@
kFloat64x2Cid,
kTypeCid,
+ kFunctionTypeCid,
kTypeRefCid,
kTypeParameterCid,
kBoundedTypeCid,
@@ -224,6 +232,7 @@
}
Dart_QualifiedFunctionName vm_entry_points[] = {
+ // Functions
{ "dart:async", "::", "_setScheduleImmediateClosure" },
{ "dart:core", "::", "_completeDeferredLoads"},
{ "dart:core", "AbstractClassInstantiationError",
@@ -262,6 +271,9 @@
{ "dart:_vmservice", "::", "_registerIsolate" },
{ "dart:_vmservice", "::", "boot" },
{ "dart:developer", "Metrics", "_printMetrics" },
+ // Fields
+ { "dart:core", "Error", "_stackTrace" },
+ { "dart:math", "_Random", "_state" },
{ NULL, NULL, NULL } // Must be terminated with NULL entries.
};
@@ -274,6 +286,7 @@
Library& lib = Library::Handle(Z);
Class& cls = Class::Handle(Z);
Function& func = Function::Handle(Z);
+ Field& field = Field::Handle(Z);
String& library_uri = String::Handle(Z);
String& class_name = String::Handle(Z);
String& function_name = String::Handle(Z);
@@ -293,6 +306,7 @@
if (class_name.raw() == Symbols::TopLevel().raw()) {
func = lib.LookupFunctionAllowPrivate(function_name);
+ field = lib.LookupFieldAllowPrivate(function_name);
} else {
cls = lib.LookupClassAllowPrivate(class_name);
if (cls.IsNull()) {
@@ -306,25 +320,31 @@
ASSERT(!cls.IsNull());
func = cls.LookupFunctionAllowPrivate(function_name);
+ field = cls.LookupField(function_name);
}
- if (func.IsNull()) {
+ if (func.IsNull() && field.IsNull()) {
if (FLAG_trace_precompiler) {
THR_Print("WARNING: Missing %s %s %s\n",
entry_points[i].library_uri,
entry_points[i].class_name,
entry_points[i].function_name);
}
- continue;
}
- AddFunction(func);
- if (func.IsGenerativeConstructor()) {
- // Allocation stubs are referenced from the call site of the constructor,
- // not in the constructor itself. So compiling the constructor isn't
- // enough for us to discover the class is instantiated if the class isn't
- // otherwise instantiated from Dart code and only instantiated from C++.
- AddInstantiatedClass(cls);
+ if (!func.IsNull()) {
+ AddFunction(func);
+ if (func.IsGenerativeConstructor()) {
+ // Allocation stubs are referenced from the call site of the
+ // constructor, not in the constructor itself. So compiling the
+ // constructor isn't enough for us to discover the class is
+ // instantiated if the class isn't otherwise instantiated from Dart
+ // code and only instantiated from C++.
+ AddInstantiatedClass(cls);
+ }
+ }
+ if (!field.IsNull()) {
+ AddField(field);
}
}
}
@@ -468,7 +488,8 @@
if (instance.IsClosure()) {
// An implicit static closure.
- const Function& func = Function::Handle(Z, Closure::function(instance));
+ const Function& func =
+ Function::Handle(Z, Closure::Cast(instance).function());
ASSERT(func.is_static());
AddFunction(func);
return;
@@ -511,10 +532,8 @@
void Precompiler::AddClosureCall(const ICData& call_site) {
const Array& arguments_descriptor =
Array::Handle(Z, call_site.arguments_descriptor());
- const Type& function_impl =
- Type::Handle(Z, I->object_store()->function_impl_type());
const Class& cache_class =
- Class::Handle(Z, function_impl.type_class());
+ Class::Handle(Z, I->object_store()->closure_class());
const Function& dispatcher = Function::Handle(Z,
cache_class.GetInvocationDispatcher(Symbols::Call(),
arguments_descriptor,
@@ -525,6 +544,8 @@
void Precompiler::AddField(const Field& field) {
+ fields_to_retain_.Insert(&Field::ZoneHandle(Z, field.raw()));
+
if (field.is_static()) {
const Object& value = Object::Handle(Z, field.StaticValue());
if (value.IsInstance()) {
@@ -906,12 +927,12 @@
}
}
- functions = Array::New(retained_functions.Length(), Heap::kOld);
- for (intptr_t j = 0; j < retained_functions.Length(); j++) {
- function ^= retained_functions.At(j);
- functions.SetAt(j, function);
+ if (retained_functions.Length() > 0) {
+ functions = Array::MakeArray(retained_functions);
+ cls.SetFunctions(functions);
+ } else {
+ cls.SetFunctions(Object::empty_array());
}
- cls.SetFunctions(functions);
}
}
@@ -933,6 +954,49 @@
}
+void Precompiler::DropFields() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& fields = Array::Handle(Z);
+ Field& field = Field::Handle(Z);
+ GrowableObjectArray& retained_fields = GrowableObjectArray::Handle(Z);
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ if (cls.IsDynamicClass()) {
+ continue; // class 'dynamic' is in the read-only VM isolate.
+ }
+
+ fields = cls.fields();
+ retained_fields = GrowableObjectArray::New();
+ for (intptr_t j = 0; j < fields.Length(); j++) {
+ field ^= fields.At(j);
+ bool drop = fields_to_retain_.Lookup(&field) == NULL;
+ if (drop) {
+ dropped_field_count_++;
+ if (FLAG_trace_precompiler) {
+ THR_Print("Precompilation dropping %s\n",
+ field.ToCString());
+ }
+ } else {
+ retained_fields.Add(field);
+ }
+ }
+
+ if (retained_fields.Length() > 0) {
+ fields = Array::MakeArray(retained_fields);
+ cls.SetFields(fields);
+ } else {
+ cls.SetFields(Object::empty_array());
+ }
+ }
+ }
+}
+
+
void Precompiler::BindStaticCalls() {
class BindStaticCallsVisitor : public FunctionVisitor {
public:
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 50f9551..fe7ec2d 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -87,6 +87,29 @@
typedef DirectChainedHashMap<FunctionKeyValueTrait> FunctionSet;
+class FieldKeyValueTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef const Field* Key;
+ typedef const Field* Value;
+ typedef const Field* Pair;
+
+ static Key KeyOf(Pair kv) { return kv; }
+
+ static Value ValueOf(Pair kv) { return kv; }
+
+ static inline intptr_t Hashcode(Key key) {
+ return key->token_pos();
+ }
+
+ static inline bool IsKeyEqual(Pair pair, Key key) {
+ return pair->raw() == key->raw();
+ }
+};
+
+typedef DirectChainedHashMap<FieldKeyValueTrait> FieldSet;
+
+
class Precompiler : public ValueObject {
public:
static RawError* CompileAll(
@@ -125,6 +148,7 @@
void CheckForNewDynamicFunctions();
void DropUncompiledFunctions();
+ void DropFields();
void CollectDynamicFunctionNames();
void BindStaticCalls();
void DedupStackmaps();
@@ -155,11 +179,13 @@
intptr_t class_count_;
intptr_t selector_count_;
intptr_t dropped_function_count_;
+ intptr_t dropped_field_count_;
const GrowableObjectArray& libraries_;
const GrowableObjectArray& pending_functions_;
SymbolSet sent_selectors_;
FunctionSet enqueued_functions_;
+ FieldSet fields_to_retain_;
Error& error_;
};
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 63ac759..4c30971 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -853,7 +853,7 @@
}
-TEST_CASE(Profiler_ClassAllocation) {
+TEST_CASE(Profiler_ClosureAllocation) {
DisableNativeProfileScope dnps;
const char* kScript =
"var msg1 = 'a';\n"
@@ -875,12 +875,12 @@
root_library ^= Api::UnwrapHandle(lib);
Isolate* isolate = thread->isolate();
- const Class& class_class =
- Class::Handle(Object::class_class());
- EXPECT(!class_class.IsNull());
- class_class.SetTraceAllocation(true);
+ const Class& closure_class =
+ Class::Handle(Isolate::Current()->object_store()->closure_class());
+ EXPECT(!closure_class.IsNull());
+ closure_class.SetTraceAllocation(true);
- // Invoke "foo" which during compilation, triggers a closure class allocation.
+ // Invoke "foo" which during compilation, triggers a closure allocation.
Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
EXPECT_VALID(result);
@@ -888,7 +888,7 @@
StackZone zone(thread);
HANDLESCOPE(thread);
Profile profile(isolate);
- AllocationFilter filter(isolate, class_class.id());
+ AllocationFilter filter(isolate, closure_class.id());
filter.set_enable_vm_ticks(true);
profile.Build(thread, &filter, Profile::kNoTags);
// We should have one allocation sample.
@@ -897,19 +897,14 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
-#if defined(TARGET_OS_WINDOWS)
- // TODO(johnmccutchan): Hookup native symbol resolver on Windows.
- EXPECT_SUBSTRING("[Native]", walker.CurrentName());
-#else
- EXPECT_SUBSTRING("dart::Profiler::SampleAllocation", walker.CurrentName());
-#endif
+ EXPECT_SUBSTRING("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
- // Disable allocation tracing for Class.
- class_class.SetTraceAllocation(false);
+ // Disable allocation tracing for Closure.
+ closure_class.SetTraceAllocation(false);
- // Invoke "bar" which during compilation, triggers a closure class allocation.
+ // Invoke "bar" which during compilation, triggers a closure allocation.
result = Dart_Invoke(lib, NewString("bar"), 0, NULL);
EXPECT_VALID(result);
@@ -917,7 +912,7 @@
StackZone zone(thread);
HANDLESCOPE(thread);
Profile profile(isolate);
- AllocationFilter filter(isolate, class_class.id());
+ AllocationFilter filter(isolate, closure_class.id());
filter.set_enable_vm_ticks(true);
profile.Build(thread, &filter, Profile::kNoTags);
// We should still only have one allocation sample.
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index ba53d37..d32b5ab 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -144,6 +144,13 @@
instance_size = PcDescriptors::InstanceSize(length);
break;
}
+ case kCodeSourceMapCid: {
+ const RawCodeSourceMap* raw_code_source_map =
+ reinterpret_cast<const RawCodeSourceMap*>(this);
+ intptr_t length = raw_code_source_map->ptr()->length_;
+ instance_size = CodeSourceMap::InstanceSize(length);
+ break;
+ }
case kStackmapCid: {
const RawStackmap* map = reinterpret_cast<const RawStackmap*>(this);
intptr_t length = map->ptr()->length_;
@@ -336,6 +343,13 @@
}
+intptr_t RawFunctionType::VisitFunctionTypePointers(
+ RawFunctionType* raw_obj, ObjectPointerVisitor* visitor) {
+ visitor->VisitPointers(raw_obj->from(), raw_obj->to());
+ return FunctionType::InstanceSize();
+}
+
+
intptr_t RawTypeRef::VisitTypeRefPointers(
RawTypeRef* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
@@ -379,6 +393,13 @@
}
+intptr_t RawClosure::VisitClosurePointers(
+ RawClosure* raw_obj, ObjectPointerVisitor* visitor) {
+ visitor->VisitPointers(raw_obj->from(), raw_obj->to());
+ return Closure::InstanceSize();
+}
+
+
intptr_t RawClosureData::VisitClosureDataPointers(
RawClosureData* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
@@ -575,6 +596,12 @@
}
+intptr_t RawCodeSourceMap::VisitCodeSourceMapPointers(
+ RawCodeSourceMap* raw_obj, ObjectPointerVisitor* visitor) {
+ return CodeSourceMap::InstanceSize(raw_obj->ptr()->length_);
+}
+
+
intptr_t RawStackmap::VisitStackmapPointers(RawStackmap* raw_obj,
ObjectPointerVisitor* visitor) {
return Stackmap::InstanceSize(raw_obj->ptr()->length_);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ee5450d..35be68a 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -33,6 +33,7 @@
V(Instructions) \
V(ObjectPool) \
V(PcDescriptors) \
+ V(CodeSourceMap) \
V(Stackmap) \
V(LocalVarDescriptors) \
V(ExceptionHandlers) \
@@ -50,10 +51,12 @@
V(LibraryPrefix) \
V(AbstractType) \
V(Type) \
+ V(FunctionType) \
V(TypeRef) \
V(TypeParameter) \
V(BoundedType) \
V(MixinAppType) \
+ V(Closure) \
V(Number) \
V(Integer) \
V(Smi) \
@@ -145,9 +148,10 @@
#define DEFINE_OBJECT_KIND(clazz) \
kTypedData##clazz##ViewCid,
CLASS_LIST_TYPED_DATA(DEFINE_OBJECT_KIND)
- kByteDataViewCid,
#undef DEFINE_OBJECT_KIND
+ kByteDataViewCid,
+
#define DEFINE_OBJECT_KIND(clazz) \
kExternalTypedData##clazz##Cid,
CLASS_LIST_TYPED_DATA(DEFINE_OBJECT_KIND)
@@ -590,8 +594,8 @@
friend class Array;
friend class Bigint;
friend class ByteBuffer;
- friend class Code;
friend class Closure;
+ friend class Code;
friend class Double;
friend class FreeListElement;
friend class Function;
@@ -659,7 +663,7 @@
RawTypeArguments* type_parameters_; // Array of TypeParameter.
RawAbstractType* super_type_;
RawType* mixin_; // Generic mixin type, e.g. M<T>, not M<int>.
- RawFunction* signature_function_; // Associated function for signature class.
+ RawFunction* signature_function_; // Associated function for typedef class.
RawArray* constants_; // Canonicalized values of this class.
RawObject* canonical_types_; // An array of canonicalized types of this class
// or the canonical type.
@@ -830,7 +834,7 @@
}
RawContextScope* context_scope_;
RawFunction* parent_function_; // Enclosing function of this local function.
- RawClass* signature_class_;
+ RawFunctionType* signature_type_;
RawInstance* closure_; // Closure object for static implicit closures.
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->closure_);
@@ -1052,6 +1056,7 @@
RawObject* owner_; // Function, Null, or a Class.
RawExceptionHandlers* exception_handlers_;
RawPcDescriptors* pc_descriptors_;
+ RawCodeSourceMap* code_source_map_;
RawArray* stackmaps_;
RawObject** to_snapshot() {
return reinterpret_cast<RawObject**>(&ptr()->stackmaps_);
@@ -1199,6 +1204,23 @@
};
+// CodeSourceMap stores a mapping between code PC ranges and source token
+// positions.
+class RawCodeSourceMap : public RawObject {
+ private:
+ RAW_HEAP_OBJECT_IMPLEMENTATION(CodeSourceMap);
+
+ int32_t length_; // Number of entries.
+
+ // Variable length data follows here.
+ uint8_t* data() { OPEN_ARRAY_START(uint8_t, intptr_t); }
+ const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, intptr_t); }
+
+ friend class Object;
+ friend class SnapshotReader;
+};
+
+
// Stackmap is an immutable representation of the layout of the stack at a
// PC. The stack map representation consists of a bit map which marks each
// live object index starting from the base of the frame.
@@ -1471,6 +1493,7 @@
return reinterpret_cast<RawObject**>(&ptr()->formatted_message_);
}
int32_t token_pos_; // Source position in script_.
+ bool report_after_token_; // Report message at or after the token.
int8_t kind_; // Of type LanguageError::Kind.
};
@@ -1562,6 +1585,25 @@
};
+class RawFunctionType : public RawAbstractType {
+ private:
+ RAW_HEAP_OBJECT_IMPLEMENTATION(FunctionType);
+
+ RawObject** from() {
+ return reinterpret_cast<RawObject**>(&ptr()->scope_class_);
+ }
+ RawClass* scope_class_;
+ RawTypeArguments* arguments_;
+ RawFunction* signature_;
+ RawLanguageError* error_; // Error object if type is malformed or malbounded.
+ RawObject** to() {
+ return reinterpret_cast<RawObject**>(&ptr()->error_);
+ }
+ int32_t token_pos_;
+ int8_t type_state_;
+};
+
+
class RawTypeRef : public RawAbstractType {
private:
RAW_HEAP_OBJECT_IMPLEMENTATION(TypeRef);
@@ -1624,6 +1666,24 @@
};
+class RawClosure : public RawInstance {
+ private:
+ RAW_HEAP_OBJECT_IMPLEMENTATION(Closure);
+
+ RawObject** from() {
+ return reinterpret_cast<RawObject**>(&ptr()->type_arguments_);
+ }
+
+ RawTypeArguments* type_arguments_;
+ RawFunction* function_;
+ RawContext* context_;
+
+ RawObject** to() {
+ return reinterpret_cast<RawObject**>(&ptr()->context_);
+ }
+};
+
+
class RawNumber : public RawInstance {
RAW_OBJECT_IMPLEMENTATION(Number);
};
@@ -2245,6 +2305,7 @@
(index == kInstructionsCid) ||
(index == kObjectPoolCid) ||
(index == kPcDescriptorsCid) ||
+ (index == kCodeSourceMapCid) ||
(index == kStackmapCid) ||
(index == kLocalVarDescriptorsCid) ||
(index == kExceptionHandlersCid) ||
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 87305ba..3a934d5 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -237,7 +237,7 @@
READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), kAsReference);
// Set the canonical bit.
- if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
+ if (!defer_canonicalization && is_canonical) {
type.SetCanonical();
}
@@ -275,15 +275,89 @@
writer->Write<int32_t>(ptr()->token_pos_);
writer->Write<int8_t>(ptr()->type_state_);
- // Write out all the object pointer fields. Since we will be canonicalizing
- // the type object when reading it back we should write out all the fields
- // inline and not as references.
+ // Write out all the object pointer fields.
ASSERT(ptr()->type_class_ != Object::null());
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
+RawFunctionType* FunctionType::ReadFrom(SnapshotReader* reader,
+ intptr_t object_id,
+ intptr_t tags,
+ Snapshot::Kind kind,
+ bool as_reference) {
+ ASSERT(reader != NULL);
+
+ // Determine if the scope class of this function type is in the full snapshot.
+ bool scopeclass_is_in_fullsnapshot = reader->Read<bool>();
+
+ // Allocate function type object.
+ FunctionType& function_type =
+ FunctionType::ZoneHandle(reader->zone(), NEW_OBJECT(FunctionType));
+ bool is_canonical = RawObject::IsCanonical(tags);
+ bool defer_canonicalization = is_canonical &&
+ (kind != Snapshot::kFull && scopeclass_is_in_fullsnapshot);
+ reader->AddBackRef(object_id,
+ &function_type,
+ kIsDeserialized,
+ defer_canonicalization);
+
+ // Set all non object fields.
+ function_type.set_token_pos(reader->Read<int32_t>());
+ function_type.set_type_state(reader->Read<int8_t>());
+
+ // Set all the object fields.
+ READ_OBJECT_FIELDS(function_type,
+ function_type.raw()->from(), function_type.raw()->to(),
+ kAsReference);
+
+ // Set the canonical bit.
+ if (!defer_canonicalization && is_canonical) {
+ function_type.SetCanonical();
+ }
+
+ return function_type.raw();
+}
+
+
+void RawFunctionType::WriteTo(SnapshotWriter* writer,
+ intptr_t object_id,
+ Snapshot::Kind kind,
+ bool as_reference) {
+ ASSERT(writer != NULL);
+
+ // Only resolved and finalized function types should be written to a snapshot.
+ ASSERT((ptr()->type_state_ == RawFunctionType::kFinalizedInstantiated) ||
+ (ptr()->type_state_ == RawFunctionType::kFinalizedUninstantiated));
+ ASSERT(ptr()->scope_class_ != Object::null());
+
+ // Write out the serialization header value for this object.
+ writer->WriteInlinedObjectHeader(object_id);
+
+ // Write out the class and tags information.
+ writer->WriteIndexedObject(kFunctionTypeCid);
+ writer->WriteTags(writer->GetObjectTags(this));
+
+ // Write out scopeclass_is_in_fullsnapshot first as this will
+ // help the reader decide on how to canonicalize the type object.
+ intptr_t tags = writer->GetObjectTags(ptr()->scope_class_);
+ bool scopeclass_is_in_fullsnapshot =
+ (ClassIdTag::decode(tags) == kClassCid) &&
+ Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->scope_class_));
+ writer->Write<bool>(scopeclass_is_in_fullsnapshot);
+
+ // Write out all the non object pointer fields.
+ writer->Write<int32_t>(ptr()->token_pos_);
+ writer->Write<int8_t>(ptr()->type_state_);
+
+ // Write out all the object pointer fields.
+ ASSERT(ptr()->scope_class_ != Object::null());
+ SnapshotWriterVisitor visitor(writer, kAsReference);
+ visitor.VisitPointers(from(), to());
+}
+
+
RawTypeRef* TypeRef::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
@@ -472,7 +546,7 @@
}
// Set the canonical bit.
- if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
+ if (!defer_canonicalization && is_canonical) {
type_arguments.SetCanonical();
}
@@ -548,6 +622,57 @@
}
+RawClosure* Closure::ReadFrom(SnapshotReader* reader,
+ intptr_t object_id,
+ intptr_t tags,
+ Snapshot::Kind kind,
+ bool as_reference) {
+ ASSERT(reader != NULL);
+ ASSERT(kind == Snapshot::kFull);
+
+ // Allocate closure object.
+ Closure& closure = Closure::ZoneHandle(
+ reader->zone(), NEW_OBJECT(Closure));
+ reader->AddBackRef(object_id, &closure, kIsDeserialized);
+
+ // Set all the object fields.
+ READ_OBJECT_FIELDS(closure,
+ closure.raw()->from(), closure.raw()->to(),
+ kAsReference);
+
+ return closure.raw();
+}
+
+
+void RawClosure::WriteTo(SnapshotWriter* writer,
+ intptr_t object_id,
+ Snapshot::Kind kind,
+ bool as_reference) {
+ ASSERT(writer != NULL);
+ if ((kind == Snapshot::kMessage) || (kind == Snapshot::kScript)) {
+ // Check if closure is serializable, throw an exception otherwise.
+ RawFunction* func = writer->IsSerializableClosure(this);
+ if (func != Function::null()) {
+ writer->WriteStaticImplicitClosure(object_id,
+ func,
+ writer->GetObjectTags(this));
+ return;
+ }
+ }
+
+ // Write out the serialization header value for this object.
+ writer->WriteInlinedObjectHeader(object_id);
+
+ // Write out the class and tags information.
+ writer->WriteIndexedObject(kClosureCid);
+ writer->WriteTags(writer->GetObjectTags(this));
+
+ // Write out all the object pointer fields.
+ SnapshotWriterVisitor visitor(writer, kAsReference);
+ visitor.VisitPointers(from(), to());
+}
+
+
RawClosureData* ClosureData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
@@ -599,8 +724,8 @@
// Parent function.
writer->WriteObjectImpl(ptr()->parent_function_, kAsInlinedObject);
- // Signature class.
- writer->WriteObjectImpl(ptr()->signature_class_, kAsInlinedObject);
+ // Signature type.
+ writer->WriteObjectImpl(ptr()->signature_type_, kAsInlinedObject);
// Static closure/Closure allocation stub.
// We don't write the closure or allocation stub in the snapshot.
@@ -665,12 +790,15 @@
reader->zone(), NEW_OBJECT(Function));
reader->AddBackRef(object_id, &func, kIsDeserialized);
- // Set all the non object fields.
- func.set_token_pos(reader->Read<int32_t>());
- func.set_end_token_pos(reader->Read<int32_t>());
+ // Set all the non object fields. Read the token positions now but
+ // don't set them until after setting the kind.
+ const int32_t token_pos = reader->Read<int32_t>();
+ const int32_t end_token_pos = reader->Read<uint32_t>();
func.set_num_fixed_parameters(reader->Read<int16_t>());
func.set_num_optional_parameters(reader->Read<int16_t>());
func.set_kind_tag(reader->Read<uint32_t>());
+ func.set_token_pos(token_pos);
+ func.set_end_token_pos(end_token_pos);
if (reader->snapshot_code()) {
func.set_usage_counter(0);
func.set_deoptimization_counter(0);
@@ -720,7 +848,7 @@
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
bool is_in_fullsnapshot = false;
bool owner_is_class = false;
- if (kind == Snapshot::kScript) {
+ if ((kind == Snapshot::kScript) && !Function::IsSignatureFunction(this)) {
intptr_t tags = writer->GetObjectTags(ptr()->owner_);
intptr_t cid = ClassIdTag::decode(tags);
owner_is_class = (cid == kClassCid);
@@ -1107,26 +1235,27 @@
// The native resolver and symbolizer are not serialized.
library.set_native_entry_resolver(NULL);
library.set_native_entry_symbol_resolver(NULL);
- // The cache of loaded scripts is not serialized.
- library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null());
// Set all the object fields.
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
- RawObject** toobj = (kind == Snapshot::kFull) ?
- library.raw()->to() : library.raw()->to_snapshot();
- intptr_t num_flds = (toobj - library.raw()->from());
+ intptr_t num_flds = (library.raw()->to_snapshot() - library.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
(*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
library.StorePointer((library.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
+ // Initialize cache of resolved names.
+ const intptr_t kInitialNameCacheSize = 64;
if (kind != Snapshot::kFull) {
// The cache of resolved names in library scope is not serialized.
- const intptr_t kInitialNameCacheSize = 64;
library.InitResolvedNamesCache(kInitialNameCacheSize);
library.Register();
+ } else {
+ library.InitResolvedNamesCache(kInitialNameCacheSize, reader);
}
+ // Initialize cache of loaded scripts.
+ library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null());
}
return library.raw();
}
@@ -1165,14 +1294,13 @@
writer->Write<bool>(ptr()->debuggable_);
// We do not serialize the native resolver or symbolizer. These need to be
// explicitly set after deserialization.
- // We do not write the loaded_scripts_ cache to the snapshot. It gets
- // set to NULL when reading the library from the snapshot, and will
- // be rebuilt lazily.
+ // We do not write the loaded_scripts_ and resolved_names_ caches to the
+ // snapshot. They get initialized when reading the library from the
+ // snapshot and will be rebuilt lazily.
// Write out all the object pointer fields.
- RawObject** toobj = (kind == Snapshot::kFull) ? to() : to_snapshot();
SnapshotWriterVisitor visitor(writer, kAsReference);
- visitor.VisitPointers(from(), toobj);
+ visitor.VisitPointers(from(), to_snapshot());
}
}
@@ -1548,6 +1676,51 @@
}
+RawCodeSourceMap* CodeSourceMap::ReadFrom(SnapshotReader* reader,
+ intptr_t object_id,
+ intptr_t tags,
+ Snapshot::Kind kind,
+ bool as_reference) {
+ ASSERT(reader->snapshot_code());
+ ASSERT(kind == Snapshot::kFull);
+
+ const int32_t length = reader->Read<int32_t>();
+ CodeSourceMap& result =
+ CodeSourceMap::ZoneHandle(reader->zone(),
+ NEW_OBJECT_WITH_LEN(CodeSourceMap, length));
+ reader->AddBackRef(object_id, &result, kIsDeserialized);
+
+ if (result.Length() > 0) {
+ NoSafepointScope no_safepoint;
+ intptr_t len = result.Length();
+ uint8_t* data = result.UnsafeMutableNonPointer(result.raw_ptr()->data());
+ reader->ReadBytes(data, len);
+ }
+
+ return result.raw();
+}
+
+
+void RawCodeSourceMap::WriteTo(SnapshotWriter* writer,
+ intptr_t object_id,
+ Snapshot::Kind kind,
+ bool as_reference) {
+ ASSERT(writer->snapshot_code());
+ ASSERT(kind == Snapshot::kFull);
+
+ // Write out the serialization header value for this object.
+ writer->WriteInlinedObjectHeader(object_id);
+ writer->WriteIndexedObject(kCodeSourceMapCid);
+ writer->WriteTags(writer->GetObjectTags(this));
+ writer->Write<int32_t>(ptr()->length_);
+ if (ptr()->length_ > 0) {
+ intptr_t len = ptr()->length_;
+ uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
+ writer->WriteBytes(data, len);
+ }
+}
+
+
RawStackmap* Stackmap::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
@@ -2037,6 +2210,7 @@
// Set all non object fields.
language_error.set_token_pos(reader->Read<int32_t>());
+ language_error.set_report_after_token(reader->Read<bool>());
language_error.set_kind(reader->Read<uint8_t>());
// Set all the object fields.
@@ -2063,6 +2237,7 @@
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->token_pos_);
+ writer->Write<bool>(ptr()->report_after_token_);
writer->Write<uint8_t>(ptr()->kind_);
// Write out all the object pointer fields.
diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
index a41db46..40043b7 100644
--- a/runtime/vm/regexp_assembler_ir.cc
+++ b/runtime/vm/regexp_assembler_ir.cc
@@ -36,7 +36,7 @@
static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex;
-static const intptr_t kNoSourcePos = Scanner::kNoSourcePos;
+static const intptr_t kNoSourcePos = Token::kNoSourcePos;
static const intptr_t kMinStackSize = 512;
@@ -588,13 +588,13 @@
LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const {
- return new(Z) LoadLocalInstr(*local);
+ return new(Z) LoadLocalInstr(*local, kNoSourcePos);
}
void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local,
Value* value) {
- Do(new(Z) StoreLocalInstr(*local, value));
+ Do(new(Z) StoreLocalInstr(*local, value, kNoSourcePos));
}
@@ -621,7 +621,7 @@
return Bind(new(Z) ConstantInstr(*local.ConstValue()));
}
ASSERT(!local.is_captured());
- return Bind(new(Z) LoadLocalInstr(local));
+ return Bind(new(Z) LoadLocalInstr(local, kNoSourcePos));
}
@@ -1924,7 +1924,7 @@
index_val,
characters,
specialization_cid_,
- Scanner::kNoSourcePos));
+ kNoSourcePos));
}
diff --git a/runtime/vm/report.cc b/runtime/vm/report.cc
index d09d2a9..e5ab2ec 100644
--- a/runtime/vm/report.cc
+++ b/runtime/vm/report.cc
@@ -26,6 +26,7 @@
RawString* Report::PrependSnippet(Kind kind,
const Script& script,
intptr_t token_pos,
+ bool report_after_token,
const String& message) {
const char* message_header;
switch (kind) {
@@ -41,8 +42,11 @@
if (!script.IsNull()) {
const String& script_url = String::Handle(script.url());
if (token_pos >= 0) {
- intptr_t line, column;
- script.GetTokenLocation(token_pos, &line, &column);
+ intptr_t line, column, token_len;
+ script.GetTokenLocation(token_pos, &line, &column, &token_len);
+ if (report_after_token) {
+ column += token_len;
+ }
// Only report the line position if we have the original source. We still
// need to get a valid column so that we can report the ^ mark below the
// snippet.
@@ -120,7 +124,7 @@
const Script& script, intptr_t token_pos,
const char* format, va_list args) {
const Error& error = Error::Handle(LanguageError::NewFormattedV(
- prev_error, script, token_pos,
+ prev_error, script, token_pos, Report::AtLocation,
kError, Heap::kNew,
format, args));
LongJump(error);
@@ -129,15 +133,18 @@
void Report::MessageF(Kind kind, const Script& script, intptr_t token_pos,
- const char* format, ...) {
+ bool report_after_token, const char* format, ...) {
va_list args;
va_start(args, format);
- MessageV(kind, script, token_pos, format, args);
+ MessageV(kind, script, token_pos, report_after_token, format, args);
va_end(args);
}
-void Report::MessageV(Kind kind, const Script& script, intptr_t token_pos,
+void Report::MessageV(Kind kind,
+ const Script& script,
+ intptr_t token_pos,
+ bool report_after_token,
const char* format, va_list args) {
if (kind < kError) {
// Reporting a warning.
@@ -147,7 +154,7 @@
if (!FLAG_warning_as_error) {
const String& msg = String::Handle(String::NewFormattedV(format, args));
const String& snippet_msg = String::Handle(
- PrependSnippet(kind, script, token_pos, msg));
+ PrependSnippet(kind, script, token_pos, report_after_token, msg));
OS::Print("%s", snippet_msg.ToCString());
if (kind == kJSWarning) {
TraceJSWarning(script, token_pos, msg);
@@ -166,7 +173,7 @@
// Reporting an error (or a warning as error).
const Error& error = Error::Handle(
LanguageError::NewFormattedV(Error::Handle(), // No previous error.
- script, token_pos,
+ script, token_pos, report_after_token,
kind, Heap::kNew,
format, args));
if (kind == kJSWarning) {
@@ -232,7 +239,7 @@
const intptr_t token_pos = caller_code.GetTokenIndexOfPC(caller_pc);
const Function& caller = Function::Handle(zone, caller_code.function());
const Script& script = Script::Handle(zone, caller.script());
- MessageF(kJSWarning, script, token_pos, "%s", msg);
+ MessageF(kJSWarning, script, token_pos, Report::AtLocation, "%s", msg);
}
diff --git a/runtime/vm/report.h b/runtime/vm/report.h
index 8cc50a1..1a8d22a 100644
--- a/runtime/vm/report.h
+++ b/runtime/vm/report.h
@@ -28,6 +28,9 @@
kBailout,
};
+ static const bool AtLocation = false;
+ static const bool AfterLocation = true;
+
// Report an already formatted error via a long jump.
static void LongJump(const Error& error);
@@ -41,8 +44,10 @@
// Report a warning/jswarning/error/bailout message.
static void MessageF(Kind kind, const Script& script, intptr_t token_pos,
- const char* format, ...) PRINTF_ATTRIBUTE(4, 5);
+ bool report_after_token,
+ const char* format, ...) PRINTF_ATTRIBUTE(5, 6);
static void MessageV(Kind kind, const Script& script, intptr_t token_pos,
+ bool report_after_token,
const char* format, va_list args);
// Support to report Javascript compatibility warnings. Note that a
@@ -67,6 +72,7 @@
static RawString* PrependSnippet(Kind kind,
const Script& script,
intptr_t token_pos,
+ bool report_after_token,
const String& message);
private:
diff --git a/runtime/vm/report_test.cc b/runtime/vm/report_test.cc
index 6338f5b..95e469e 100644
--- a/runtime/vm/report_test.cc
+++ b/runtime/vm/report_test.cc
@@ -21,7 +21,8 @@
{
const intptr_t token_pos = 0;
const char* message = "High Voltage";
- Report::MessageF(Report::kJSWarning, script, token_pos, "%s", message);
+ Report::MessageF(Report::kJSWarning,
+ script, token_pos, Report::AtLocation, "%s", message);
{
JSONStream js;
trace_buffer->PrintToJSONStream(&js);
@@ -45,7 +46,8 @@
{
const intptr_t token_pos = 1;
const char* message = "Low Voltage";
- Report::MessageF(Report::kJSWarning, script, token_pos, "%s", message);
+ Report::MessageF(Report::kJSWarning,
+ script, token_pos, Report::AtLocation, "%s", message);
}
EXPECT_EQ(2, trace_buffer->Length());
EXPECT_SUBSTRING("{\"type\":\"JSCompatibilityWarning\",\"script\":{\"type\":"
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index f177a10..6e0b1bb 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -17,7 +17,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const String& function_name = String::ZoneHandle(Symbols::New(name));
const Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
diff --git a/runtime/vm/scanner.h b/runtime/vm/scanner.h
index 7a81040..5b35317 100644
--- a/runtime/vm/scanner.h
+++ b/runtime/vm/scanner.h
@@ -44,13 +44,6 @@
const String* literal; // Identifier, number or string literal.
};
- // Dummy token index reflecting an unknown source position.
- static const intptr_t kNoSourcePos = -1;
-
- static bool ValidSourcePosition(intptr_t token_pos) {
- return (token_pos >= 0) || (token_pos == kNoSourcePos);
- }
-
typedef ZoneGrowableArray<TokenDescriptor> GrowableTokenStream;
// Initializes scanner to scan string source.
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index 4c52227..9b609c1 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -29,8 +29,8 @@
loop_level_(loop_level),
context_level_(LocalScope::kUnitializedContextLevel),
num_context_variables_(0),
- begin_token_pos_(Scanner::kNoSourcePos),
- end_token_pos_(Scanner::kNoSourcePos),
+ begin_token_pos_(Token::kNoSourcePos),
+ end_token_pos_(Token::kNoSourcePos),
variables_(),
labels_(),
referenced_() {
diff --git a/runtime/vm/scopes_test.cc b/runtime/vm/scopes_test.cc
index 3640937..c3ad21d 100644
--- a/runtime/vm/scopes_test.cc
+++ b/runtime/vm/scopes_test.cc
@@ -14,18 +14,18 @@
const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
const String& a = String::ZoneHandle(Symbols::New("a"));
LocalVariable* var_a =
- new LocalVariable(Scanner::kNoSourcePos, a, dynamic_type);
+ new LocalVariable(Token::kNoSourcePos, a, dynamic_type);
LocalVariable* inner_var_a =
- new LocalVariable(Scanner::kNoSourcePos, a, dynamic_type);
+ new LocalVariable(Token::kNoSourcePos, a, dynamic_type);
const String& b = String::ZoneHandle(Symbols::New("b"));
LocalVariable* var_b =
- new LocalVariable(Scanner::kNoSourcePos, b, dynamic_type);
+ new LocalVariable(Token::kNoSourcePos, b, dynamic_type);
const String& c = String::ZoneHandle(Symbols::New("c"));
LocalVariable* var_c =
- new LocalVariable(Scanner::kNoSourcePos, c, dynamic_type);
+ new LocalVariable(Token::kNoSourcePos, c, dynamic_type);
const String& L = String::ZoneHandle(Symbols::New("L"));
SourceLabel* label_L =
- new SourceLabel(Scanner::kNoSourcePos, L, SourceLabel::kFor);
+ new SourceLabel(Token::kNoSourcePos, L, SourceLabel::kFor);
LocalScope* outer_scope = new LocalScope(NULL, 0, 0);
LocalScope* inner_scope1 = new LocalScope(outer_scope, 0, 0);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 631a4ec..8991390 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2311,13 +2311,15 @@
}
-static const char* kCallSitesStr = "CallSites";
+static const char* kCallSitesStr = "_CallSites";
static const char* kCoverageStr = "Coverage";
+static const char* kPossibleBreakpointsStr = "PossibleBreakpoints";
static const char* const report_enum_names[] = {
kCallSitesStr,
kCoverageStr,
+ kPossibleBreakpointsStr,
NULL,
};
@@ -2346,6 +2348,8 @@
report_set |= SourceReport::kCallSites;
} else if (strcmp(*reports, kCoverageStr) == 0) {
report_set |= SourceReport::kCoverage;
+ } else if (strcmp(*reports, kPossibleBreakpointsStr) == 0) {
+ report_set |= SourceReport::kPossibleBreakpoints;
}
reports++;
}
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index a57296f..a1c1d5c 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -28,6 +28,9 @@
namespace dart {
+DECLARE_FLAG(bool, use_field_guards);
+
+
static const int kNumVmIsolateSnapshotReferences = 32 * KB;
static const int kNumInitialReferencesInFullSnapshot = 160 * KB;
static const int kNumInitialReferences = 64;
@@ -480,6 +483,8 @@
AddBackRef(object_id, result, state);
cls_ ^= ReadObjectImpl(kAsInlinedObject);
ASSERT(!cls_.IsNull());
+ // Closure instances are handled by Closure::ReadFrom().
+ ASSERT(!cls_.IsClosureClass());
instance_size = cls_.instance_size();
ASSERT(instance_size > 0);
// Allocate the instance and read in all the fields for the object.
@@ -495,8 +500,7 @@
}
if (!as_reference) {
// Read all the individual fields for inlined objects.
- intptr_t next_field_offset = Class::IsSignatureClass(cls_.raw())
- ? Closure::InstanceSize() : cls_.next_field_offset();
+ intptr_t next_field_offset = cls_.next_field_offset();
intptr_t type_argument_field_offset = cls_.type_arguments_field_offset();
ASSERT(next_field_offset > 0);
@@ -509,7 +513,8 @@
pobj_ = ReadObjectImpl(read_as_reference);
result->SetFieldAtOffset(offset, pobj_);
if ((offset != type_argument_field_offset) &&
- (kind_ == Snapshot::kMessage)) {
+ (kind_ == Snapshot::kMessage) &&
+ FLAG_use_field_guards) {
// TODO(fschneider): Consider hoisting these lookups out of the loop.
// This would involve creating a handle, since cls_ can't be reused
// across the call to ReadObjectImpl.
@@ -781,6 +786,17 @@
}
+RawCodeSourceMap* SnapshotReader::NewCodeSourceMap(intptr_t len) {
+ ASSERT(kind_ == Snapshot::kFull);
+ ASSERT_NO_SAFEPOINT_SCOPE();
+ RawCodeSourceMap* obj = reinterpret_cast<RawCodeSourceMap*>(
+ AllocateUninitialized(kCodeSourceMapCid,
+ CodeSourceMap::InstanceSize(len)));
+ obj->ptr()->length_ = len;
+ return obj;
+}
+
+
RawStackmap* SnapshotReader::NewStackmap(intptr_t len) {
ASSERT(kind_ == Snapshot::kFull);
ASSERT_NO_SAFEPOINT_SCOPE();
@@ -921,6 +937,11 @@
}
+RawFunctionType* SnapshotReader::NewFunctionType() {
+ ALLOC_NEW_OBJECT(FunctionType);
+}
+
+
RawTypeRef* SnapshotReader::NewTypeRef() {
ALLOC_NEW_OBJECT(TypeRef);
}
@@ -946,6 +967,11 @@
}
+RawClosure* SnapshotReader::NewClosure() {
+ ALLOC_NEW_OBJECT(Closure);
+}
+
+
RawClosureData* SnapshotReader::NewClosureData() {
ALLOC_NEW_OBJECT(ClosureData);
}
@@ -1389,16 +1415,20 @@
void SnapshotReader::ProcessDeferredCanonicalizations() {
Type& typeobj = Type::Handle();
+ FunctionType& funtypeobj = FunctionType::Handle();
TypeArguments& typeargs = TypeArguments::Handle();
Object& newobj = Object::Handle();
for (intptr_t i = 0; i < backward_references_->length(); i++) {
BackRefNode& backref = (*backward_references_)[i];
if (backref.defer_canonicalization()) {
Object* objref = backref.reference();
- // Object should either be an abstract type or a type argument.
+ // Object should either be a type, a function type, or a type argument.
if (objref->IsType()) {
typeobj ^= objref->raw();
newobj = typeobj.Canonicalize();
+ } else if (objref->IsFunctionType()) {
+ funtypeobj ^= objref->raw();
+ newobj = funtypeobj.Canonicalize();
} else {
ASSERT(objref->IsTypeArguments());
typeargs ^= objref->raw();
@@ -2321,33 +2351,28 @@
}
-RawFunction* SnapshotWriter::IsSerializableClosure(RawClass* cls,
- RawObject* obj) {
- if (Class::IsSignatureClass(cls)) {
- // 'obj' is a closure as its class is a signature class, extract
- // the function object to check if this closure can be sent in an
- // isolate message.
- RawFunction* func = Closure::GetFunction(obj);
- // We only allow closure of top level methods or static functions in a
- // class to be sent in isolate messages.
- if (can_send_any_object() &&
- Function::IsImplicitStaticClosureFunction(func)) {
- return func;
- }
- // Not a closure of a top level method or static function, throw an
- // exception as we do not allow these objects to be serialized.
- HANDLESCOPE(thread());
-
- const Class& clazz = Class::Handle(zone(), cls);
- const Function& errorFunc = Function::Handle(zone(), func);
- ASSERT(!errorFunc.IsNull());
-
- // All other closures are errors.
- char* chars = OS::SCreate(thread()->zone(),
- "Illegal argument in isolate message : (object is a closure - %s %s)",
- clazz.ToCString(), errorFunc.ToCString());
- SetWriteException(Exceptions::kArgument, chars);
+RawFunction* SnapshotWriter::IsSerializableClosure(RawClosure* closure) {
+ // Extract the function object to check if this closure
+ // can be sent in an isolate message.
+ RawFunction* func = closure->ptr()->function_;
+ // We only allow closure of top level methods or static functions in a
+ // class to be sent in isolate messages.
+ if (can_send_any_object() &&
+ Function::IsImplicitStaticClosureFunction(func)) {
+ return func;
}
+ // Not a closure of a top level method or static function, throw an
+ // exception as we do not allow these objects to be serialized.
+ HANDLESCOPE(thread());
+
+ const Function& errorFunc = Function::Handle(zone(), func);
+ ASSERT(!errorFunc.IsNull());
+
+ // All other closures are errors.
+ char* chars = OS::SCreate(thread()->zone(),
+ "Illegal argument in isolate message : (object is a closure - %s)",
+ errorFunc.ToCString());
+ SetWriteException(Exceptions::kArgument, chars);
return Function::null();
}
@@ -2393,20 +2418,12 @@
intptr_t tags,
intptr_t object_id,
bool as_reference) {
+ // Closure instances are handled by RawClosure::WriteTo().
+ ASSERT(!Class::IsClosureClass(cls));
+
// Check if the instance has native fields and throw an exception if it does.
CheckForNativeFields(cls);
- if ((kind() == Snapshot::kMessage) || (kind() == Snapshot::kScript)) {
- // Check if object is a closure that is serializable, if the object is a
- // closure that is not serializable this will throw an exception.
- RawFunction* func = IsSerializableClosure(cls, raw);
- if (func != Function::null()) {
- forward_list_->SetState(object_id, kIsSerialized);
- WriteStaticImplicitClosure(object_id, func, tags);
- return;
- }
- }
-
// Object is regular dart instance.
if (as_reference) {
// Write out the serialization header value for this object.
@@ -2419,8 +2436,7 @@
// Write out the class information for this object.
WriteObjectImpl(cls, kAsInlinedObject);
} else {
- intptr_t next_field_offset = Class::IsSignatureClass(cls) ?
- Closure::InstanceSize() :
+ intptr_t next_field_offset =
cls->ptr()->next_field_offset_in_words_ << kWordSizeLog2;
ASSERT(next_field_offset > 0);
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 8570a06..f635618 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -22,6 +22,7 @@
class Array;
class Class;
class ClassTable;
+class Closure;
class Code;
class ExternalTypedData;
class GrowableObjectArray;
@@ -40,7 +41,9 @@
class RawBoundedType;
class RawCapability;
class RawClass;
+class RawClosure;
class RawClosureData;
+class RawCodeSourceMap;
class RawContext;
class RawContextScope;
class RawDouble;
@@ -49,6 +52,7 @@
class RawFloat32x4;
class RawFloat64x2;
class RawFunction;
+class RawFunctionType;
class RawGrowableObjectArray;
class RawICData;
class RawImmutableArray;
@@ -412,17 +416,20 @@
RawDouble* NewDouble(double value);
RawUnresolvedClass* NewUnresolvedClass();
RawType* NewType();
+ RawFunctionType* NewFunctionType();
RawTypeRef* NewTypeRef();
RawTypeParameter* NewTypeParameter();
RawBoundedType* NewBoundedType();
RawMixinAppType* NewMixinAppType();
RawPatchClass* NewPatchClass();
+ RawClosure* NewClosure();
RawClosureData* NewClosureData();
RawRedirectionData* NewRedirectionData();
RawFunction* NewFunction();
RawCode* NewCode(intptr_t pointer_offsets_length);
RawObjectPool* NewObjectPool(intptr_t length);
RawPcDescriptors* NewPcDescriptors(intptr_t length);
+ RawCodeSourceMap* NewCodeSourceMap(intptr_t length);
RawLocalVarDescriptors* NewLocalVarDescriptors(intptr_t num_entries);
RawExceptionHandlers* NewExceptionHandlers(intptr_t num_entries);
RawStackmap* NewStackmap(intptr_t length);
@@ -558,6 +565,7 @@
friend class Bigint;
friend class BoundedType;
friend class Class;
+ friend class Closure;
friend class ClosureData;
friend class Code;
friend class Context;
@@ -588,6 +596,7 @@
friend class SubtypeTestCache;
friend class TokenStream;
friend class Type;
+ friend class FunctionType;
friend class TypeArguments;
friend class TypeParameter;
friend class TypeRef;
@@ -921,14 +930,17 @@
void WriteFunctionId(RawFunction* func, bool owner_is_class);
+ RawFunction* IsSerializableClosure(RawClosure* closure);
+
+ void WriteStaticImplicitClosure(intptr_t object_id,
+ RawFunction* func,
+ intptr_t tags);
+
protected:
bool CheckAndWritePredefinedObject(RawObject* raw);
bool HandleVMIsolateObject(RawObject* raw);
void WriteClassId(RawClass* cls);
- void WriteStaticImplicitClosure(intptr_t object_id,
- RawFunction* func,
- intptr_t tags);
void WriteObjectImpl(RawObject* raw, bool as_reference);
void WriteMarkedObjectImpl(RawObject* raw,
intptr_t tags,
@@ -942,7 +954,6 @@
RawTypeArguments* type_arguments,
RawObject* data[],
bool as_reference);
- RawFunction* IsSerializableClosure(RawClass* cls, RawObject* obj);
RawClass* GetFunctionOwner(RawFunction* func);
void CheckForNativeFields(RawClass* cls);
void SetWriteException(Exceptions::ExceptionType type, const char* msg);
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index 8c08726..93400bb 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -206,6 +206,44 @@
}
}
+void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj,
+ const Function& func,
+ const Code& code) {
+ const uint8_t kSafepointKind = (RawPcDescriptors::kIcCall |
+ RawPcDescriptors::kUnoptStaticCall |
+ RawPcDescriptors::kRuntimeCall);
+ const intptr_t begin_pos = func.token_pos();
+ const intptr_t end_pos = func.end_token_pos();
+
+ const PcDescriptors& descriptors = PcDescriptors::Handle(
+ zone(), code.pc_descriptors());
+
+ intptr_t func_length = (end_pos - begin_pos) + 1;
+ GrowableArray<char> possible(func_length);
+ possible.SetLength(func_length);
+ for (int i = 0; i < func_length; i++) {
+ possible[i] = false;
+ }
+
+ PcDescriptors::Iterator iter(descriptors, kSafepointKind);
+ while (iter.MoveNext()) {
+ const intptr_t token_pos = iter.TokenPos();
+ if ((token_pos < begin_pos) || (token_pos > end_pos)) {
+ // Does not correspond to a valid source position.
+ continue;
+ }
+ intptr_t token_offset = token_pos - begin_pos;
+ possible[token_offset] = true;
+ }
+
+ JSONArray bpts(jsobj, "possibleBreakpoints");
+ for (int i = 0; i < func_length; i++) {
+ if (possible[i]) {
+ bpts.AddValue(begin_pos + i); // Add the token position.
+ }
+ }
+}
+
void SourceReport::PrintScriptTable(JSONArray* scripts) {
for (int i = 0; i < script_table_entries_.length(); i++) {
@@ -265,6 +303,9 @@
if (IsReportRequested(kCoverage)) {
PrintCoverageData(&range, func, code);
}
+ if (IsReportRequested(kPossibleBreakpoints)) {
+ PrintPossibleBreakpointsData(&range, func, code);
+ }
}
diff --git a/runtime/vm/source_report.h b/runtime/vm/source_report.h
index 09c8092..9b03a23 100644
--- a/runtime/vm/source_report.h
+++ b/runtime/vm/source_report.h
@@ -18,8 +18,9 @@
class SourceReport {
public:
enum ReportKind {
- kCallSites = 0x1,
- kCoverage = 0x2,
+ kCallSites = 0x1,
+ kCoverage = 0x2,
+ kPossibleBreakpoints = 0x4,
};
enum CompileMode {
@@ -55,6 +56,8 @@
const Function& func, const Code& code);
void PrintCoverageData(JSONObject* jsobj,
const Function& func, const Code& code);
+ void PrintPossibleBreakpointsData(JSONObject* jsobj,
+ const Function& func, const Code& code);
void PrintScriptTable(JSONArray* jsarr);
void VisitFunction(JSONArray* jsarr, const Function& func);
diff --git a/runtime/vm/source_report_test.cc b/runtime/vm/source_report_test.cc
index 0e1bb79..b213a20 100644
--- a/runtime/vm/source_report_test.cc
+++ b/runtime/vm/source_report_test.cc
@@ -458,4 +458,49 @@
buffer);
}
+
+TEST_CASE(SourceReport_PossibleBreakpoints_Simple) {
+ char buffer[1024];
+ const char* kScript =
+ "helper0() {}\n"
+ "helper1() {}\n"
+ "main() {\n"
+ " if (true) {\n"
+ " helper0();\n"
+ " } else {\n"
+ " helper1();\n"
+ " }\n"
+ "}";
+
+ Library& lib = Library::Handle();
+ lib ^= ExecuteScript(kScript);
+ ASSERT(!lib.IsNull());
+ const Script& script = Script::Handle(lib.LookupScript(
+ String::Handle(String::New("test-lib"))));
+
+ SourceReport report(SourceReport::kPossibleBreakpoints);
+ JSONStream js;
+ report.PrintJSON(&js, script);
+ ElideJSONSubstring("classes", js.ToCString(), buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // helper0.
+ "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":4,\"compiled\":true,"
+ "\"possibleBreakpoints\":[1,4]},"
+
+ // One range not compiled (helper1).
+ "{\"scriptIndex\":0,\"startPos\":6,\"endPos\":10,\"compiled\":false},"
+
+ // main.
+ "{\"scriptIndex\":0,\"startPos\":12,\"endPos\":39,\"compiled\":true,"
+ "\"possibleBreakpoints\":[13,23,32,39]}],"
+
+ // Only one script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
} // namespace dart
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index ad3c995..d4be5b5 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -45,13 +45,13 @@
void StubCode::InitOnce() {
-#if !defined(DART_PRECOMPILED)
+#if !defined(DART_PRECOMPILED_RUNTIME)
// Generate all the stubs.
Code& code = Code::Handle();
VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
#else
UNREACHABLE();
-#endif // DART_PRECOMPILED
+#endif // DART_PRECOMPILED_RUNTIME
}
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 711c901..4cf291b 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1804,8 +1804,12 @@
// R3: instance class id.
// R4: instance type arguments.
__ SmiTag(R3);
+ __ CompareImmediate(R3, Smi::RawValue(kClosureCid));
+ __ ldr(R3, FieldAddress(R0, Closure::function_offset()), EQ);
+ // R3: instance class id as Smi or function.
__ Bind(&loop);
- __ ldr(R9, Address(R2, kWordSize * SubtypeTestCache::kInstanceClassId));
+ __ ldr(R9,
+ Address(R2, kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
__ CompareObject(R9, Object::null_object());
__ b(¬_found, EQ);
__ cmp(R9, Operand(R3));
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 0585653..5db34dc 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -1865,9 +1865,13 @@
// R3: instance class id.
// R4: instance type arguments.
__ SmiTag(R3);
+ __ CompareImmediate(R3, Smi::RawValue(kClosureCid));
+ __ b(&loop, NE);
+ __ LoadFieldFromOffset(R3, R0, Closure::function_offset());
+ // R3: instance class id as Smi or function.
__ Bind(&loop);
__ LoadFromOffset(
- R5, R2, kWordSize * SubtypeTestCache::kInstanceClassId);
+ R5, R2, kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction);
__ CompareObject(R5, Object::null_object());
__ b(¬_found, EQ);
__ CompareRegisters(R5, R3);
diff --git a/runtime/vm/stub_code_arm64_test.cc b/runtime/vm/stub_code_arm64_test.cc
index eba3949..a64d6f7 100644
--- a/runtime/vm/stub_code_arm64_test.cc
+++ b/runtime/vm/stub_code_arm64_test.cc
@@ -23,7 +23,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const Library& lib = Library::Handle(Library::New(class_name));
owner_class.set_library(lib);
const String& function_name = String::ZoneHandle(Symbols::New(name));
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index 39aa9e6..36d703e 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -23,7 +23,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const Library& lib = Library::Handle(Library::New(class_name));
owner_class.set_library(lib);
const String& function_name = String::ZoneHandle(Symbols::New(name));
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index b6302d3..e1e3fff 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1781,8 +1781,14 @@
// ECX: instance class id.
// EBX: instance type arguments.
__ SmiTag(ECX);
+ __ cmpl(ECX, Immediate(Smi::RawValue(kClosureCid)));
+ __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+ __ movl(ECX, FieldAddress(EAX, Closure::function_offset()));
+ // ECX: instance class id as Smi or function.
__ Bind(&loop);
- __ movl(EDI, Address(EDX, kWordSize * SubtypeTestCache::kInstanceClassId));
+ __ movl(EDI,
+ Address(EDX,
+ kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
__ cmpl(EDI, raw_null);
__ j(EQUAL, ¬_found, Assembler::kNearJump);
__ cmpl(EDI, ECX);
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index 1ab200b..fff4bc7 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -23,7 +23,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const Library& lib = Library::Handle(Library::New(class_name));
owner_class.set_library(lib);
const String& function_name = String::ZoneHandle(Symbols::New(name));
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 58af418..bd6567d 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -1943,8 +1943,12 @@
// T2: Entry start.
// T7: null.
__ SmiTag(T0);
+ __ BranchNotEqual(T0, Immediate(Smi::RawValue(kClosureCid)), &loop);
+ __ lw(T0, FieldAddress(A0, Closure::function_offset()));
+ // T0: instance class id as Smi or function.
__ Bind(&loop);
- __ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId));
+ __ lw(T3,
+ Address(T2, kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
__ beq(T3, T7, ¬_found);
if (n == 1) {
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index 512baaf..21e7768 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -23,7 +23,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const Library& lib = Library::Handle(Library::New(class_name));
owner_class.set_library(lib);
const String& function_name = String::ZoneHandle(Symbols::New(name));
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 39d8dc9..024fbfa 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -1841,8 +1841,14 @@
// R13: instance type arguments.
Label loop, found, not_found, next_iteration;
__ SmiTag(R10);
+ __ cmpq(R10, Immediate(Smi::RawValue(kClosureCid)));
+ __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+ __ movq(R10, FieldAddress(RAX, Closure::function_offset()));
+ // R10: instance class id as Smi or function.
__ Bind(&loop);
- __ movq(RDI, Address(RDX, kWordSize * SubtypeTestCache::kInstanceClassId));
+ __ movq(RDI,
+ Address(RDX,
+ kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
__ cmpq(RDI, R9);
__ j(EQUAL, ¬_found, Assembler::kNearJump);
__ cmpq(RDI, R10);
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index ff020e7..2716433 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -23,7 +23,7 @@
const String& class_name = String::Handle(Symbols::New("ownerClass"));
const Script& script = Script::Handle();
const Class& owner_class =
- Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+ Class::Handle(Class::New(class_name, script, Token::kNoSourcePos));
const Library& lib = Library::Handle(Library::New(class_name));
owner_class.set_library(lib);
const String& function_name = String::ZoneHandle(Symbols::New(name));
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 1c40fb5..eae0796 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -55,6 +55,7 @@
V(_EnumNames, "_enum_names") \
V(ExprTemp, ":expr_temp") \
V(AnonymousClosure, "<anonymous closure>") \
+ V(AnonymousSignature, "<anonymous signature>") \
V(ImplicitClosure, "<implicit closure>") \
V(ClosureParameter, ":closure") \
V(TypeArgumentsParameter, ":type_arguments") \
@@ -135,6 +136,7 @@
V(Dynamic, "dynamic") \
V(UnresolvedClass, "UnresolvedClass") \
V(Type, "_Type") \
+ V(FunctionType, "_FunctionType") \
V(TypeRef, "_TypeRef") \
V(TypeParameter, "_TypeParameter") \
V(BoundedType, "_BoundedType") \
@@ -143,7 +145,7 @@
V(Patch, "patch") \
V(PatchClass, "PatchClass") \
V(Function, "Function") \
- V(FunctionImpl, "_FunctionImpl") \
+ V(_Closure, "_Closure") \
V(FunctionResult, "function result") \
V(FactoryResult, "factory result") \
V(ClosureData, "ClosureData") \
@@ -159,6 +161,7 @@
V(Instructions, "Instructions") \
V(ObjectPool, "ObjectPool") \
V(PcDescriptors, "PcDescriptors") \
+ V(CodeSourceMap, "CodeSourceMap") \
V(Stackmap, "Stackmap") \
V(LocalVarDescriptors, "LocalVarDescriptors") \
V(ExceptionHandlers, "ExceptionHandlers") \
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 64c7127..76d4729 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -80,12 +80,10 @@
} else if (use_ring_recorder) {
recorder_ = new TimelineEventRingRecorder();
}
- vm_stream_ = new TimelineStream();
- vm_stream_->Init("VM", EnableStreamByDefault("VM"), NULL);
- vm_api_stream_ = new TimelineStream();
- vm_api_stream_->Init("API",
- EnableStreamByDefault("API"),
- &stream_API_enabled_);
+ vm_stream_.Init("VM", EnableStreamByDefault("VM"), NULL);
+ vm_api_stream_.Init("API",
+ EnableStreamByDefault("API"),
+ &stream_API_enabled_);
// Global overrides.
#define ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \
stream_##name##_enabled_ = EnableStreamByDefault(#name);
@@ -99,12 +97,15 @@
if (FLAG_timeline_dir != NULL) {
recorder_->WriteTo(FLAG_timeline_dir);
}
+ // Disable global streams.
+ vm_stream_.set_enabled(false);
+ vm_api_stream_.set_enabled(false);
+#define ISOLATE_TIMELINE_STREAM_DISABLE(name, not_used) \
+ stream_##name##_enabled_ = false;
+ ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DISABLE)
+#undef ISOLATE_TIMELINE_STREAM_DISABLE
delete recorder_;
recorder_ = NULL;
- delete vm_stream_;
- vm_stream_ = NULL;
- delete vm_api_stream_;
- vm_api_stream_ = NULL;
}
@@ -120,14 +121,12 @@
TimelineStream* Timeline::GetVMStream() {
- ASSERT(vm_stream_ != NULL);
- return vm_stream_;
+ return &vm_stream_;
}
TimelineStream* Timeline::GetVMApiStream() {
- ASSERT(vm_api_stream_ != NULL);
- return vm_api_stream_;
+ return &vm_api_stream_;
}
@@ -164,8 +163,8 @@
TimelineEventRecorder* Timeline::recorder_ = NULL;
-TimelineStream* Timeline::vm_stream_ = NULL;
-TimelineStream* Timeline::vm_api_stream_ = NULL;
+TimelineStream Timeline::vm_stream_;
+TimelineStream Timeline::vm_api_stream_;
#define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \
bool Timeline::stream_##name##_enabled_ = enabled_by_default;
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index d0c43e0..168956a 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -69,8 +69,8 @@
private:
static TimelineEventRecorder* recorder_;
- static TimelineStream* vm_stream_;
- static TimelineStream* vm_api_stream_;
+ static TimelineStream vm_stream_;
+ static TimelineStream vm_api_stream_;
#define ISOLATE_TIMELINE_STREAM_DECLARE_FLAG(name, not_used) \
static bool stream_##name##_enabled_;
diff --git a/runtime/vm/token.cc b/runtime/vm/token.cc
index 75872e5..504b6d9 100644
--- a/runtime/vm/token.cc
+++ b/runtime/vm/token.cc
@@ -78,4 +78,21 @@
}
+const char* ClassifyingTokenPositions::ToCString(intptr_t token_pos) {
+ ASSERT(token_pos < Token::kMinSourcePos);
+ COMPILE_ASSERT(ClassifyingTokenPositions::kPrivate ==
+ (Token::kNoSourcePos - 1));
+ COMPILE_ASSERT(kLast < kPrivate);
+ switch (token_pos) {
+ case Token::kNoSourcePos: return "NoSource";
+#define DEFINE_CASE(name, value) \
+ case value: return #name;
+ CLASSIFYING_TOKEN_POSITIONS(DEFINE_CASE);
+#undef DEFINE_CASE
+ default:
+ UNIMPLEMENTED();
+ return NULL;
+ }
+}
+
} // namespace dart
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index a1018f8..39659d9 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -6,6 +6,7 @@
#define VM_TOKEN_H_
#include "platform/assert.h"
+#include "vm/allocation.h"
namespace dart {
@@ -193,9 +194,55 @@
KW(kWHILE, "while", 0, kKeyword) \
KW(kWITH, "with", 0, kKeyword) /* == kLastKeyword */
-
class String;
+// The token space is organized as follows:
+//
+// Sentinel values start at -1 and move towards negative infinity:
+// kNoSourcePos -> -1
+// ClassifyingTokenPositions 1 -> -1 - 1
+// ClassifyingTokenPositions N -> -1 - N
+//
+// Synthetically created AstNodes are given real source positions but encoded
+// as negative numbers from [kSmiMin32, -1 - N]. For example:
+//
+// A source position of 0 in a synthetic AstNode would be encoded as -2 - N.
+// A source position of 1 in a synthetic AstNode would be encoded as -3 - N.
+//
+// All other AstNodes are given real source positions encoded as positive
+// integers.
+//
+// This organization allows for ~1 billion token positions.
+//
+// NOTE: While token positions are passed around as an intptr_t they are encoded
+// into the snapshot as an int32_t.
+
+// These token positions are used to classify instructions that can't be
+// directly tied to an actual source position.
+#define CLASSIFYING_TOKEN_POSITIONS(V) \
+ V(Private, -2) \
+ V(Box, -3) \
+ V(ParallelMove, -4) \
+ V(TempMove, -5) \
+ V(Constant, -6) \
+ V(PushArgument, -7) \
+ V(ControlFlow, -8) \
+ V(Context, -9) \
+ V(MethodExtractor, -10) \
+ V(Last, -11) // Always keep this at the end.
+
+
+class ClassifyingTokenPositions : public AllStatic {
+ public:
+#define DEFINE_VALUES(name, value) \
+ static const intptr_t k##name = value;
+ CLASSIFYING_TOKEN_POSITIONS(DEFINE_VALUES);
+#undef DEFINE_VALUES
+
+ static const char* ToCString(intptr_t token_pos);
+};
+
+
class Token {
public:
#define T(t, s, p, a) t,
@@ -212,6 +259,78 @@
kPseudoKeyword = 1 << 1,
};
+ // Token position constants.
+ static const intptr_t kNoSourcePos = -1;
+ static const intptr_t kMinSourcePos = 0;
+ static const intptr_t kMaxSourcePos =
+ kSmiMax32 - (-ClassifyingTokenPositions::kLast) - 2;
+
+ // Is |token_pos| a classifying sentinel source position?
+ static bool IsClassifying(intptr_t token_pos) {
+ return (token_pos >= ClassifyingTokenPositions::kPrivate) &&
+ (token_pos <= ClassifyingTokenPositions::kLast);
+ }
+
+ // Is |token_pos| a synthetic source position?
+ static bool IsSynthetic(intptr_t token_pos) {
+ if (token_pos >= kMinSourcePos) {
+ return false;
+ }
+ if (token_pos < ClassifyingTokenPositions::kLast) {
+ return true;
+ }
+ return false;
+ }
+
+ // Is |token_pos| the no source position sentinel?
+ static bool IsNoSource(intptr_t token_pos) {
+ return token_pos == kNoSourcePos;
+ }
+
+ // Is |token_pos| a real source position?
+ static bool IsReal(intptr_t token_pos) {
+ return token_pos >= kMinSourcePos;
+ }
+
+ // Is |token_pos| a source position?
+ static bool IsSourcePosition(intptr_t token_pos) {
+ return IsReal(token_pos) || IsNoSource(token_pos) || IsSynthetic(token_pos);
+ }
+
+ // Is |token_pos| a debug pause source position?
+ static bool IsDebugPause(intptr_t token_pos) {
+ return IsReal(token_pos);
+ }
+
+ // Encode |token_pos| into a synthetic source position.
+ static intptr_t ToSynthetic(intptr_t token_pos) {
+ if (IsClassifying(token_pos) || IsNoSource(token_pos)) {
+ return token_pos;
+ }
+ if (IsSynthetic(token_pos)) {
+ return token_pos;
+ }
+ ASSERT(!IsSynthetic(token_pos));
+ const intptr_t value = (ClassifyingTokenPositions::kLast - 1) - token_pos;
+ ASSERT(IsSynthetic(value));
+ ASSERT(value < ClassifyingTokenPositions::kLast);
+ return value;
+ }
+
+ // Decode |token_pos| from a synthetic source position.
+ static intptr_t FromSynthetic(intptr_t token_pos) {
+ if (IsClassifying(token_pos) || IsNoSource(token_pos)) {
+ return token_pos;
+ }
+ if (!IsSynthetic(token_pos)) {
+ return token_pos;
+ }
+ ASSERT(IsSynthetic(token_pos));
+ const intptr_t value = -token_pos + (ClassifyingTokenPositions::kLast - 1);
+ ASSERT(!IsSynthetic(value));
+ return value;
+ }
+
static const Kind kFirstKeyword = kABSTRACT;
static const Kind kLastKeyword = kWITH;
static const int kNumKeywords = kLastKeyword - kFirstKeyword + 1;
@@ -328,7 +447,6 @@
static const Attribute attributes_[];
};
-
} // namespace dart
#endif // VM_TOKEN_H_
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index b3df320..c686463 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -96,7 +96,7 @@
}]],
},
{
- 'target_name': 'libdart_vm_precompiled',
+ 'target_name': 'libdart_vm_precompiled_runtime',
'type': 'static_library',
'toolsets':['host', 'target'],
'includes': [
@@ -112,7 +112,7 @@
'..',
],
'defines': [
- 'DART_PRECOMPILED',
+ 'DART_PRECOMPILED_RUNTIME',
],
'conditions': [
['OS=="linux"', {
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index dfed0df..b5ad1e8 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -106,37 +106,61 @@
// Patch for Expando implementation.
@patch
class Expando<T> {
+ static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
+
+ // Incremented to make unique keys.
+ static int _keyCount = 0;
+
+ // Stores either a JS WeakMap or a "unique" string key.
+ final Object _jsWeakMapOrKey;
+
@patch
- Expando([String name]) : this.name = name;
+ Expando([String name])
+ : this.name = name,
+ _jsWeakMapOrKey = JS('bool', 'typeof WeakMap == "function"')
+ ? JS('=Object|Null', 'new WeakMap()')
+ : _createKey();
@patch
T operator[](Object object) {
- var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
- return (values == null) ? null : Primitives.getProperty(values, _getKey());
+ if (_jsWeakMapOrKey is! String) {
+ _checkType(object); // WeakMap doesn't check on reading, only writing.
+ return JS('', '#.get(#)', _jsWeakMapOrKey, object);
+ }
+ return _getFromObject(_jsWeakMapOrKey, object);
}
@patch
void operator[]=(Object object, T value) {
+ if (_jsWeakMapOrKey is! String) {
+ JS('void', '#.set(#, #)', _jsWeakMapOrKey, object, value);
+ } else {
+ _setOnObject(_jsWeakMapOrKey, object, value);
+ }
+ }
+
+ static Object _getFromObject(String key, Object object) {
+ var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+ return (values == null) ? null : Primitives.getProperty(values, key);
+ }
+
+ static void _setOnObject(String key, Object object, Object value) {
var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
if (values == null) {
values = new Object();
Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values);
}
- Primitives.setProperty(values, _getKey(), value);
+ Primitives.setProperty(values, key, value);
}
- String _getKey() {
- String key = Primitives.getProperty(this, _KEY_PROPERTY_NAME);
- if (key == null) {
- key = "expando\$key\$${_keyCount++}";
- Primitives.setProperty(this, _KEY_PROPERTY_NAME, key);
+ static String _createKey() => "expando\$key\$${_keyCount++}";
+
+ static _checkType(object) {
+ if (object == null || object is bool || object is num || object is String) {
+ throw new ArgumentError.value(object,
+ "Expandos are not allowed on strings, numbers, booleans or null");
}
- return key;
}
-
- static const String _KEY_PROPERTY_NAME = 'expando\$key';
- static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
- static int _keyCount = 0;
}
@patch
@@ -316,20 +340,11 @@
static int _now() => Primitives.timerTicks();
}
-class _ListConstructorSentinel extends JSInt {
- const _ListConstructorSentinel();
-}
-
// Patch for List implementation.
@patch
class List<E> {
@patch
- factory List([int length = const _ListConstructorSentinel()]) {
- if (length == const _ListConstructorSentinel()) {
- return new JSArray<E>.emptyGrowable();
- }
- return new JSArray<E>.fixed(length);
- }
+ factory List([int length]) = JSArray<E>.list;
@patch
factory List.filled(int length, E fill, {bool growable: false}) {
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index 78e53b1..004127b 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -4,6 +4,11 @@
part of _interceptors;
+class _Growable {
+ const _Growable();
+}
+const _ListConstructorSentinel = const _Growable();
+
/**
* The interceptor class for [List]. The compiler recognizes this
* class as an interceptor, and changes references to [:this:] to
@@ -14,6 +19,16 @@
const JSArray();
+ // This factory constructor is the redirection target of the List() factory
+ // constructor. [length] has no type to permit the sentinel value.
+ factory JSArray.list([length = _ListConstructorSentinel]) {
+ if (_ListConstructorSentinel == length) {
+ return new JSArray<E>.emptyGrowable();
+ }
+ return new JSArray<E>.fixed(length);
+ }
+
+
/**
* Returns a fresh JavaScript Array, marked as fixed-length.
*
@@ -21,7 +36,8 @@
*/
factory JSArray.fixed(int length) {
// Explicit type test is necessary to guard against JavaScript conversions
- // in unchecked mode.
+ // in unchecked mode, and against `new Array(null)` which creates a single
+ // element Array containing `null`.
if (length is !int) {
throw new ArgumentError.value(length, "length", "is not an integer");
}
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index 6f4ddab..a926f1d 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.dart
@@ -23,7 +23,7 @@
// TODO(lrn): Use the _state field on _ControllerSubscription to
// also store this state. Requires that the subscription implementation
// does not assume that it's use of the state integer is the only use.
- int _eventState;
+ int _eventState = 0; // Initialized to help dart2js type inference.
_BroadcastSubscriptionLink _next;
_BroadcastSubscriptionLink _previous;
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 48f968f..709a73d 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -225,7 +225,7 @@
_Future result = new _Future<T>();
new Timer(duration, () {
try {
- result._complete(computation == null ? null : computation());
+ result._complete(computation?.call());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index c2b6c68..510cccb 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -325,6 +325,10 @@
* two arguments it is called with the stack trace (which could be `null` if
* the stream itself received an error without stack trace).
* Otherwise it is called with just the error object.
+ * If [onError] is omitted, any errors on the stream are considered unhandled,
+ * and will be passed to the current [Zone]'s error handler.
+ * By default unhandled async errors are treated
+ * as if they were uncaught top-level errors.
*
* If this stream closes, the [onDone] handler is called.
*
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index c8a2465..cd69f44 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -68,9 +68,16 @@
* If [sync] is true, the returned stream controller is a
* [SynchronousStreamController], and must be used with the care
* and attention necessary to not break the [Stream] contract.
+ * See [Completer.sync] for some explanations on when a synchronous
+ * dispatching can be used.
+ * If in doubt, keep the controller non-sync.
*
- * The controller will buffer all incoming events until the subscriber is
- * registered.
+ * A Stream should be inert until a subscriber starts listening on it (using
+ * the [onListen] callback to start producing events). Streams should not
+ * leak resources (like websockets) when no user ever listens on the stream.
+ *
+ * The controller buffers all incoming events until a subscriber is
+ * registered, but this feature should only be used in rare circumstances.
*
* The [onPause] function is called when the stream becomes
* paused. [onResume] is called when the stream resumed.
@@ -100,6 +107,12 @@
* The [Stream] returned by [stream] is a broadcast stream.
* It can be listened to more than once.
*
+ * A Stream should be inert until a subscriber starts listening on it (using
+ * the [onListen] callback to start producing events). Streams should not
+ * leak resources (like websockets) when no user ever listens on the stream.
+ *
+ * Broadcast streams do not buffer events when there is no listener.
+ *
* The controller distributes any events to all currently subscribed
* listeners at the time when [add], [addError] or [close] is called.
* It is not allowed to call `add`, `addError`, or `close` before a previous
@@ -116,6 +129,9 @@
* The returned stream controller is a [SynchronousStreamController],
* and must be used with the care and attention necessary to not break
* the [Stream] contract.
+ * See [Completer.sync] for some explanations on when a synchronous
+ * dispatching can be used.
+ * If in doubt, keep the controller non-sync.
*
* If [sync] is false, the event will always be fired at a later time,
* after the code adding the event has completed.
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index d84f01b..5cc4d88 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -135,33 +135,21 @@
Map zoneValues): null
}) {
return new ZoneSpecification(
- handleUncaughtError: handleUncaughtError != null
- ? handleUncaughtError
- : other.handleUncaughtError,
- run: run != null ? run : other.run,
- runUnary: runUnary != null ? runUnary : other.runUnary,
- runBinary: runBinary != null ? runBinary : other.runBinary,
- registerCallback: registerCallback != null
- ? registerCallback
- : other.registerCallback,
- registerUnaryCallback: registerUnaryCallback != null
- ? registerUnaryCallback
- : other.registerUnaryCallback,
- registerBinaryCallback: registerBinaryCallback != null
- ? registerBinaryCallback
- : other.registerBinaryCallback,
- errorCallback: errorCallback != null
- ? errorCallback
- : other.errorCallback,
- scheduleMicrotask: scheduleMicrotask != null
- ? scheduleMicrotask
- : other.scheduleMicrotask,
- createTimer : createTimer != null ? createTimer : other.createTimer,
- createPeriodicTimer: createPeriodicTimer != null
- ? createPeriodicTimer
- : other.createPeriodicTimer,
- print : print != null ? print : other.print,
- fork: fork != null ? fork : other.fork);
+ handleUncaughtError: handleUncaughtError ?? other.handleUncaughtError,
+ run: run ?? other.run,
+ runUnary: runUnary ?? other.runUnary,
+ runBinary: runBinary ?? other.runBinary,
+ registerCallback: registerCallback ?? other.registerCallback,
+ registerUnaryCallback: registerUnaryCallback ??
+ other.registerUnaryCallback,
+ registerBinaryCallback: registerBinaryCallback ??
+ other.registerBinaryCallback,
+ errorCallback: errorCallback ?? other.errorCallback,
+ scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
+ createTimer : createTimer ?? other.createTimer,
+ createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer,
+ print : print ?? other.print,
+ fork: fork ?? other.fork);
}
HandleUncaughtErrorHandler get handleUncaughtError;
diff --git a/sdk/lib/core/regexp.dart b/sdk/lib/core/regexp.dart
index 0d92345..09874c4 100644
--- a/sdk/lib/core/regexp.dart
+++ b/sdk/lib/core/regexp.dart
@@ -28,6 +28,10 @@
* RegExp exp = new RegExp(r"(\w+)");
* String str = "Parse my string";
* Iterable<Match> matches = exp.allMatches(str);
+ *
+ * Note the use of a _raw string_ (a string prefixed with `r`)
+ * in the example above. Use a raw string to treat each character in a string
+ * as a literal character.
*/
abstract class RegExp implements Pattern {
/**
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index e4a31aa..a1a5b5d 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -76,6 +76,7 @@
* Cache the computed return value of [queryParameters].
*/
Map<String, String> _queryParameters;
+ Map<String, List<String>> _queryParameterLists;
/// Internal non-verifying constructor. Only call with validated arguments.
Uri._internal(this.scheme,
@@ -116,39 +117,46 @@
* default port.
*
* If any of `userInfo`, `host` or `port` are provided,
- * the URI will have an autority according to [hasAuthority].
+ * the URI has an autority according to [hasAuthority].
*
* The path component is set through either [path] or
- * [pathSegments]. When [path] is used, it should be a valid URI path,
+ * [pathSegments].
+ * When [path] is used, it should be a valid URI path,
* but invalid characters, except the general delimiters ':/@[]?#',
* will be escaped if necessary.
* When [pathSegments] is used, each of the provided segments
* is first percent-encoded and then joined using the forward slash
- * separator. The percent-encoding of the path segments encodes all
+ * separator.
+ *
+ * The percent-encoding of the path segments encodes all
* characters except for the unreserved characters and the following
* list of characters: `!$&'()*+,;=:@`. If the other components
- * calls for an absolute path a leading slash `/` is prepended if
+ * necessitate an absolute path, a leading slash `/` is prepended if
* not already there.
*
- * The query component is set through either [query] or
- * [queryParameters]. When [query] is used the provided string should
- * be a valid URI query, but invalid characters other than general delimiters,
+ * The query component is set through either [query] or [queryParameters].
+ * When [query] is used, the provided string should be a valid URI query,
+ * but invalid characters, other than general delimiters,
* will be escaped if necessary.
* When [queryParameters] is used the query is built from the
* provided map. Each key and value in the map is percent-encoded
- * and joined using equal and ampersand characters. The
- * percent-encoding of the keys and values encodes all characters
- * except for the unreserved characters.
+ * and joined using equal and ampersand characters.
+ * A value in the map must be either a string, or an [Iterable] of strings,
+ * where the latter corresponds to multiple values for the same key.
+ *
+ * The percent-encoding of the keys and values encodes all characters
+ * except for the unreserved characters, and replaces spaces with `+`.
* If `query` is the empty string, it is equivalent to omitting it.
* To have an actual empty query part,
* use an empty list for `queryParameters`.
- * If both `query` and `queryParameters` are omitted or `null`, the
- * URI will have no query part.
+ *
+ * If both `query` and `queryParameters` are omitted or `null`,
+ * the URI has no query part.
*
* The fragment component is set through [fragment].
* It should be a valid URI fragment, but invalid characters other than
- * general delimiters, will be escaped if necessary.
- * If `fragment` is omitted or `null`, the URI will have no fragment part.
+ * general delimiters, are escaped if necessary.
+ * If `fragment` is omitted or `null`, the URI has no fragment part.
*/
factory Uri({String scheme : "",
String userInfo : "",
@@ -157,7 +165,7 @@
String path,
Iterable<String> pathSegments,
String query,
- Map<String, String> queryParameters,
+ Map<String, dynamic> queryParameters,
String fragment}) {
scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme));
userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo));
@@ -207,7 +215,7 @@
*
* The `userInfo`, `host` and `port` components are set from the
* [authority] argument. If `authority` is `null` or empty,
- * the created `Uri` will have no authority, and will not be directly usable
+ * the created `Uri` has no authority, and isn't directly usable
* as an HTTP URL, which must have a non-empty host.
*
* The `path` component is set from the [unencodedPath]
@@ -1104,23 +1112,53 @@
* Returns the URI query split into a map according to the rules
* specified for FORM post in the [HTML 4.01 specification section
* 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
- * Each key and value in the returned map has been decoded. If there is no
- * query the empty map is returned.
+ * Each key and value in the returned map has been decoded.
+ * If there is no query the empty map is returned.
*
* Keys in the query string that have no value are mapped to the
* empty string.
+ * If a key occurs more than once in the query string, it is mapped to
+ * an arbitrary choice of possible value.
+ * The [queryParametersAll] getter can provide a map
+ * that maps keys to all of their values.
*
- * The returned map is unmodifiable and will throw [UnsupportedError] on any
- * calls that would mutate it.
+ * The returned map is unmodifiable.
*/
Map<String, String> get queryParameters {
if (_queryParameters == null) {
- _queryParameters = new UnmodifiableMapView(splitQueryString(query));
+ _queryParameters =
+ new UnmodifiableMapView<String, String>(splitQueryString(query));
}
return _queryParameters;
}
/**
+ * Returns the URI query split into a map according to the rules
+ * specified for FORM post in the [HTML 4.01 specification section
+ * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ * Each key and value in the returned map has been decoded. If there is no
+ * query the empty map is returned.
+ *
+ * Keys are mapped to lists of their values. If a key occurs only once,
+ * its value is a singleton list. If a key occurs with no value, the
+ * empty string is used as the value for that occurrence.
+ *
+ * The returned map and the lists it contains are unmodifiable.
+ */
+ Map<String, List<String>> get queryParametersAll {
+ if (_queryParameterLists == null) {
+ Map queryParameterLists = _splitQueryStringAll(query);
+ for (var key in queryParameterLists.keys) {
+ queryParameterLists[key] =
+ new List<String>.unmodifiable(queryParameterLists[key]);
+ }
+ _queryParameterLists =
+ new Map<String, List<String>>.unmodifiable(queryParameterLists);
+ }
+ return _queryParameterLists;
+ }
+
+ /**
* Returns a URI where the path has been normalized.
*
* A normalized path does not contain `.` segments or non-leading `..`
@@ -1344,17 +1382,27 @@
if (query != null) return _normalize(query, start, end, _queryCharTable);
var result = new StringBuffer();
- var first = true;
- queryParameters.forEach((key, value) {
- if (!first) {
- result.write("&");
- }
- first = false;
+ var separator = "";
+
+ void writeParameter(String key, String value) {
+ result.write(separator);
+ separator = "&";
result.write(Uri.encodeQueryComponent(key));
- if (value != null && !value.isEmpty) {
+ if (value != null && value.isNotEmpty) {
result.write("=");
result.write(Uri.encodeQueryComponent(value));
}
+ }
+
+ queryParameters.forEach((key, value) {
+ if (value == null || value is String) {
+ writeParameter(key, value);
+ } else {
+ Iterable values = value;
+ for (String value in values) {
+ writeParameter(key, value);
+ }
+ }
});
return result.toString();
}
@@ -2156,6 +2204,46 @@
});
}
+ static List _createList() => [];
+
+ static Map _splitQueryStringAll(
+ String query, {Encoding encoding: UTF8}) {
+ Map result = {};
+ int i = 0;
+ int start = 0;
+ int equalsIndex = -1;
+
+ void parsePair(int start, int equalsIndex, int end) {
+ String key;
+ String value;
+ if (start == end) return;
+ if (equalsIndex < 0) {
+ key = _uriDecode(query, start, end, encoding, true);
+ value = "";
+ } else {
+ key = _uriDecode(query, start, equalsIndex, encoding, true);
+ value = _uriDecode(query, equalsIndex + 1, end, encoding, true);
+ }
+ result.putIfAbsent(key, _createList).add(value);
+ }
+
+ const int _equals = 0x3d;
+ const int _ampersand = 0x26;
+ while (i < query.length) {
+ int char = query.codeUnitAt(i);
+ if (char == _equals) {
+ if (equalsIndex < 0) equalsIndex = i;
+ } else if (char == _ampersand) {
+ parsePair(start, equalsIndex, i);
+ start = i + 1;
+ equalsIndex = -1;
+ }
+ i++;
+ }
+ parsePair(start, equalsIndex, i);
+ return result;
+ }
+
/**
* Parse the [host] as an IP version 4 (IPv4) address, returning the address
* as a list of 4 bytes in network byte order (big endian).
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 3ef584b..8d4c3de 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -126,9 +126,9 @@
'_DOMWindowCrossFrame': () => _DOMWindowCrossFrame,
// FIXME: Move these to better locations.
'DateTime': () => DateTime,
- 'JsObject': () => js.JsObjectImpl,
- 'JsFunction': () => js.JsFunctionImpl,
- 'JsArray': () => js.JsArrayImpl,
+ 'JsObject': () => js.JsObject,
+ 'JsFunction': () => js.JsFunction,
+ 'JsArray': () => js.JsArray,
'AbstractWorker': () => AbstractWorker,
'Animation': () => Animation,
'AnimationEffect': () => AnimationEffect,
@@ -1128,7 +1128,7 @@
} else if (runtimeType == TemplateElement) {
// Data binding with a Dart class.
tag = element.attributes['is'];
- } else if (runtimeType == js.JsObjectImpl) {
+ } else if (runtimeType == js.JsObject) {
// It's a Polymer core element (written in JS).
// Make sure it's an element anything else we can ignore.
if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
@@ -1141,7 +1141,7 @@
}
}
} else {
- throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+ throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
}
return tag;
@@ -1149,15 +1149,9 @@
/// An abstract class for all DOM objects we wrap in dart:html and related
/// libraries.
-///
-/// ** Internal Use Only **
@Deprecated("Internal Use Only")
-class DartHtmlDomObject {
-
- /// The underlying JS DOM object.
- @Deprecated("Internal Use Only")
- js.JsObject blink_jsObject;
-
+class DartHtmlDomObject extends js.JSObject {
+ DartHtmlDomObject() : super.internal();
}
@Deprecated("Internal Use Only")
@@ -1173,24 +1167,6 @@
}
}
-// TODO(terry): Manage JS interop JsFunctions for each listener used for add/
-// removeEventListener. These JsFunctions will leak look at
-// fixing with weak-refs in C++. The key are the hashcodes of the
-// user's this (this is needed for futures) and listener function.
-Map<int, Map<int, js.JsFunction>> _knownListeners = {};
-
-@Deprecated("Internal Use Only")
-js.JsFunction wrap_event_listener(theObject, Function listener) {
- var thisHashCode = theObject.hashCode;
- var listenerHashCode = identityHashCode(listener);
-
- _knownListeners.putIfAbsent(thisHashCode, () => new Map<int, js.JsFunction>());
- _knownListeners[thisHashCode].putIfAbsent(listenerHashCode, () =>
- new js.JsFunction.withThis((theObject, event) => listener(wrap_jso(event))));
-
- return _knownListeners[thisHashCode][listenerHashCode];
-}
-
@Deprecated("Internal Use Only")
Map<String, dynamic> convertNativeObjectToDartMap(js.JsObject jsObject) {
var result = new Map();
@@ -1279,9 +1255,7 @@
return new AnchorElement._internalWrap();
}
- factory AnchorElement._internalWrap() {
- return new AnchorElement.internal_();
- }
+ external factory AnchorElement._internalWrap();
@Deprecated("Internal Use Only")
AnchorElement.internal_() : super.internal_();
@@ -1474,9 +1448,7 @@
return new Animation._internalWrap();
}
- factory Animation._internalWrap() {
- return new Animation.internal_();
- }
+ external factory Animation._internalWrap();
@Deprecated("Internal Use Only")
Animation.internal_() : super.internal_();
@@ -1535,9 +1507,7 @@
return new AnimationEvent._internalWrap();
}
- factory AnimationEvent._internalWrap() {
- return new AnimationEvent.internal_();
- }
+ external factory AnimationEvent._internalWrap();
@Deprecated("Internal Use Only")
AnimationEvent.internal_() : super.internal_();
@@ -1642,9 +1612,7 @@
return new AnimationPlayer._internalWrap();
}
- factory AnimationPlayer._internalWrap() {
- return new AnimationPlayer.internal_();
- }
+ external factory AnimationPlayer._internalWrap();
@Deprecated("Internal Use Only")
AnimationPlayer.internal_() : super.internal_();
@@ -1744,9 +1712,7 @@
return new AnimationPlayerEvent._internalWrap();
}
- factory AnimationPlayerEvent._internalWrap() {
- return new AnimationPlayerEvent.internal_();
- }
+ external factory AnimationPlayerEvent._internalWrap();
@Deprecated("Internal Use Only")
AnimationPlayerEvent.internal_() : super.internal_();
@@ -1916,9 +1882,7 @@
return new ApplicationCache._internalWrap();
}
- factory ApplicationCache._internalWrap() {
- return new ApplicationCache.internal_();
- }
+ external factory ApplicationCache._internalWrap();
@Deprecated("Internal Use Only")
ApplicationCache.internal_() : super.internal_();
@@ -2028,9 +1992,7 @@
return new ApplicationCacheErrorEvent._internalWrap();
}
- factory ApplicationCacheErrorEvent._internalWrap() {
- return new ApplicationCacheErrorEvent.internal_();
- }
+ external factory ApplicationCacheErrorEvent._internalWrap();
@Deprecated("Internal Use Only")
ApplicationCacheErrorEvent.internal_() : super.internal_();
@@ -2090,9 +2052,7 @@
return new AreaElement._internalWrap();
}
- factory AreaElement._internalWrap() {
- return new AreaElement.internal_();
- }
+ external factory AreaElement._internalWrap();
@Deprecated("Internal Use Only")
AreaElement.internal_() : super.internal_();
@@ -2252,9 +2212,7 @@
return new AudioElement._internalWrap();
}
- factory AudioElement._internalWrap() {
- return new AudioElement.internal_();
- }
+ external factory AudioElement._internalWrap();
@Deprecated("Internal Use Only")
AudioElement.internal_() : super.internal_();
@@ -2358,9 +2316,7 @@
return new AudioTrackList._internalWrap();
}
- factory AudioTrackList._internalWrap() {
- return new AudioTrackList.internal_();
- }
+ external factory AudioTrackList._internalWrap();
@Deprecated("Internal Use Only")
AudioTrackList.internal_() : super.internal_();
@@ -2408,9 +2364,7 @@
return new AutocompleteErrorEvent._internalWrap();
}
- factory AutocompleteErrorEvent._internalWrap() {
- return new AutocompleteErrorEvent.internal_();
- }
+ external factory AutocompleteErrorEvent._internalWrap();
@Deprecated("Internal Use Only")
AutocompleteErrorEvent.internal_() : super.internal_();
@@ -2444,9 +2398,7 @@
return new BRElement._internalWrap();
}
- factory BRElement._internalWrap() {
- return new BRElement.internal_();
- }
+ external factory BRElement._internalWrap();
@Deprecated("Internal Use Only")
BRElement.internal_() : super.internal_();
@@ -2517,9 +2469,7 @@
return new BaseElement._internalWrap();
}
- factory BaseElement._internalWrap() {
- return new BaseElement.internal_();
- }
+ external factory BaseElement._internalWrap();
@Deprecated("Internal Use Only")
BaseElement.internal_() : super.internal_();
@@ -2569,9 +2519,7 @@
return new BatteryManager._internalWrap();
}
- factory BatteryManager._internalWrap() {
- return new BatteryManager.internal_();
- }
+ external factory BatteryManager._internalWrap();
@Deprecated("Internal Use Only")
BatteryManager.internal_() : super.internal_();
@@ -2613,9 +2561,7 @@
return new BeforeUnloadEvent._internalWrap();
}
- factory BeforeUnloadEvent._internalWrap() {
- return new BeforeUnloadEvent.internal_();
- }
+ external factory BeforeUnloadEvent._internalWrap();
@Deprecated("Internal Use Only")
BeforeUnloadEvent.internal_() : super.internal_();
@@ -2899,9 +2845,7 @@
return new BodyElement._internalWrap();
}
- factory BodyElement._internalWrap() {
- return new BodyElement.internal_();
- }
+ external factory BodyElement._internalWrap();
@Deprecated("Internal Use Only")
BodyElement.internal_() : super.internal_();
@@ -3002,9 +2946,7 @@
return new ButtonElement._internalWrap();
}
- factory ButtonElement._internalWrap() {
- return new ButtonElement.internal_();
- }
+ external factory ButtonElement._internalWrap();
@Deprecated("Internal Use Only")
ButtonElement.internal_() : super.internal_();
@@ -3147,9 +3089,7 @@
return new CDataSection._internalWrap();
}
- factory CDataSection._internalWrap() {
- return new CDataSection.internal_();
- }
+ external factory CDataSection._internalWrap();
@Deprecated("Internal Use Only")
CDataSection.internal_() : super.internal_();
@@ -3305,9 +3245,7 @@
return new CanvasElement._internalWrap();
}
- factory CanvasElement._internalWrap() {
- return new CanvasElement.internal_();
- }
+ external factory CanvasElement._internalWrap();
@Deprecated("Internal Use Only")
CanvasElement.internal_() : super.internal_();
@@ -4377,9 +4315,7 @@
return new CharacterData._internalWrap();
}
- factory CharacterData._internalWrap() {
- return new CharacterData.internal_();
- }
+ external factory CharacterData._internalWrap();
@Deprecated("Internal Use Only")
CharacterData.internal_() : super.internal_();
@@ -4483,9 +4419,7 @@
return new CircularGeofencingRegion._internalWrap();
}
- factory CircularGeofencingRegion._internalWrap() {
- return new CircularGeofencingRegion.internal_();
- }
+ external factory CircularGeofencingRegion._internalWrap();
@Deprecated("Internal Use Only")
CircularGeofencingRegion.internal_() : super.internal_();
@@ -4536,9 +4470,7 @@
return new CloseEvent._internalWrap();
}
- factory CloseEvent._internalWrap() {
- return new CloseEvent.internal_();
- }
+ external factory CloseEvent._internalWrap();
@Deprecated("Internal Use Only")
CloseEvent.internal_() : super.internal_();
@@ -4583,9 +4515,7 @@
return new Comment._internalWrap();
}
- factory Comment._internalWrap() {
- return new Comment.internal_();
- }
+ external factory Comment._internalWrap();
@Deprecated("Internal Use Only")
Comment.internal_() : super.internal_();
@@ -4622,9 +4552,7 @@
return new CompositionEvent._internalWrap();
}
- factory CompositionEvent._internalWrap() {
- return new CompositionEvent.internal_();
- }
+ external factory CompositionEvent._internalWrap();
@Deprecated("Internal Use Only")
CompositionEvent.internal_() : super.internal_();
@@ -4673,9 +4601,7 @@
return new Console._internalWrap();
}
- factory Console._internalWrap() {
- return new Console.internal_();
- }
+ external factory Console._internalWrap();
@Deprecated("Internal Use Only")
Console.internal_() : super.internal_();
@@ -4858,9 +4784,7 @@
return new ContentElement._internalWrap();
}
- factory ContentElement._internalWrap() {
- return new ContentElement.internal_();
- }
+ external factory ContentElement._internalWrap();
@Deprecated("Internal Use Only")
ContentElement.internal_() : super.internal_();
@@ -5207,9 +5131,7 @@
return new CssCharsetRule._internalWrap();
}
- factory CssCharsetRule._internalWrap() {
- return new CssCharsetRule.internal_();
- }
+ external factory CssCharsetRule._internalWrap();
@Deprecated("Internal Use Only")
CssCharsetRule.internal_() : super.internal_();
@@ -5247,9 +5169,7 @@
return new CssFilterRule._internalWrap();
}
- factory CssFilterRule._internalWrap() {
- return new CssFilterRule.internal_();
- }
+ external factory CssFilterRule._internalWrap();
@Deprecated("Internal Use Only")
CssFilterRule.internal_() : super.internal_();
@@ -5279,9 +5199,7 @@
return new CssFontFaceRule._internalWrap();
}
- factory CssFontFaceRule._internalWrap() {
- return new CssFontFaceRule.internal_();
- }
+ external factory CssFontFaceRule._internalWrap();
@Deprecated("Internal Use Only")
CssFontFaceRule.internal_() : super.internal_();
@@ -5311,9 +5229,7 @@
return new CssImportRule._internalWrap();
}
- factory CssImportRule._internalWrap() {
- return new CssImportRule.internal_();
- }
+ external factory CssImportRule._internalWrap();
@Deprecated("Internal Use Only")
CssImportRule.internal_() : super.internal_();
@@ -5352,9 +5268,7 @@
return new CssKeyframeRule._internalWrap();
}
- factory CssKeyframeRule._internalWrap() {
- return new CssKeyframeRule.internal_();
- }
+ external factory CssKeyframeRule._internalWrap();
@Deprecated("Internal Use Only")
CssKeyframeRule.internal_() : super.internal_();
@@ -5396,9 +5310,7 @@
return new CssKeyframesRule._internalWrap();
}
- factory CssKeyframesRule._internalWrap() {
- return new CssKeyframesRule.internal_();
- }
+ external factory CssKeyframesRule._internalWrap();
@Deprecated("Internal Use Only")
CssKeyframesRule.internal_() : super.internal_();
@@ -5459,9 +5371,7 @@
return new CssMediaRule._internalWrap();
}
- factory CssMediaRule._internalWrap() {
- return new CssMediaRule.internal_();
- }
+ external factory CssMediaRule._internalWrap();
@Deprecated("Internal Use Only")
CssMediaRule.internal_() : super.internal_();
@@ -5503,9 +5413,7 @@
return new CssPageRule._internalWrap();
}
- factory CssPageRule._internalWrap() {
- return new CssPageRule.internal_();
- }
+ external factory CssPageRule._internalWrap();
@Deprecated("Internal Use Only")
CssPageRule.internal_() : super.internal_();
@@ -8940,9 +8848,7 @@
return new CssStyleRule._internalWrap();
}
- factory CssStyleRule._internalWrap() {
- return new CssStyleRule.internal_();
- }
+ external factory CssStyleRule._internalWrap();
@Deprecated("Internal Use Only")
CssStyleRule.internal_() : super.internal_();
@@ -8980,9 +8886,7 @@
return new CssStyleSheet._internalWrap();
}
- factory CssStyleSheet._internalWrap() {
- return new CssStyleSheet.internal_();
- }
+ external factory CssStyleSheet._internalWrap();
@Deprecated("Internal Use Only")
CssStyleSheet.internal_() : super.internal_();
@@ -9044,9 +8948,7 @@
return new CssSupportsRule._internalWrap();
}
- factory CssSupportsRule._internalWrap() {
- return new CssSupportsRule.internal_();
- }
+ external factory CssSupportsRule._internalWrap();
@Deprecated("Internal Use Only")
CssSupportsRule.internal_() : super.internal_();
@@ -9089,9 +8991,7 @@
return new CssViewportRule._internalWrap();
}
- factory CssViewportRule._internalWrap() {
- return new CssViewportRule.internal_();
- }
+ external factory CssViewportRule._internalWrap();
@Deprecated("Internal Use Only")
CssViewportRule.internal_() : super.internal_();
@@ -9155,9 +9055,7 @@
return new CustomEvent._internalWrap();
}
- factory CustomEvent._internalWrap() {
- return new CustomEvent.internal_();
- }
+ external factory CustomEvent._internalWrap();
@Deprecated("Internal Use Only")
CustomEvent.internal_() : super.internal_();
@@ -9195,9 +9093,7 @@
return new DListElement._internalWrap();
}
- factory DListElement._internalWrap() {
- return new DListElement.internal_();
- }
+ external factory DListElement._internalWrap();
@Deprecated("Internal Use Only")
DListElement.internal_() : super.internal_();
@@ -9237,9 +9133,7 @@
return new DataListElement._internalWrap();
}
- factory DataListElement._internalWrap() {
- return new DataListElement.internal_();
- }
+ external factory DataListElement._internalWrap();
@Deprecated("Internal Use Only")
DataListElement.internal_() : super.internal_();
@@ -9524,9 +9418,7 @@
return new DedicatedWorkerGlobalScope._internalWrap();
}
- factory DedicatedWorkerGlobalScope._internalWrap() {
- return new DedicatedWorkerGlobalScope.internal_();
- }
+ external factory DedicatedWorkerGlobalScope._internalWrap();
@Deprecated("Internal Use Only")
DedicatedWorkerGlobalScope.internal_() : super.internal_();
@@ -9688,9 +9580,7 @@
return new DetailsElement._internalWrap();
}
- factory DetailsElement._internalWrap() {
- return new DetailsElement.internal_();
- }
+ external factory DetailsElement._internalWrap();
@Deprecated("Internal Use Only")
DetailsElement.internal_() : super.internal_();
@@ -9777,9 +9667,7 @@
return new DeviceLightEvent._internalWrap();
}
- factory DeviceLightEvent._internalWrap() {
- return new DeviceLightEvent.internal_();
- }
+ external factory DeviceLightEvent._internalWrap();
@Deprecated("Internal Use Only")
DeviceLightEvent.internal_() : super.internal_();
@@ -9812,9 +9700,7 @@
return new DeviceMotionEvent._internalWrap();
}
- factory DeviceMotionEvent._internalWrap() {
- return new DeviceMotionEvent.internal_();
- }
+ external factory DeviceMotionEvent._internalWrap();
@Deprecated("Internal Use Only")
DeviceMotionEvent.internal_() : super.internal_();
@@ -9869,9 +9755,7 @@
return new DeviceOrientationEvent._internalWrap();
}
- factory DeviceOrientationEvent._internalWrap() {
- return new DeviceOrientationEvent.internal_();
- }
+ external factory DeviceOrientationEvent._internalWrap();
@Deprecated("Internal Use Only")
DeviceOrientationEvent.internal_() : super.internal_();
@@ -9961,9 +9845,7 @@
return new DialogElement._internalWrap();
}
- factory DialogElement._internalWrap() {
- return new DialogElement.internal_();
- }
+ external factory DialogElement._internalWrap();
@Deprecated("Internal Use Only")
DialogElement.internal_() : super.internal_();
@@ -10061,9 +9943,7 @@
return new DirectoryEntry._internalWrap();
}
- factory DirectoryEntry._internalWrap() {
- return new DirectoryEntry.internal_();
- }
+ external factory DirectoryEntry._internalWrap();
@Deprecated("Internal Use Only")
DirectoryEntry.internal_() : super.internal_();
@@ -10234,9 +10114,7 @@
return new DivElement._internalWrap();
}
- factory DivElement._internalWrap() {
- return new DivElement.internal_();
- }
+ external factory DivElement._internalWrap();
@Deprecated("Internal Use Only")
DivElement.internal_() : super.internal_();
@@ -10319,9 +10197,7 @@
return new Document._internalWrap();
}
- factory Document._internalWrap() {
- return new Document.internal_();
- }
+ external factory Document._internalWrap();
@Deprecated("Internal Use Only")
Document.internal_() : super.internal_();
@@ -11258,9 +11134,7 @@
return new DocumentFragment._internalWrap();
}
- factory DocumentFragment._internalWrap() {
- return new DocumentFragment.internal_();
- }
+ external factory DocumentFragment._internalWrap();
@Deprecated("Internal Use Only")
DocumentFragment.internal_() : super.internal_();
@@ -11390,12 +11264,7 @@
return new DomException._internalWrap();
}
- @Deprecated("Internal Use Only")
- js.JsObject blink_jsObject;
-
- factory DomException._internalWrap() {
- return new DomException.internal_();
- }
+ external factory DomException._internalWrap();
@Deprecated("Internal Use Only")
DomException.internal_() { }
@@ -11539,9 +11408,7 @@
return new DomMatrix._internalWrap();
}
- factory DomMatrix._internalWrap() {
- return new DomMatrix.internal_();
- }
+ external factory DomMatrix._internalWrap();
@Deprecated("Internal Use Only")
DomMatrix.internal_() : super.internal_();
@@ -12122,9 +11989,7 @@
return new DomPoint._internalWrap();
}
- factory DomPoint._internalWrap() {
- return new DomPoint.internal_();
- }
+ external factory DomPoint._internalWrap();
@Deprecated("Internal Use Only")
DomPoint.internal_() : super.internal_();
@@ -12411,9 +12276,7 @@
return new DomSettableTokenList._internalWrap();
}
- factory DomSettableTokenList._internalWrap() {
- return new DomSettableTokenList.internal_();
- }
+ external factory DomSettableTokenList._internalWrap();
@Deprecated("Internal Use Only")
DomSettableTokenList.internal_() : super.internal_();
@@ -15593,9 +15456,7 @@
return new Element._internalWrap();
}
- factory Element._internalWrap() {
- return new Element.internal_();
- }
+ external factory Element._internalWrap();
@Deprecated("Internal Use Only")
Element.internal_() : super.internal_();
@@ -16481,9 +16342,7 @@
return new EmbedElement._internalWrap();
}
- factory EmbedElement._internalWrap() {
- return new EmbedElement.internal_();
- }
+ external factory EmbedElement._internalWrap();
@Deprecated("Internal Use Only")
EmbedElement.internal_() : super.internal_();
@@ -16770,9 +16629,7 @@
return new ErrorEvent._internalWrap();
}
- factory ErrorEvent._internalWrap() {
- return new ErrorEvent.internal_();
- }
+ external factory ErrorEvent._internalWrap();
@Deprecated("Internal Use Only")
ErrorEvent.internal_() : super.internal_();
@@ -17060,9 +16917,7 @@
return new EventSource._internalWrap();
}
- factory EventSource._internalWrap() {
- return new EventSource.internal_();
- }
+ external factory EventSource._internalWrap();
@Deprecated("Internal Use Only")
EventSource.internal_() : super.internal_();
@@ -17257,11 +17112,11 @@
void _addEventListener([String type, EventListener listener, bool useCapture]) {
if (useCapture != null) {
- _blink.BlinkEventTarget.instance.addEventListener_Callback_3_(unwrap_jso(this), type, wrap_event_listener(this, listener), useCapture);
+ _blink.BlinkEventTarget.instance.addEventListener_Callback_3_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)), useCapture);
return;
}
if (listener != null) {
- _blink.BlinkEventTarget.instance.addEventListener_Callback_2_(unwrap_jso(this), type, wrap_event_listener(this, listener));
+ _blink.BlinkEventTarget.instance.addEventListener_Callback_2_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)));
return;
}
if (type != null) {
@@ -17278,11 +17133,11 @@
void _removeEventListener([String type, EventListener listener, bool useCapture]) {
if (useCapture != null) {
- _blink.BlinkEventTarget.instance.removeEventListener_Callback_3_(unwrap_jso(this), type, _knownListeners[this.hashCode][identityHashCode(listener)], useCapture);
+ _blink.BlinkEventTarget.instance.removeEventListener_Callback_3_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)), useCapture);
return;
}
if (listener != null) {
- _blink.BlinkEventTarget.instance.removeEventListener_Callback_2_(unwrap_jso(this), type, _knownListeners[this.hashCode][identityHashCode(listener)]);
+ _blink.BlinkEventTarget.instance.removeEventListener_Callback_2_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)));
return;
}
if (type != null) {
@@ -17314,9 +17169,7 @@
return new ExtendableEvent._internalWrap();
}
- factory ExtendableEvent._internalWrap() {
- return new ExtendableEvent.internal_();
- }
+ external factory ExtendableEvent._internalWrap();
@Deprecated("Internal Use Only")
ExtendableEvent.internal_() : super.internal_();
@@ -17354,9 +17207,7 @@
return new FederatedCredential._internalWrap();
}
- factory FederatedCredential._internalWrap() {
- return new FederatedCredential.internal_();
- }
+ external factory FederatedCredential._internalWrap();
@Deprecated("Internal Use Only")
FederatedCredential.internal_() : super.internal_();
@@ -17388,9 +17239,7 @@
return new FetchEvent._internalWrap();
}
- factory FetchEvent._internalWrap() {
- return new FetchEvent.internal_();
- }
+ external factory FetchEvent._internalWrap();
@Deprecated("Internal Use Only")
FetchEvent.internal_() : super.internal_();
@@ -17436,9 +17285,7 @@
return new FieldSetElement._internalWrap();
}
- factory FieldSetElement._internalWrap() {
- return new FieldSetElement.internal_();
- }
+ external factory FieldSetElement._internalWrap();
@Deprecated("Internal Use Only")
FieldSetElement.internal_() : super.internal_();
@@ -17518,9 +17365,7 @@
return new File._internalWrap();
}
- factory File._internalWrap() {
- return new File.internal_();
- }
+ external factory File._internalWrap();
@Deprecated("Internal Use Only")
File.internal_() : super.internal_();
@@ -17580,9 +17425,7 @@
return new FileEntry._internalWrap();
}
- factory FileEntry._internalWrap() {
- return new FileEntry.internal_();
- }
+ external factory FileEntry._internalWrap();
@Deprecated("Internal Use Only")
FileEntry.internal_() : super.internal_();
@@ -17644,9 +17487,7 @@
return new FileError._internalWrap();
}
- factory FileError._internalWrap() {
- return new FileError.internal_();
- }
+ external factory FileError._internalWrap();
@Deprecated("Internal Use Only")
FileError.internal_() : super.internal_();
@@ -17882,9 +17723,7 @@
return new FileReader._internalWrap();
}
- factory FileReader._internalWrap() {
- return new FileReader.internal_();
- }
+ external factory FileReader._internalWrap();
@Deprecated("Internal Use Only")
FileReader.internal_() : super.internal_();
@@ -18136,9 +17975,7 @@
return new FileWriter._internalWrap();
}
- factory FileWriter._internalWrap() {
- return new FileWriter.internal_();
- }
+ external factory FileWriter._internalWrap();
@Deprecated("Internal Use Only")
FileWriter.internal_() : super.internal_();
@@ -18249,9 +18086,7 @@
return new FocusEvent._internalWrap();
}
- factory FocusEvent._internalWrap() {
- return new FocusEvent.internal_();
- }
+ external factory FocusEvent._internalWrap();
@Deprecated("Internal Use Only")
FocusEvent.internal_() : super.internal_();
@@ -18424,9 +18259,7 @@
return new FontFaceSet._internalWrap();
}
- factory FontFaceSet._internalWrap() {
- return new FontFaceSet.internal_();
- }
+ external factory FontFaceSet._internalWrap();
@Deprecated("Internal Use Only")
FontFaceSet.internal_() : super.internal_();
@@ -18509,9 +18342,7 @@
return new FontFaceSetLoadEvent._internalWrap();
}
- factory FontFaceSetLoadEvent._internalWrap() {
- return new FontFaceSetLoadEvent.internal_();
- }
+ external factory FontFaceSetLoadEvent._internalWrap();
@Deprecated("Internal Use Only")
FontFaceSetLoadEvent.internal_() : super.internal_();
@@ -18597,9 +18428,7 @@
return new FormElement._internalWrap();
}
- factory FormElement._internalWrap() {
- return new FormElement.internal_();
- }
+ external factory FormElement._internalWrap();
@Deprecated("Internal Use Only")
FormElement.internal_() : super.internal_();
@@ -18837,9 +18666,7 @@
return new GamepadEvent._internalWrap();
}
- factory GamepadEvent._internalWrap() {
- return new GamepadEvent.internal_();
- }
+ external factory GamepadEvent._internalWrap();
@Deprecated("Internal Use Only")
GamepadEvent.internal_() : super.internal_();
@@ -19662,9 +19489,7 @@
return new HRElement._internalWrap();
}
- factory HRElement._internalWrap() {
- return new HRElement.internal_();
- }
+ external factory HRElement._internalWrap();
@Deprecated("Internal Use Only")
HRElement.internal_() : super.internal_();
@@ -19719,9 +19544,7 @@
return new HashChangeEvent._internalWrap();
}
- factory HashChangeEvent._internalWrap() {
- return new HashChangeEvent.internal_();
- }
+ external factory HashChangeEvent._internalWrap();
@Deprecated("Internal Use Only")
HashChangeEvent.internal_() : super.internal_();
@@ -19766,9 +19589,7 @@
return new HeadElement._internalWrap();
}
- factory HeadElement._internalWrap() {
- return new HeadElement.internal_();
- }
+ external factory HeadElement._internalWrap();
@Deprecated("Internal Use Only")
HeadElement.internal_() : super.internal_();
@@ -19894,9 +19715,7 @@
return new HeadingElement._internalWrap();
}
- factory HeadingElement._internalWrap() {
- return new HeadingElement.internal_();
- }
+ external factory HeadingElement._internalWrap();
@Deprecated("Internal Use Only")
HeadingElement.internal_() : super.internal_();
@@ -20086,9 +19905,7 @@
return new HtmlDocument._internalWrap();
}
- factory HtmlDocument._internalWrap() {
- return new HtmlDocument.internal_();
- }
+ external factory HtmlDocument._internalWrap();
@Deprecated("Internal Use Only")
HtmlDocument.internal_() : super.internal_();
@@ -20888,9 +20705,7 @@
return new HtmlElement._internalWrap();
}
- factory HtmlElement._internalWrap() {
- return new HtmlElement.internal_();
- }
+ external factory HtmlElement._internalWrap();
@Deprecated("Internal Use Only")
HtmlElement.internal_() : super.internal_();
@@ -21309,9 +21124,7 @@
return new HtmlFormControlsCollection._internalWrap();
}
- factory HtmlFormControlsCollection._internalWrap() {
- return new HtmlFormControlsCollection.internal_();
- }
+ external factory HtmlFormControlsCollection._internalWrap();
@Deprecated("Internal Use Only")
HtmlFormControlsCollection.internal_() : super.internal_();
@@ -21345,9 +21158,7 @@
return new HtmlHtmlElement._internalWrap();
}
- factory HtmlHtmlElement._internalWrap() {
- return new HtmlHtmlElement.internal_();
- }
+ external factory HtmlHtmlElement._internalWrap();
@Deprecated("Internal Use Only")
HtmlHtmlElement.internal_() : super.internal_();
@@ -21379,9 +21190,7 @@
return new HtmlOptionsCollection._internalWrap();
}
- factory HtmlOptionsCollection._internalWrap() {
- return new HtmlOptionsCollection.internal_();
- }
+ external factory HtmlOptionsCollection._internalWrap();
@Deprecated("Internal Use Only")
HtmlOptionsCollection.internal_() : super.internal_();
@@ -21791,9 +21600,7 @@
return new HttpRequest._internalWrap();
}
- factory HttpRequest._internalWrap() {
- return new HttpRequest.internal_();
- }
+ external factory HttpRequest._internalWrap();
@Deprecated("Internal Use Only")
HttpRequest.internal_() : super.internal_();
@@ -22204,9 +22011,7 @@
return new HttpRequestEventTarget._internalWrap();
}
- factory HttpRequestEventTarget._internalWrap() {
- return new HttpRequestEventTarget.internal_();
- }
+ external factory HttpRequestEventTarget._internalWrap();
@Deprecated("Internal Use Only")
HttpRequestEventTarget.internal_() : super.internal_();
@@ -22284,9 +22089,7 @@
return new HttpRequestUpload._internalWrap();
}
- factory HttpRequestUpload._internalWrap() {
- return new HttpRequestUpload.internal_();
- }
+ external factory HttpRequestUpload._internalWrap();
@Deprecated("Internal Use Only")
HttpRequestUpload.internal_() : super.internal_();
@@ -22316,9 +22119,7 @@
return new IFrameElement._internalWrap();
}
- factory IFrameElement._internalWrap() {
- return new IFrameElement.internal_();
- }
+ external factory IFrameElement._internalWrap();
@Deprecated("Internal Use Only")
IFrameElement.internal_() : super.internal_();
@@ -22527,9 +22328,7 @@
return new ImageElement._internalWrap();
}
- factory ImageElement._internalWrap() {
- return new ImageElement.internal_();
- }
+ external factory ImageElement._internalWrap();
@Deprecated("Internal Use Only")
ImageElement.internal_() : super.internal_();
@@ -22729,9 +22528,7 @@
return new InputElement._internalWrap();
}
- factory InputElement._internalWrap() {
- return new InputElement.internal_();
- }
+ external factory InputElement._internalWrap();
@Deprecated("Internal Use Only")
InputElement.internal_() : super.internal_();
@@ -23751,9 +23548,7 @@
return new InputMethodContext._internalWrap();
}
- factory InputMethodContext._internalWrap() {
- return new InputMethodContext.internal_();
- }
+ external factory InputMethodContext._internalWrap();
@Deprecated("Internal Use Only")
InputMethodContext.internal_() : super.internal_();
@@ -23803,9 +23598,7 @@
return new InstallEvent._internalWrap();
}
- factory InstallEvent._internalWrap() {
- return new InstallEvent.internal_();
- }
+ external factory InstallEvent._internalWrap();
@Deprecated("Internal Use Only")
InstallEvent.internal_() : super.internal_();
@@ -23857,9 +23650,7 @@
return new KeyboardEvent._internalWrap();
}
- factory KeyboardEvent._internalWrap() {
- return new KeyboardEvent.internal_();
- }
+ external factory KeyboardEvent._internalWrap();
@Deprecated("Internal Use Only")
KeyboardEvent.internal_() : super.internal_();
@@ -23958,9 +23749,7 @@
return new KeygenElement._internalWrap();
}
- factory KeygenElement._internalWrap() {
- return new KeygenElement.internal_();
- }
+ external factory KeygenElement._internalWrap();
@Deprecated("Internal Use Only")
KeygenElement.internal_() : super.internal_();
@@ -24072,9 +23861,7 @@
return new LIElement._internalWrap();
}
- factory LIElement._internalWrap() {
- return new LIElement.internal_();
- }
+ external factory LIElement._internalWrap();
@Deprecated("Internal Use Only")
LIElement.internal_() : super.internal_();
@@ -24118,9 +23905,7 @@
return new LabelElement._internalWrap();
}
- factory LabelElement._internalWrap() {
- return new LabelElement.internal_();
- }
+ external factory LabelElement._internalWrap();
@Deprecated("Internal Use Only")
LabelElement.internal_() : super.internal_();
@@ -24172,9 +23957,7 @@
return new LegendElement._internalWrap();
}
- factory LegendElement._internalWrap() {
- return new LegendElement.internal_();
- }
+ external factory LegendElement._internalWrap();
@Deprecated("Internal Use Only")
LegendElement.internal_() : super.internal_();
@@ -24212,9 +23995,7 @@
return new LinkElement._internalWrap();
}
- factory LinkElement._internalWrap() {
- return new LinkElement.internal_();
- }
+ external factory LinkElement._internalWrap();
@Deprecated("Internal Use Only")
LinkElement.internal_() : super.internal_();
@@ -24340,9 +24121,7 @@
return new LocalCredential._internalWrap();
}
- factory LocalCredential._internalWrap() {
- return new LocalCredential.internal_();
- }
+ external factory LocalCredential._internalWrap();
@Deprecated("Internal Use Only")
LocalCredential.internal_() : super.internal_();
@@ -24518,9 +24297,7 @@
return new MapElement._internalWrap();
}
- factory MapElement._internalWrap() {
- return new MapElement.internal_();
- }
+ external factory MapElement._internalWrap();
@Deprecated("Internal Use Only")
MapElement.internal_() : super.internal_();
@@ -24572,9 +24349,7 @@
return new MediaController._internalWrap();
}
- factory MediaController._internalWrap() {
- return new MediaController.internal_();
- }
+ external factory MediaController._internalWrap();
@Deprecated("Internal Use Only")
MediaController.internal_() : super.internal_();
@@ -24793,9 +24568,7 @@
return new MediaElement._internalWrap();
}
- factory MediaElement._internalWrap() {
- return new MediaElement.internal_();
- }
+ external factory MediaElement._internalWrap();
@Deprecated("Internal Use Only")
MediaElement.internal_() : super.internal_();
@@ -25279,9 +25052,7 @@
return new MediaKeyEvent._internalWrap();
}
- factory MediaKeyEvent._internalWrap() {
- return new MediaKeyEvent.internal_();
- }
+ external factory MediaKeyEvent._internalWrap();
@Deprecated("Internal Use Only")
MediaKeyEvent.internal_() : super.internal_();
@@ -25337,9 +25108,7 @@
return new MediaKeyMessageEvent._internalWrap();
}
- factory MediaKeyMessageEvent._internalWrap() {
- return new MediaKeyMessageEvent.internal_();
- }
+ external factory MediaKeyMessageEvent._internalWrap();
@Deprecated("Internal Use Only")
MediaKeyMessageEvent.internal_() : super.internal_();
@@ -25375,9 +25144,7 @@
return new MediaKeyNeededEvent._internalWrap();
}
- factory MediaKeyNeededEvent._internalWrap() {
- return new MediaKeyNeededEvent.internal_();
- }
+ external factory MediaKeyNeededEvent._internalWrap();
@Deprecated("Internal Use Only")
MediaKeyNeededEvent.internal_() : super.internal_();
@@ -25414,9 +25181,7 @@
return new MediaKeySession._internalWrap();
}
- factory MediaKeySession._internalWrap() {
- return new MediaKeySession.internal_();
- }
+ external factory MediaKeySession._internalWrap();
@Deprecated("Internal Use Only")
MediaKeySession.internal_() : super.internal_();
@@ -25596,9 +25361,7 @@
return new MediaQueryList._internalWrap();
}
- factory MediaQueryList._internalWrap() {
- return new MediaQueryList.internal_();
- }
+ external factory MediaQueryList._internalWrap();
@Deprecated("Internal Use Only")
MediaQueryList.internal_() : super.internal_();
@@ -25646,9 +25409,7 @@
return new MediaQueryListEvent._internalWrap();
}
- factory MediaQueryListEvent._internalWrap() {
- return new MediaQueryListEvent.internal_();
- }
+ external factory MediaQueryListEvent._internalWrap();
@Deprecated("Internal Use Only")
MediaQueryListEvent.internal_() : super.internal_();
@@ -25694,9 +25455,7 @@
return new MediaSource._internalWrap();
}
- factory MediaSource._internalWrap() {
- return new MediaSource.internal_();
- }
+ external factory MediaSource._internalWrap();
@Deprecated("Internal Use Only")
MediaSource.internal_() : super.internal_();
@@ -25811,9 +25570,7 @@
return new MediaStream._internalWrap();
}
- factory MediaStream._internalWrap() {
- return new MediaStream.internal_();
- }
+ external factory MediaStream._internalWrap();
@Deprecated("Internal Use Only")
MediaStream.internal_() : super.internal_();
@@ -25913,9 +25670,7 @@
return new MediaStreamEvent._internalWrap();
}
- factory MediaStreamEvent._internalWrap() {
- return new MediaStreamEvent.internal_();
- }
+ external factory MediaStreamEvent._internalWrap();
@Deprecated("Internal Use Only")
MediaStreamEvent.internal_() : super.internal_();
@@ -25981,9 +25736,7 @@
return new MediaStreamTrack._internalWrap();
}
- factory MediaStreamTrack._internalWrap() {
- return new MediaStreamTrack.internal_();
- }
+ external factory MediaStreamTrack._internalWrap();
@Deprecated("Internal Use Only")
MediaStreamTrack.internal_() : super.internal_();
@@ -26078,9 +25831,7 @@
return new MediaStreamTrackEvent._internalWrap();
}
- factory MediaStreamTrackEvent._internalWrap() {
- return new MediaStreamTrackEvent.internal_();
- }
+ external factory MediaStreamTrackEvent._internalWrap();
@Deprecated("Internal Use Only")
MediaStreamTrackEvent.internal_() : super.internal_();
@@ -26179,9 +25930,7 @@
return new MenuElement._internalWrap();
}
- factory MenuElement._internalWrap() {
- return new MenuElement.internal_();
- }
+ external factory MenuElement._internalWrap();
@Deprecated("Internal Use Only")
MenuElement.internal_() : super.internal_();
@@ -26234,9 +25983,7 @@
return new MenuItemElement._internalWrap();
}
- factory MenuItemElement._internalWrap() {
- return new MenuItemElement.internal_();
- }
+ external factory MenuItemElement._internalWrap();
@Deprecated("Internal Use Only")
MenuItemElement.internal_() : super.internal_();
@@ -26367,9 +26114,7 @@
return new MessageEvent._internalWrap();
}
- factory MessageEvent._internalWrap() {
- return new MessageEvent.internal_();
- }
+ external factory MessageEvent._internalWrap();
@Deprecated("Internal Use Only")
MessageEvent.internal_() : super.internal_();
@@ -26427,9 +26172,7 @@
return new MessagePort._internalWrap();
}
- factory MessagePort._internalWrap() {
- return new MessagePort.internal_();
- }
+ external factory MessagePort._internalWrap();
@Deprecated("Internal Use Only")
MessagePort.internal_() : super.internal_();
@@ -26476,9 +26219,7 @@
return new MetaElement._internalWrap();
}
- factory MetaElement._internalWrap() {
- return new MetaElement.internal_();
- }
+ external factory MetaElement._internalWrap();
@Deprecated("Internal Use Only")
MetaElement.internal_() : super.internal_();
@@ -26592,9 +26333,7 @@
return new MeterElement._internalWrap();
}
- factory MeterElement._internalWrap() {
- return new MeterElement.internal_();
- }
+ external factory MeterElement._internalWrap();
@Deprecated("Internal Use Only")
MeterElement.internal_() : super.internal_();
@@ -26704,9 +26443,7 @@
return new MidiAccess._internalWrap();
}
- factory MidiAccess._internalWrap() {
- return new MidiAccess.internal_();
- }
+ external factory MidiAccess._internalWrap();
@Deprecated("Internal Use Only")
MidiAccess.internal_() : super.internal_();
@@ -26757,9 +26494,7 @@
return new MidiConnectionEvent._internalWrap();
}
- factory MidiConnectionEvent._internalWrap() {
- return new MidiConnectionEvent.internal_();
- }
+ external factory MidiConnectionEvent._internalWrap();
@Deprecated("Internal Use Only")
MidiConnectionEvent.internal_() : super.internal_();
@@ -26801,9 +26536,7 @@
return new MidiInput._internalWrap();
}
- factory MidiInput._internalWrap() {
- return new MidiInput.internal_();
- }
+ external factory MidiInput._internalWrap();
@Deprecated("Internal Use Only")
MidiInput.internal_() : super.internal_();
@@ -26896,9 +26629,7 @@
return new MidiMessageEvent._internalWrap();
}
- factory MidiMessageEvent._internalWrap() {
- return new MidiMessageEvent.internal_();
- }
+ external factory MidiMessageEvent._internalWrap();
@Deprecated("Internal Use Only")
MidiMessageEvent.internal_() : super.internal_();
@@ -26934,9 +26665,7 @@
return new MidiOutput._internalWrap();
}
- factory MidiOutput._internalWrap() {
- return new MidiOutput.internal_();
- }
+ external factory MidiOutput._internalWrap();
@Deprecated("Internal Use Only")
MidiOutput.internal_() : super.internal_();
@@ -27043,9 +26772,7 @@
return new MidiPort._internalWrap();
}
- factory MidiPort._internalWrap() {
- return new MidiPort.internal_();
- }
+ external factory MidiPort._internalWrap();
@Deprecated("Internal Use Only")
MidiPort.internal_() : super.internal_();
@@ -27235,9 +26962,7 @@
return new ModElement._internalWrap();
}
- factory ModElement._internalWrap() {
- return new ModElement.internal_();
- }
+ external factory ModElement._internalWrap();
@Deprecated("Internal Use Only")
ModElement.internal_() : super.internal_();
@@ -27299,9 +27024,7 @@
return new MouseEvent._internalWrap();
}
- factory MouseEvent._internalWrap() {
- return new MouseEvent.internal_();
- }
+ external factory MouseEvent._internalWrap();
@Deprecated("Internal Use Only")
MouseEvent.internal_() : super.internal_();
@@ -28118,9 +27841,7 @@
return new NetworkInformation._internalWrap();
}
- factory NetworkInformation._internalWrap() {
- return new NetworkInformation.internal_();
- }
+ external factory NetworkInformation._internalWrap();
@Deprecated("Internal Use Only")
NetworkInformation.internal_() : super.internal_();
@@ -28420,9 +28141,7 @@
return new Node._internalWrap();
}
- factory Node._internalWrap() {
- return new Node.internal_();
- }
+ external factory Node._internalWrap();
@Deprecated("Internal Use Only")
Node.internal_() : super.internal_();
@@ -29026,9 +28745,7 @@
return new Notification._internalWrap();
}
- factory Notification._internalWrap() {
- return new Notification.internal_();
- }
+ external factory Notification._internalWrap();
@Deprecated("Internal Use Only")
Notification.internal_() : super.internal_();
@@ -29146,9 +28863,7 @@
return new OListElement._internalWrap();
}
- factory OListElement._internalWrap() {
- return new OListElement.internal_();
- }
+ external factory OListElement._internalWrap();
@Deprecated("Internal Use Only")
OListElement.internal_() : super.internal_();
@@ -29212,9 +28927,7 @@
return new ObjectElement._internalWrap();
}
- factory ObjectElement._internalWrap() {
- return new ObjectElement.internal_();
- }
+ external factory ObjectElement._internalWrap();
@Deprecated("Internal Use Only")
ObjectElement.internal_() : super.internal_();
@@ -29343,9 +29056,7 @@
return new OptGroupElement._internalWrap();
}
- factory OptGroupElement._internalWrap() {
- return new OptGroupElement.internal_();
- }
+ external factory OptGroupElement._internalWrap();
@Deprecated("Internal Use Only")
OptGroupElement.internal_() : super.internal_();
@@ -29397,9 +29108,7 @@
return new OptionElement._internalWrap();
}
- factory OptionElement._internalWrap() {
- return new OptionElement.internal_();
- }
+ external factory OptionElement._internalWrap();
@Deprecated("Internal Use Only")
OptionElement.internal_() : super.internal_();
@@ -29486,9 +29195,7 @@
return new OutputElement._internalWrap();
}
- factory OutputElement._internalWrap() {
- return new OutputElement.internal_();
- }
+ external factory OutputElement._internalWrap();
@Deprecated("Internal Use Only")
OutputElement.internal_() : super.internal_();
@@ -29585,9 +29292,7 @@
return new OverflowEvent._internalWrap();
}
- factory OverflowEvent._internalWrap() {
- return new OverflowEvent.internal_();
- }
+ external factory OverflowEvent._internalWrap();
@Deprecated("Internal Use Only")
OverflowEvent.internal_() : super.internal_();
@@ -29639,9 +29344,7 @@
return new PageTransitionEvent._internalWrap();
}
- factory PageTransitionEvent._internalWrap() {
- return new PageTransitionEvent.internal_();
- }
+ external factory PageTransitionEvent._internalWrap();
@Deprecated("Internal Use Only")
PageTransitionEvent.internal_() : super.internal_();
@@ -29675,9 +29378,7 @@
return new ParagraphElement._internalWrap();
}
- factory ParagraphElement._internalWrap() {
- return new ParagraphElement.internal_();
- }
+ external factory ParagraphElement._internalWrap();
@Deprecated("Internal Use Only")
ParagraphElement.internal_() : super.internal_();
@@ -29714,9 +29415,7 @@
return new ParamElement._internalWrap();
}
- factory ParamElement._internalWrap() {
- return new ParamElement.internal_();
- }
+ external factory ParamElement._internalWrap();
@Deprecated("Internal Use Only")
ParamElement.internal_() : super.internal_();
@@ -29925,9 +29624,7 @@
return new Performance._internalWrap();
}
- factory Performance._internalWrap() {
- return new Performance.internal_();
- }
+ external factory Performance._internalWrap();
@Deprecated("Internal Use Only")
Performance.internal_() : super.internal_();
@@ -30087,9 +29784,7 @@
return new PerformanceMark._internalWrap();
}
- factory PerformanceMark._internalWrap() {
- return new PerformanceMark.internal_();
- }
+ external factory PerformanceMark._internalWrap();
@Deprecated("Internal Use Only")
PerformanceMark.internal_() : super.internal_();
@@ -30117,9 +29812,7 @@
return new PerformanceMeasure._internalWrap();
}
- factory PerformanceMeasure._internalWrap() {
- return new PerformanceMeasure.internal_();
- }
+ external factory PerformanceMeasure._internalWrap();
@Deprecated("Internal Use Only")
PerformanceMeasure.internal_() : super.internal_();
@@ -30201,9 +29894,7 @@
return new PerformanceResourceTiming._internalWrap();
}
- factory PerformanceResourceTiming._internalWrap() {
- return new PerformanceResourceTiming.internal_();
- }
+ external factory PerformanceResourceTiming._internalWrap();
@Deprecated("Internal Use Only")
PerformanceResourceTiming.internal_() : super.internal_();
@@ -30395,9 +30086,7 @@
return new PictureElement._internalWrap();
}
- factory PictureElement._internalWrap() {
- return new PictureElement.internal_();
- }
+ external factory PictureElement._internalWrap();
@Deprecated("Internal Use Only")
PictureElement.internal_() : super.internal_();
@@ -30584,9 +30273,7 @@
return new PluginPlaceholderElement._internalWrap();
}
- factory PluginPlaceholderElement._internalWrap() {
- return new PluginPlaceholderElement.internal_();
- }
+ external factory PluginPlaceholderElement._internalWrap();
@Deprecated("Internal Use Only")
PluginPlaceholderElement.internal_() : super.internal_();
@@ -30637,9 +30324,7 @@
return new PopStateEvent._internalWrap();
}
- factory PopStateEvent._internalWrap() {
- return new PopStateEvent.internal_();
- }
+ external factory PopStateEvent._internalWrap();
@Deprecated("Internal Use Only")
PopStateEvent.internal_() : super.internal_();
@@ -30743,9 +30428,7 @@
return new PreElement._internalWrap();
}
- factory PreElement._internalWrap() {
- return new PreElement.internal_();
- }
+ external factory PreElement._internalWrap();
@Deprecated("Internal Use Only")
PreElement.internal_() : super.internal_();
@@ -30778,9 +30461,7 @@
return new Presentation._internalWrap();
}
- factory Presentation._internalWrap() {
- return new Presentation.internal_();
- }
+ external factory Presentation._internalWrap();
@Deprecated("Internal Use Only")
Presentation.internal_() : super.internal_();
@@ -30807,9 +30488,7 @@
return new ProcessingInstruction._internalWrap();
}
- factory ProcessingInstruction._internalWrap() {
- return new ProcessingInstruction.internal_();
- }
+ external factory ProcessingInstruction._internalWrap();
@Deprecated("Internal Use Only")
ProcessingInstruction.internal_() : super.internal_();
@@ -30852,9 +30531,7 @@
return new ProgressElement._internalWrap();
}
- factory ProgressElement._internalWrap() {
- return new ProgressElement.internal_();
- }
+ external factory ProgressElement._internalWrap();
@Deprecated("Internal Use Only")
ProgressElement.internal_() : super.internal_();
@@ -30914,9 +30591,7 @@
return new ProgressEvent._internalWrap();
}
- factory ProgressEvent._internalWrap() {
- return new ProgressEvent.internal_();
- }
+ external factory ProgressEvent._internalWrap();
@Deprecated("Internal Use Only")
ProgressEvent.internal_() : super.internal_();
@@ -30955,9 +30630,7 @@
return new PushEvent._internalWrap();
}
- factory PushEvent._internalWrap() {
- return new PushEvent.internal_();
- }
+ external factory PushEvent._internalWrap();
@Deprecated("Internal Use Only")
PushEvent.internal_() : super.internal_();
@@ -31067,9 +30740,7 @@
return new QuoteElement._internalWrap();
}
- factory QuoteElement._internalWrap() {
- return new QuoteElement.internal_();
- }
+ external factory QuoteElement._internalWrap();
@Deprecated("Internal Use Only")
QuoteElement.internal_() : super.internal_();
@@ -31399,9 +31070,7 @@
return new RelatedEvent._internalWrap();
}
- factory RelatedEvent._internalWrap() {
- return new RelatedEvent.internal_();
- }
+ external factory RelatedEvent._internalWrap();
@Deprecated("Internal Use Only")
RelatedEvent.internal_() : super.internal_();
@@ -31443,9 +31112,7 @@
return new ResourceProgressEvent._internalWrap();
}
- factory ResourceProgressEvent._internalWrap() {
- return new ResourceProgressEvent.internal_();
- }
+ external factory ResourceProgressEvent._internalWrap();
@Deprecated("Internal Use Only")
ResourceProgressEvent.internal_() : super.internal_();
@@ -31517,9 +31184,7 @@
return new RtcDataChannel._internalWrap();
}
- factory RtcDataChannel._internalWrap() {
- return new RtcDataChannel.internal_();
- }
+ external factory RtcDataChannel._internalWrap();
@Deprecated("Internal Use Only")
RtcDataChannel.internal_() : super.internal_();
@@ -31661,9 +31326,7 @@
return new RtcDataChannelEvent._internalWrap();
}
- factory RtcDataChannelEvent._internalWrap() {
- return new RtcDataChannelEvent.internal_();
- }
+ external factory RtcDataChannelEvent._internalWrap();
@Deprecated("Internal Use Only")
RtcDataChannelEvent.internal_() : super.internal_();
@@ -31705,9 +31368,7 @@
return new RtcDtmfSender._internalWrap();
}
- factory RtcDtmfSender._internalWrap() {
- return new RtcDtmfSender.internal_();
- }
+ external factory RtcDtmfSender._internalWrap();
@Deprecated("Internal Use Only")
RtcDtmfSender.internal_() : super.internal_();
@@ -31773,9 +31434,7 @@
return new RtcDtmfToneChangeEvent._internalWrap();
}
- factory RtcDtmfToneChangeEvent._internalWrap() {
- return new RtcDtmfToneChangeEvent.internal_();
- }
+ external factory RtcDtmfToneChangeEvent._internalWrap();
@Deprecated("Internal Use Only")
RtcDtmfToneChangeEvent.internal_() : super.internal_();
@@ -31870,9 +31529,7 @@
return new RtcIceCandidateEvent._internalWrap();
}
- factory RtcIceCandidateEvent._internalWrap() {
- return new RtcIceCandidateEvent.internal_();
- }
+ external factory RtcIceCandidateEvent._internalWrap();
@Deprecated("Internal Use Only")
RtcIceCandidateEvent.internal_() : super.internal_();
@@ -32012,9 +31669,7 @@
return new RtcPeerConnection._internalWrap();
}
- factory RtcPeerConnection._internalWrap() {
- return new RtcPeerConnection.internal_();
- }
+ external factory RtcPeerConnection._internalWrap();
@Deprecated("Internal Use Only")
RtcPeerConnection.internal_() : super.internal_();
@@ -32436,9 +32091,7 @@
return new ScreenOrientation._internalWrap();
}
- factory ScreenOrientation._internalWrap() {
- return new ScreenOrientation.internal_();
- }
+ external factory ScreenOrientation._internalWrap();
@Deprecated("Internal Use Only")
ScreenOrientation.internal_() : super.internal_();
@@ -32493,9 +32146,7 @@
return new ScriptElement._internalWrap();
}
- factory ScriptElement._internalWrap() {
- return new ScriptElement.internal_();
- }
+ external factory ScriptElement._internalWrap();
@Deprecated("Internal Use Only")
ScriptElement.internal_() : super.internal_();
@@ -32603,9 +32254,7 @@
return new SecurityPolicyViolationEvent._internalWrap();
}
- factory SecurityPolicyViolationEvent._internalWrap() {
- return new SecurityPolicyViolationEvent.internal_();
- }
+ external factory SecurityPolicyViolationEvent._internalWrap();
@Deprecated("Internal Use Only")
SecurityPolicyViolationEvent.internal_() : super.internal_();
@@ -32673,9 +32322,7 @@
return new SelectElement._internalWrap();
}
- factory SelectElement._internalWrap() {
- return new SelectElement.internal_();
- }
+ external factory SelectElement._internalWrap();
@Deprecated("Internal Use Only")
SelectElement.internal_() : super.internal_();
@@ -33137,9 +32784,7 @@
return new ServiceWorkerGlobalScope._internalWrap();
}
- factory ServiceWorkerGlobalScope._internalWrap() {
- return new ServiceWorkerGlobalScope.internal_();
- }
+ external factory ServiceWorkerGlobalScope._internalWrap();
@Deprecated("Internal Use Only")
ServiceWorkerGlobalScope.internal_() : super.internal_();
@@ -33207,9 +32852,7 @@
return new ServiceWorkerRegistration._internalWrap();
}
- factory ServiceWorkerRegistration._internalWrap() {
- return new ServiceWorkerRegistration.internal_();
- }
+ external factory ServiceWorkerRegistration._internalWrap();
@Deprecated("Internal Use Only")
ServiceWorkerRegistration.internal_() : super.internal_();
@@ -33267,9 +32910,7 @@
return new ShadowElement._internalWrap();
}
- factory ShadowElement._internalWrap() {
- return new ShadowElement.internal_();
- }
+ external factory ShadowElement._internalWrap();
@Deprecated("Internal Use Only")
ShadowElement.internal_() : super.internal_();
@@ -33311,9 +32952,7 @@
return new ShadowRoot._internalWrap();
}
- factory ShadowRoot._internalWrap() {
- return new ShadowRoot.internal_();
- }
+ external factory ShadowRoot._internalWrap();
@Deprecated("Internal Use Only")
ShadowRoot.internal_() : super.internal_();
@@ -33439,9 +33078,7 @@
return new SharedWorker._internalWrap();
}
- factory SharedWorker._internalWrap() {
- return new SharedWorker.internal_();
- }
+ external factory SharedWorker._internalWrap();
@Deprecated("Internal Use Only")
SharedWorker.internal_() : super.internal_();
@@ -33493,9 +33130,7 @@
return new SharedWorkerGlobalScope._internalWrap();
}
- factory SharedWorkerGlobalScope._internalWrap() {
- return new SharedWorkerGlobalScope.internal_();
- }
+ external factory SharedWorkerGlobalScope._internalWrap();
@Deprecated("Internal Use Only")
SharedWorkerGlobalScope.internal_() : super.internal_();
@@ -33534,9 +33169,7 @@
return new SourceBuffer._internalWrap();
}
- factory SourceBuffer._internalWrap() {
- return new SourceBuffer.internal_();
- }
+ external factory SourceBuffer._internalWrap();
@Deprecated("Internal Use Only")
SourceBuffer.internal_() : super.internal_();
@@ -33639,9 +33272,7 @@
return new SourceBufferList._internalWrap();
}
- factory SourceBufferList._internalWrap() {
- return new SourceBufferList.internal_();
- }
+ external factory SourceBufferList._internalWrap();
@Deprecated("Internal Use Only")
SourceBufferList.internal_() : super.internal_();
@@ -33725,9 +33356,7 @@
return new SourceElement._internalWrap();
}
- factory SourceElement._internalWrap() {
- return new SourceElement.internal_();
- }
+ external factory SourceElement._internalWrap();
@Deprecated("Internal Use Only")
SourceElement.internal_() : super.internal_();
@@ -33867,9 +33496,7 @@
return new SpanElement._internalWrap();
}
- factory SpanElement._internalWrap() {
- return new SpanElement.internal_();
- }
+ external factory SpanElement._internalWrap();
@Deprecated("Internal Use Only")
SpanElement.internal_() : super.internal_();
@@ -34182,9 +33809,7 @@
return new SpeechRecognition._internalWrap();
}
- factory SpeechRecognition._internalWrap() {
- return new SpeechRecognition.internal_();
- }
+ external factory SpeechRecognition._internalWrap();
@Deprecated("Internal Use Only")
SpeechRecognition.internal_() : super.internal_();
@@ -34363,9 +33988,7 @@
return new SpeechRecognitionError._internalWrap();
}
- factory SpeechRecognitionError._internalWrap() {
- return new SpeechRecognitionError.internal_();
- }
+ external factory SpeechRecognitionError._internalWrap();
@Deprecated("Internal Use Only")
SpeechRecognitionError.internal_() : super.internal_();
@@ -34402,9 +34025,7 @@
return new SpeechRecognitionEvent._internalWrap();
}
- factory SpeechRecognitionEvent._internalWrap() {
- return new SpeechRecognitionEvent.internal_();
- }
+ external factory SpeechRecognitionEvent._internalWrap();
@Deprecated("Internal Use Only")
SpeechRecognitionEvent.internal_() : super.internal_();
@@ -34492,9 +34113,7 @@
return new SpeechSynthesis._internalWrap();
}
- factory SpeechSynthesis._internalWrap() {
- return new SpeechSynthesis.internal_();
- }
+ external factory SpeechSynthesis._internalWrap();
@Deprecated("Internal Use Only")
SpeechSynthesis.internal_() : super.internal_();
@@ -34554,9 +34173,7 @@
return new SpeechSynthesisEvent._internalWrap();
}
- factory SpeechSynthesisEvent._internalWrap() {
- return new SpeechSynthesisEvent.internal_();
- }
+ external factory SpeechSynthesisEvent._internalWrap();
@Deprecated("Internal Use Only")
SpeechSynthesisEvent.internal_() : super.internal_();
@@ -34672,9 +34289,7 @@
return new SpeechSynthesisUtterance._internalWrap();
}
- factory SpeechSynthesisUtterance._internalWrap() {
- return new SpeechSynthesisUtterance.internal_();
- }
+ external factory SpeechSynthesisUtterance._internalWrap();
@Deprecated("Internal Use Only")
SpeechSynthesisUtterance.internal_() : super.internal_();
@@ -35016,9 +34631,7 @@
return new StorageEvent._internalWrap();
}
- factory StorageEvent._internalWrap() {
- return new StorageEvent.internal_();
- }
+ external factory StorageEvent._internalWrap();
@Deprecated("Internal Use Only")
StorageEvent.internal_() : super.internal_();
@@ -35192,9 +34805,7 @@
return new StyleElement._internalWrap();
}
- factory StyleElement._internalWrap() {
- return new StyleElement.internal_();
- }
+ external factory StyleElement._internalWrap();
@Deprecated("Internal Use Only")
StyleElement.internal_() : super.internal_();
@@ -35358,9 +34969,7 @@
return new TableCaptionElement._internalWrap();
}
- factory TableCaptionElement._internalWrap() {
- return new TableCaptionElement.internal_();
- }
+ external factory TableCaptionElement._internalWrap();
@Deprecated("Internal Use Only")
TableCaptionElement.internal_() : super.internal_();
@@ -35396,9 +35005,7 @@
return new TableCellElement._internalWrap();
}
- factory TableCellElement._internalWrap() {
- return new TableCellElement.internal_();
- }
+ external factory TableCellElement._internalWrap();
@Deprecated("Internal Use Only")
TableCellElement.internal_() : super.internal_();
@@ -35462,9 +35069,7 @@
return new TableColElement._internalWrap();
}
- factory TableColElement._internalWrap() {
- return new TableColElement.internal_();
- }
+ external factory TableColElement._internalWrap();
@Deprecated("Internal Use Only")
TableColElement.internal_() : super.internal_();
@@ -35526,9 +35131,7 @@
return new TableElement._internalWrap();
}
- factory TableElement._internalWrap() {
- return new TableElement.internal_();
- }
+ external factory TableElement._internalWrap();
@Deprecated("Internal Use Only")
TableElement.internal_() : super.internal_();
@@ -35644,9 +35247,7 @@
return new TableRowElement._internalWrap();
}
- factory TableRowElement._internalWrap() {
- return new TableRowElement.internal_();
- }
+ external factory TableRowElement._internalWrap();
@Deprecated("Internal Use Only")
TableRowElement.internal_() : super.internal_();
@@ -35710,9 +35311,7 @@
return new TableSectionElement._internalWrap();
}
- factory TableSectionElement._internalWrap() {
- return new TableSectionElement.internal_();
- }
+ external factory TableSectionElement._internalWrap();
@Deprecated("Internal Use Only")
TableSectionElement.internal_() : super.internal_();
@@ -35765,9 +35364,7 @@
return new TemplateElement._internalWrap();
}
- factory TemplateElement._internalWrap() {
- return new TemplateElement.internal_();
- }
+ external factory TemplateElement._internalWrap();
@Deprecated("Internal Use Only")
TemplateElement.internal_() : super.internal_();
@@ -35822,9 +35419,7 @@
return new Text._internalWrap();
}
- factory Text._internalWrap() {
- return new Text.internal_();
- }
+ external factory Text._internalWrap();
@Deprecated("Internal Use Only")
Text.internal_() : super.internal_();
@@ -35867,9 +35462,7 @@
return new TextAreaElement._internalWrap();
}
- factory TextAreaElement._internalWrap() {
- return new TextAreaElement.internal_();
- }
+ external factory TextAreaElement._internalWrap();
@Deprecated("Internal Use Only")
TextAreaElement.internal_() : super.internal_();
@@ -36114,9 +35707,7 @@
return new TextEvent._internalWrap();
}
- factory TextEvent._internalWrap() {
- return new TextEvent.internal_();
- }
+ external factory TextEvent._internalWrap();
@Deprecated("Internal Use Only")
TextEvent.internal_() : super.internal_();
@@ -36250,9 +35841,7 @@
return new TextTrack._internalWrap();
}
- factory TextTrack._internalWrap() {
- return new TextTrack.internal_();
- }
+ external factory TextTrack._internalWrap();
@Deprecated("Internal Use Only")
TextTrack.internal_() : super.internal_();
@@ -36361,9 +35950,7 @@
return new TextTrackCue._internalWrap();
}
- factory TextTrackCue._internalWrap() {
- return new TextTrackCue.internal_();
- }
+ external factory TextTrackCue._internalWrap();
@Deprecated("Internal Use Only")
TextTrackCue.internal_() : super.internal_();
@@ -36541,9 +36128,7 @@
return new TextTrackList._internalWrap();
}
- factory TextTrackList._internalWrap() {
- return new TextTrackList.internal_();
- }
+ external factory TextTrackList._internalWrap();
@Deprecated("Internal Use Only")
TextTrackList.internal_() : super.internal_();
@@ -36813,9 +36398,7 @@
return new TitleElement._internalWrap();
}
- factory TitleElement._internalWrap() {
- return new TitleElement.internal_();
- }
+ external factory TitleElement._internalWrap();
@Deprecated("Internal Use Only")
TitleElement.internal_() : super.internal_();
@@ -36982,9 +36565,7 @@
return new TouchEvent._internalWrap();
}
- factory TouchEvent._internalWrap() {
- return new TouchEvent.internal_();
- }
+ external factory TouchEvent._internalWrap();
@Deprecated("Internal Use Only")
TouchEvent.internal_() : super.internal_();
@@ -37151,9 +36732,7 @@
return new TrackElement._internalWrap();
}
- factory TrackElement._internalWrap() {
- return new TrackElement.internal_();
- }
+ external factory TrackElement._internalWrap();
@Deprecated("Internal Use Only")
TrackElement.internal_() : super.internal_();
@@ -37263,9 +36842,7 @@
return new TrackEvent._internalWrap();
}
- factory TrackEvent._internalWrap() {
- return new TrackEvent.internal_();
- }
+ external factory TrackEvent._internalWrap();
@Deprecated("Internal Use Only")
TrackEvent.internal_() : super.internal_();
@@ -37295,9 +36872,7 @@
return new TransitionEvent._internalWrap();
}
- factory TransitionEvent._internalWrap() {
- return new TransitionEvent.internal_();
- }
+ external factory TransitionEvent._internalWrap();
@Deprecated("Internal Use Only")
TransitionEvent.internal_() : super.internal_();
@@ -37428,9 +37003,7 @@
return new UIEvent._internalWrap();
}
- factory UIEvent._internalWrap() {
- return new UIEvent.internal_();
- }
+ external factory UIEvent._internalWrap();
@Deprecated("Internal Use Only")
UIEvent.internal_() : super.internal_();
@@ -37519,9 +37092,7 @@
return new UListElement._internalWrap();
}
- factory UListElement._internalWrap() {
- return new UListElement.internal_();
- }
+ external factory UListElement._internalWrap();
@Deprecated("Internal Use Only")
UListElement.internal_() : super.internal_();
@@ -37553,9 +37124,7 @@
return new UnknownElement._internalWrap();
}
- factory UnknownElement._internalWrap() {
- return new UnknownElement.internal_();
- }
+ external factory UnknownElement._internalWrap();
@Deprecated("Internal Use Only")
UnknownElement.internal_() : super.internal_();
@@ -38015,9 +37584,7 @@
return new VideoElement._internalWrap();
}
- factory VideoElement._internalWrap() {
- return new VideoElement.internal_();
- }
+ external factory VideoElement._internalWrap();
@Deprecated("Internal Use Only")
VideoElement.internal_() : super.internal_();
@@ -38232,9 +37799,7 @@
return new VideoTrackList._internalWrap();
}
- factory VideoTrackList._internalWrap() {
- return new VideoTrackList.internal_();
- }
+ external factory VideoTrackList._internalWrap();
@Deprecated("Internal Use Only")
VideoTrackList.internal_() : super.internal_();
@@ -38303,9 +37868,7 @@
return new VttCue._internalWrap();
}
- factory VttCue._internalWrap() {
- return new VttCue.internal_();
- }
+ external factory VttCue._internalWrap();
@Deprecated("Internal Use Only")
VttCue.internal_() : super.internal_();
@@ -38677,9 +38240,7 @@
return new WebSocket._internalWrap();
}
- factory WebSocket._internalWrap() {
- return new WebSocket.internal_();
- }
+ external factory WebSocket._internalWrap();
@Deprecated("Internal Use Only")
WebSocket.internal_() : super.internal_();
@@ -38851,9 +38412,7 @@
return new WheelEvent._internalWrap();
}
- factory WheelEvent._internalWrap() {
- return new WheelEvent.internal_();
- }
+ external factory WheelEvent._internalWrap();
@Deprecated("Internal Use Only")
WheelEvent.internal_() : super.internal_();
@@ -39193,9 +38752,7 @@
return new Window._internalWrap();
}
- factory Window._internalWrap() {
- return new Window.internal_();
- }
+ external factory Window._internalWrap();
@Deprecated("Internal Use Only")
Window.internal_() : super.internal_();
@@ -40663,9 +40220,7 @@
return new Worker._internalWrap();
}
- factory Worker._internalWrap() {
- return new Worker.internal_();
- }
+ external factory Worker._internalWrap();
@Deprecated("Internal Use Only")
Worker.internal_() : super.internal_();
@@ -40714,9 +40269,7 @@
return new WorkerConsole._internalWrap();
}
- factory WorkerConsole._internalWrap() {
- return new WorkerConsole.internal_();
- }
+ external factory WorkerConsole._internalWrap();
@Deprecated("Internal Use Only")
WorkerConsole.internal_() : super.internal_();
@@ -40754,9 +40307,7 @@
return new WorkerGlobalScope._internalWrap();
}
- factory WorkerGlobalScope._internalWrap() {
- return new WorkerGlobalScope.internal_();
- }
+ external factory WorkerGlobalScope._internalWrap();
@Deprecated("Internal Use Only")
WorkerGlobalScope.internal_() : super.internal_();
@@ -41194,9 +40745,7 @@
return new XmlDocument._internalWrap();
}
- factory XmlDocument._internalWrap() {
- return new XmlDocument.internal_();
- }
+ external factory XmlDocument._internalWrap();
@Deprecated("Internal Use Only")
XmlDocument.internal_() : super.internal_();
@@ -41337,9 +40886,7 @@
return new _Attr._internalWrap();
}
- factory _Attr._internalWrap() {
- return new _Attr.internal_();
- }
+ external factory _Attr._internalWrap();
@Deprecated("Internal Use Only")
_Attr.internal_() : super.internal_();
@@ -41404,9 +40951,7 @@
return new _CSSPrimitiveValue._internalWrap();
}
- factory _CSSPrimitiveValue._internalWrap() {
- return new _CSSPrimitiveValue.internal_();
- }
+ external factory _CSSPrimitiveValue._internalWrap();
@Deprecated("Internal Use Only")
_CSSPrimitiveValue.internal_() : super.internal_();
@@ -41434,9 +40979,7 @@
return new _CSSUnknownRule._internalWrap();
}
- factory _CSSUnknownRule._internalWrap() {
- return new _CSSUnknownRule.internal_();
- }
+ external factory _CSSUnknownRule._internalWrap();
@Deprecated("Internal Use Only")
_CSSUnknownRule.internal_() : super.internal_();
@@ -41912,9 +41455,7 @@
return new _CssValueList._internalWrap();
}
- factory _CssValueList._internalWrap() {
- return new _CssValueList.internal_();
- }
+ external factory _CssValueList._internalWrap();
@Deprecated("Internal Use Only")
_CssValueList.internal_() : super.internal_();
@@ -42028,9 +41569,7 @@
return new _DirectoryEntrySync._internalWrap();
}
- factory _DirectoryEntrySync._internalWrap() {
- return new _DirectoryEntrySync.internal_();
- }
+ external factory _DirectoryEntrySync._internalWrap();
@Deprecated("Internal Use Only")
_DirectoryEntrySync.internal_() : super.internal_();
@@ -42087,9 +41626,7 @@
return new _DocumentType._internalWrap();
}
- factory _DocumentType._internalWrap() {
- return new _DocumentType.internal_();
- }
+ external factory _DocumentType._internalWrap();
@Deprecated("Internal Use Only")
_DocumentType.internal_() : super.internal_();
@@ -42138,9 +41675,7 @@
return new _DomRect._internalWrap();
}
- factory _DomRect._internalWrap() {
- return new _DomRect.internal_();
- }
+ external factory _DomRect._internalWrap();
@Deprecated("Internal Use Only")
_DomRect.internal_() : super.internal_();
@@ -42239,9 +41774,7 @@
return new _FileEntrySync._internalWrap();
}
- factory _FileEntrySync._internalWrap() {
- return new _FileEntrySync.internal_();
- }
+ external factory _FileEntrySync._internalWrap();
@Deprecated("Internal Use Only")
_FileEntrySync.internal_() : super.internal_();
@@ -42457,9 +41990,7 @@
return new _HTMLAppletElement._internalWrap();
}
- factory _HTMLAppletElement._internalWrap() {
- return new _HTMLAppletElement.internal_();
- }
+ external factory _HTMLAppletElement._internalWrap();
@Deprecated("Internal Use Only")
_HTMLAppletElement.internal_() : super.internal_();
@@ -42493,9 +42024,7 @@
return new _HTMLDirectoryElement._internalWrap();
}
- factory _HTMLDirectoryElement._internalWrap() {
- return new _HTMLDirectoryElement.internal_();
- }
+ external factory _HTMLDirectoryElement._internalWrap();
@Deprecated("Internal Use Only")
_HTMLDirectoryElement.internal_() : super.internal_();
@@ -42529,9 +42058,7 @@
return new _HTMLFontElement._internalWrap();
}
- factory _HTMLFontElement._internalWrap() {
- return new _HTMLFontElement.internal_();
- }
+ external factory _HTMLFontElement._internalWrap();
@Deprecated("Internal Use Only")
_HTMLFontElement.internal_() : super.internal_();
@@ -42565,9 +42092,7 @@
return new _HTMLFrameElement._internalWrap();
}
- factory _HTMLFrameElement._internalWrap() {
- return new _HTMLFrameElement.internal_();
- }
+ external factory _HTMLFrameElement._internalWrap();
@Deprecated("Internal Use Only")
_HTMLFrameElement.internal_() : super.internal_();
@@ -42599,9 +42124,7 @@
return new _HTMLFrameSetElement._internalWrap();
}
- factory _HTMLFrameSetElement._internalWrap() {
- return new _HTMLFrameSetElement.internal_();
- }
+ external factory _HTMLFrameSetElement._internalWrap();
@Deprecated("Internal Use Only")
_HTMLFrameSetElement.internal_() : super.internal_();
@@ -42644,9 +42167,7 @@
return new _HTMLMarqueeElement._internalWrap();
}
- factory _HTMLMarqueeElement._internalWrap() {
- return new _HTMLMarqueeElement.internal_();
- }
+ external factory _HTMLMarqueeElement._internalWrap();
@Deprecated("Internal Use Only")
_HTMLMarqueeElement.internal_() : super.internal_();
@@ -42686,9 +42207,7 @@
return new _MutationEvent._internalWrap();
}
- factory _MutationEvent._internalWrap() {
- return new _MutationEvent.internal_();
- }
+ external factory _MutationEvent._internalWrap();
@Deprecated("Internal Use Only")
_MutationEvent.internal_() : super.internal_();
@@ -42885,9 +42404,7 @@
return new _RadioNodeList._internalWrap();
}
- factory _RadioNodeList._internalWrap() {
- return new _RadioNodeList.internal_();
- }
+ external factory _RadioNodeList._internalWrap();
@Deprecated("Internal Use Only")
_RadioNodeList.internal_() : super.internal_();
@@ -42965,9 +42482,7 @@
return new _Request._internalWrap();
}
- factory _Request._internalWrap() {
- return new _Request.internal_();
- }
+ external factory _Request._internalWrap();
@Deprecated("Internal Use Only")
_Request.internal_() : super.internal_();
@@ -43058,9 +42573,7 @@
return new _Response._internalWrap();
}
- factory _Response._internalWrap() {
- return new _Response.internal_();
- }
+ external factory _Response._internalWrap();
@Deprecated("Internal Use Only")
_Response.internal_() : super.internal_();
@@ -43085,9 +42598,7 @@
return new _ServiceWorker._internalWrap();
}
- factory _ServiceWorker._internalWrap() {
- return new _ServiceWorker.internal_();
- }
+ external factory _ServiceWorker._internalWrap();
@Deprecated("Internal Use Only")
_ServiceWorker.internal_() : super.internal_();
@@ -43320,9 +42831,7 @@
return new _WebKitCSSFilterValue._internalWrap();
}
- factory _WebKitCSSFilterValue._internalWrap() {
- return new _WebKitCSSFilterValue.internal_();
- }
+ external factory _WebKitCSSFilterValue._internalWrap();
@Deprecated("Internal Use Only")
_WebKitCSSFilterValue.internal_() : super.internal_();
@@ -43390,9 +42899,7 @@
return new _WebKitCSSTransformValue._internalWrap();
}
- factory _WebKitCSSTransformValue._internalWrap() {
- return new _WebKitCSSTransformValue.internal_();
- }
+ external factory _WebKitCSSTransformValue._internalWrap();
@Deprecated("Internal Use Only")
_WebKitCSSTransformValue.internal_() : super.internal_();
@@ -43534,9 +43041,7 @@
return new _XMLHttpRequestProgressEvent._internalWrap();
}
- factory _XMLHttpRequestProgressEvent._internalWrap() {
- return new _XMLHttpRequestProgressEvent.internal_();
- }
+ external factory _XMLHttpRequestProgressEvent._internalWrap();
@Deprecated("Internal Use Only")
_XMLHttpRequestProgressEvent.internal_() : super.internal_();
@@ -47719,7 +47224,7 @@
throw new UnsupportedError('$tag is not registered.');
}
jsObject = unwrap_jso(element);
- } else if (element.runtimeType == js.JsObjectImpl) {
+ } else if (element.runtimeType == js.JsObject) {
// It's a Polymer core element (written in JS).
jsObject = element;
} else if (isNativeElementExtension) {
@@ -47731,7 +47236,7 @@
} else if (tag != null && element.localName != tag) {
throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
} else if (tag == null) {
- throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
+ throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObject.');
}
// Remember Dart class to tagName for any upgrading done in wrap_jso.
diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
index 2403387..3e3e5c1 100644
--- a/sdk/lib/html/html_common/conversions_dartium.dart
+++ b/sdk/lib/html/html_common/conversions_dartium.dart
@@ -126,9 +126,14 @@
}
if (jsObject is js.JsArray) {
- var wrappingList = new DartHtmlWrappingList(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrappingList);
- return wrappingList;
+ wrapper = new js.JSArray.create(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrapper);
+ return wrapper;
+ }
+ if (jsObject is js.JsFunction) {
+ wrapper = new js.JSFunction.create(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrapper);
+ return wrapper;
}
// Try the most general type conversions on it.
@@ -144,14 +149,15 @@
if (constructor == null) {
// Perfectly valid case for JavaScript objects where __proto__ has
// intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
+ js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
return jsObject;
}
var jsTypeName = js.JsNative.getProperty(constructor, 'name');
if (jsTypeName is! String || jsTypeName.length == 0) {
// Not an html type.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
+ wrapper = new js.JSObject.create(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrapper);
+ return wrapper;
}
var dartClass_instance;
@@ -204,12 +210,11 @@
// TODO(jacobr): cache that this is not a dart:html JS class.
return dartClass_instance;
- } catch(e, stacktrace){
+ } catch (e, stacktrace) {
if (interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
+ if (e is DebugAssertException) window.console
+ .log("${e.message}\n ${stacktrace}");
+ else window.console.log("${stacktrace}");
}
}
@@ -236,31 +241,30 @@
return wrapper;
}
- // TODO(jacobr): auomatically wrapping JsArray here is fundamentally broken
- // as it hijacks adding custom methods on JS Array classes as part of the
- // new typed DartJsInterop.
- // To make this work we really need to make DartHtmlWrappingList extend
- // JsArrayImpl. Fixing this issue needs to be part of a broader refactor
- // that allows calling custom typed JS interop methods on all dart:html
- // classes.
if (jsObject is js.JsArray) {
- var wrappingList = new DartHtmlWrappingList(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrappingList);
- return wrappingList;
+ wrapper = new js.JSArray.create(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrapper);
+ return wrapper;
+ }
+ if (jsObject is js.JsFunction) {
+ wrapper = new js.JSFunction.create(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrapper);
+ return wrapper;
}
var constructor = js.JsNative.getProperty(jsObject, 'constructor');
if (constructor == null) {
// Perfectly valid case for JavaScript objects where __proto__ has
// intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
+ js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
return jsObject;
}
var jsTypeName = js.JsNative.getProperty(constructor, 'name');
if (jsTypeName is! String || jsTypeName.length == 0) {
// Not an html type.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
+ wrapper = new js.JSObject.create(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrapper);
+ return wrapper;
}
var func = getHtmlCreateFunction(jsTypeName);
@@ -270,13 +274,14 @@
js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
return dartClass_instance;
}
- return jsObject;
- } catch(e, stacktrace){
+ wrapper = new js.JSObject.create(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrapper);
+ return wrapper;
+ } catch (e, stacktrace) {
if (interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
+ if (e is DebugAssertException) window.console
+ .log("${e.message}\n ${stacktrace}");
+ else window.console.log("${stacktrace}");
}
}
@@ -333,7 +338,7 @@
} else if (runtimeType == TemplateElement) {
// Data binding with a Dart class.
tag = element.attributes['is'];
- } else if (runtimeType == js.JsObjectImpl) {
+ } else if (runtimeType == js.JsObject) {
// It's a Polymer core element (written in JS).
// Make sure it's an element anything else we can ignore.
if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
@@ -347,7 +352,8 @@
}
}
} else {
- throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+ throw new UnsupportedError(
+ 'Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
}
var entry = _knownCustomElements[tag];
@@ -378,19 +384,3 @@
}
return null;
}
-
-/**
- * Wraps a JsArray and will call wrap_jso on its entries.
- */
-class DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
- DartHtmlWrappingList(this.blink_jsObject);
-
- final js.JsArray blink_jsObject;
-
- operator [](int index) => wrap_jso_no_SerializedScriptvalue(js.JsNative.getArrayIndex(blink_jsObject, index));
-
- operator []=(int index, value) => blink_jsObject[index] = value;
-
- int get length => blink_jsObject.length;
- int set length(int newLength) => blink_jsObject.length = newLength;
-}
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 4ab3e30..36b35e3 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -247,9 +247,7 @@
return new CursorWithValue._internalWrap();
}
- factory CursorWithValue._internalWrap() {
- return new CursorWithValue.internal_();
- }
+ external factory CursorWithValue._internalWrap();
@Deprecated("Internal Use Only")
CursorWithValue.internal_() : super.internal_();
@@ -365,9 +363,7 @@
return new Database._internalWrap();
}
- factory Database._internalWrap() {
- return new Database.internal_();
- }
+ external factory Database._internalWrap();
@Deprecated("Internal Use Only")
Database.internal_() : super.internal_();
@@ -1126,9 +1122,7 @@
return new OpenDBRequest._internalWrap();
}
- factory OpenDBRequest._internalWrap() {
- return new OpenDBRequest.internal_();
- }
+ external factory OpenDBRequest._internalWrap();
@Deprecated("Internal Use Only")
OpenDBRequest.internal_() : super.internal_();
@@ -1185,9 +1179,7 @@
return new Request._internalWrap();
}
- factory Request._internalWrap() {
- return new Request.internal_();
- }
+ external factory Request._internalWrap();
@Deprecated("Internal Use Only")
Request.internal_() : super.internal_();
@@ -1300,9 +1292,7 @@
return new Transaction._internalWrap();
}
- factory Transaction._internalWrap() {
- return new Transaction.internal_();
- }
+ external factory Transaction._internalWrap();
@Deprecated("Internal Use Only")
Transaction.internal_() : super.internal_();
@@ -1364,9 +1354,7 @@
return new VersionChangeEvent._internalWrap();
}
- factory VersionChangeEvent._internalWrap() {
- return new VersionChangeEvent.internal_();
- }
+ external factory VersionChangeEvent._internalWrap();
@Deprecated("Internal Use Only")
VersionChangeEvent.internal_() : super.internal_();
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index 326597f..d881ce5 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -181,20 +181,20 @@
static List<String> get executableArguments => _Platform.executableArguments;
/**
- * Returns the value of the --package-root flag passed to the executable
+ * Returns the value of the `--package-root` flag passed to the executable
* used to run the script in this isolate. This is the directory in which
* Dart packages are looked up.
*
- * If there is no --package-root flag, then null is returned.
+ * If there is no `--package-root` flag, `null` is returned.
*/
static String get packageRoot => _Platform.packageRoot;
/**
- * Returns the value of the --packages flag passed to the executable
- * used to run the script in this isolate. This is the configuration which
+ * Returns the value of the `--packages` flag passed to the executable
+ * used to run the script in this isolate. This is the configuration which
* specifies how Dart packages are looked up.
*
- * If there is no --packages flag, then the null is returned.
+ * If there is no `--packages` flag, `null` is returned.
*/
static String get packageConfig => _Platform.packageConfig;
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index ce2c5a2..d2b1f39 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -101,6 +101,26 @@
@Deprecated("Internal Use Only")
final bool CHECK_JS_INVOCATIONS = true;
+final String _DART_RESERVED_NAME_PREFIX = r'JS$';
+
+String _stripReservedNamePrefix(String name) =>
+ name.startsWith(_DART_RESERVED_NAME_PREFIX)
+ ? name.substring(_DART_RESERVED_NAME_PREFIX.length)
+ : name;
+
+_buildArgs(Invocation invocation) {
+ if (invocation.namedArguments.isEmpty) {
+ return invocation.positionalArguments;
+ } else {
+ var varArgs = new Map<String, Object>();
+ invocation.namedArguments.forEach((symbol, val) {
+ varArgs[mirrors.MirrorSystem.getName(symbol)] = val;
+ });
+ return invocation.positionalArguments.toList()
+ ..add(maybeWrapTypedInterop(new JsObject.jsify(varArgs)));
+ }
+}
+
final _allowedMethods = new Map<Symbol, _DeclarationSet>();
final _allowedGetters = new Map<Symbol, _DeclarationSet>();
final _allowedSetters = new Map<Symbol, _DeclarationSet>();
@@ -292,6 +312,20 @@
bool _hasJsName(mirrors.DeclarationMirror mirror) => _getJsName(mirror) != null;
+bool hasDomName(mirrors.DeclarationMirror mirror) {
+ var location = mirror.location;
+ if (location == null || location.sourceUri.scheme != 'dart') return false;
+ for (var annotation in mirror.metadata) {
+ if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "DomName") {
+ // We can't make sure the annotation is in dart: as Dartium believes it
+ // is file://dart/sdk/lib/html/html_common/metadata.dart
+ // instead of a proper dart: location.
+ return true;
+ }
+ }
+ return false;
+}
+
_getJsMemberName(mirrors.DeclarationMirror mirror) {
var name = _getJsName(mirror);
return name == null || name.isEmpty ? _getDeclarationName(mirror) : name;
@@ -304,7 +338,7 @@
assert(name.endsWith("="));
name = name.substring(0, name.length - 1);
}
- return name;
+ return _stripReservedNamePrefix(name);
}
final _JS_LIBRARY_PREFIX = "js_library";
@@ -347,16 +381,20 @@
}
sb.write(" ");
if (declaration.isGetter) {
- sb.write("get $name => ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPath(path)});");
+ sb.write(
+ "get $name => ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPath(path)});");
} else if (declaration.isSetter) {
- sb.write("set $name(v) => ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPathSetter(path)});");
+ sb.write("set $name(v) {\n"
+ " ${_JS_LIBRARY_PREFIX}.safeForTypedInterop(v);\n"
+ " return ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPathSetter(path)});\n"
+ "}\n");
} else {
sb.write("$name(");
bool hasOptional = false;
int i = 0;
var args = <String>[];
for (var p in declaration.parameters) {
- assert(!p.isNamed); // XXX throw
+ assert(!p.isNamed); // TODO(jacobr): throw.
assert(!p.hasDefaultValue);
if (i > 0) {
sb.write(", ");
@@ -377,8 +415,11 @@
sb.write("]");
}
// TODO(jacobr):
- sb.write(") => ");
- sb.write('${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(');
+ sb.write(") {\n");
+ for (var arg in args) {
+ sb.write(" ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($arg);\n");
+ }
+ sb.write(" return ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(");
if (declaration.isConstructor) {
sb.write("new ${_JS_LIBRARY_PREFIX}.JsObject(");
}
@@ -391,6 +432,7 @@
sb.write(".takeWhile((i) => i != ${_UNDEFINED_VAR}).toList()");
}
sb.write("));");
+ sb.write("}\n");
}
sb.write("\n");
}
@@ -399,7 +441,7 @@
// This try-catch block is a workaround for BUG:24834.
try {
return mirror.isExternal;
- } catch (e) { }
+ } catch (e) {}
return false;
}
@@ -416,195 +458,106 @@
}
} else if (declaration is mirrors.ClassMirror) {
mirrors.ClassMirror clazz = declaration;
- if (_hasJsName(clazz)) {
+ var isDom = hasDomName(clazz);
+ var isJsInterop = _hasJsName(clazz);
+ if (isDom || isJsInterop) {
// TODO(jacobr): verify class implements JavaScriptObject.
- String jsClassName = _getJsMemberName(clazz);
var className = mirrors.MirrorSystem.getName(clazz.simpleName);
+ var classNameImpl = '${className}Impl';
var sbPatch = new StringBuffer();
- jsInterfaceTypes.add(clazz);
- clazz.declarations.forEach((name, declaration) {
- if (declaration is! mirrors.MethodMirror ||
- !_isExternal(declaration)) return;
- if (declaration.isFactoryConstructor && _isAnonymousClass(clazz)) {
- sbPatch.write(" factory ${className}(");
- int i = 0;
- var args = <String>[];
- for (var p in declaration.parameters) {
- args.add(mirrors.MirrorSystem.getName(p.simpleName));
- i++;
- }
- if (args.isNotEmpty) {
- sbPatch
- ..write('{')
- ..write(
- args.map((name) => '$name:${_UNDEFINED_VAR}').join(", "))
- ..write('}');
- }
- sbPatch.write(") {\n"
+ if (isJsInterop) {
+ String jsClassName = _getJsMemberName(clazz);
+
+ jsInterfaceTypes.add(clazz);
+ clazz.declarations.forEach((name, declaration) {
+ if (declaration is! mirrors.MethodMirror ||
+ !_isExternal(declaration)) return;
+ if (declaration.isFactoryConstructor &&
+ _isAnonymousClass(clazz)) {
+ sbPatch.write(" factory ${className}(");
+ int i = 0;
+ var args = <String>[];
+ for (var p in declaration.parameters) {
+ args.add(mirrors.MirrorSystem.getName(p.simpleName));
+ i++;
+ }
+ if (args.isNotEmpty) {
+ sbPatch
+ ..write('{')
+ ..write(args
+ .map((name) => '$name:${_UNDEFINED_VAR}')
+ .join(", "))
+ ..write('}');
+ }
+ sbPatch.write(") {\n"
" var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});\n");
- i = 0;
- for (var p in declaration.parameters) {
- assert(p.isNamed); // XXX throw
- var name = args[i];
- var jsName = mirrors.MirrorSystem.getName(p.simpleName);
- // XXX apply name conversion rules.
+ i = 0;
+ for (var p in declaration.parameters) {
+ assert(p.isNamed); // TODO(jacobr): throw.
+ var name = args[i];
+ var jsName = _stripReservedNamePrefix(
+ mirrors.MirrorSystem.getName(p.simpleName));
+ sbPatch.write(" if($name != ${_UNDEFINED_VAR}) {\n"
+ " ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($name);\n"
+ " ret['$jsName'] = $name;\n"
+ " }\n");
+ i++;
+ }
+
sbPatch.write(
- " if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n");
- i++;
+ " return new ${_JS_LIBRARY_PREFIX}.JSObject.create(ret);\n"
+ " }\n");
+ } else if (declaration.isConstructor ||
+ declaration.isFactoryConstructor) {
+ sbPatch.write(" ");
+ addMemberHelper(
+ declaration,
+ (jsLibraryName != null && jsLibraryName.isNotEmpty)
+ ? "${jsLibraryName}.${jsClassName}"
+ : jsClassName,
+ sbPatch,
+ isStatic: true,
+ memberName: className);
}
+ });
- sbPatch.write(" return ret;\n"
- " }\n");
- } else if (declaration.isConstructor ||
- declaration.isFactoryConstructor) {
- sbPatch.write(" ");
- addMemberHelper(
- declaration,
- (jsLibraryName != null && jsLibraryName.isNotEmpty)
- ? "${jsLibraryName}.${jsClassName}"
- : jsClassName,
- sbPatch,
- isStatic: true,
- memberName: className);
- }
- });
-
- clazz.staticMembers.forEach((memberName, member) {
- if (_isExternal(member)) {
- sbPatch.write(" ");
- addMemberHelper(
- member,
- (jsLibraryName != null && jsLibraryName.isNotEmpty)
- ? "${jsLibraryName}.${jsClassName}"
- : jsClassName,
- sbPatch,
- isStatic: true);
- }
- });
- var typeVariablesClause = '';
- if (!clazz.typeVariables.isEmpty) {
- typeVariablesClause =
- '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
+ clazz.staticMembers.forEach((memberName, member) {
+ if (_isExternal(member)) {
+ sbPatch.write(" ");
+ addMemberHelper(
+ member,
+ (jsLibraryName != null && jsLibraryName.isNotEmpty)
+ ? "${jsLibraryName}.${jsClassName}"
+ : jsClassName,
+ sbPatch,
+ isStatic: true);
+ }
+ });
+ }
+ if (isDom) {
+ sbPatch.write(" factory ${className}._internalWrap() => "
+ "new ${classNameImpl}.internal_();\n");
}
if (sbPatch.isNotEmpty) {
+ var typeVariablesClause = '';
+ if (!clazz.typeVariables.isEmpty) {
+ typeVariablesClause =
+ '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
+ }
sb.write("""
patch class $className$typeVariablesClause {
$sbPatch
}
""");
- }
- }
- }
- });
- if (sb.isNotEmpty) {
- staticCodegen
- ..add(uri.toString())
- ..add("${uri}_js_interop_patch.dart")
- ..add("""
-import 'dart:js' as ${_JS_LIBRARY_PREFIX};
-
-/**
- * Placeholder object for cases where we need to determine exactly how many
- * args were passed to a function.
- */
-const ${_UNDEFINED_VAR} = const Object();
-
-${sb}
-""");
- }
- });
-
- return staticCodegen;
-}
-
-List<String> _generateExternalMethods2() {
- var staticCodegen = <String>[];
- mirrors.currentMirrorSystem().libraries.forEach((uri, library) {
- var sb = new StringBuffer();
- String jsLibraryName = _getJsName(library);
- library.declarations.forEach((name, declaration) {
- var isExternal = _isExternal(declaration);
- if (declaration is mirrors.MethodMirror) {
- if (isExternal && (_hasJsName(declaration) || jsLibraryName != null)) {
- addMemberHelper(declaration, jsLibraryName, sb);
- }
- } else if (declaration is mirrors.ClassMirror) {
- mirrors.ClassMirror clazz = declaration;
- if (_hasJsName(clazz)) {
- // TODO(jacobr): verify class implements JavaScriptObject.
- String jsClassName = _getJsMemberName(clazz);
- var className = mirrors.MirrorSystem.getName(clazz.simpleName);
- var sbPatch = new StringBuffer();
- jsInterfaceTypes.add(clazz);
- clazz.declarations.forEach((name, declaration) {
- if (declaration is! mirrors.MethodMirror ||
- !declaration.isAbstract ||
- !isExternal) return;
- if (_hasLiteralAnnotation(declaration) &&
- declaration.isFactoryConstructor) {
- sbPatch.write(" factory ${className}({");
- int i = 0;
- var args = <String>[];
- for (var p in declaration.parameters) {
- assert(p.isNamed); // XXX throw
- args.add(mirrors.MirrorSystem.getName(p.simpleName));
- i++;
- }
- sbPatch
- ..write(
- args.map((name) => '$name:${_UNDEFINED_VAR}').join(", "))
- ..write("}) {\n"
- " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});\n");
- i = 0;
- for (var p in declaration.parameters) {
- assert(p.isNamed); // XXX throw
- var name = args[i];
- var jsName = mirrors.MirrorSystem.getName(p.simpleName);
- // XXX apply name conversion rules.
- sbPatch.write(
- " if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n");
- i++;
- }
-
- sbPatch.write(" return ret;\n"
- " }\n");
- } else if (declaration.isConstructor ||
- declaration.isFactoryConstructor) {
- sbPatch.write(" ");
- addMemberHelper(
- declaration,
- (jsLibraryName != null && jsLibraryName.isNotEmpty)
- ? "${jsLibraryName}.${jsClassName}"
- : jsClassName,
- sbPatch,
- isStatic: true,
- memberName: className);
- }
- });
-
- clazz.staticMembers.forEach((memberName, member) {
- if (_isExternal(member)) {
- sbPatch.write(" ");
- addMemberHelper(
- member,
- (jsLibraryName != null && jsLibraryName.isNotEmpty)
- ? "${jsLibraryName}.${jsClassName}"
- : jsClassName,
- sbPatch,
- isStatic: true);
- }
- });
- var typeVariablesClause = '';
- if (!clazz.typeVariables.isEmpty) {
- typeVariablesClause =
- '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
- }
- if (sbPatch.isNotEmpty) {
- sb.write("""
-patch class $className$typeVariablesClause {
-$sbPatch
+ if (isDom) {
+ sb.write("""
+class $classNameImpl$typeVariablesClause extends $className implements ${_JS_LIBRARY_PREFIX}.JSObjectInterfacesDom {
+ ${classNameImpl}.internal_() : super.internal_();
+ get runtimeType => $className;
+ toString() => super.toString();
}
""");
+ }
}
}
}
@@ -631,9 +584,9 @@
}
/**
- * Generates a part file defining source code for JsObjectImpl and related
- * classes. This calass is needed so that type checks for all registered JavaScript
- * interop classes pass.
+ * Generates part files defining source code for JSObjectImpl, all DOM classes
+ * classes. This codegen is needed so that type checks for all registered
+ * JavaScript interop classes pass.
*/
List<String> _generateInteropPatchFiles() {
var ret = _generateExternalMethods();
@@ -643,7 +596,10 @@
var implements = <String>[];
var implementsArray = <String>[];
+ var implementsDom = <String>[];
var listMirror = mirrors.reflectType(List);
+ var functionMirror = mirrors.reflectType(Function);
+ var jsObjectMirror = mirrors.reflectType(JSObject);
for (var typeMirror in jsInterfaceTypes) {
mirrors.LibraryMirror libraryMirror = typeMirror.owner;
@@ -665,8 +621,25 @@
libraryPrefixes[libraryMirror] = prefixName;
}
var isArray = typeMirror.isSubtypeOf(listMirror);
- (isArray ? implementsArray : implements).add(
- '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}');
+ var isFunction = typeMirror.isSubtypeOf(functionMirror);
+ var isJSObject = typeMirror.isSubtypeOf(jsObjectMirror);
+ var fullName =
+ '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}';
+ (isArray ? implementsArray : implements).add(fullName);
+ if (!isArray && !isFunction && !isJSObject) {
+ // For DOM classes we need to be a bit more conservative at tagging them
+ // as implementing JS inteorp classes risks strange unintended
+ // consequences as unrleated code may have instanceof checks. Checking
+ // for isJSObject ensures we do not accidentally pull in existing
+ // dart:html classes as they all have JSObject as a base class.
+ // Note that methods from these classes can still be called on a
+ // dart:html instance but checked mode type checks will fail. This is
+ // not ideal but is better than causing strange breaks in existing
+ // code that uses dart:html.
+ // TODO(jacobr): consider throwing compile time errors if @JS classes
+ // extend JSObject as that case cannot be safely handled in Dartium.
+ implementsDom.add(fullName);
+ }
}
libraryPrefixes.forEach((libraryMirror, prefix) {
sb.writeln('import "${libraryMirror.uri}" as $prefix;');
@@ -674,20 +647,51 @@
buildImplementsClause(classes) =>
classes.isEmpty ? "" : "implements ${classes.join(', ')}";
var implementsClause = buildImplementsClause(implements);
+ var implementsClauseDom = buildImplementsClause(implementsDom);
// TODO(jacobr): only certain classes need to be implemented by
// JsFunctionImpl.
var allTypes = []..addAll(implements)..addAll(implementsArray);
sb.write('''
-class JsObjectImpl extends JsObject $implementsClause {
- JsObjectImpl.internal() : super.internal();
+class JSObjectImpl extends JSObject $implementsClause {
+ JSObjectImpl.internal() : super.internal();
}
-class JsFunctionImpl extends JsFunction $implementsClause {
- JsFunctionImpl.internal() : super.internal();
+class JSFunctionImpl extends JSFunction $implementsClause {
+ JSFunctionImpl.internal() : super.internal();
}
-class JsArrayImpl<E> extends JsArray<E> ${buildImplementsClause(implementsArray)} {
- JsArrayImpl.internal() : super.internal();
+class JSArrayImpl extends JSArray ${buildImplementsClause(implementsArray)} {
+ JSArrayImpl.internal() : super.internal();
+}
+
+// Interfaces that are safe to slam on all DOM classes.
+// Adding implementsClause would be risky as it could contain Function which
+// is likely to break a lot of instanceof checks.
+abstract class JSObjectInterfacesDom $implementsClauseDom {
+}
+
+patch class JSObject {
+ factory JSObject.create(JsObject jsObject) {
+ var ret = new JSObjectImpl.internal()..blink_jsObject = jsObject;
+ jsObject._dartHtmlWrapper = ret;
+ return ret;
+ }
+}
+
+patch class JSFunction {
+ factory JSFunction.create(JsObject jsObject) {
+ var ret = new JSFunctionImpl.internal()..blink_jsObject = jsObject;
+ jsObject._dartHtmlWrapper = ret;
+ return ret;
+ }
+}
+
+patch class JSArray {
+ factory JSArray.create(JsObject jsObject) {
+ var ret = new JSArrayImpl.internal()..blink_jsObject = jsObject;
+ jsObject._dartHtmlWrapper = ret;
+ return ret;
+ }
}
_registerAllJsInterfaces() {
@@ -695,7 +699,7 @@
}
''');
- ret..addAll(["dart:js", "JsInteropImpl.dart", sb.toString()]);
+ ret..addAll(["dart:js", "JSInteropImpl.dart", sb.toString()]);
return ret;
}
@@ -870,8 +874,7 @@
}
@Deprecated("Internal Use Only")
-maybeWrapTypedInterop(o) =>
- html_common.wrap_jso_no_SerializedScriptvalue(o);
+maybeWrapTypedInterop(o) => html_common.wrap_jso_no_SerializedScriptvalue(o);
_maybeWrap(o) {
var wrapped = html_common.wrap_jso_no_SerializedScriptvalue(o);
@@ -910,7 +913,7 @@
*/
@Deprecated("Internal Use Only")
unwrap_jso(dartClass_instance) {
- if (dartClass_instance is html.DartHtmlDomObject &&
+ if (dartClass_instance is JSObject &&
dartClass_instance is! JsObject) return dartClass_instance.blink_jsObject;
else return dartClass_instance;
}
@@ -946,19 +949,6 @@
static JsObject _create(JsFunction constructor, arguments)
native "JsObject_constructorCallback";
- _buildArgs(Invocation invocation) {
- if (invocation.namedArguments.isEmpty) {
- return invocation.positionalArguments;
- } else {
- var varArgs = new Map<String, Object>();
- invocation.namedArguments.forEach((symbol, val) {
- varArgs[mirrors.MirrorSystem.getName(symbol)] = val;
- });
- return invocation.positionalArguments.toList()
- ..add(new JsObject.jsify(varArgs));
- }
- }
-
/**
* Constructs a [JsObject] that proxies a native Dart object; _for expert use
* only_.
@@ -1099,13 +1089,28 @@
}
}
+ _callMethod(String name, List args) native "JsObject_callMethod";
+}
+
+/// Base class for all JS objects used through dart:html and typed JS interop.
+@Deprecated("Internal Use Only")
+class JSObject {
+ JSObject.internal() {}
+ external factory JSObject.create(JsObject jsObject);
+
+ @Deprecated("Internal Use Only")
+ JsObject blink_jsObject;
+
+ String toString() => blink_jsObject.toString();
+
noSuchMethod(Invocation invocation) {
throwError() {
- throw new NoSuchMethodError(this, invocation.memberName,
- invocation.positionalArguments, invocation.namedArguments);
+ super.noSuchMethod(invocation);
}
- String name = mirrors.MirrorSystem.getName(invocation.memberName);
+ String name = _stripReservedNamePrefix(
+ mirrors.MirrorSystem.getName(invocation.memberName));
+ argsSafeForTypedInterop(invocation.positionalArguments);
if (invocation.isGetter) {
if (CHECK_JS_INVOCATIONS) {
var matches = _allowedGetters[invocation.memberName];
@@ -1113,8 +1118,8 @@
!_allowedMethods.containsKey(invocation.memberName)) {
throwError();
}
- var ret = this[name];
- if (matches != null && matches._checkReturnType(ret)) return ret;
+ var ret = maybeWrapTypedInterop(blink_jsObject._operator_getter(name));
+ if (matches != null) return ret;
if (ret is Function ||
(ret is JsFunction /* shouldn't be needed in the future*/) &&
_allowedMethods.containsKey(
@@ -1122,7 +1127,7 @@
throwError();
} else {
// TODO(jacobr): should we throw if the JavaScript object doesn't have the property?
- return maybeWrapTypedInterop(this._operator_getter(name));
+ return maybeWrapTypedInterop(blink_jsObject._operator_getter(name));
}
} else if (invocation.isSetter) {
if (CHECK_JS_INVOCATIONS) {
@@ -1132,7 +1137,7 @@
}
assert(name.endsWith("="));
name = name.substring(0, name.length - 1);
- return maybeWrapTypedInterop(_operator_setter(
+ return maybeWrapTypedInterop(blink_jsObject._operator_setter(
name, invocation.positionalArguments.first));
} else {
// TODO(jacobr): also allow calling getters that look like functions.
@@ -1142,15 +1147,61 @@
if (matches == null ||
!matches.checkInvocation(invocation)) throwError();
}
- var ret = maybeWrapTypedInterop(this._callMethod(name, _buildArgs(invocation)));
+ var ret = maybeWrapTypedInterop(
+ blink_jsObject._callMethod(name, _buildArgs(invocation)));
if (CHECK_JS_INVOCATIONS) {
- if (!matches._checkReturnType(ret)) throwError();
+ if (!matches._checkReturnType(ret)) {
+ html.window.console.error("Return value for method: ${name} is "
+ "${ret.runtimeType} which is inconsistent with all typed "
+ "JS interop definitions for method ${name}.");
+ }
}
return ret;
}
}
+}
- _callMethod(String name, List args) native "JsObject_callMethod";
+@Deprecated("Internal Use Only")
+class JSArray extends JSObject with ListMixin {
+ JSArray.internal() : super.internal();
+ external factory JSArray.create(JsObject jsObject);
+ operator [](int index) =>
+ maybeWrapTypedInterop(JsNative.getArrayIndex(blink_jsObject, index));
+
+ operator []=(int index, value) => blink_jsObject[index] = value;
+
+ int get length => blink_jsObject.length;
+ int set length(int newLength) => blink_jsObject.length = newLength;
+}
+
+@Deprecated("Internal Use Only")
+class JSFunction extends JSObject implements Function {
+ JSFunction.internal() : super.internal();
+
+ external factory JSFunction.create(JsObject jsObject);
+
+ call(
+ [a1 = _UNDEFINED,
+ a2 = _UNDEFINED,
+ a3 = _UNDEFINED,
+ a4 = _UNDEFINED,
+ a5 = _UNDEFINED,
+ a6 = _UNDEFINED,
+ a7 = _UNDEFINED,
+ a8 = _UNDEFINED,
+ a9 = _UNDEFINED,
+ a10 = _UNDEFINED]) {
+ return maybeWrapTypedInterop(blink_jsObject
+ .apply(_stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])));
+ }
+
+ noSuchMethod(Invocation invocation) {
+ if (invocation.isMethod && invocation.memberName == #call) {
+ return maybeWrapTypedInterop(
+ blink_jsObject.apply(_buildArgs(invocation)));
+ }
+ return super.noSuchMethod(invocation);
+ }
}
// JavaScript interop methods that do not automatically wrap to dart:html types.
@@ -1185,7 +1236,7 @@
/**
* Proxies a JavaScript Function object.
*/
-class JsFunction extends JsObject implements Function {
+class JsFunction extends JsObject {
JsFunction.internal() : super.internal();
/**
@@ -1203,27 +1254,6 @@
dynamic _apply(List args, {thisArg}) native "JsFunction_apply";
- call([a1 = _UNDEFINED,
- a2 = _UNDEFINED,
- a3 = _UNDEFINED,
- a4 = _UNDEFINED,
- a5 = _UNDEFINED,
- a6 = _UNDEFINED,
- a7 = _UNDEFINED,
- a8 = _UNDEFINED,
- a9 = _UNDEFINED,
- a10 = _UNDEFINED]) {
- return apply(
- _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
- }
-
- noSuchMethod(Invocation invocation) {
- if (invocation.isMethod && invocation.memberName == #call) {
- return apply(_buildArgs(invocation));
- }
- return super.noSuchMethod(invocation);
- }
-
/**
* Internal only version of apply which uses debugger proxies of Dart objects
* rather than opaque handles. This method is private because it cannot be
@@ -1349,6 +1379,39 @@
args.takeWhile((i) => i != _UNDEFINED).toList();
/**
+ * Check that that if [arg] is a [Function] it is safe to pass to JavaScript.
+ * To make a function safe, call [allowInterop] or [allowInteropCaptureThis].
+ */
+@Deprecated("Internal Use Only")
+safeForTypedInterop(arg) {
+ if (CHECK_JS_INVOCATIONS && arg is Function && arg is! JSFunction) {
+ throw new ArgumentError(
+ "Attempt to pass Function '$arg' to JavaScript via without calling allowInterop or allowInteropCaptureThis");
+ }
+}
+
+/**
+ * Check that that if any elements of [args] are [Function] it is safe to pass
+ * to JavaScript. To make a function safe, call [allowInterop] or
+ * [allowInteropCaptureThis].
+ */
+@Deprecated("Internal Use Only")
+void argsSafeForTypedInterop(Iterable args) {
+ for (var arg in args) {
+ safeForTypedInterop(arg);
+ }
+}
+
+List _stripAndWrapArgs(Iterable args) {
+ var ret = [];
+ for (var arg in args) {
+ if (arg == _UNDEFINED) break;
+ ret.add(maybeWrapTypedInterop(arg));
+ }
+ return ret;
+}
+
+/**
* Returns a method that can be called with an arbitrary number (for n less
* than 11) of arguments without violating Dart type checks.
*/
@@ -1366,9 +1429,89 @@
jsFunction._applyDebuggerOnly(
_stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
-// The allowInterop method is a no-op in Dartium.
-// TODO(jacobr): tag methods so we can throw if a Dart method is passed to
-// JavaScript using the new interop without calling allowInterop.
+/// This helper is purely a hack so we can reuse JsFunction.withThis even when
+/// we don't care about passing JS "this". In an ideal world we would implement
+/// helpers in C++ that directly implement allowInterop and
+/// allowInteropCaptureThis.
+class _CreateDartFunctionForInteropIgnoreThis implements Function {
+ Function _fn;
+
+ _CreateDartFunctionForInteropIgnoreThis(this._fn);
+
+ call(
+ [ignoredThis = _UNDEFINED,
+ a1 = _UNDEFINED,
+ a2 = _UNDEFINED,
+ a3 = _UNDEFINED,
+ a4 = _UNDEFINED,
+ a5 = _UNDEFINED,
+ a6 = _UNDEFINED,
+ a7 = _UNDEFINED,
+ a8 = _UNDEFINED,
+ a9 = _UNDEFINED,
+ a10 = _UNDEFINED]) {
+ var ret = Function.apply(
+ _fn, _stripAndWrapArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
+ safeForTypedInterop(ret);
+ return ret;
+ }
+
+ noSuchMethod(Invocation invocation) {
+ if (invocation.isMethod && invocation.memberName == #call) {
+ // Named arguments not yet supported.
+ if (invocation.namedArguments.isNotEmpty) return;
+ var ret = Function.apply(
+ _fn, _stripAndWrapArgs(invocation.positionalArguments.skip(1)));
+ // TODO(jacobr): it would be nice to check that the return value is safe
+ // for interop but we don't want to break existing addEventListener users.
+ // safeForTypedInterop(ret);
+ safeForTypedInterop(ret);
+ return ret;
+ }
+ return super.noSuchMethod(invocation);
+ }
+}
+
+/// See comment for [_CreateDartFunctionForInteropIgnoreThis].
+/// This Function exists purely because JsObject doesn't have the DOM type
+/// conversion semantics we want for JS typed interop.
+class _CreateDartFunctionForInterop implements Function {
+ Function _fn;
+
+ _CreateDartFunctionForInterop(this._fn);
+
+ call(
+ [a1 = _UNDEFINED,
+ a2 = _UNDEFINED,
+ a3 = _UNDEFINED,
+ a4 = _UNDEFINED,
+ a5 = _UNDEFINED,
+ a6 = _UNDEFINED,
+ a7 = _UNDEFINED,
+ a8 = _UNDEFINED,
+ a9 = _UNDEFINED,
+ a10 = _UNDEFINED]) {
+ var ret = Function.apply(
+ _fn, _stripAndWrapArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
+ safeForTypedInterop(ret);
+ return ret;
+ }
+
+ noSuchMethod(Invocation invocation) {
+ if (invocation.isMethod && invocation.memberName == #call) {
+ // Named arguments not yet supported.
+ if (invocation.namedArguments.isNotEmpty) return;
+ var ret = Function.apply(
+ _fn, _stripAndWrapArgs(invocation.positionalArguments));
+ safeForTypedInterop(ret);
+ return ret;
+ }
+ return super.noSuchMethod(invocation);
+ }
+}
+
+/// Cached JSFunction associated with the Dart Function.
+Expando<JSFunction> _interopExpando = new Expando<JSFunction>();
/// Returns a wrapper around function [f] that can be called from JavaScript
/// using the package:js Dart-JavaScript interop.
@@ -1381,9 +1524,25 @@
/// JavaScript. We may remove the need to call this method completely in the
/// future if Dart2Js is refactored so that its function calling conventions
/// are more compatible with JavaScript.
-Function allowInterop(Function f) => f;
+JSFunction allowInterop(Function f) {
+ if (f is JSFunction) {
+ // The function is already a JSFunction... no need to do anything.
+ return f;
+ } else {
+ var ret = _interopExpando[f];
+ if (ret == null) {
+ // TODO(jacobr): we could optimize this.
+ ret = new JSFunction.create(new JsFunction.withThis(
+ new _CreateDartFunctionForInteropIgnoreThis(f)));
+ _interopExpando[f] = ret;
+ }
+ return ret;
+ }
+}
-Expando<JsFunction> _interopCaptureThisExpando = new Expando<JsFunction>();
+/// Cached JSFunction associated with the Dart function when "this" is
+/// captured.
+Expando<JSFunction> _interopCaptureThisExpando = new Expando<JSFunction>();
/// Returns a [Function] that when called from JavaScript captures its 'this'
/// binding and calls [f] with the value of this passed as the first argument.
@@ -1391,8 +1550,8 @@
///
/// See the documention for [allowInterop]. This method should only be used with
/// package:js Dart-JavaScript interop.
-Function allowInteropCaptureThis(Function f) {
- if (f is JsFunction) {
+JSFunction allowInteropCaptureThis(Function f) {
+ if (f is JSFunction) {
// Behavior when the function is already a JS function is unspecified.
throw new ArgumentError(
"Function is already a JS function so cannot capture this.");
@@ -1400,7 +1559,9 @@
} else {
var ret = _interopCaptureThisExpando[f];
if (ret == null) {
- ret = new JsFunction.withThis(f);
+ // TODO(jacobr): we could optimize this.
+ ret = new JSFunction.create(
+ new JsFunction.withThis(new _CreateDartFunctionForInterop(f)));
_interopCaptureThisExpando[f] = ret;
}
return ret;
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index c093cab..7795952 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -349,9 +349,7 @@
return new AElement._internalWrap();
}
- factory AElement._internalWrap() {
- return new AElement.internal_();
- }
+ external factory AElement._internalWrap();
@Deprecated("Internal Use Only")
AElement.internal_() : super.internal_();
@@ -399,9 +397,7 @@
return new AltGlyphElement._internalWrap();
}
- factory AltGlyphElement._internalWrap() {
- return new AltGlyphElement.internal_();
- }
+ external factory AltGlyphElement._internalWrap();
@Deprecated("Internal Use Only")
AltGlyphElement.internal_() : super.internal_();
@@ -550,9 +546,7 @@
return new AnimateElement._internalWrap();
}
- factory AnimateElement._internalWrap() {
- return new AnimateElement.internal_();
- }
+ external factory AnimateElement._internalWrap();
@Deprecated("Internal Use Only")
AnimateElement.internal_() : super.internal_();
@@ -595,9 +589,7 @@
return new AnimateMotionElement._internalWrap();
}
- factory AnimateMotionElement._internalWrap() {
- return new AnimateMotionElement.internal_();
- }
+ external factory AnimateMotionElement._internalWrap();
@Deprecated("Internal Use Only")
AnimateMotionElement.internal_() : super.internal_();
@@ -640,9 +632,7 @@
return new AnimateTransformElement._internalWrap();
}
- factory AnimateTransformElement._internalWrap() {
- return new AnimateTransformElement.internal_();
- }
+ external factory AnimateTransformElement._internalWrap();
@Deprecated("Internal Use Only")
AnimateTransformElement.internal_() : super.internal_();
@@ -1158,9 +1148,7 @@
return new AnimationElement._internalWrap();
}
- factory AnimationElement._internalWrap() {
- return new AnimationElement.internal_();
- }
+ external factory AnimationElement._internalWrap();
@Deprecated("Internal Use Only")
AnimationElement.internal_() : super.internal_();
@@ -1245,9 +1233,7 @@
return new CircleElement._internalWrap();
}
- factory CircleElement._internalWrap() {
- return new CircleElement.internal_();
- }
+ external factory CircleElement._internalWrap();
@Deprecated("Internal Use Only")
CircleElement.internal_() : super.internal_();
@@ -1296,9 +1282,7 @@
return new ClipPathElement._internalWrap();
}
- factory ClipPathElement._internalWrap() {
- return new ClipPathElement.internal_();
- }
+ external factory ClipPathElement._internalWrap();
@Deprecated("Internal Use Only")
ClipPathElement.internal_() : super.internal_();
@@ -1339,9 +1323,7 @@
return new DefsElement._internalWrap();
}
- factory DefsElement._internalWrap() {
- return new DefsElement.internal_();
- }
+ external factory DefsElement._internalWrap();
@Deprecated("Internal Use Only")
DefsElement.internal_() : super.internal_();
@@ -1378,9 +1360,7 @@
return new DescElement._internalWrap();
}
- factory DescElement._internalWrap() {
- return new DescElement.internal_();
- }
+ external factory DescElement._internalWrap();
@Deprecated("Internal Use Only")
DescElement.internal_() : super.internal_();
@@ -1413,9 +1393,7 @@
return new DiscardElement._internalWrap();
}
- factory DiscardElement._internalWrap() {
- return new DiscardElement.internal_();
- }
+ external factory DiscardElement._internalWrap();
@Deprecated("Internal Use Only")
DiscardElement.internal_() : super.internal_();
@@ -1452,9 +1430,7 @@
return new EllipseElement._internalWrap();
}
- factory EllipseElement._internalWrap() {
- return new EllipseElement.internal_();
- }
+ external factory EllipseElement._internalWrap();
@Deprecated("Internal Use Only")
EllipseElement.internal_() : super.internal_();
@@ -1511,9 +1487,7 @@
return new FEBlendElement._internalWrap();
}
- factory FEBlendElement._internalWrap() {
- return new FEBlendElement.internal_();
- }
+ external factory FEBlendElement._internalWrap();
@Deprecated("Internal Use Only")
FEBlendElement.internal_() : super.internal_();
@@ -1613,9 +1587,7 @@
return new FEColorMatrixElement._internalWrap();
}
- factory FEColorMatrixElement._internalWrap() {
- return new FEColorMatrixElement.internal_();
- }
+ external factory FEColorMatrixElement._internalWrap();
@Deprecated("Internal Use Only")
FEColorMatrixElement.internal_() : super.internal_();
@@ -1711,9 +1683,7 @@
return new FEComponentTransferElement._internalWrap();
}
- factory FEComponentTransferElement._internalWrap() {
- return new FEComponentTransferElement.internal_();
- }
+ external factory FEComponentTransferElement._internalWrap();
@Deprecated("Internal Use Only")
FEComponentTransferElement.internal_() : super.internal_();
@@ -1773,9 +1743,7 @@
return new FECompositeElement._internalWrap();
}
- factory FECompositeElement._internalWrap() {
- return new FECompositeElement.internal_();
- }
+ external factory FECompositeElement._internalWrap();
@Deprecated("Internal Use Only")
FECompositeElement.internal_() : super.internal_();
@@ -1892,9 +1860,7 @@
return new FEConvolveMatrixElement._internalWrap();
}
- factory FEConvolveMatrixElement._internalWrap() {
- return new FEConvolveMatrixElement.internal_();
- }
+ external factory FEConvolveMatrixElement._internalWrap();
@Deprecated("Internal Use Only")
FEConvolveMatrixElement.internal_() : super.internal_();
@@ -2022,9 +1988,7 @@
return new FEDiffuseLightingElement._internalWrap();
}
- factory FEDiffuseLightingElement._internalWrap() {
- return new FEDiffuseLightingElement.internal_();
- }
+ external factory FEDiffuseLightingElement._internalWrap();
@Deprecated("Internal Use Only")
FEDiffuseLightingElement.internal_() : super.internal_();
@@ -2108,9 +2072,7 @@
return new FEDisplacementMapElement._internalWrap();
}
- factory FEDisplacementMapElement._internalWrap() {
- return new FEDisplacementMapElement.internal_();
- }
+ external factory FEDisplacementMapElement._internalWrap();
@Deprecated("Internal Use Only")
FEDisplacementMapElement.internal_() : super.internal_();
@@ -2214,9 +2176,7 @@
return new FEDistantLightElement._internalWrap();
}
- factory FEDistantLightElement._internalWrap() {
- return new FEDistantLightElement.internal_();
- }
+ external factory FEDistantLightElement._internalWrap();
@Deprecated("Internal Use Only")
FEDistantLightElement.internal_() : super.internal_();
@@ -2268,9 +2228,7 @@
return new FEFloodElement._internalWrap();
}
- factory FEFloodElement._internalWrap() {
- return new FEFloodElement.internal_();
- }
+ external factory FEFloodElement._internalWrap();
@Deprecated("Internal Use Only")
FEFloodElement.internal_() : super.internal_();
@@ -2334,9 +2292,7 @@
return new FEFuncAElement._internalWrap();
}
- factory FEFuncAElement._internalWrap() {
- return new FEFuncAElement.internal_();
- }
+ external factory FEFuncAElement._internalWrap();
@Deprecated("Internal Use Only")
FEFuncAElement.internal_() : super.internal_();
@@ -2380,9 +2336,7 @@
return new FEFuncBElement._internalWrap();
}
- factory FEFuncBElement._internalWrap() {
- return new FEFuncBElement.internal_();
- }
+ external factory FEFuncBElement._internalWrap();
@Deprecated("Internal Use Only")
FEFuncBElement.internal_() : super.internal_();
@@ -2426,9 +2380,7 @@
return new FEFuncGElement._internalWrap();
}
- factory FEFuncGElement._internalWrap() {
- return new FEFuncGElement.internal_();
- }
+ external factory FEFuncGElement._internalWrap();
@Deprecated("Internal Use Only")
FEFuncGElement.internal_() : super.internal_();
@@ -2472,9 +2424,7 @@
return new FEFuncRElement._internalWrap();
}
- factory FEFuncRElement._internalWrap() {
- return new FEFuncRElement.internal_();
- }
+ external factory FEFuncRElement._internalWrap();
@Deprecated("Internal Use Only")
FEFuncRElement.internal_() : super.internal_();
@@ -2518,9 +2468,7 @@
return new FEGaussianBlurElement._internalWrap();
}
- factory FEGaussianBlurElement._internalWrap() {
- return new FEGaussianBlurElement.internal_();
- }
+ external factory FEGaussianBlurElement._internalWrap();
@Deprecated("Internal Use Only")
FEGaussianBlurElement.internal_() : super.internal_();
@@ -2600,9 +2548,7 @@
return new FEImageElement._internalWrap();
}
- factory FEImageElement._internalWrap() {
- return new FEImageElement.internal_();
- }
+ external factory FEImageElement._internalWrap();
@Deprecated("Internal Use Only")
FEImageElement.internal_() : super.internal_();
@@ -2674,9 +2620,7 @@
return new FEMergeElement._internalWrap();
}
- factory FEMergeElement._internalWrap() {
- return new FEMergeElement.internal_();
- }
+ external factory FEMergeElement._internalWrap();
@Deprecated("Internal Use Only")
FEMergeElement.internal_() : super.internal_();
@@ -2740,9 +2684,7 @@
return new FEMergeNodeElement._internalWrap();
}
- factory FEMergeNodeElement._internalWrap() {
- return new FEMergeNodeElement.internal_();
- }
+ external factory FEMergeNodeElement._internalWrap();
@Deprecated("Internal Use Only")
FEMergeNodeElement.internal_() : super.internal_();
@@ -2786,9 +2728,7 @@
return new FEMorphologyElement._internalWrap();
}
- factory FEMorphologyElement._internalWrap() {
- return new FEMorphologyElement.internal_();
- }
+ external factory FEMorphologyElement._internalWrap();
@Deprecated("Internal Use Only")
FEMorphologyElement.internal_() : super.internal_();
@@ -2877,9 +2817,7 @@
return new FEOffsetElement._internalWrap();
}
- factory FEOffsetElement._internalWrap() {
- return new FEOffsetElement.internal_();
- }
+ external factory FEOffsetElement._internalWrap();
@Deprecated("Internal Use Only")
FEOffsetElement.internal_() : super.internal_();
@@ -2955,9 +2893,7 @@
return new FEPointLightElement._internalWrap();
}
- factory FEPointLightElement._internalWrap() {
- return new FEPointLightElement.internal_();
- }
+ external factory FEPointLightElement._internalWrap();
@Deprecated("Internal Use Only")
FEPointLightElement.internal_() : super.internal_();
@@ -3013,9 +2949,7 @@
return new FESpecularLightingElement._internalWrap();
}
- factory FESpecularLightingElement._internalWrap() {
- return new FESpecularLightingElement.internal_();
- }
+ external factory FESpecularLightingElement._internalWrap();
@Deprecated("Internal Use Only")
FESpecularLightingElement.internal_() : super.internal_();
@@ -3095,9 +3029,7 @@
return new FESpotLightElement._internalWrap();
}
- factory FESpotLightElement._internalWrap() {
- return new FESpotLightElement.internal_();
- }
+ external factory FESpotLightElement._internalWrap();
@Deprecated("Internal Use Only")
FESpotLightElement.internal_() : super.internal_();
@@ -3173,9 +3105,7 @@
return new FETileElement._internalWrap();
}
- factory FETileElement._internalWrap() {
- return new FETileElement.internal_();
- }
+ external factory FETileElement._internalWrap();
@Deprecated("Internal Use Only")
FETileElement.internal_() : super.internal_();
@@ -3243,9 +3173,7 @@
return new FETurbulenceElement._internalWrap();
}
- factory FETurbulenceElement._internalWrap() {
- return new FETurbulenceElement.internal_();
- }
+ external factory FETurbulenceElement._internalWrap();
@Deprecated("Internal Use Only")
FETurbulenceElement.internal_() : super.internal_();
@@ -3357,9 +3285,7 @@
return new FilterElement._internalWrap();
}
- factory FilterElement._internalWrap() {
- return new FilterElement.internal_();
- }
+ external factory FilterElement._internalWrap();
@Deprecated("Internal Use Only")
FilterElement.internal_() : super.internal_();
@@ -3500,9 +3426,7 @@
return new ForeignObjectElement._internalWrap();
}
- factory ForeignObjectElement._internalWrap() {
- return new ForeignObjectElement.internal_();
- }
+ external factory ForeignObjectElement._internalWrap();
@Deprecated("Internal Use Only")
ForeignObjectElement.internal_() : super.internal_();
@@ -3558,9 +3482,7 @@
return new GElement._internalWrap();
}
- factory GElement._internalWrap() {
- return new GElement.internal_();
- }
+ external factory GElement._internalWrap();
@Deprecated("Internal Use Only")
GElement.internal_() : super.internal_();
@@ -3593,9 +3515,7 @@
return new GeometryElement._internalWrap();
}
- factory GeometryElement._internalWrap() {
- return new GeometryElement.internal_();
- }
+ external factory GeometryElement._internalWrap();
@Deprecated("Internal Use Only")
GeometryElement.internal_() : super.internal_();
@@ -3638,9 +3558,7 @@
return new GraphicsElement._internalWrap();
}
- factory GraphicsElement._internalWrap() {
- return new GraphicsElement.internal_();
- }
+ external factory GraphicsElement._internalWrap();
@Deprecated("Internal Use Only")
GraphicsElement.internal_() : super.internal_();
@@ -3732,9 +3650,7 @@
return new ImageElement._internalWrap();
}
- factory ImageElement._internalWrap() {
- return new ImageElement.internal_();
- }
+ external factory ImageElement._internalWrap();
@Deprecated("Internal Use Only")
ImageElement.internal_() : super.internal_();
@@ -4021,9 +3937,7 @@
return new LineElement._internalWrap();
}
- factory LineElement._internalWrap() {
- return new LineElement.internal_();
- }
+ external factory LineElement._internalWrap();
@Deprecated("Internal Use Only")
LineElement.internal_() : super.internal_();
@@ -4076,9 +3990,7 @@
return new LinearGradientElement._internalWrap();
}
- factory LinearGradientElement._internalWrap() {
- return new LinearGradientElement.internal_();
- }
+ external factory LinearGradientElement._internalWrap();
@Deprecated("Internal Use Only")
LinearGradientElement.internal_() : super.internal_();
@@ -4131,9 +4043,7 @@
return new MarkerElement._internalWrap();
}
- factory MarkerElement._internalWrap() {
- return new MarkerElement.internal_();
- }
+ external factory MarkerElement._internalWrap();
@Deprecated("Internal Use Only")
MarkerElement.internal_() : super.internal_();
@@ -4238,9 +4148,7 @@
return new MaskElement._internalWrap();
}
- factory MaskElement._internalWrap() {
- return new MaskElement.internal_();
- }
+ external factory MaskElement._internalWrap();
@Deprecated("Internal Use Only")
MaskElement.internal_() : super.internal_();
@@ -4435,9 +4343,7 @@
return new MetadataElement._internalWrap();
}
- factory MetadataElement._internalWrap() {
- return new MetadataElement.internal_();
- }
+ external factory MetadataElement._internalWrap();
@Deprecated("Internal Use Only")
MetadataElement.internal_() : super.internal_();
@@ -4628,9 +4534,7 @@
return new PathElement._internalWrap();
}
- factory PathElement._internalWrap() {
- return new PathElement.internal_();
- }
+ external factory PathElement._internalWrap();
@Deprecated("Internal Use Only")
PathElement.internal_() : super.internal_();
@@ -4889,9 +4793,7 @@
return new PathSegArcAbs._internalWrap();
}
- factory PathSegArcAbs._internalWrap() {
- return new PathSegArcAbs.internal_();
- }
+ external factory PathSegArcAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegArcAbs.internal_() : super.internal_();
@@ -4974,9 +4876,7 @@
return new PathSegArcRel._internalWrap();
}
- factory PathSegArcRel._internalWrap() {
- return new PathSegArcRel.internal_();
- }
+ external factory PathSegArcRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegArcRel.internal_() : super.internal_();
@@ -5059,9 +4959,7 @@
return new PathSegClosePath._internalWrap();
}
- factory PathSegClosePath._internalWrap() {
- return new PathSegClosePath.internal_();
- }
+ external factory PathSegClosePath._internalWrap();
@Deprecated("Internal Use Only")
PathSegClosePath.internal_() : super.internal_();
@@ -5088,9 +4986,7 @@
return new PathSegCurvetoCubicAbs._internalWrap();
}
- factory PathSegCurvetoCubicAbs._internalWrap() {
- return new PathSegCurvetoCubicAbs.internal_();
- }
+ external factory PathSegCurvetoCubicAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoCubicAbs.internal_() : super.internal_();
@@ -5165,9 +5061,7 @@
return new PathSegCurvetoCubicRel._internalWrap();
}
- factory PathSegCurvetoCubicRel._internalWrap() {
- return new PathSegCurvetoCubicRel.internal_();
- }
+ external factory PathSegCurvetoCubicRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoCubicRel.internal_() : super.internal_();
@@ -5242,9 +5136,7 @@
return new PathSegCurvetoCubicSmoothAbs._internalWrap();
}
- factory PathSegCurvetoCubicSmoothAbs._internalWrap() {
- return new PathSegCurvetoCubicSmoothAbs.internal_();
- }
+ external factory PathSegCurvetoCubicSmoothAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoCubicSmoothAbs.internal_() : super.internal_();
@@ -5303,9 +5195,7 @@
return new PathSegCurvetoCubicSmoothRel._internalWrap();
}
- factory PathSegCurvetoCubicSmoothRel._internalWrap() {
- return new PathSegCurvetoCubicSmoothRel.internal_();
- }
+ external factory PathSegCurvetoCubicSmoothRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoCubicSmoothRel.internal_() : super.internal_();
@@ -5364,9 +5254,7 @@
return new PathSegCurvetoQuadraticAbs._internalWrap();
}
- factory PathSegCurvetoQuadraticAbs._internalWrap() {
- return new PathSegCurvetoQuadraticAbs.internal_();
- }
+ external factory PathSegCurvetoQuadraticAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoQuadraticAbs.internal_() : super.internal_();
@@ -5425,9 +5313,7 @@
return new PathSegCurvetoQuadraticRel._internalWrap();
}
- factory PathSegCurvetoQuadraticRel._internalWrap() {
- return new PathSegCurvetoQuadraticRel.internal_();
- }
+ external factory PathSegCurvetoQuadraticRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoQuadraticRel.internal_() : super.internal_();
@@ -5486,9 +5372,7 @@
return new PathSegCurvetoQuadraticSmoothAbs._internalWrap();
}
- factory PathSegCurvetoQuadraticSmoothAbs._internalWrap() {
- return new PathSegCurvetoQuadraticSmoothAbs.internal_();
- }
+ external factory PathSegCurvetoQuadraticSmoothAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoQuadraticSmoothAbs.internal_() : super.internal_();
@@ -5531,9 +5415,7 @@
return new PathSegCurvetoQuadraticSmoothRel._internalWrap();
}
- factory PathSegCurvetoQuadraticSmoothRel._internalWrap() {
- return new PathSegCurvetoQuadraticSmoothRel.internal_();
- }
+ external factory PathSegCurvetoQuadraticSmoothRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegCurvetoQuadraticSmoothRel.internal_() : super.internal_();
@@ -5576,9 +5458,7 @@
return new PathSegLinetoAbs._internalWrap();
}
- factory PathSegLinetoAbs._internalWrap() {
- return new PathSegLinetoAbs.internal_();
- }
+ external factory PathSegLinetoAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegLinetoAbs.internal_() : super.internal_();
@@ -5621,9 +5501,7 @@
return new PathSegLinetoHorizontalAbs._internalWrap();
}
- factory PathSegLinetoHorizontalAbs._internalWrap() {
- return new PathSegLinetoHorizontalAbs.internal_();
- }
+ external factory PathSegLinetoHorizontalAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegLinetoHorizontalAbs.internal_() : super.internal_();
@@ -5658,9 +5536,7 @@
return new PathSegLinetoHorizontalRel._internalWrap();
}
- factory PathSegLinetoHorizontalRel._internalWrap() {
- return new PathSegLinetoHorizontalRel.internal_();
- }
+ external factory PathSegLinetoHorizontalRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegLinetoHorizontalRel.internal_() : super.internal_();
@@ -5695,9 +5571,7 @@
return new PathSegLinetoRel._internalWrap();
}
- factory PathSegLinetoRel._internalWrap() {
- return new PathSegLinetoRel.internal_();
- }
+ external factory PathSegLinetoRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegLinetoRel.internal_() : super.internal_();
@@ -5740,9 +5614,7 @@
return new PathSegLinetoVerticalAbs._internalWrap();
}
- factory PathSegLinetoVerticalAbs._internalWrap() {
- return new PathSegLinetoVerticalAbs.internal_();
- }
+ external factory PathSegLinetoVerticalAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegLinetoVerticalAbs.internal_() : super.internal_();
@@ -5777,9 +5649,7 @@
return new PathSegLinetoVerticalRel._internalWrap();
}
- factory PathSegLinetoVerticalRel._internalWrap() {
- return new PathSegLinetoVerticalRel.internal_();
- }
+ external factory PathSegLinetoVerticalRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegLinetoVerticalRel.internal_() : super.internal_();
@@ -5930,9 +5800,7 @@
return new PathSegMovetoAbs._internalWrap();
}
- factory PathSegMovetoAbs._internalWrap() {
- return new PathSegMovetoAbs.internal_();
- }
+ external factory PathSegMovetoAbs._internalWrap();
@Deprecated("Internal Use Only")
PathSegMovetoAbs.internal_() : super.internal_();
@@ -5975,9 +5843,7 @@
return new PathSegMovetoRel._internalWrap();
}
- factory PathSegMovetoRel._internalWrap() {
- return new PathSegMovetoRel.internal_();
- }
+ external factory PathSegMovetoRel._internalWrap();
@Deprecated("Internal Use Only")
PathSegMovetoRel.internal_() : super.internal_();
@@ -6024,9 +5890,7 @@
return new PatternElement._internalWrap();
}
- factory PatternElement._internalWrap() {
- return new PatternElement.internal_();
- }
+ external factory PatternElement._internalWrap();
@Deprecated("Internal Use Only")
PatternElement.internal_() : super.internal_();
@@ -6241,9 +6105,7 @@
return new PolygonElement._internalWrap();
}
- factory PolygonElement._internalWrap() {
- return new PolygonElement.internal_();
- }
+ external factory PolygonElement._internalWrap();
@Deprecated("Internal Use Only")
PolygonElement.internal_() : super.internal_();
@@ -6288,9 +6150,7 @@
return new PolylineElement._internalWrap();
}
- factory PolylineElement._internalWrap() {
- return new PolylineElement.internal_();
- }
+ external factory PolylineElement._internalWrap();
@Deprecated("Internal Use Only")
PolylineElement.internal_() : super.internal_();
@@ -6437,9 +6297,7 @@
return new RadialGradientElement._internalWrap();
}
- factory RadialGradientElement._internalWrap() {
- return new RadialGradientElement.internal_();
- }
+ external factory RadialGradientElement._internalWrap();
@Deprecated("Internal Use Only")
RadialGradientElement.internal_() : super.internal_();
@@ -6562,9 +6420,7 @@
return new RectElement._internalWrap();
}
- factory RectElement._internalWrap() {
- return new RectElement.internal_();
- }
+ external factory RectElement._internalWrap();
@Deprecated("Internal Use Only")
RectElement.internal_() : super.internal_();
@@ -6679,9 +6535,7 @@
return new ScriptElement._internalWrap();
}
- factory ScriptElement._internalWrap() {
- return new ScriptElement.internal_();
- }
+ external factory ScriptElement._internalWrap();
@Deprecated("Internal Use Only")
ScriptElement.internal_() : super.internal_();
@@ -6733,9 +6587,7 @@
return new SetElement._internalWrap();
}
- factory SetElement._internalWrap() {
- return new SetElement.internal_();
- }
+ external factory SetElement._internalWrap();
@Deprecated("Internal Use Only")
SetElement.internal_() : super.internal_();
@@ -6775,9 +6627,7 @@
return new StopElement._internalWrap();
}
- factory StopElement._internalWrap() {
- return new StopElement.internal_();
- }
+ external factory StopElement._internalWrap();
@Deprecated("Internal Use Only")
StopElement.internal_() : super.internal_();
@@ -6935,9 +6785,7 @@
return new StyleElement._internalWrap();
}
- factory StyleElement._internalWrap() {
- return new StyleElement.internal_();
- }
+ external factory StyleElement._internalWrap();
@Deprecated("Internal Use Only")
StyleElement.internal_() : super.internal_();
@@ -7416,9 +7264,7 @@
return new SvgElement._internalWrap();
}
- factory SvgElement._internalWrap() {
- return new SvgElement.internal_();
- }
+ external factory SvgElement._internalWrap();
@Deprecated("Internal Use Only")
SvgElement.internal_() : super.internal_();
@@ -7771,9 +7617,7 @@
return new SvgSvgElement._internalWrap();
}
- factory SvgSvgElement._internalWrap() {
- return new SvgSvgElement.internal_();
- }
+ external factory SvgSvgElement._internalWrap();
@Deprecated("Internal Use Only")
SvgSvgElement.internal_() : super.internal_();
@@ -7974,9 +7818,7 @@
return new SwitchElement._internalWrap();
}
- factory SwitchElement._internalWrap() {
- return new SwitchElement.internal_();
- }
+ external factory SwitchElement._internalWrap();
@Deprecated("Internal Use Only")
SwitchElement.internal_() : super.internal_();
@@ -8013,9 +7855,7 @@
return new SymbolElement._internalWrap();
}
- factory SymbolElement._internalWrap() {
- return new SymbolElement.internal_();
- }
+ external factory SymbolElement._internalWrap();
@Deprecated("Internal Use Only")
SymbolElement.internal_() : super.internal_();
@@ -8060,9 +7900,7 @@
return new TSpanElement._internalWrap();
}
- factory TSpanElement._internalWrap() {
- return new TSpanElement.internal_();
- }
+ external factory TSpanElement._internalWrap();
@Deprecated("Internal Use Only")
TSpanElement.internal_() : super.internal_();
@@ -8126,9 +7964,7 @@
return new TextContentElement._internalWrap();
}
- factory TextContentElement._internalWrap() {
- return new TextContentElement.internal_();
- }
+ external factory TextContentElement._internalWrap();
@Deprecated("Internal Use Only")
TextContentElement.internal_() : super.internal_();
@@ -8221,9 +8057,7 @@
return new TextElement._internalWrap();
}
- factory TextElement._internalWrap() {
- return new TextElement.internal_();
- }
+ external factory TextElement._internalWrap();
@Deprecated("Internal Use Only")
TextElement.internal_() : super.internal_();
@@ -8256,9 +8090,7 @@
return new TextPathElement._internalWrap();
}
- factory TextPathElement._internalWrap() {
- return new TextPathElement.internal_();
- }
+ external factory TextPathElement._internalWrap();
@Deprecated("Internal Use Only")
TextPathElement.internal_() : super.internal_();
@@ -8331,9 +8163,7 @@
return new TextPositioningElement._internalWrap();
}
- factory TextPositioningElement._internalWrap() {
- return new TextPositioningElement.internal_();
- }
+ external factory TextPositioningElement._internalWrap();
@Deprecated("Internal Use Only")
TextPositioningElement.internal_() : super.internal_();
@@ -8390,9 +8220,7 @@
return new TitleElement._internalWrap();
}
- factory TitleElement._internalWrap() {
- return new TitleElement.internal_();
- }
+ external factory TitleElement._internalWrap();
@Deprecated("Internal Use Only")
TitleElement.internal_() : super.internal_();
@@ -8708,9 +8536,7 @@
return new UseElement._internalWrap();
}
- factory UseElement._internalWrap() {
- return new UseElement.internal_();
- }
+ external factory UseElement._internalWrap();
@Deprecated("Internal Use Only")
UseElement.internal_() : super.internal_();
@@ -8767,9 +8593,7 @@
return new ViewElement._internalWrap();
}
- factory ViewElement._internalWrap() {
- return new ViewElement.internal_();
- }
+ external factory ViewElement._internalWrap();
@Deprecated("Internal Use Only")
ViewElement.internal_() : super.internal_();
@@ -8931,9 +8755,7 @@
return new ZoomEvent._internalWrap();
}
- factory ZoomEvent._internalWrap() {
- return new ZoomEvent.internal_();
- }
+ external factory ZoomEvent._internalWrap();
@Deprecated("Internal Use Only")
ZoomEvent.internal_() : super.internal_();
@@ -8980,9 +8802,7 @@
return new _GradientElement._internalWrap();
}
- factory _GradientElement._internalWrap() {
- return new _GradientElement.internal_();
- }
+ external factory _GradientElement._internalWrap();
@Deprecated("Internal Use Only")
_GradientElement.internal_() : super.internal_();
@@ -9047,9 +8867,7 @@
return new _SVGAltGlyphDefElement._internalWrap();
}
- factory _SVGAltGlyphDefElement._internalWrap() {
- return new _SVGAltGlyphDefElement.internal_();
- }
+ external factory _SVGAltGlyphDefElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGAltGlyphDefElement.internal_() : super.internal_();
@@ -9082,9 +8900,7 @@
return new _SVGAltGlyphItemElement._internalWrap();
}
- factory _SVGAltGlyphItemElement._internalWrap() {
- return new _SVGAltGlyphItemElement.internal_();
- }
+ external factory _SVGAltGlyphItemElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGAltGlyphItemElement.internal_() : super.internal_();
@@ -9117,9 +8933,7 @@
return new _SVGComponentTransferFunctionElement._internalWrap();
}
- factory _SVGComponentTransferFunctionElement._internalWrap() {
- return new _SVGComponentTransferFunctionElement.internal_();
- }
+ external factory _SVGComponentTransferFunctionElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGComponentTransferFunctionElement.internal_() : super.internal_();
@@ -9154,9 +8968,7 @@
return new _SVGCursorElement._internalWrap();
}
- factory _SVGCursorElement._internalWrap() {
- return new _SVGCursorElement.internal_();
- }
+ external factory _SVGCursorElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGCursorElement.internal_() : super.internal_();
@@ -9197,9 +9009,7 @@
return new _SVGFEDropShadowElement._internalWrap();
}
- factory _SVGFEDropShadowElement._internalWrap() {
- return new _SVGFEDropShadowElement.internal_();
- }
+ external factory _SVGFEDropShadowElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGFEDropShadowElement.internal_() : super.internal_();
@@ -9239,9 +9049,7 @@
return new _SVGFontElement._internalWrap();
}
- factory _SVGFontElement._internalWrap() {
- return new _SVGFontElement.internal_();
- }
+ external factory _SVGFontElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGFontElement.internal_() : super.internal_();
@@ -9274,9 +9082,7 @@
return new _SVGFontFaceElement._internalWrap();
}
- factory _SVGFontFaceElement._internalWrap() {
- return new _SVGFontFaceElement.internal_();
- }
+ external factory _SVGFontFaceElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGFontFaceElement.internal_() : super.internal_();
@@ -9309,9 +9115,7 @@
return new _SVGFontFaceFormatElement._internalWrap();
}
- factory _SVGFontFaceFormatElement._internalWrap() {
- return new _SVGFontFaceFormatElement.internal_();
- }
+ external factory _SVGFontFaceFormatElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGFontFaceFormatElement.internal_() : super.internal_();
@@ -9344,9 +9148,7 @@
return new _SVGFontFaceNameElement._internalWrap();
}
- factory _SVGFontFaceNameElement._internalWrap() {
- return new _SVGFontFaceNameElement.internal_();
- }
+ external factory _SVGFontFaceNameElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGFontFaceNameElement.internal_() : super.internal_();
@@ -9379,9 +9181,7 @@
return new _SVGFontFaceSrcElement._internalWrap();
}
- factory _SVGFontFaceSrcElement._internalWrap() {
- return new _SVGFontFaceSrcElement.internal_();
- }
+ external factory _SVGFontFaceSrcElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGFontFaceSrcElement.internal_() : super.internal_();
@@ -9414,9 +9214,7 @@
return new _SVGFontFaceUriElement._internalWrap();
}
- factory _SVGFontFaceUriElement._internalWrap() {
- return new _SVGFontFaceUriElement.internal_();
- }
+ external factory _SVGFontFaceUriElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGFontFaceUriElement.internal_() : super.internal_();
@@ -9453,9 +9251,7 @@
return new _SVGGlyphElement._internalWrap();
}
- factory _SVGGlyphElement._internalWrap() {
- return new _SVGGlyphElement.internal_();
- }
+ external factory _SVGGlyphElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGGlyphElement.internal_() : super.internal_();
@@ -9486,9 +9282,7 @@
return new _SVGGlyphRefElement._internalWrap();
}
- factory _SVGGlyphRefElement._internalWrap() {
- return new _SVGGlyphRefElement.internal_();
- }
+ external factory _SVGGlyphRefElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGGlyphRefElement.internal_() : super.internal_();
@@ -9528,9 +9322,7 @@
return new _SVGHKernElement._internalWrap();
}
- factory _SVGHKernElement._internalWrap() {
- return new _SVGHKernElement.internal_();
- }
+ external factory _SVGHKernElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGHKernElement.internal_() : super.internal_();
@@ -9564,9 +9356,7 @@
return new _SVGMPathElement._internalWrap();
}
- factory _SVGMPathElement._internalWrap() {
- return new _SVGMPathElement.internal_();
- }
+ external factory _SVGMPathElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGMPathElement.internal_() : super.internal_();
@@ -9602,9 +9392,7 @@
return new _SVGMissingGlyphElement._internalWrap();
}
- factory _SVGMissingGlyphElement._internalWrap() {
- return new _SVGMissingGlyphElement.internal_();
- }
+ external factory _SVGMissingGlyphElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGMissingGlyphElement.internal_() : super.internal_();
@@ -9641,9 +9429,7 @@
return new _SVGVKernElement._internalWrap();
}
- factory _SVGVKernElement._internalWrap() {
- return new _SVGVKernElement.internal_();
- }
+ external factory _SVGVKernElement._internalWrap();
@Deprecated("Internal Use Only")
_SVGVKernElement.internal_() : super.internal_();
diff --git a/sdk/lib/web_audio/dartium/web_audio_dartium.dart b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
index cc99534..7a3a9c4 100644
--- a/sdk/lib/web_audio/dartium/web_audio_dartium.dart
+++ b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
@@ -104,9 +104,7 @@
return new AnalyserNode._internalWrap();
}
- factory AnalyserNode._internalWrap() {
- return new AnalyserNode.internal_();
- }
+ external factory AnalyserNode._internalWrap();
@Deprecated("Internal Use Only")
AnalyserNode.internal_() : super.internal_();
@@ -262,9 +260,7 @@
return new AudioBufferSourceNode._internalWrap();
}
- factory AudioBufferSourceNode._internalWrap() {
- return new AudioBufferSourceNode.internal_();
- }
+ external factory AudioBufferSourceNode._internalWrap();
@Deprecated("Internal Use Only")
AudioBufferSourceNode.internal_() : super.internal_();
@@ -375,9 +371,7 @@
return new AudioContext._internalWrap();
}
- factory AudioContext._internalWrap() {
- return new AudioContext.internal_();
- }
+ external factory AudioContext._internalWrap();
@Deprecated("Internal Use Only")
AudioContext.internal_() : super.internal_();
@@ -542,9 +536,7 @@
return new AudioDestinationNode._internalWrap();
}
- factory AudioDestinationNode._internalWrap() {
- return new AudioDestinationNode.internal_();
- }
+ external factory AudioDestinationNode._internalWrap();
@Deprecated("Internal Use Only")
AudioDestinationNode.internal_() : super.internal_();
@@ -632,9 +624,7 @@
return new AudioNode._internalWrap();
}
- factory AudioNode._internalWrap() {
- return new AudioNode.internal_();
- }
+ external factory AudioNode._internalWrap();
@Deprecated("Internal Use Only")
AudioNode.internal_() : super.internal_();
@@ -788,9 +778,7 @@
return new AudioProcessingEvent._internalWrap();
}
- factory AudioProcessingEvent._internalWrap() {
- return new AudioProcessingEvent.internal_();
- }
+ external factory AudioProcessingEvent._internalWrap();
@Deprecated("Internal Use Only")
AudioProcessingEvent.internal_() : super.internal_();
@@ -831,9 +819,7 @@
return new AudioSourceNode._internalWrap();
}
- factory AudioSourceNode._internalWrap() {
- return new AudioSourceNode.internal_();
- }
+ external factory AudioSourceNode._internalWrap();
@Deprecated("Internal Use Only")
AudioSourceNode.internal_() : super.internal_();
@@ -861,9 +847,7 @@
return new BiquadFilterNode._internalWrap();
}
- factory BiquadFilterNode._internalWrap() {
- return new BiquadFilterNode.internal_();
- }
+ external factory BiquadFilterNode._internalWrap();
@Deprecated("Internal Use Only")
BiquadFilterNode.internal_() : super.internal_();
@@ -919,9 +903,7 @@
return new ChannelMergerNode._internalWrap();
}
- factory ChannelMergerNode._internalWrap() {
- return new ChannelMergerNode.internal_();
- }
+ external factory ChannelMergerNode._internalWrap();
@Deprecated("Internal Use Only")
ChannelMergerNode.internal_() : super.internal_();
@@ -949,9 +931,7 @@
return new ChannelSplitterNode._internalWrap();
}
- factory ChannelSplitterNode._internalWrap() {
- return new ChannelSplitterNode.internal_();
- }
+ external factory ChannelSplitterNode._internalWrap();
@Deprecated("Internal Use Only")
ChannelSplitterNode.internal_() : super.internal_();
@@ -979,9 +959,7 @@
return new ConvolverNode._internalWrap();
}
- factory ConvolverNode._internalWrap() {
- return new ConvolverNode.internal_();
- }
+ external factory ConvolverNode._internalWrap();
@Deprecated("Internal Use Only")
ConvolverNode.internal_() : super.internal_();
@@ -1025,9 +1003,7 @@
return new DelayNode._internalWrap();
}
- factory DelayNode._internalWrap() {
- return new DelayNode.internal_();
- }
+ external factory DelayNode._internalWrap();
@Deprecated("Internal Use Only")
DelayNode.internal_() : super.internal_();
@@ -1059,9 +1035,7 @@
return new DynamicsCompressorNode._internalWrap();
}
- factory DynamicsCompressorNode._internalWrap() {
- return new DynamicsCompressorNode.internal_();
- }
+ external factory DynamicsCompressorNode._internalWrap();
@Deprecated("Internal Use Only")
DynamicsCompressorNode.internal_() : super.internal_();
@@ -1113,9 +1087,7 @@
return new GainNode._internalWrap();
}
- factory GainNode._internalWrap() {
- return new GainNode.internal_();
- }
+ external factory GainNode._internalWrap();
@Deprecated("Internal Use Only")
GainNode.internal_() : super.internal_();
@@ -1147,9 +1119,7 @@
return new MediaElementAudioSourceNode._internalWrap();
}
- factory MediaElementAudioSourceNode._internalWrap() {
- return new MediaElementAudioSourceNode.internal_();
- }
+ external factory MediaElementAudioSourceNode._internalWrap();
@Deprecated("Internal Use Only")
MediaElementAudioSourceNode.internal_() : super.internal_();
@@ -1182,9 +1152,7 @@
return new MediaStreamAudioDestinationNode._internalWrap();
}
- factory MediaStreamAudioDestinationNode._internalWrap() {
- return new MediaStreamAudioDestinationNode.internal_();
- }
+ external factory MediaStreamAudioDestinationNode._internalWrap();
@Deprecated("Internal Use Only")
MediaStreamAudioDestinationNode.internal_() : super.internal_();
@@ -1216,9 +1184,7 @@
return new MediaStreamAudioSourceNode._internalWrap();
}
- factory MediaStreamAudioSourceNode._internalWrap() {
- return new MediaStreamAudioSourceNode.internal_();
- }
+ external factory MediaStreamAudioSourceNode._internalWrap();
@Deprecated("Internal Use Only")
MediaStreamAudioSourceNode.internal_() : super.internal_();
@@ -1250,9 +1216,7 @@
return new OfflineAudioCompletionEvent._internalWrap();
}
- factory OfflineAudioCompletionEvent._internalWrap() {
- return new OfflineAudioCompletionEvent.internal_();
- }
+ external factory OfflineAudioCompletionEvent._internalWrap();
@Deprecated("Internal Use Only")
OfflineAudioCompletionEvent.internal_() : super.internal_();
@@ -1290,9 +1254,7 @@
return new OfflineAudioContext._internalWrap();
}
- factory OfflineAudioContext._internalWrap() {
- return new OfflineAudioContext.internal_();
- }
+ external factory OfflineAudioContext._internalWrap();
@Deprecated("Internal Use Only")
OfflineAudioContext.internal_() : super.internal_();
@@ -1331,9 +1293,7 @@
return new OscillatorNode._internalWrap();
}
- factory OscillatorNode._internalWrap() {
- return new OscillatorNode.internal_();
- }
+ external factory OscillatorNode._internalWrap();
@Deprecated("Internal Use Only")
OscillatorNode.internal_() : super.internal_();
@@ -1414,9 +1374,7 @@
return new PannerNode._internalWrap();
}
- factory PannerNode._internalWrap() {
- return new PannerNode.internal_();
- }
+ external factory PannerNode._internalWrap();
@Deprecated("Internal Use Only")
PannerNode.internal_() : super.internal_();
@@ -1561,9 +1519,7 @@
return new ScriptProcessorNode._internalWrap();
}
- factory ScriptProcessorNode._internalWrap() {
- return new ScriptProcessorNode.internal_();
- }
+ external factory ScriptProcessorNode._internalWrap();
@Deprecated("Internal Use Only")
ScriptProcessorNode.internal_() : super.internal_();
@@ -1613,9 +1569,7 @@
return new WaveShaperNode._internalWrap();
}
- factory WaveShaperNode._internalWrap() {
- return new WaveShaperNode.internal_();
- }
+ external factory WaveShaperNode._internalWrap();
@Deprecated("Internal Use Only")
WaveShaperNode.internal_() : super.internal_();
diff --git a/sdk/lib/web_gl/dartium/web_gl_dartium.dart b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
index 1fdf4c7..707af2d 100644
--- a/sdk/lib/web_gl/dartium/web_gl_dartium.dart
+++ b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
@@ -824,9 +824,7 @@
return new ContextEvent._internalWrap();
}
- factory ContextEvent._internalWrap() {
- return new ContextEvent.internal_();
- }
+ external factory ContextEvent._internalWrap();
@Deprecated("Internal Use Only")
ContextEvent.internal_() : super.internal_();
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index a5781a6..f47d3ce 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -149,8 +149,8 @@
LibTest/core/List/getRange_A03_t01: RuntimeError, OK # Tests that fail because they use the legacy try-catch syntax. co19 issue 184.
LibTest/core/List/removeAt_A02_t01: RuntimeError # Issue 1533
LibTest/core/List/sort_A01_t06: Slow, Pass # Slow tests that needs extra time to finish.
-LibTest/core/double/INFINITY_A01_t04: RuntimeError # Please triage this failure.
-LibTest/core/double/NEGATIVE_INFINITY_A01_t04: RuntimeError # Please triage this failure.
+LibTest/core/double/INFINITY_A01_t04: RuntimeError # Expected to fail because double.INFINITY is int.
+LibTest/core/double/NEGATIVE_INFINITY_A01_t04: RuntimeError # Expected to fail because double.NEGATIVE_INFINITY is int.
LibTest/core/int/hashCode_A01_t01: RuntimeError, OK # co19 issue 308
LibTest/core/int/isEven_A01_t01: RuntimeError, OK # co19 issue 277
LibTest/core/int/isOdd_A01_t01: RuntimeError, OK # co19 issue 277
@@ -687,7 +687,7 @@
LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/webgl-layer-update_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css-generated-content/hit-test-generated-content_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/css-generated-content/malformed-url_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css-generated-content/malformed-url_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css-generated-content/pseudo-animation-before-onload_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css-generated-content/pseudo-animation-display_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css-generated-content/pseudo-animation_t01: Pass, RuntimeError # Please triage this failure
@@ -9616,9 +9616,7 @@
WebPlatformTest/webstorage/storage_local_setitem_quotaexceedederr_t01: Skip # Times out. Please triage this failure
[ $compiler == dart2js && $cps_ir ]
-Language/Statements/Labels/scope_t04: Crash # (switch (i){L:case 0:flag=true;break;case 2:continue L;}): continue to a labeled switch case
-Language/Statements/Continue/label_t12: Crash # (switch (2){L:case 1:flag=true;break;case 2:continue L;}): continue to a labeled switch case
-Language/Statements/Continue/label_t13: Crash # (switch (2){case 2:continue L;L:case 1:flag=true;}): continue to a labeled switch case
+Language/Types/Interface_Types/subtype_t09: Crash # Pending static: JSArray
Language/Types/Interface_Types/subtype_t39: RuntimeError # Please triage this failure.
LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Timeout
LibTest/core/Invocation/isAccessor_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
@@ -9632,5 +9630,3 @@
LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # Please triage this failure.
LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Please triage this failure.
LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Please triage this failure.
-LibTest/core/double/INFINITY_A01_t04: Pass # Please triage this failure.
-LibTest/core/double/NEGATIVE_INFINITY_A01_t04: Pass # Please triage this failure.
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index f97f79d..061649b 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -20,7 +20,6 @@
LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/dom/navigatorcontentutils/is-protocol-handler-registered_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/dom/navigatorcontentutils/unregister-protocol-handler_t01: RuntimeError # Dartium JSInterop failure
-LayoutTests/fast/events/remove-event-listener_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/xpath/4XPath/Core/test_parser_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/xpath/attr-namespace_t01: RuntimeError # Dartium JsInterop failure
LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
@@ -241,7 +240,6 @@
LayoutTests/fast/css3-text/css3-text-indent/getComputedStyle/getComputedStyle-text-indent-inherited_t01: RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/css3-text/css3-text-indent/getComputedStyle/getComputedStyle-text-indent_t01: RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/css3-text/css3-text-justify/getComputedStyle/getComputedStyle-text-justify_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/dom/52776_t01: RuntimeError # Please triage this failure.
LayoutTests/fast/dom/DOMImplementation/createDocument-namespace-err_t01: RuntimeError # co19-roll r706. Please triage this failure.
LayoutTests/fast/dom/Document/CaretRangeFromPoint/basic_t01: RuntimeError # co19-roll r706. Please triage this failure.
LayoutTests/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-strict-mode-wtih-checkbox_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
@@ -265,7 +263,6 @@
LayoutTests/fast/dom/HTMLDialogElement/dialog-scrolled-viewport_t01: RuntimeError # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLDialogElement/dialog-show-modal_t01: RuntimeError, Pass # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLDialogElement/inert-node-is-unfocusable_t01: RuntimeError # co19-roll r722: Please triage this failure.
-LayoutTests/fast/dom/HTMLDialogElement/inert-node-is-unselectable_t01: RuntimeError # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLDialogElement/multiple-centered-dialogs_t01: RuntimeError # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLDialogElement/non-anchored-dialog-positioning_t01: RuntimeError # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLDialogElement/show-modal-focusing-steps_t01: RuntimeError # co19-roll r722: Please triage this failure.
@@ -285,7 +282,6 @@
LayoutTests/fast/dom/HTMLLinkElement/resolve-url-on-insertion_t01: RuntimeError # co19-roll r722: Issue 18010
LayoutTests/fast/dom/HTMLObjectElement/beforeload-set-text-crash_t01: Skip # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLOptionElement/collection-setter-getter_t01: RuntimeError # co19-roll r722: Please triage this failure.
-LayoutTests/fast/dom/HTMLOutputElement/dom-settable-token-list_t01: RuntimeError # Issue 18931
LayoutTests/fast/dom/HTMLScriptElement/async-false-inside-async-false-load_t01: RuntimeError # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLScriptElement/async-inline-script_t01: RuntimeError # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/HTMLScriptElement/async-onbeforeload_t01: RuntimeError # co19-roll r722: Please triage this failure.
@@ -303,14 +299,8 @@
LayoutTests/fast/dom/Node/fragment-mutation_t01: RuntimeError # Please triage this failure.
LayoutTests/fast/dom/Node/initial-values_t01: RuntimeError # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/Range/bug-19527_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/insertNode-empty-fragment-crash_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/mutation_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-constructor_t01: RuntimeError # Please triage this failure.
LayoutTests/fast/dom/Range/range-created-during-remove-children_t01: RuntimeError, Pass # co19-roll r722: Please triage this failure.
LayoutTests/fast/dom/Range/range-detached-exceptions_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-expand_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-insertNode-separate-endContainer_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-insertNode-splittext_t01: RuntimeError # Please triage this failure.
LayoutTests/fast/dom/StyleSheet/discarded-sheet-owner-null_t01: Skip # Test reloads itself. Issue 18558.
LayoutTests/fast/dom/Window/window-resize-contents_t01: Pass, RuntimeError # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/Window/window-resize_t01: RuntimeError # co19-roll r738: Please triage this failure.
@@ -331,7 +321,6 @@
LayoutTests/fast/dom/focus-contenteditable_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/getElementsByClassName/011_t01: RuntimeError # Chrome 39 roll. Please triage this failure
LayoutTests/fast/dom/horizontal-scrollbar-in-rtl-doesnt-fire-onscroll_t01: RuntimeError # co19-roll r738: Please triage this failure.
-LayoutTests/fast/dom/horizontal-scrollbar-in-rtl_t01: RuntimeError # Please triage this failure.
LayoutTests/fast/dom/horizontal-scrollbar-when-dir-change_t01: RuntimeError # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/location-hash_t01: Pass, RuntimeError # co19-roll r738: Please triage this failure.
LayoutTests/fast/dom/option-properties_t01: RuntimeError # co19-roll r738: Please triage this failure.
@@ -636,7 +625,6 @@
LayoutTests/fast/text/font-ligatures-linebreak-word_t01: Skip # co19 issue 11.
LayoutTests/fast/text/font-ligatures-linebreak_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/text/glyph-reordering_t01: Pass, RuntimeError # This is a false pass. The font gets sanitized, so whether it works or not probably depends on default sizes. # co19 issue 11.
-LayoutTests/fast/text/international/cjk-segmentation_t01: RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/text/international/complex-text-rectangle_t01: Skip # co19 issue 732.
LayoutTests/fast/text/international/iso-8859-8_t01: RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/text/international/listbox-width-rtl_t01: RuntimeError # co19 issue 11.
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index a11b526..ae94df1 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -74,7 +74,7 @@
LibTest/isolate/Isolate/spawnUri_A01_t04: Crash, Pass # Issue 17440
LibTest/isolate/Isolate/spawn_A01_t04: Crash, Pass # Issue 17440
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ($arch == simarm || $arch == simarmv5te || $arch == simmips || $arch == simarm64) ]
+[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ($arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simmips || $arch == simarm64) ]
LibTest/core/Uri/Uri_A06_t03: Skip # Timeout
LibTest/collection/ListMixin/ListMixin_class_A01_t01: Skip # Timeout
LibTest/collection/ListBase/ListBase_class_A01_t01: Skip # Timeout
@@ -135,9 +135,6 @@
Language/Mixins/not_object_superclass_t01: MissingCompileTimeError # Please triage this failure
Language/Mixins/reference_to_super_t01: MissingCompileTimeError # Please triage this failure
-[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug ]
-Language/Mixins/Mixin_Application/wrong_type_t02: Crash # Please triage this failure
-
[ ($runtime == vm || $runtime == dart_precompiled) && $checked ]
Language/Errors_and_Warnings/static_warning_t01: RuntimeError # Please triage this failure
Language/Errors_and_Warnings/static_warning_t02: RuntimeError # Please triage this failure
diff --git a/tests/compiler/dart2js/class_set_test.dart b/tests/compiler/dart2js/class_set_test.dart
index d88745d..71fbd97 100644
--- a/tests/compiler/dart2js/class_set_test.dart
+++ b/tests/compiler/dart2js/class_set_test.dart
@@ -17,7 +17,14 @@
import 'package:compiler/src/world.dart';
void main() {
- asyncTest(() => TypeEnvironment.create(r"""
+ asyncTest(() async {
+ await testIterators();
+ await testForEach();
+ });
+}
+
+testIterators() async {
+ var env = await TypeEnvironment.create(r"""
/// A
/// / \
/// B C
@@ -42,305 +49,536 @@
new G();
}
""",
- useMockCompiler: false).then((env) {
- World world = env.compiler.world;
+ useMockCompiler: false);
+ World world = env.compiler.world;
- ClassElement A = env.getElement("A");
- ClassElement B = env.getElement("B");
- ClassElement C = env.getElement("C");
- ClassElement D = env.getElement("D");
- ClassElement E = env.getElement("E");
- ClassElement F = env.getElement("F");
- ClassElement G = env.getElement("G");
+ ClassElement A = env.getElement("A");
+ ClassElement B = env.getElement("B");
+ ClassElement C = env.getElement("C");
+ ClassElement D = env.getElement("D");
+ ClassElement E = env.getElement("E");
+ ClassElement F = env.getElement("F");
+ ClassElement G = env.getElement("G");
- void checkClass(ClassElement cls,
- {bool directlyInstantiated: false,
- bool indirectlyInstantiated: false}) {
- ClassHierarchyNode node = world.getClassHierarchyNode(cls);
- Expect.isNotNull(node, "Expected ClassHierarchyNode for $cls.");
- Expect.equals(
- directlyInstantiated || indirectlyInstantiated,
- node.isInstantiated,
- "Unexpected `isInstantiated` on ClassHierarchyNode for $cls.");
- Expect.equals(
- directlyInstantiated,
- node.isDirectlyInstantiated,
- "Unexpected `isDirectlyInstantiated` on ClassHierarchyNode for "
- "$cls.");
- Expect.equals(
- indirectlyInstantiated,
- node.isIndirectlyInstantiated,
- "Unexpected `isIndirectlyInstantiated` on ClassHierarchyNode for "
- "$cls.");
+ void checkClass(ClassElement cls,
+ {bool directlyInstantiated: false,
+ bool indirectlyInstantiated: false}) {
+ ClassHierarchyNode node = world.getClassHierarchyNode(cls);
+ Expect.isNotNull(node, "Expected ClassHierarchyNode for $cls.");
+ Expect.equals(
+ directlyInstantiated || indirectlyInstantiated,
+ node.isInstantiated,
+ "Unexpected `isInstantiated` on ClassHierarchyNode for $cls.");
+ Expect.equals(
+ directlyInstantiated,
+ node.isDirectlyInstantiated,
+ "Unexpected `isDirectlyInstantiated` on ClassHierarchyNode for "
+ "$cls.");
+ Expect.equals(
+ indirectlyInstantiated,
+ node.isIndirectlyInstantiated,
+ "Unexpected `isIndirectlyInstantiated` on ClassHierarchyNode for "
+ "$cls.");
+ }
+
+
+ checkClass(A, directlyInstantiated: true, indirectlyInstantiated: true);
+ checkClass(B, indirectlyInstantiated: true);
+ checkClass(C, directlyInstantiated: true, indirectlyInstantiated: true);
+ checkClass(D, directlyInstantiated: true);
+ checkClass(E, directlyInstantiated: true);
+ checkClass(F, directlyInstantiated: true);
+ checkClass(G, directlyInstantiated: true);
+
+ ClassHierarchyNodeIterator iterator;
+
+ void checkState(
+ ClassElement root,
+ {ClassElement currentNode,
+ List<List<ClassElement>> stack}) {
+
+ ClassElement classOf(ClassHierarchyNode node) {
+ return node != null ? node.cls : null;
}
-
- checkClass(A, directlyInstantiated: true, indirectlyInstantiated: true);
- checkClass(B, indirectlyInstantiated: true);
- checkClass(C, directlyInstantiated: true, indirectlyInstantiated: true);
- checkClass(D, directlyInstantiated: true);
- checkClass(E, directlyInstantiated: true);
- checkClass(F, directlyInstantiated: true);
- checkClass(G, directlyInstantiated: true);
-
- ClassHierarchyNodeIterator iterator;
-
- void checkState(
- ClassElement root,
- {ClassElement currentNode,
- List<List<ClassElement>> stack}) {
-
- ClassElement classOf(ClassHierarchyNode node) {
- return node != null ? node.cls : null;
- }
-
- List<ClassElement> classesOf(Link<ClassHierarchyNode> link) {
- if (link == null) return null;
- return link.map(classOf).toList();
- }
-
- ClassElement foundRoot = iterator.root.cls;
- ClassElement foundCurrentNode = classOf(iterator.currentNode);
- List<ClassElement> foundStack = classesOf(iterator.stack);
-
- StringBuffer sb = new StringBuffer();
- sb.write('{\n root: $foundRoot');
- sb.write('\n currentNode: $foundCurrentNode');
- sb.write('\n stack: $foundStack\n}');
-
- Expect.equals(root, foundRoot,
- "Expected root $root in $sb.");
- if (currentNode == null) {
- Expect.isNull(iterator.currentNode,
- "Unexpected non-null currentNode in $sb.");
- } else {
- Expect.isNotNull(foundCurrentNode,
- "Expected non-null currentNode ${currentNode} in $sb.");
- Expect.equals(currentNode, foundCurrentNode,
- "Expected currentNode $currentNode in $sb.");
- }
- if (stack == null) {
- Expect.isNull(foundStack,
- "Unexpected non-null stack in $sb.");
- } else {
- Expect.isNotNull(foundStack,
- "Expected non-null stack ${stack} in $sb.");
- Expect.listEquals(stack, foundStack,
- "Expected stack ${stack}, "
- "found ${foundStack} in $sb.");
- }
+ List<ClassElement> classesOf(Link<ClassHierarchyNode> link) {
+ if (link == null) return null;
+ return link.map(classOf).toList();
}
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(G),
- ClassHierarchyNode.ALL).iterator;
- checkState(G, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(G, currentNode: G, stack: []);
- Expect.equals(G, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(G, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ ClassElement foundRoot = iterator.root.cls;
+ ClassElement foundCurrentNode = classOf(iterator.currentNode);
+ List<ClassElement> foundStack = classesOf(iterator.stack);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(G),
- ClassHierarchyNode.ALL,
- includeRoot: false).iterator;
- checkState(G, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(G, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ StringBuffer sb = new StringBuffer();
+ sb.write('{\n root: $foundRoot');
+ sb.write('\n currentNode: $foundCurrentNode');
+ sb.write('\n stack: $foundStack\n}');
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(C),
- ClassHierarchyNode.ALL).iterator;
- checkState(C, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(C, currentNode: C, stack: [E, F, G]);
- Expect.equals(C, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(C, currentNode: E, stack: [F, G]);
- Expect.equals(E, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(C, currentNode: F, stack: [G]);
- Expect.equals(F, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(C, currentNode: G, stack: []);
- Expect.equals(G, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(C, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ Expect.equals(root, foundRoot,
+ "Expected root $root in $sb.");
+ if (currentNode == null) {
+ Expect.isNull(iterator.currentNode,
+ "Unexpected non-null currentNode in $sb.");
+ } else {
+ Expect.isNotNull(foundCurrentNode,
+ "Expected non-null currentNode ${currentNode} in $sb.");
+ Expect.equals(currentNode, foundCurrentNode,
+ "Expected currentNode $currentNode in $sb.");
+ }
+ if (stack == null) {
+ Expect.isNull(foundStack,
+ "Unexpected non-null stack in $sb.");
+ } else {
+ Expect.isNotNull(foundStack,
+ "Expected non-null stack ${stack} in $sb.");
+ Expect.listEquals(stack, foundStack,
+ "Expected stack ${stack}, "
+ "found ${foundStack} in $sb.");
+ }
+ }
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(D),
- ClassHierarchyNode.ALL).iterator;
- checkState(D, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(D, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(D, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(G),
+ ClassHierarchyNode.ALL).iterator;
+ checkState(G, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(G, currentNode: G, stack: []);
+ Expect.equals(G, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(G, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(B),
- ClassHierarchyNode.ALL).iterator;
- checkState(B, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(B, currentNode: B, stack: [D]);
- Expect.equals(B, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(B, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(B, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(G),
+ ClassHierarchyNode.ALL,
+ includeRoot: false).iterator;
+ checkState(G, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(G, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(B),
- ClassHierarchyNode.ALL,
- includeRoot: false).iterator;
- checkState(B, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(B, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(B, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(C),
+ ClassHierarchyNode.ALL).iterator;
+ checkState(C, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: C, stack: [E, F, G]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: E, stack: [F, G]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: F, stack: [G]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: G, stack: []);
+ Expect.equals(G, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(C, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(B),
- new EnumSet<Instantiation>.fromValues(<Instantiation>[
- Instantiation.DIRECTLY_INSTANTIATED,
- Instantiation.UNINSTANTIATED])).iterator;
- checkState(B, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(B, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(B, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(D),
+ ClassHierarchyNode.ALL).iterator;
+ checkState(D, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(D, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(D, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(A),
- ClassHierarchyNode.ALL).iterator;
- checkState(A, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: A, stack: [C, B]);
- Expect.equals(A, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: C, stack: [E, F, G, B]);
- Expect.equals(C, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: E, stack: [F, G, B]);
- Expect.equals(E, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: F, stack: [G, B]);
- Expect.equals(F, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: G, stack: [B]);
- Expect.equals(G, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: B, stack: [D]);
- Expect.equals(B, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(A, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(B),
+ ClassHierarchyNode.ALL).iterator;
+ checkState(B, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: B, stack: [D]);
+ Expect.equals(B, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(B, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(A),
- ClassHierarchyNode.ALL,
- includeRoot: false).iterator;
- checkState(A, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: C, stack: [E, F, G, B]);
- Expect.equals(C, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: E, stack: [F, G, B]);
- Expect.equals(E, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: F, stack: [G, B]);
- Expect.equals(F, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: G, stack: [B]);
- Expect.equals(G, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: B, stack: [D]);
- Expect.equals(B, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(A, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(B),
+ ClassHierarchyNode.ALL,
+ includeRoot: false).iterator;
+ checkState(B, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(B, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(A),
- new EnumSet<Instantiation>.fromValues(<Instantiation>[
- Instantiation.DIRECTLY_INSTANTIATED,
- Instantiation.UNINSTANTIATED])).iterator;
- checkState(A, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: A, stack: [C, B]);
- Expect.equals(A, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: C, stack: [E, F, G, B]);
- Expect.equals(C, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: E, stack: [F, G, B]);
- Expect.equals(E, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: F, stack: [G, B]);
- Expect.equals(F, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: G, stack: [B]);
- Expect.equals(G, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(A, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(B),
+ new EnumSet<Instantiation>.fromValues(<Instantiation>[
+ Instantiation.DIRECTLY_INSTANTIATED,
+ Instantiation.UNINSTANTIATED])).iterator;
+ checkState(B, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(B, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
- iterator = new ClassHierarchyNodeIterable(
- world.getClassHierarchyNode(A),
- new EnumSet<Instantiation>.fromValues(<Instantiation>[
- Instantiation.DIRECTLY_INSTANTIATED,
- Instantiation.UNINSTANTIATED]),
- includeRoot: false).iterator;
- checkState(A, currentNode: null, stack: null);
- Expect.isNull(iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: C, stack: [E, F, G, B]);
- Expect.equals(C, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: E, stack: [F, G, B]);
- Expect.equals(E, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: F, stack: [G, B]);
- Expect.equals(F, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: G, stack: [B]);
- Expect.equals(G, iterator.current);
- Expect.isTrue(iterator.moveNext());
- checkState(A, currentNode: D, stack: []);
- Expect.equals(D, iterator.current);
- Expect.isFalse(iterator.moveNext());
- checkState(A, currentNode: null, stack: []);
- Expect.isNull(iterator.current);
- }));
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(A),
+ ClassHierarchyNode.ALL).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: A, stack: [C, B]);
+ Expect.equals(A, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: B, stack: [D]);
+ Expect.equals(B, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(A),
+ ClassHierarchyNode.ALL,
+ includeRoot: false).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: B, stack: [D]);
+ Expect.equals(B, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(A),
+ new EnumSet<Instantiation>.fromValues(<Instantiation>[
+ Instantiation.DIRECTLY_INSTANTIATED,
+ Instantiation.UNINSTANTIATED])).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: A, stack: [C, B]);
+ Expect.equals(A, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.getClassHierarchyNode(A),
+ new EnumSet<Instantiation>.fromValues(<Instantiation>[
+ Instantiation.DIRECTLY_INSTANTIATED,
+ Instantiation.UNINSTANTIATED]),
+ includeRoot: false).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
}
+testForEach() async {
+ var env = await TypeEnvironment.create(r"""
+ /// A
+ /// / \
+ /// B C
+ /// / /|\
+ /// D E F G
+ /// / \
+ /// H I
+ ///
+ class A implements X {}
+ class B extends A {}
+ class C extends A {}
+ class D extends B {}
+ class E extends C {}
+ class F extends C implements B {}
+ class G extends C implements D {}
+ class H extends F {}
+ class I extends F {}
+ class X {}
+ """,
+ mainSource: r"""
+ main() {
+ new A();
+ new C();
+ new D();
+ new E();
+ new F();
+ new G();
+ new H();
+ new I();
+ }
+ """,
+ useMockCompiler: false);
+ World world = env.compiler.world;
+
+ ClassElement A = env.getElement("A");
+ ClassElement B = env.getElement("B");
+ ClassElement C = env.getElement("C");
+ ClassElement D = env.getElement("D");
+ ClassElement E = env.getElement("E");
+ ClassElement F = env.getElement("F");
+ ClassElement G = env.getElement("G");
+ ClassElement H = env.getElement("H");
+ ClassElement I = env.getElement("I");
+ ClassElement X = env.getElement("X");
+
+ void checkForEachSubclass(ClassElement cls, List<ClassElement> expected) {
+ ClassSet classSet = world.getClassSet(cls);
+ List<ClassElement> visited = <ClassElement>[];
+ classSet.forEachSubclass((ClassElement cls) {
+ visited.add(cls);
+ }, ClassHierarchyNode.ALL);
+
+ Expect.listEquals(expected, visited,
+ "Unexpected classes on $cls.forEachSubclass:\n"
+ "Actual: $visited, expected: $expected\n$classSet");
+
+ visited = <ClassElement>[];
+ classSet.forEachSubclass((ClassElement cls) {
+ visited.add(cls);
+ return ForEach.CONTINUE;
+ }, ClassHierarchyNode.ALL);
+
+ Expect.listEquals(expected, visited,
+ "Unexpected classes on $cls.forEachSubclass:\n"
+ "Actual: $visited, expected: $expected\n$classSet");
+ }
+
+ checkForEachSubclass(A, [A, B, D, C, G, F, I, H, E]);
+ checkForEachSubclass(B, [B, D]);
+ checkForEachSubclass(C, [C, G, F, I, H, E]);
+ checkForEachSubclass(D, [D]);
+ checkForEachSubclass(E, [E]);
+ checkForEachSubclass(F, [F, I, H]);
+ checkForEachSubclass(G, [G]);
+ checkForEachSubclass(H, [H]);
+ checkForEachSubclass(I, [I]);
+ checkForEachSubclass(X, [X]);
+
+ void checkForEachSubtype(ClassElement cls, List<ClassElement> expected) {
+ ClassSet classSet = world.getClassSet(cls);
+ List<ClassElement> visited = <ClassElement>[];
+ classSet.forEachSubtype((ClassElement cls) {
+ visited.add(cls);
+ }, ClassHierarchyNode.ALL);
+
+ Expect.listEquals(expected, visited,
+ "Unexpected classes on $cls.forEachSubtype:\n"
+ "Actual: $visited, expected: $expected\n$classSet");
+
+ visited = <ClassElement>[];
+ classSet.forEachSubtype((ClassElement cls) {
+ visited.add(cls);
+ return ForEach.CONTINUE;
+ }, ClassHierarchyNode.ALL);
+
+ Expect.listEquals(expected, visited,
+ "Unexpected classes on $cls.forEachSubtype:\n"
+ "Actual: $visited, expected: $expected\n$classSet");
+ }
+
+ checkForEachSubtype(A, [A, B, D, C, G, F, I, H, E]);
+ checkForEachSubtype(B, [B, D, F, I, H, G]);
+ checkForEachSubtype(C, [C, G, F, I, H, E]);
+ checkForEachSubtype(D, [D, G]);
+ checkForEachSubtype(E, [E]);
+ checkForEachSubtype(F, [F, I, H]);
+ checkForEachSubtype(G, [G]);
+ checkForEachSubtype(H, [H]);
+ checkForEachSubtype(I, [I]);
+ checkForEachSubtype(X, [X, A, B, D, C, G, F, I, H, E]);
+
+ void checkForEach(
+ ClassElement cls,
+ List<ClassElement> expected,
+ {ClassElement stop,
+ List<ClassElement> skipSubclasses: const <ClassElement>[],
+ bool forEachSubtype: false,
+ EnumSet<Instantiation> mask}) {
+
+ if (mask == null) {
+ mask = ClassHierarchyNode.ALL;
+ }
+
+ ClassSet classSet = world.getClassSet(cls);
+ List<ClassElement> visited = <ClassElement>[];
+
+ ForEach visit(ClassElement cls) {
+ visited.add(cls);
+ if (cls == stop) {
+ return ForEach.STOP;
+ } else if (skipSubclasses.contains(cls)) {
+ return ForEach.SKIP_SUBCLASSES;
+ }
+ return ForEach.CONTINUE;
+ }
+
+ if (forEachSubtype) {
+ classSet.forEachSubtype(visit, mask);
+ } else {
+ classSet.forEachSubclass(visit, mask);
+ }
+
+ Expect.listEquals(expected, visited,
+ "Unexpected classes on $cls."
+ "forEach${forEachSubtype ? 'Subtype' : 'Subclass'} "
+ "(stop:$stop, skipSubclasses:$skipSubclasses):\n"
+ "Actual: $visited, expected: $expected\n$classSet");
+ }
+
+ checkForEach(A, [A, B, D, C, G, F, I, H, E]);
+ checkForEach(A, [A], stop: A);
+ checkForEach(A, [A, B, C, G, F, I, H, E], skipSubclasses: [B]);
+ checkForEach(A, [A, B, C], skipSubclasses: [B, C]);
+ checkForEach(A, [A, B, C, G], stop: G, skipSubclasses: [B]);
+
+ checkForEach(B, [B, D, F, I, H, G], forEachSubtype: true);
+ checkForEach(B, [B, D], stop: D, forEachSubtype: true);
+ checkForEach(B, [B, D, F, G], skipSubclasses: [F], forEachSubtype: true);
+ checkForEach(B, [B, F, I, H, G], skipSubclasses: [B], forEachSubtype: true);
+ checkForEach(B, [B, D, F, I, H, G], skipSubclasses: [D], forEachSubtype: true);
+
+ checkForEach(X, [X, A, B, D, C, G, F, I, H, E], forEachSubtype: true);
+ checkForEach(X, [X, A, B, D], stop: D, forEachSubtype: true);
+ checkForEach(X, [X, A, B, D, C, G, F, E],
+ skipSubclasses: [F], forEachSubtype: true);
+ checkForEach(X, [X, A, B, D, C, G, F, I, H, E],
+ skipSubclasses: [X], forEachSubtype: true);
+ checkForEach(X, [X, A, B, D, C, G, F, I, H, E],
+ skipSubclasses: [D], forEachSubtype: true);
+ checkForEach(X, [A, D, C, G, F, I, H, E],
+ forEachSubtype: true,
+ mask: ClassHierarchyNode.DIRECTLY_INSTANTIATED);
+ checkForEach(X, [A, B, D, C, G, F, I, H, E],
+ forEachSubtype: true,
+ mask: ClassHierarchyNode.INSTANTIATED);
+
+ void checkAny(
+ ClassElement cls,
+ List<ClassElement> expected,
+ {ClassElement find,
+ bool expectedResult,
+ bool anySubtype: false}) {
+ ClassSet classSet = world.getClassSet(cls);
+ List<ClassElement> visited = <ClassElement>[];
+
+ bool visit(ClassElement cls) {
+ visited.add(cls);
+ return cls == find;
+ }
+
+ bool result;
+ if (anySubtype) {
+ result = classSet.anySubtype(visit, ClassHierarchyNode.ALL);
+ } else {
+ result = classSet.anySubclass(visit, ClassHierarchyNode.ALL);
+ }
+
+ Expect.equals(expectedResult, result,
+ "Unexpected result on $cls."
+ "any${anySubtype ? 'Subtype' : 'Subclass'} "
+ "(find:$find).");
+
+ Expect.listEquals(expected, visited,
+ "Unexpected classes on $cls."
+ "any${anySubtype ? 'Subtype' : 'Subclass'} "
+ "(find:$find):\n"
+ "Actual: $visited, expected: $expected\n$classSet");
+ }
+
+ checkAny(A, [A, B, D, C, G, F, I, H, E], expectedResult: false);
+ checkAny(A, [A], find: A, expectedResult: true);
+ checkAny(A, [A, B, D, C, G, F, I], find: I, expectedResult: true);
+
+ checkAny(B, [B, D, F, I, H, G], anySubtype: true, expectedResult: false);
+ checkAny(B, [B, D, F, I, H, G],
+ find: A, anySubtype: true, expectedResult: false);
+ checkAny(B, [B, D],
+ find: D, anySubtype: true, expectedResult: true);
+ checkAny(B, [B, D, F, I],
+ find: I, anySubtype: true, expectedResult: true);
+
+ checkAny(X, [X, A, B, D, C, G, F, I, H, E],
+ anySubtype: true, expectedResult: false);
+ checkAny(X, [X, A],
+ find: A, anySubtype: true, expectedResult: true);
+ checkAny(X, [X, A, B, D],
+ find: D, anySubtype: true, expectedResult: true);
+ checkAny(X, [X, A, B, D, C, G, F, I],
+ find: I, anySubtype: true, expectedResult: true);
+}
diff --git a/tests/compiler/dart2js/cps_ir/closures_16_test.dart b/tests/compiler/dart2js/cps_ir/closures_16_test.dart
new file mode 100644
index 0000000..6b359ec
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/closures_16_test.dart
@@ -0,0 +1,15 @@
+// ---- AUTO-GENERATED -------------------
+// This file was autogenerated by running:
+//
+// dart path/to/up_to_date_test.dart update
+//
+// Do not edit this file by hand.
+// ---------------------------------------
+
+library tests.compiler.dart2js.cps_ir.closures_16.dart;
+
+import 'runner.dart';
+
+main(args) {
+ runTest("closures_16.dart", update: args.length > 0 && args[0] == "update");
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
index 589d358..2c4e7c7 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
@@ -16,15 +16,6 @@
P.print(v0);
if (!v0)
throw H.wrapException(H.argumentErrorValue(y));
- if (x < y)
- v0 = -1;
- else if (x > y)
- v0 = 1;
- else if (x === y) {
- v0 = x === 0;
- v0 = v0 ? (y === 0 ? 1 / y < 0 : y < 0) === (v0 ? 1 / x < 0 : x < 0) ? 0 : (v0 ? 1 / x < 0 : x < 0) ? -1 : 1 : 0;
- } else
- v0 = isNaN(x) ? isNaN(y) ? 0 : 1 : -1;
- P.print(v0);
+ P.print(x < y ? -1 : x > y ? 1 : x === y ? x === 0 ? 1 / x < 0 === (y === 0 ? 1 / y < 0 : y < 0) ? 0 : 1 / x < 0 ? -1 : 1 : 0 : isNaN(x) ? isNaN(y) ? 0 : 1 : -1);
P.print(true);
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_1.js b/tests/compiler/dart2js/cps_ir/expected/basic_1.js
index 1cf4ed5..5ae55be 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_1.js
@@ -15,12 +15,12 @@
// }
function() {
- var l = [1, 2, 3], m = P.LinkedHashMap_LinkedHashMap$_literal(["s", 1]);
+ var l = [1, 2, 3], m = P.LinkedHashMap__makeLiteral(["s", 1]);
P.print("()");
P.print("(true)");
P.print("(1)");
P.print("(" + P.IterableBase_iterableToFullString([1, 2, 3], "[", "]") + ")");
- P.print("(" + P.Maps_mapToString(P.LinkedHashMap_LinkedHashMap$_literal(["s", 1])) + ")");
+ P.print("(" + P.Maps_mapToString(P.LinkedHashMap__makeLiteral(["s", 1])) + ")");
P.print("(1)");
P.print("(" + P.IterableBase_iterableToFullString(l, "[", "]") + ")");
P.print("(" + P.Maps_mapToString(m) + ")");
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_10.js b/tests/compiler/dart2js/cps_ir/expected/basic_10.js
index cfd6571..104f614 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_10.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_10.js
@@ -4,7 +4,7 @@
// }
function() {
- var v0 = Date.now() < Date.now(), line = v0 ? "true" : false === v0 ? "false" : String(v0);
+ var line = Date.now() < Date.now() ? "true" : "false";
if (typeof dartPrint == "function")
dartPrint(line);
else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_10.js b/tests/compiler/dart2js/cps_ir/expected/closures_10.js
index a628815..64e5e31 100644
--- a/tests/compiler/dart2js/cps_ir/expected/closures_10.js
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_10.js
@@ -8,7 +8,7 @@
// }
function() {
- var line = H.S(new V.A_b_closure(V.A$()).call$0());
+ var line = H.S(V.A$().a$0());
if (typeof dartPrint == "function")
dartPrint(line);
else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_15.js b/tests/compiler/dart2js/cps_ir/expected/closures_15.js
index 46c7d38..cf37dd2 100644
--- a/tests/compiler/dart2js/cps_ir/expected/closures_15.js
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_15.js
@@ -13,5 +13,5 @@
function(x) {
V.Foo$();
P.print("getter");
- P.print(new V.Foo_getter_closure().call$1(123));
+ P.print(123);
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_16.js b/tests/compiler/dart2js/cps_ir/expected/closures_16.js
new file mode 100644
index 0000000..e589971
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_16.js
@@ -0,0 +1,17 @@
+// Expectation for test:
+// class Foo {
+// get getter {
+// print('getter');
+// return (x) { try { return x; } finally { } }; // Inhibit inlining.
+// }
+// }
+// main(x) {
+// // Getter may or may not be inlined.
+// var notTearOff = new Foo().getter;
+// // Closure is not inlined.
+// print(notTearOff(123));
+// }
+
+function(x) {
+ P.print(V.Foo$().get$getter().call$1(123));
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
index 73e278b..4fdd8a2 100644
--- a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
@@ -11,13 +11,12 @@
// }
function() {
- var v0 = "ABC".length, sum = 0, i = 0;
- for (; i < v0; sum += "ABC".charCodeAt(i), ++i)
+ var sum = 0, i = 0;
+ for (; i < 3; sum += "ABC".charCodeAt(i), ++i)
;
P.print(sum);
- v0 = "Hello".length;
sum = 0;
- for (i = 0; i < v0; sum += "Hello".charCodeAt(i), ++i)
+ for (i = 0; i < 5; sum += "Hello".charCodeAt(i), ++i)
;
P.print(sum);
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
index 950d594..7fd9aff 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
@@ -4,6 +4,6 @@
// }
function() {
- while (true)
+ for (;;)
;
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
index 79c2ddd..3cb9718 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
@@ -1,5 +1,5 @@
// Expectation for test:
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
//
// main() {
// while (true) {
@@ -14,20 +14,14 @@
// }
function() {
- L1:
- while (true)
- L0:
- while (true)
- while (true) {
- P.print(true);
- if (false) {
- P.print(1);
- continue L0;
- }
- P.print(false);
- if (false) {
- P.print(2);
- continue L1;
- }
+ L0:
+ for (;;)
+ for (;;) {
+ while (V.foo(true))
+ if (V.foo(false)) {
+ P.print(2);
+ continue L0;
}
+ P.print(1);
+ }
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
index 514ed7b..f7c0900 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
@@ -1,5 +1,5 @@
// Expectation for test:
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
//
// main() {
// for (int i = 0; foo(true); i = foo(i)) {
@@ -10,17 +10,11 @@
// }
function() {
- while (true) {
- P.print(true);
- if (true === true) {
- P.print(1);
- P.print(false);
- if (false !== true) {
- P.print(0);
- continue;
- }
- }
- P.print(2);
- return null;
+ var i = 0;
+ for (; V.foo(true) === true; i = V.foo(i)) {
+ P.print(1);
+ if (V.foo(false) === true)
+ break;
}
+ P.print(2);
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
index 00099d0..dae4cc7 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
@@ -1,5 +1,5 @@
// Expectation for test:
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
//
// main() {
// foo(false);
@@ -12,8 +12,7 @@
// }
function() {
- P.print(false);
- P.print(true);
- true ? P.print(1) : P.print(2);
+ V.foo(false);
+ V.foo(true) ? P.print(1) : P.print(2);
P.print(3);
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
index 78c0641..0f28201 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
@@ -1,5 +1,5 @@
// Expectation for test:
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
//
// main() {
// foo(false);
@@ -14,9 +14,8 @@
// }
function() {
- P.print(false);
- P.print(true);
- if (true) {
+ V.foo(false);
+ if (V.foo(true)) {
P.print(1);
P.print(1);
} else {
diff --git a/tests/compiler/dart2js/cps_ir/expected/literals_1.js b/tests/compiler/dart2js/cps_ir/expected/literals_1.js
index ef654f5..d70ebf8 100644
--- a/tests/compiler/dart2js/cps_ir/expected/literals_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/literals_1.js
@@ -14,7 +14,7 @@
P.print([1]);
P.print([1, 2]);
P.print([1, [1, 2]]);
- P.print(P.LinkedHashMap_LinkedHashMap$_empty());
- P.print(P.LinkedHashMap_LinkedHashMap$_literal([1, 2]));
- P.print(P.LinkedHashMap_LinkedHashMap$_literal([[1, 2], [3, 4]]));
+ P.print(P.LinkedHashMap__makeEmpty());
+ P.print(P.LinkedHashMap__makeLiteral([1, 2]));
+ P.print(P.LinkedHashMap__makeLiteral([[1, 2], [3, 4]]));
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_1.js b/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
index 5e39b1e..71a1da5 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
@@ -1,11 +1,12 @@
// Expectation for test:
+// // Method to test: function(foo)
// foo(a, b) => ((a & 0xff0000) >> 1) & b;
// main() {
+// print(foo.toString());
// print(foo(123, 234));
// print(foo(0, 2));
// }
-function() {
- P.print((123 & 16711680) >>> 1 & 234);
- P.print((0 & 16711680) >>> 1 & 2);
+function(a, b) {
+ return (a & 16711680) >>> 1 & b;
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_2.js b/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
index 8d6d52d..7858649 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
@@ -1,11 +1,12 @@
// Expectation for test:
+// // Method to test: function(foo)
// foo(a) => ~a;
// main() {
+// print(foo.toString());
// print(foo(1));
// print(foo(10));
// }
-function() {
- P.print(~1 >>> 0);
- P.print(~10 >>> 0);
+function(a) {
+ return ~a >>> 0;
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_3.js b/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
index ff5d25d..bf578b2 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
@@ -8,5 +8,5 @@
function(a) {
var result = a % 13;
- return result === 0 ? 0 : result > 0 ? result : 13 < 0 ? result - 13 : result + 13;
+ return result === 0 ? 0 : result > 0 ? result : result + 13;
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_7.js b/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
index 837393f..9faff59 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
@@ -1,11 +1,12 @@
// Expectation for test:
+// // Method to test: function(foo)
// foo(a) => a ~/ 13;
// main() {
+// print(foo.toString());
// print(foo(5));
// print(foo(100));
// }
-function() {
- P.print(5 / 13 | 0);
- P.print(100 / 13 | 0);
+function(a) {
+ return a / 13 | 0;
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_4.js b/tests/compiler/dart2js/cps_ir/expected/operators_4.js
index f86a490..ccfc0a8 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators_4.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators_4.js
@@ -16,7 +16,7 @@
v0 = false;
} else
v0 = false;
- line = false === v0 ? "false" : String(v0);
+ line = v0 ? String(v0) : "false";
}
if (typeof dartPrint == "function")
dartPrint(line);
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_5.js b/tests/compiler/dart2js/cps_ir/expected/operators_5.js
index 3ff812c..d2986cc 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators_5.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators_5.js
@@ -10,7 +10,7 @@
if (!(v0 > 10)) {
$.x = v0 = $.x + 1;
if (!(v0 > 10)) {
- line = false === false ? "false" : String(false);
+ line = "false";
break L0;
}
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js b/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js
new file mode 100644
index 0000000..21c1d71
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js
@@ -0,0 +1,37 @@
+// Expectation for test:
+// // Method to test: function(test)
+// import 'package:expect/expect.dart';
+//
+// // This example illustrates a case we wish to do better in terms of inlining and
+// // code generation.
+// //
+// // Today this function is compiled without inlining Wrapper.[], JSArray.[] and
+// // Wrapper.[]= because:
+// // JSArray.[] is too big (14 nodes)
+// // Wrapper.[] is too big if we force inlining of JSArray (15 nodes)
+// // Wrapper.[]= is even bigger (46 nodes)
+// //
+// // See #25478 for ideas on how to make this better.
+// @NoInline()
+// test(data, x) {
+// data[x + 1] = data[x];
+// }
+//
+// main() {
+// var wrapper = new Wrapper();
+// wrapper[33] = wrapper[1]; // make Wrapper.[]= and [] used more than once.
+// print(test(new Wrapper(), int.parse('2')));
+// }
+//
+// class Wrapper {
+// final List arr = <bool>[true, false, false, true];
+// operator[](int i) => this.arr[i];
+// operator[]=(int i, v) {
+// if (i > arr.length - 1) arr.length = i + 1;
+// return arr[i] = v;
+// }
+// }
+
+function(data, x) {
+ data.$indexSet(0, J.$add$ns(x, 1), C.JSArray_methods.$index(data.arr, x));
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js b/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js
new file mode 100644
index 0000000..a3a2ae0
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js
@@ -0,0 +1,35 @@
+// Expectation for test:
+// // This test illustrates an opportunity to remove redundant code by
+// // propagating inforamtion after inlining.
+// //
+// // The code below inlines `foo` twice, but we don't propagate that we already
+// // know from the first `foo` that `a` is an int, so the second check can be
+// // removed entirely.
+//
+// import 'package:expect/expect.dart';
+//
+// main() {
+// var a = nextNumber();
+// action(foo(a));
+// action(foo(a));
+// }
+//
+// foo(x) {
+// if (x is! int) throw "error 1";
+// return x + 5 % 100;
+// }
+//
+// @NoInline() @AssumeDynamic()
+// nextNumber() => int.parse('33');
+//
+// @NoInline()
+// action(v) => print(v);
+
+function() {
+ var a = V.nextNumber();
+ if (!(typeof a === "number" && Math.floor(a) === a))
+ throw H.wrapException("error 1");
+ a += 5;
+ V.action(a);
+ V.action(a);
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_1.js b/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
index 4c7ee26..cc601dd 100644
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
@@ -1,7 +1,7 @@
// Expectation for test:
// class Base {
// m(x) {
-// print(x+1);
+// try { print(x+1); } finally { }
// }
// }
// class Sub extends Base {
@@ -12,15 +12,6 @@
// }
function() {
- var line = "" + (100 + 10 + 1);
- V.Sub$();
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
+ var v0 = V.Sub$();
+ V.Base.prototype.m$1.call(v0, 110);
}
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_2.js b/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
index 13b1d21..27f6c2b 100644
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
@@ -25,5 +25,5 @@
function() {
var v0 = V.Sub$();
- V.Base.prototype.$add.call(v0, v0, 10000 + 1);
+ V.Base.prototype.$add.call(v0, v0, 10001);
}
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_16.dart b/tests/compiler/dart2js/cps_ir/input/closures_16.dart
new file mode 100644
index 0000000..0d57270
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/input/closures_16.dart
@@ -0,0 +1,12 @@
+class Foo {
+ get getter {
+ print('getter');
+ return (x) { try { return x; } finally { } }; // Inhibit inlining.
+ }
+}
+main(x) {
+ // Getter may or may not be inlined.
+ var notTearOff = new Foo().getter;
+ // Closure is not inlined.
+ print(notTearOff(123));
+}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
index dd06bed..a7baf52 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
main() {
while (true) {
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
index 51cead4..8335da4 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
main() {
for (int i = 0; foo(true); i = foo(i)) {
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
index 881d8ce..dd9fa9c 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
main() {
foo(false);
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
index 6efe03c..ee75818 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
main() {
foo(false);
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_1.dart b/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
index 05da19c..38b8f4f 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
@@ -1,5 +1,7 @@
+// Method to test: function(foo)
foo(a, b) => ((a & 0xff0000) >> 1) & b;
main() {
+ print(foo.toString());
print(foo(123, 234));
print(foo(0, 2));
}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_2.dart b/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
index 56bebd9..f38e967 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
@@ -1,5 +1,7 @@
+// Method to test: function(foo)
foo(a) => ~a;
main() {
+ print(foo.toString());
print(foo(1));
print(foo(10));
}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_7.dart b/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
index f2c68ee..225701b 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
@@ -1,5 +1,7 @@
+// Method to test: function(foo)
foo(a) => a ~/ 13;
main() {
+ print(foo.toString());
print(foo(5));
print(foo(100));
}
diff --git a/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart b/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart
new file mode 100644
index 0000000..084bc34
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart
@@ -0,0 +1,32 @@
+// Method to test: function(test)
+import 'package:expect/expect.dart';
+
+// This example illustrates a case we wish to do better in terms of inlining and
+// code generation.
+//
+// Today this function is compiled without inlining Wrapper.[], JSArray.[] and
+// Wrapper.[]= because:
+// JSArray.[] is too big (14 nodes)
+// Wrapper.[] is too big if we force inlining of JSArray (15 nodes)
+// Wrapper.[]= is even bigger (46 nodes)
+//
+// See #25478 for ideas on how to make this better.
+@NoInline()
+test(data, x) {
+ data[x + 1] = data[x];
+}
+
+main() {
+ var wrapper = new Wrapper();
+ wrapper[33] = wrapper[1]; // make Wrapper.[]= and [] used more than once.
+ print(test(new Wrapper(), int.parse('2')));
+}
+
+class Wrapper {
+ final List arr = <bool>[true, false, false, true];
+ operator[](int i) => this.arr[i];
+ operator[]=(int i, v) {
+ if (i > arr.length - 1) arr.length = i + 1;
+ return arr[i] = v;
+ }
+}
diff --git a/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart b/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart
new file mode 100644
index 0000000..913dfc5
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart
@@ -0,0 +1,25 @@
+// This test illustrates an opportunity to remove redundant code by
+// propagating inforamtion after inlining.
+//
+// The code below inlines `foo` twice, but we don't propagate that we already
+// know from the first `foo` that `a` is an int, so the second check can be
+// removed entirely.
+
+import 'package:expect/expect.dart';
+
+main() {
+ var a = nextNumber();
+ action(foo(a));
+ action(foo(a));
+}
+
+foo(x) {
+ if (x is! int) throw "error 1";
+ return x + 5 % 100;
+}
+
+@NoInline() @AssumeDynamic()
+nextNumber() => int.parse('33');
+
+@NoInline()
+action(v) => print(v);
diff --git a/tests/compiler/dart2js/cps_ir/input/supercall_1.dart b/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
index 04d5817..0ac95c8d 100644
--- a/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
+++ b/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
@@ -1,6 +1,6 @@
class Base {
m(x) {
- print(x+1);
+ try { print(x+1); } finally { }
}
}
class Sub extends Base {
diff --git a/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart b/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart
new file mode 100644
index 0000000..eaf0b4a
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart
@@ -0,0 +1,15 @@
+// ---- AUTO-GENERATED -------------------
+// This file was autogenerated by running:
+//
+// dart path/to/up_to_date_test.dart update
+//
+// Do not edit this file by hand.
+// ---------------------------------------
+
+library tests.compiler.dart2js.cps_ir.optimize_indexers.dart;
+
+import 'runner.dart';
+
+main(args) {
+ runTest("optimize_indexers.dart", update: args.length > 0 && args[0] == "update");
+}
diff --git a/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart b/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart
new file mode 100644
index 0000000..e97e0ac
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart
@@ -0,0 +1,15 @@
+// ---- AUTO-GENERATED -------------------
+// This file was autogenerated by running:
+//
+// dart path/to/up_to_date_test.dart update
+//
+// Do not edit this file by hand.
+// ---------------------------------------
+
+library tests.compiler.dart2js.cps_ir.redundant_condition.dart;
+
+import 'runner.dart';
+
+main(args) {
+ runTest("redundant_condition.dart", update: args.length > 0 && args[0] == "update");
+}
diff --git a/tests/compiler/dart2js/cps_ir/runner.dart b/tests/compiler/dart2js/cps_ir/runner.dart
index a71bd9a..af77384 100644
--- a/tests/compiler/dart2js/cps_ir/runner.dart
+++ b/tests/compiler/dart2js/cps_ir/runner.dart
@@ -33,7 +33,20 @@
var match = elementNameRegExp.firstMatch(source);
var elementName = match?.group(1);
- Map files = {TEST_MAIN_FILE: source};
+ Map files = {
+ TEST_MAIN_FILE: source,
+ 'package:expect/expect.dart': '''
+ class NoInline {
+ const NoInline();
+ }
+ class TrustTypeAnnotations {
+ const TrustTypeAnnotations();
+ }
+ class AssumeDynamic {
+ const AssumeDynamic();
+ }
+ ''',
+ };
asyncTest(() async {
Uri uri = Uri.parse('memory:$TEST_MAIN_FILE');
String found = null;
@@ -105,7 +118,7 @@
String _getCodeForMain(CompilerImpl compiler) {
Element mainFunction = compiler.mainFunction;
js.Node ast = compiler.enqueuer.codegen.generatedCode[mainFunction];
- return js.prettyPrint(ast, compiler).getText();
+ return js.prettyPrint(ast, compiler);
}
String _getCodeForMethod(CompilerImpl compiler,
@@ -125,5 +138,5 @@
}
js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement];
- return js.prettyPrint(ast, compiler).getText();
+ return js.prettyPrint(ast, compiler);
}
diff --git a/tests/compiler/dart2js/cps_ir/update_all.dart b/tests/compiler/dart2js/cps_ir/update_all.dart
index 726f2e4..5874a25 100644
--- a/tests/compiler/dart2js/cps_ir/update_all.dart
+++ b/tests/compiler/dart2js/cps_ir/update_all.dart
@@ -79,6 +79,7 @@
runTest('closures_13.dart', update: true);
runTest('closures_14.dart', update: true);
runTest('closures_15.dart', update: true);
+ runTest('closures_16.dart', update: true);
runTest('closures_2.dart', update: true);
runTest('closures_3.dart', update: true);
runTest('closures_4.dart', update: true);
@@ -132,6 +133,8 @@
runTest('operators_6.dart', update: true);
runTest('operators_7.dart', update: true);
runTest('operators_8.dart', update: true);
+ runTest('optimize_indexers.dart', update: true);
+ runTest('redundant_condition.dart', update: true);
runTest('runtime_types_1.dart', update: true);
runTest('runtime_types_2.dart', update: true);
runTest('runtime_types_3.dart', update: true);
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
index 2c68f48..781ef91 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
@@ -60,7 +60,7 @@
}
js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement];
- return js.prettyPrint(ast, compiler).getText();
+ return js.prettyPrint(ast, compiler);
}
runTests(List<TestEntry> tests) {
diff --git a/tests/compiler/dart2js/js_parser_statements_test.dart b/tests/compiler/dart2js/js_parser_statements_test.dart
index 2c12440..6c18de3 100644
--- a/tests/compiler/dart2js/js_parser_statements_test.dart
+++ b/tests/compiler/dart2js/js_parser_statements_test.dart
@@ -14,8 +14,7 @@
jsAst.Node node = js.statement(statement, arguments);
return MockCompiler.create((MockCompiler compiler) {
String jsText =
- jsAst.prettyPrint(node, compiler, allowVariableMinification: false)
- .getText();
+ jsAst.prettyPrint(node, compiler, allowVariableMinification: false);
Expect.stringEquals(expect.trim(), jsText.trim());
});
diff --git a/tests/compiler/dart2js/js_parser_test.dart b/tests/compiler/dart2js/js_parser_test.dart
index 4022724..89d51070 100644
--- a/tests/compiler/dart2js/js_parser_test.dart
+++ b/tests/compiler/dart2js/js_parser_test.dart
@@ -15,7 +15,7 @@
String jsText =
jsAst.prettyPrint(node,
compiler,
- allowVariableMinification: false).getText();
+ allowVariableMinification: false);
if (expect == "") {
Expect.stringEquals(expression, jsText);
} else {
diff --git a/tests/compiler/dart2js/library_env_test.dart b/tests/compiler/dart2js/library_env_test.dart
new file mode 100644
index 0000000..0f0ff6d
--- /dev/null
+++ b/tests/compiler/dart2js/library_env_test.dart
@@ -0,0 +1,152 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Check that 'dart:' libraries have their corresponding dart.library.X
+/// environment variable set.
+
+import "dart:io";
+
+import "dart:async";
+
+import "memory_source_file_helper.dart";
+
+import "package:async_helper/async_helper.dart";
+
+import 'package:expect/expect.dart' show
+ Expect;
+
+import 'package:compiler/src/elements/elements.dart' show
+ LibraryElement;
+
+import 'package:compiler/src/null_compiler_output.dart' show
+ NullCompilerOutput;
+
+import 'package:compiler/compiler_new.dart' show
+ CompilerInput,
+ CompilerDiagnostics;
+
+import 'package:sdk_library_metadata/libraries.dart' show
+ LibraryInfo;
+
+const clientPlatform = r'''
+[dart-spec]
+spec: 3rd edition.
+
+[features]
+# No extra features
+
+[libraries]
+mock.client: mock1.dart
+mock.shared: mock3.dart
+collection: collection/collection.dart
+html: html/dart2js/html_dart2js.dart
+''';
+
+const serverPlatform = r'''
+[dart-spec]
+spec: 3rd edition.
+
+[features]
+# No extra features
+
+[libraries]
+mock.server: mock2.dart
+mock.shared: mock3.dart
+collection: collection/collection.dart
+io: io/io.dart
+''';
+
+class DummyCompilerInput implements CompilerInput {
+ const DummyCompilerInput();
+
+ readFromUri(uri) async {
+ if (uri.toString().endsWith("dart_client.platform")) {
+ return clientPlatform;
+ } else if (uri.toString().endsWith("dart_server.platform")) {
+ return serverPlatform;
+ } else {
+ throw "should not be needed $uri";
+ }
+ }
+}
+
+class DummyCompilerDiagnostics implements CompilerDiagnostics {
+ const DummyCompilerDiagnostics();
+
+ report(code, uri, begin, end, text, kind) {
+ throw "should not be needed";
+ }
+}
+
+class CustomCompiler extends CompilerImpl {
+ CustomCompiler(
+ options,
+ environment)
+ : super(
+ const DummyCompilerInput(),
+ const NullCompilerOutput(),
+ const DummyCompilerDiagnostics(),
+ Uri.base.resolve("sdk/"),
+ null,
+ options,
+ environment);
+}
+
+runTest() async {
+ var compiler = new CustomCompiler(
+ [],
+ {});
+
+ await compiler.setupSdk();
+
+ // Core libraries are always present.
+ Expect.equals("true", compiler.fromEnvironment("dart.library.collection"));
+ // Non-existing entries in the environment return 'null'.
+ Expect.isNull(compiler.fromEnvironment("not in env"));
+ // Check for client libraries (default if there are no flags to the compiler).
+ Expect.equals("true", compiler.fromEnvironment("dart.library.mock.client"));
+ Expect.equals("true", compiler.fromEnvironment("dart.library.html"));
+ // Check for shared libraries..
+ Expect.equals("true", compiler.fromEnvironment("dart.library.mock.shared"));
+ // Check server libraries are not present.
+ Expect.equals(null, compiler.fromEnvironment("dart.library.mock.server"));
+ Expect.equals(null, compiler.fromEnvironment("dart.library.io"));
+
+ compiler = new CustomCompiler(
+ ['--categories=Server'],
+ {});
+
+ await compiler.setupSdk();
+
+ // Core libraries are always present.
+ Expect.equals("true", compiler.fromEnvironment("dart.library.collection"));
+ // Non-existing entries in the environment return 'null'.
+ Expect.isNull(compiler.fromEnvironment("not in env"));
+ // Check client libraries are not present.
+ Expect.equals(null, compiler.fromEnvironment("dart.library.mock.client"));
+ Expect.equals(null, compiler.fromEnvironment("dart.library.html"));
+ // Check for shared libraries..
+ Expect.equals("true", compiler.fromEnvironment("dart.library.mock.shared"));
+ // Check for server libraries.
+ Expect.equals("true", compiler.fromEnvironment("dart.library.mock.server"));
+ Expect.equals("true", compiler.fromEnvironment("dart.library.io"));
+
+ // Check that user-defined env-variables win.
+ compiler = new CustomCompiler(
+ [],
+ {'dart.library.collection': "false",
+ 'dart.library.mock.client': "foo"});
+
+ await compiler.setupSdk();
+
+ Expect.equals("false", compiler.fromEnvironment("dart.library.collection"));
+ Expect.equals("foo", compiler.fromEnvironment("dart.library.mock.client"));
+}
+
+main() {
+ asyncStart();
+ runTest().then((_) {
+ asyncEnd();
+ });
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/message_kind_test.dart b/tests/compiler/dart2js/message_kind_test.dart
index c3954f0..a886f42 100644
--- a/tests/compiler/dart2js/message_kind_test.dart
+++ b/tests/compiler/dart2js/message_kind_test.dart
@@ -7,13 +7,19 @@
import "package:async_helper/async_helper.dart";
import 'package:compiler/src/diagnostics/messages.dart' show
MessageKind,
- MessageTemplate;
+ MessageTemplate,
+ SharedMessageKind;
import 'message_kind_helper.dart';
main(List<String> arguments) {
List<MessageTemplate> examples = <MessageTemplate>[];
- for (MessageKind kind in MessageKind.values) {
+ List allMessageKinds = []
+ ..addAll(MessageKind.values)
+ ..addAll(SharedMessageKind.values);
+ for (var kind in allMessageKinds) {
+ if (kind == SharedMessageKind.exampleMessage) continue;
+
MessageTemplate template = MessageTemplate.TEMPLATES[kind];
Expect.isNotNull(template, "No template for $kind.");
Expect.equals(kind, template.kind,
diff --git a/tests/compiler/dart2js/override_inheritance_test.dart b/tests/compiler/dart2js/override_inheritance_test.dart
index 628f625..ef4387f 100644
--- a/tests/compiler/dart2js/override_inheritance_test.dart
+++ b/tests/compiler/dart2js/override_inheritance_test.dart
@@ -1548,7 +1548,6 @@
}
class Class extends A {
}
- """, warnings: MessageKind.UNIMPLEMENTED_METHOD_ONE,
- infos: MessageKind.UNIMPLEMENTED_METHOD_CONT),
+ """),
]);
}
diff --git a/tests/compiler/dart2js/proxy_test.dart b/tests/compiler/dart2js/proxy_test.dart
index bdba67f..3a0af23 100644
--- a/tests/compiler/dart2js/proxy_test.dart
+++ b/tests/compiler/dart2js/proxy_test.dart
@@ -15,6 +15,9 @@
const Map<String, dynamic> TESTS = const {
'language/proxy_test.dart': null,
'language/proxy2_test.dart': null,
+ 'language/proxy3_test.dart': null,
+ 'language/proxy4_test.dart': null,
+ 'language/proxy5_test.dart': null,
};
void main(List<String> args) {
diff --git a/tests/compiler/dart2js/sourcemaps/diff_view.dart b/tests/compiler/dart2js/sourcemaps/diff_view.dart
new file mode 100644
index 0000000..0448a7f
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/diff_view.dart
@@ -0,0 +1,871 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library sourcemap.diff_view;
+
+import 'dart:async';
+import 'dart:io';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/diagnostics/invariant.dart';
+import 'package:compiler/src/io/position_information.dart';
+import 'package:compiler/src/js/js.dart' as js;
+import 'sourcemap_helper.dart';
+import 'sourcemap_html_helper.dart';
+import 'trace_graph.dart';
+import 'js_tracer.dart';
+
+const String WITH_SOURCE_INFO_STYLE = 'background-color:#FF8080;';
+const String WITHOUT_SOURCE_INFO_STYLE = 'border: solid 1px #FF8080;';
+const String ADDITIONAL_SOURCE_INFO_STYLE = 'border: solid 1px #8080FF;';
+
+main(List<String> args) async {
+ DEBUG_MODE = true;
+ String out = 'out.js.diff_view.html';
+ String filename;
+ List<String> currentOptions = [];
+ List<List<String>> options = [currentOptions];
+ int argGroup = 0;
+ for (String arg in args) {
+ if (arg == '--') {
+ currentOptions = [];
+ options.add(currentOptions);
+ argGroup++;
+ } else if (arg.startsWith('-o')) {
+ out = arg.substring('-o'.length);
+ } else if (arg.startsWith('--out=')) {
+ out = arg.substring('--out='.length);
+ } else if (arg.startsWith('-')) {
+ currentOptions.add(arg);
+ } else {
+ filename = arg;
+ }
+ }
+ List<String> commonArguments = options[0];
+ List<String> options1;
+ List<String> options2;
+ if (options.length == 1) {
+ // Use default options; comparing SSA and CPS output using the new
+ // source information strategy.
+ options1 = [USE_NEW_SOURCE_INFO]..addAll(commonArguments);
+ options2 = [USE_NEW_SOURCE_INFO, Flags.useCpsIr]..addAll(commonArguments);
+ } else if (options.length == 2) {
+ // Use alternative options for the second output column.
+ options1 = commonArguments;
+ options2 = options[1]..addAll(commonArguments);
+ } else {
+ // Use specific options for both output columns.
+ options1 = options[1]..addAll(commonArguments);
+ options2 = options[2]..addAll(commonArguments);
+ }
+
+ print('Compiling ${options1.join(' ')} $filename');
+ CodeLinesResult result1 = await computeCodeLines(options1, filename);
+ print('Compiling ${options2.join(' ')} $filename');
+ CodeLinesResult result2 = await computeCodeLines(options2, filename);
+
+ StringBuffer sb = new StringBuffer();
+ sb.write('''
+<html>
+<head>
+<title>Diff for $filename</title>
+<style>
+.lineNumber {
+ font-size: smaller;
+ color: #888;
+}
+.header {
+ position: fixed;
+ width: 50%;
+ background-color: #400000;
+ color: #FFFFFF;
+ height: 20px;
+ top: 0px;
+ z-index: 1000;
+}
+.cell {
+ max-width:500px;
+ overflow-x:auto;
+ vertical-align:top;
+}
+.corresponding1 {
+ background-color: #FFFFE0;
+}
+.corresponding2 {
+ background-color: #EFEFD0;
+}
+.identical1 {
+ background-color: #E0F0E0;
+}
+.identical2 {
+ background-color: #C0E0C0;
+}
+</style>
+</head>
+<body>''');
+
+ sb.write('''
+<div class="header" style="left: 0px;">[${options1.join(',')}]</div>
+<div class="header" style="right: 0px;">[${options2.join(',')}]</div>
+<div style="position:absolute;top:22px;width:100%;height:18px;">
+ <span class="identical1"> </span>
+ <span class="identical2"> </span>
+ identical blocks
+ <span class="corresponding1"> </span>
+ <span class="corresponding2"> </span>
+ corresponding blocks
+ <span style="$WITH_SOURCE_INFO_STYLE"> </span>
+ offset with source information
+ <span style="$WITHOUT_SOURCE_INFO_STYLE"> </span>
+ offset without source information
+ <span style="$ADDITIONAL_SOURCE_INFO_STYLE"> </span>
+ offset with unneeded source information
+</div>
+<table style="position:absolute;top:40px;width:100%;"><tr>
+''');
+
+ void addCell(String content) {
+ sb.write('''
+<td class="cell"><pre>
+''');
+ sb.write(content);
+ sb.write('''
+</pre></td>
+''');
+ }
+
+ List<OutputStructure> structures = [
+ OutputStructure.parse(result1.codeLines),
+ OutputStructure.parse(result2.codeLines)];
+ List<List<CodeLine>> inputLines = [result1.codeLines, result2.codeLines];
+ List<List<HtmlPart>> outputLines = [<HtmlPart>[], <HtmlPart>[]];
+
+ /// Marker to alternate output colors.
+ bool alternating = false;
+
+ /// Enable 'corresponding' background colors for [f].
+ void withMatching(f()) {
+ HtmlPart start = new ConstHtmlPart(
+ '<div class="corresponding${alternating ? '1' : '2'}">');
+ HtmlPart end = new ConstHtmlPart('</div>');
+ alternating = !alternating;
+ outputLines[0].add(start);
+ outputLines[1].add(start);
+ f();
+ outputLines[0].add(end);
+ outputLines[1].add(end);
+ }
+
+ /// Enable 'identical' background colors for [f].
+ void withIdentical(f()) {
+ HtmlPart start = new ConstHtmlPart(
+ '<div class="identical${alternating ? '1' : '2'}">');
+ HtmlPart end = new ConstHtmlPart('</div>');
+ alternating = !alternating;
+ outputLines[0].add(start);
+ outputLines[1].add(start);
+ f();
+ outputLines[0].add(end);
+ outputLines[1].add(end);
+ }
+
+ /// Output code lines in [range] from input number [index], padding the other
+ /// column with empty lines.
+ void handleSkew(int index, Interval range) {
+ int from = range.from;
+ while (from < range.to) {
+ outputLines[1 - index].add(const ConstHtmlPart('\n'));
+ outputLines[index].add(
+ new CodeLineHtmlPart(inputLines[index][from++]));
+ }
+ }
+
+ /// Output code lines of the [indices] from the corresponding inputs.
+ void addBoth(List<int> indices) {
+ outputLines[0].add(new CodeLineHtmlPart(inputLines[0][indices[0]]));
+ outputLines[1].add(new CodeLineHtmlPart(inputLines[1][indices[1]]));
+ }
+
+ /// Output code lines of the [ranges] from the corresponding inputs.
+ void addBothLines(List<Interval> ranges) {
+ Interval range1 = ranges[0];
+ Interval range2 = ranges[1];
+ int offset = 0;
+ while (range1.from + offset < range1.to &&
+ range2.from + offset < range2.to) {
+ addBoth([range1.from + offset, range2.from + offset]);
+ offset++;
+ }
+ if (range1.from + offset < range1.to) {
+ handleSkew(0, new Interval(range1.from + offset, range1.to));
+ }
+ if (range2.from + offset < range2.to) {
+ handleSkew(1, new Interval(range2.from + offset, range2.to));
+ }
+ }
+
+ /// Merge the code lines in [range1] and [range2] of the corresponding input.
+ void addRaw(Interval range1, Interval range2) {
+ match(a, b) => a.code == b.code;
+
+ List<Interval> currentMatchedIntervals;
+
+ void flushMatching() {
+ if (currentMatchedIntervals != null) {
+ withIdentical(() {
+ addBothLines(currentMatchedIntervals);
+ });
+ }
+ currentMatchedIntervals = null;
+ }
+
+ align(
+ inputLines[0],
+ inputLines[1],
+ range1: range1,
+ range2: range2,
+ match: match,
+ handleSkew: (int listIndex, Interval range) {
+ flushMatching();
+ handleSkew(listIndex, range);
+ },
+ handleMatched: (List<int> indices) {
+ if (currentMatchedIntervals == null) {
+ currentMatchedIntervals = [
+ new Interval(indices[0], indices[0] + 1),
+ new Interval(indices[1], indices[1] + 1)];
+ } else {
+ currentMatchedIntervals[0] =
+ new Interval(currentMatchedIntervals[0].from, indices[0] + 1);
+ currentMatchedIntervals[1] =
+ new Interval(currentMatchedIntervals[1].from, indices[1] + 1);
+ }
+ },
+ handleUnmatched: (List<int> indices) {
+ flushMatching();
+ addBoth(indices);
+ });
+
+ flushMatching();
+ }
+
+ /// Output the lines of the library blocks in [childRange] in
+ /// `structures[index]`, padding the other column with empty lines.
+ void addBlock(int index, Interval childRange) {
+ handleSkew(index, structures[index].getChildInterval(childRange));
+ }
+
+ /// Output the members of the [classes] aligned.
+ void addMatchingClasses(List<LibraryClass> classes) {
+ withMatching(() {
+ addBothLines(classes.map((c) => c.header).toList());
+ });
+ align(classes[0].children, classes[1].children,
+ match: (a, b) => a.name == b.name,
+ handleSkew: (int listIndex, Interval childRange) {
+ handleSkew(listIndex,
+ classes[listIndex].getChildInterval(childRange));
+ },
+ handleMatched: (List<int> indices) {
+ List<Interval> intervals = [
+ classes[0].getChild(indices[0]).interval,
+ classes[1].getChild(indices[1]).interval];
+ withMatching(() {
+ addBothLines(intervals);
+ });
+ },
+ handleUnmatched: (List<int> indices) {
+ List<Interval> intervals = [
+ classes[0].getChild(indices[0]).interval,
+ classes[1].getChild(indices[1]).interval];
+ addBothLines(intervals);
+ });
+ withMatching(() {
+ addBothLines(classes.map((c) => c.footer).toList());
+ });
+ }
+
+ /// Output the library blocks in [indices] from the corresponding
+ /// [OutputStructure]s, aligning their content.
+ void addMatchingBlocks(List<int> indices) {
+ List<LibraryBlock> blocks = [
+ structures[0].getChild(indices[0]),
+ structures[1].getChild(indices[1])];
+
+ withMatching(() {
+ addBothLines(blocks.map((b) => b.header).toList());
+ });
+ align(blocks[0].children, blocks[1].children,
+ match: (a, b) => a.name == b.name,
+ handleSkew: (int listIndex, Interval childRange) {
+ handleSkew(listIndex, blocks[listIndex].getChildInterval(childRange));
+ },
+ handleMatched: (List<int> indices) {
+ List<BasicEntity> entities = [
+ blocks[0].getChild(indices[0]),
+ blocks[1].getChild(indices[1])];
+ if (entities.every((e) => e is LibraryClass)) {
+ addMatchingClasses(entities);
+ } else {
+ withMatching(() {
+ addBothLines(entities.map((e) => e.interval).toList());
+ });
+ }
+ },
+ handleUnmatched: (List<int> indices) {
+ List<Interval> intervals = [
+ blocks[0].getChild(indices[0]).interval,
+ blocks[1].getChild(indices[1]).interval];
+ addBothLines(intervals);
+ });
+ withMatching(() {
+ addBothLines(blocks.map((b) => b.footer).toList());
+ });
+ }
+
+ /// Output the lines of the blocks in [indices] from the corresponding
+ /// [OutputStructure]s.
+ void addUnmatchedBlocks(List<int> indices) {
+ List<LibraryBlock> blocks = [
+ structures[0].getChild(indices[0]),
+ structures[1].getChild(indices[1])];
+ addBothLines([blocks[0].interval, blocks[1].interval]);
+ }
+
+
+ addRaw(structures[0].header, structures[1].header);
+
+ align(structures[0].children,
+ structures[1].children,
+ match: (a, b) => a.name == b.name,
+ handleSkew: addBlock,
+ handleMatched: addMatchingBlocks,
+ handleUnmatched: addUnmatchedBlocks);
+
+ addRaw(structures[0].footer, structures[1].footer);
+
+ addCell(htmlPartsToString(outputLines[0], inputLines[0]));
+ addCell(htmlPartsToString(outputLines[1], inputLines[1]));
+
+ sb.write('''</tr><tr>''');
+ addCell(result1.coverage.getCoverageReport());
+ addCell(result2.coverage.getCoverageReport());
+
+ sb.write('''
+</tr></table>
+</body>
+</html>
+''');
+
+ new File(out).writeAsStringSync(sb.toString());
+ print('Diff generated in $out');
+}
+
+/// Align the content of [list1] and [list2].
+///
+/// If provided, [range1] and [range2] aligned the subranges of [list1] and
+/// [list2], otherwise the whole lists are aligned.
+///
+/// If provided, [match] determines the equality between members of [list1] and
+/// [list2], otherwise `==` is used.
+///
+/// [handleSkew] is called when a subrange of one list is not found in the
+/// other.
+///
+/// [handleMatched] is called when two indices match up.
+///
+/// [handleUnmatched] is called when two indices don't match up (none are found
+/// in the other list).
+void align(List list1,
+ List list2,
+ {Interval range1,
+ Interval range2,
+ bool match(a, b),
+ void handleSkew(int listIndex, Interval range),
+ void handleMatched(List<int> indices),
+ void handleUnmatched(List<int> indices)}) {
+ if (match == null) {
+ match = (a, b) => a == b;
+ }
+
+ if (range1 == null) {
+ range1 = new Interval(0, list1.length);
+ }
+ if (range2 == null) {
+ range2 = new Interval(0, list2.length);
+ }
+
+ Interval findInOther(
+ List thisLines, Interval thisRange,
+ List otherLines, Interval otherRange) {
+ for (int index = otherRange.from; index < otherRange.to; index++) {
+ if (match(thisLines[thisRange.from], otherLines[index])) {
+ int offset = 1;
+ while (thisRange.from + offset < thisRange.to &&
+ otherRange.from + offset < otherRange.to &&
+ match(thisLines[thisRange.from + offset],
+ otherLines[otherRange.from + offset])) {
+ offset++;
+ }
+ return new Interval(index, index + offset);
+ }
+ }
+ return null;
+ }
+
+ int start1 = range1.from;
+ int end1 = range1.to;
+ int start2 = range2.from;
+ int end2 = range2.to;
+
+ const int ALIGN1 = -1;
+ const int UNMATCHED = 0;
+ const int ALIGN2 = 1;
+
+ while (start1 < end1 && start2 < end2) {
+ if (match(list1[start1], list2[start2])) {
+ handleMatched([start1++, start2++]);
+ } else {
+ Interval subrange1 = new Interval(start1, end1);
+ Interval subrange2 = new Interval(start2, end2);
+ Interval element2inList1 =
+ findInOther(list1, subrange1, list2, subrange2);
+ Interval element1inList2 =
+ findInOther(list2, subrange2, list1, subrange1);
+ int choice = 0;
+ if (element2inList1 != null) {
+ if (element1inList2 != null) {
+ if (element1inList2.length > 1 && element2inList1.length > 1) {
+ choice =
+ element2inList1.from < element1inList2.from ? ALIGN2 : ALIGN1;
+ } else if (element2inList1.length > 1) {
+ choice = ALIGN2;
+ } else if (element1inList2.length > 1) {
+ choice = ALIGN1;
+ } else {
+ choice =
+ element2inList1.from < element1inList2.from ? ALIGN2 : ALIGN1;
+ }
+ } else {
+ choice = ALIGN2;
+ }
+ } else if (element1inList2 != null) {
+ choice = ALIGN1;
+ }
+ switch (choice) {
+ case ALIGN1:
+ handleSkew(0, new Interval(start1, element1inList2.from));
+ start1 = element1inList2.from;
+ break;
+ case ALIGN2:
+ handleSkew(1, new Interval(start2, element2inList1.from));
+ start2 = element2inList1.from;
+ break;
+ case UNMATCHED:
+ handleUnmatched([start1++, start2++]);
+ break;
+ }
+ }
+ }
+ if (start1 < end1) {
+ handleSkew(0, new Interval(start1, end1));
+ }
+ if (start2 < end2) {
+ handleSkew(1, new Interval(start2, end2));
+ }
+}
+
+// Constants used to identify the subsection of the JavaScript output. These
+// are specifically for the unminified full_emitter output.
+const String HEAD = ' var dart = [';
+const String TAIL = ' }], ';
+const String END = ' setupProgram(dart';
+
+final RegExp TOP_LEVEL_VALUE = new RegExp(r'^ (".+?"):');
+final RegExp TOP_LEVEL_FUNCTION =
+ new RegExp(r'^ ([a-zA-Z0-9_$]+): \[?function');
+final RegExp TOP_LEVEL_CLASS = new RegExp(r'^ ([a-zA-Z0-9_$]+): \[?\{');
+
+final RegExp MEMBER_VALUE = new RegExp(r'^ (".+?"):');
+final RegExp MEMBER_FUNCTION =
+ new RegExp(r'^ ([a-zA-Z0-9_$]+): \[?function');
+final RegExp MEMBER_OBJECT = new RegExp(r'^ ([a-zA-Z0-9_$]+): \[?\{');
+
+/// Subrange of the JavaScript output.
+abstract class OutputEntity {
+ Interval get interval;
+ Interval get header;
+ Interval get footer;
+
+ List<OutputEntity> get children;
+
+ Interval getChildInterval(Interval childIndex) {
+ return new Interval(
+ children[childIndex.from].interval.from,
+ children[childIndex.to - 1].interval.to);
+
+ }
+
+ OutputEntity getChild(int index) {
+ return children[index];
+ }
+}
+
+/// The whole JavaScript output.
+class OutputStructure extends OutputEntity {
+ final List<CodeLine> lines;
+ final int headerEnd;
+ final int footerStart;
+ final List<LibraryBlock> children;
+
+ OutputStructure(
+ this.lines,
+ this.headerEnd,
+ this.footerStart,
+ this.children);
+
+ Interval get interval => new Interval(0, lines.length);
+
+ Interval get header => new Interval(0, headerEnd);
+
+ Interval get footer => new Interval(footerStart, lines.length);
+
+ /// Compute the structure of the JavaScript [lines].
+ static OutputStructure parse(List<CodeLine> lines) {
+
+ int findHeaderStart(List<CodeLine> lines) {
+ int index = 0;
+ for (CodeLine line in lines) {
+ if (line.code.startsWith(HEAD)) {
+ return index;
+ }
+ index++;
+ }
+ return lines.length;
+ }
+
+ int findHeaderEnd(int start, List<CodeLine> lines) {
+ int index = start;
+ for (CodeLine line in lines.skip(start)) {
+ if (line.code.startsWith(END)) {
+ return index;
+ }
+ index++;
+ }
+ return lines.length;
+ }
+
+ String readHeader(CodeLine line) {
+ String code = line.code;
+ String ssaLineHeader;
+ if (code.startsWith(HEAD)) {
+ return code.substring(HEAD.length);
+ } else if (code.startsWith(TAIL)) {
+ return code.substring(TAIL.length);
+ }
+ return null;
+ }
+
+ List<LibraryBlock> computeHeaderMap(
+ List<CodeLine> lines, int start, int end) {
+ List<LibraryBlock> libraryBlocks = <LibraryBlock>[];
+ LibraryBlock current;
+ for (int index = start; index < end; index++) {
+ String header = readHeader(lines[index]);
+ if (header != null) {
+ if (current != null) {
+ current.to = index;
+ }
+ libraryBlocks.add(current = new LibraryBlock(header, index));
+ }
+ }
+ if (current != null) {
+ current.to = end;
+ }
+ return libraryBlocks;
+ }
+
+ int headerEnd = findHeaderStart(lines);
+ int footerStart = findHeaderEnd(headerEnd, lines);
+ List<LibraryBlock> libraryBlocks =
+ computeHeaderMap(lines, headerEnd, footerStart);
+ for (LibraryBlock block in libraryBlocks) {
+ block.preprocess(lines);
+ }
+
+ return new OutputStructure(
+ lines, headerEnd, footerStart, libraryBlocks);
+ }
+}
+
+abstract class AbstractEntity extends OutputEntity {
+ final String name;
+ final int from;
+ int to;
+
+ AbstractEntity(this.name, this.from);
+
+ Interval get interval => new Interval(from, to);
+}
+
+/// A block defining the content of a Dart library.
+class LibraryBlock extends AbstractEntity {
+ List<BasicEntity> children = <BasicEntity>[];
+ int get headerEnd => from + 2;
+ int get footerStart => to - 1;
+
+ LibraryBlock(String name, int from) : super(name, from);
+
+ Interval get header => new Interval(from, headerEnd);
+
+ Interval get footer => new Interval(footerStart, to);
+
+ void preprocess(List<CodeLine> lines) {
+ int index = headerEnd;
+ BasicEntity current;
+ while (index < footerStart) {
+ String line = lines[index].code;
+ BasicEntity next;
+ Match matchFunction = TOP_LEVEL_FUNCTION.firstMatch(line);
+ if (matchFunction != null) {
+ next = new BasicEntity(matchFunction.group(1), index);
+ } else {
+ Match matchClass = TOP_LEVEL_CLASS.firstMatch(line);
+ if (matchClass != null) {
+ next = new LibraryClass(matchClass.group(1), index);
+ } else {
+ Match matchValue = TOP_LEVEL_VALUE.firstMatch(line);
+ if (matchValue != null) {
+ next = new BasicEntity(matchValue.group(1), index);
+ }
+ }
+ }
+ if (next != null) {
+ if (current != null) {
+ current.to = index;
+ }
+ children.add(current = next);
+ } else if (index == headerEnd) {
+ throw 'Failed to match first library block line:\n$line';
+ }
+
+ index++;
+ }
+ if (current != null) {
+ current.to = footerStart;
+ }
+
+ for (BasicEntity entity in children) {
+ entity.preprocess(lines);
+ }
+ }
+}
+
+/// A simple member of a library or class.
+class BasicEntity extends AbstractEntity {
+ BasicEntity(String name, int from) : super(name, from);
+
+ Interval get header => new Interval(from, to);
+
+ Interval get footer => new Interval(to, to);
+
+ List<OutputEntity> get children => const <OutputEntity>[];
+
+ void preprocess(List<CodeLine> lines) {}
+}
+
+/// A block defining a Dart class.
+class LibraryClass extends BasicEntity {
+ List<BasicEntity> children = <BasicEntity>[];
+ int get headerEnd => from + 1;
+ int get footerStart => to - 1;
+
+ LibraryClass(String name, int from) : super(name, from);
+
+ Interval get header => new Interval(from, headerEnd);
+
+ Interval get footer => new Interval(footerStart, to);
+
+ void preprocess(List<CodeLine> lines) {
+ int index = headerEnd;
+ BasicEntity current;
+ while (index < footerStart) {
+ String line = lines[index].code;
+ BasicEntity next;
+ Match matchFunction = MEMBER_FUNCTION.firstMatch(line);
+ if (matchFunction != null) {
+ next = new BasicEntity(matchFunction.group(1), index);
+ } else {
+ Match matchClass = MEMBER_OBJECT.firstMatch(line);
+ if (matchClass != null) {
+ next = new BasicEntity(matchClass.group(1), index);
+ } else {
+ Match matchValue = MEMBER_VALUE.firstMatch(line);
+ if (matchValue != null) {
+ next = new BasicEntity(matchValue.group(1), index);
+ }
+ }
+ }
+ if (next != null) {
+ if (current != null) {
+ current.to = index;
+ }
+ children.add(current = next);
+ } else if (index == headerEnd) {
+ throw 'Failed to match first library block line:\n$line';
+ }
+
+ index++;
+ }
+ if (current != null) {
+ current.to = footerStart;
+ }
+ }
+}
+
+class Interval {
+ final int from;
+ final int to;
+
+ const Interval(this.from, this.to);
+
+ int get length => to - from;
+}
+
+class HtmlPart {
+ void printHtmlOn(StringBuffer buffer) {}
+}
+
+class ConstHtmlPart implements HtmlPart {
+ final String html;
+
+ const ConstHtmlPart(this.html);
+
+ @override
+ void printHtmlOn(StringBuffer buffer) {
+ buffer.write(html);
+ }
+}
+
+class CodeLineHtmlPart implements HtmlPart {
+ final CodeLine line;
+
+ CodeLineHtmlPart(this.line);
+
+ @override
+ void printHtmlOn(StringBuffer buffer, [int lineNoWidth]) {
+ line.printHtmlOn(buffer, lineNoWidth);
+ }
+}
+
+/// Convert [parts] to an HTML string while checking invariants for [lines].
+String htmlPartsToString(List<HtmlPart> parts, List<CodeLine> lines) {
+ int lineNoWidth;
+ if (lines.isNotEmpty) {
+ lineNoWidth = '${lines.last.lineNo + 1}'.length;
+ }
+ StringBuffer buffer = new StringBuffer();
+ int expectedLineNo = 0;
+ for (HtmlPart part in parts) {
+ if (part is CodeLineHtmlPart) {
+ if (part.line.lineNo != expectedLineNo) {
+ print('Expected line no $expectedLineNo, found ${part.line.lineNo}');
+ if (part.line.lineNo < expectedLineNo) {
+ print('Duplicate lines:');
+ int index = part.line.lineNo;
+ while (index <= expectedLineNo) {
+ print(lines[index++].code);
+ }
+ } else {
+ print('Missing lines:');
+ int index = expectedLineNo;
+ while (index <= part.line.lineNo) {
+ print(lines[index++].code);
+ }
+ }
+ expectedLineNo = part.line.lineNo;
+ }
+ expectedLineNo++;
+ part.printHtmlOn(buffer, lineNoWidth);
+ } else {
+ part.printHtmlOn(buffer);
+ }
+ }
+ return buffer.toString();
+}
+
+class CodeLinesResult {
+ final List<CodeLine> codeLines;
+ final Coverage coverage;
+
+ CodeLinesResult(this.codeLines, this.coverage);
+}
+
+/// Compute [CodeLine]s and [Coverage] for [filename] using the given [options].
+Future<CodeLinesResult> computeCodeLines(
+ List<String> options,
+ String filename) async {
+ SourceMapProcessor processor = new SourceMapProcessor(filename);
+ List<SourceMapInfo> sourceMapInfoList =
+ await processor.process(options, perElement: false);
+
+ const int WITH_SOURCE_INFO = 0;
+ const int WITHOUT_SOURCE_INFO = 1;
+ const int ADDITIONAL_SOURCE_INFO = 2;
+
+ for (SourceMapInfo info in sourceMapInfoList) {
+ if (info.element != null) continue;
+
+ List<CodeLine> codeLines;
+ Coverage coverage = new Coverage();
+ List<Annotation> annotations = <Annotation>[];
+ String code = info.code;
+ TraceGraph graph = createTraceGraph(info, coverage);
+ Set<js.Node> mappedNodes = new Set<js.Node>();
+ for (TraceStep step in graph.steps) {
+ int offset;
+ if (options.contains(USE_NEW_SOURCE_INFO)) {
+ offset = step.offset.subexpressionOffset;
+ } else {
+ offset = info.jsCodePositions[step.node].startPosition;
+ }
+ if (offset != null) {
+ int id = step.sourceLocation != null
+ ? WITH_SOURCE_INFO : WITHOUT_SOURCE_INFO;
+ annotations.add(
+ new Annotation(id, offset, null));
+ }
+ }
+ if (!options.contains(USE_NEW_SOURCE_INFO)) {
+ for (js.Node node in info.nodeMap.nodes) {
+ if (!mappedNodes.contains(node)) {
+ int offset = info.jsCodePositions[node].startPosition;
+ annotations.add(
+ new Annotation(ADDITIONAL_SOURCE_INFO, offset, null));
+ }
+ }
+ }
+ codeLines = convertAnnotatedCodeToCodeLines(
+ code,
+ annotations,
+ colorScheme: new CustomColorScheme(
+ single: (int id) {
+ if (id == WITH_SOURCE_INFO) {
+ return WITH_SOURCE_INFO_STYLE;
+ } else if (id == ADDITIONAL_SOURCE_INFO) {
+ return ADDITIONAL_SOURCE_INFO_STYLE;
+ }
+ return WITHOUT_SOURCE_INFO_STYLE;
+ },
+ multi: (List ids) {
+ if (ids.contains(WITH_SOURCE_INFO)) {
+ return WITH_SOURCE_INFO_STYLE;
+ } else if (ids.contains(ADDITIONAL_SOURCE_INFO)) {
+ return ADDITIONAL_SOURCE_INFO_STYLE;
+ }
+ return WITHOUT_SOURCE_INFO_STYLE;
+ }
+ ));
+ return new CodeLinesResult(codeLines, coverage);
+ }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/js_tracer.dart b/tests/compiler/dart2js/sourcemaps/js_tracer.dart
new file mode 100644
index 0000000..1aa40fe
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/js_tracer.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2016, 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 sourcemap.js_tracer;
+
+import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/io/position_information.dart';
+import 'package:compiler/src/js/js.dart' as js;
+import 'sourcemap_helper.dart';
+import 'trace_graph.dart';
+
+/// Create a [TraceGraph] for [info] registering usage in [coverage].
+TraceGraph createTraceGraph(SourceMapInfo info, Coverage coverage) {
+ TraceGraph graph = new TraceGraph();
+ TraceListener listener = new StepTraceListener(graph);
+ CodePositionMap codePositions =
+ new CodePositionCoverage(info.jsCodePositions, coverage);
+ JavaScriptTracer tracer = new JavaScriptTracer(
+ codePositions, [new CoverageListener(coverage), listener]);
+ info.node.accept(tracer);
+ return graph;
+}
+
+class StepTraceListener extends TraceListener {
+ Map<js.Node, TraceStep> steppableMap = <js.Node, TraceStep>{};
+ final TraceGraph graph;
+
+ StepTraceListener(this.graph);
+
+ @override
+ void onStep(js.Node node, Offset offset, StepKind kind) {
+ SourceInformation sourceInformation = node.sourceInformation;
+ SourcePositionKind sourcePositionKind = SourcePositionKind.START;
+ List text = [node];
+ switch (kind) {
+ case StepKind.FUN:
+ sourcePositionKind = SourcePositionKind.INNER;
+ text = ['<exit>'];
+ break;
+ case StepKind.CALL:
+ CallPosition callPosition =
+ CallPosition.getSemanticPositionForCall(node);
+ sourcePositionKind = callPosition.sourcePositionKind;
+ break;
+ case StepKind.NEW:
+ case StepKind.RETURN:
+ case StepKind.BREAK:
+ case StepKind.CONTINUE:
+ case StepKind.THROW:
+ case StepKind.EXPRESSION_STATEMENT:
+ break;
+ case StepKind.IF_CONDITION:
+ js.If ifNode = node;
+ text = ['if(', ifNode.condition, ') ...'];
+ break;
+ case StepKind.FOR_INITIALIZER:
+ js.For forNode = node;
+ text = ['for(', forNode.init, '; ...) ...'];
+ break;
+ case StepKind.FOR_CONDITION:
+ js.For forNode = node;
+ text = ['for(...;', forNode.condition, '; ...) ...'];
+ break;
+ case StepKind.FOR_UPDATE:
+ js.For forNode = node;
+ text = ['for(...; ...', forNode.update, ') ...'];
+ break;
+ case StepKind.WHILE_CONDITION:
+ js.While whileNode = node;
+ text = ['while(', whileNode.condition, ') ...'];
+ break;
+ case StepKind.DO_CONDITION:
+ js.Do doNode = node;
+ text = ['do {... } (', doNode.condition, ')'];
+ break;
+ case StepKind.SWITCH_EXPRESSION:
+ js.Switch switchNode = node;
+ text = ['switch(', switchNode.key, ') ...'];
+ break;
+
+ }
+ createTraceStep(
+ node,
+ offset: offset,
+ sourceLocation: getSourceLocation(
+ node.sourceInformation, sourcePositionKind),
+ text: text);
+ }
+
+ void createTraceStep(
+ js.Node node,
+ {Offset offset,
+ List text,
+ String note,
+ SourceLocation sourceLocation}) {
+ int id = steppableMap.length;
+
+ if (text == null) {
+ text = [node];
+ }
+
+ TraceStep step = new TraceStep(
+ id, node,
+ offset,
+ text, sourceLocation);
+ graph.addStep(step);
+
+ steppableMap[node] = step;
+ }
+
+
+ void pushBranch(BranchKind kind, [value]) {
+ var branch;
+ switch (kind) {
+ case BranchKind.CONDITION:
+ branch = value ? 't' : 'f';
+ break;
+ case BranchKind.LOOP:
+ branch = 'l';
+ break;
+ case BranchKind.CATCH:
+ branch = 'c';
+ break;
+ case BranchKind.FINALLY:
+ branch = 'F';
+ break;
+ case BranchKind.CASE:
+ branch = '$value';
+ break;
+ }
+ graph.pushBranch(branch);
+ }
+
+ void popBranch() {
+ graph.popBranch();
+ }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
index 9cb53e5..123cbe2 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
@@ -11,8 +11,10 @@
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/helpers/helpers.dart';
import 'package:compiler/src/filenames.dart';
+import 'package:compiler/src/io/code_output.dart';
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/io/position_information.dart';
import 'package:compiler/src/js/js.dart' as js;
import 'package:compiler/src/js/js_debug.dart';
import 'package:compiler/src/js/js_source_mapping.dart';
@@ -21,15 +23,51 @@
import '../memory_compiler.dart';
import '../output_collector.dart';
+class SourceFileSink implements EventSink<String> {
+ final String filename;
+ StringBuffer sb = new StringBuffer();
+ SourceFile sourceFile;
+
+ SourceFileSink(this.filename);
+
+ @override
+ void add(String event) {
+ sb.write(event);
+ }
+
+ @override
+ void addError(errorEvent, [StackTrace stackTrace]) {
+ // Ignore.
+ }
+
+ @override
+ void close() {
+ sourceFile = new StringSourceFile.fromName(filename, sb.toString());
+ }
+}
+
class OutputProvider implements CompilerOutput {
- BufferedEventSink jsMapOutput;
+ Map<Uri, SourceFileSink> outputMap = <Uri, SourceFileSink>{};
+
+ SourceFile getSourceFile(Uri uri) {
+ SourceFileSink sink = outputMap[uri];
+ if (sink != null) {
+ return sink.sourceFile;
+ }
+ return null;
+ }
+
+ SourceFileSink createSourceFileSink(String name, String extension) {
+ String filename = '$name.$extension';
+ SourceFileSink sink = new SourceFileSink(filename);
+ Uri uri = Uri.parse(filename);
+ outputMap[uri] = sink;
+ return sink;
+ }
@override
EventSink<String> createEventSink(String name, String extension) {
- if (extension == 'js.map') {
- return jsMapOutput = new BufferedEventSink();
- }
- return new NullSink('$name.$extension');
+ return createSourceFileSink(name, extension);
}
}
@@ -42,11 +80,8 @@
@override
EventSink<String> createEventSink(String name, String extension) {
EventSink<String> output = outputProvider(name, extension);
- if (extension == 'js.map') {
- output = new CloningEventSink(
- [output, jsMapOutput = new BufferedEventSink()]);
- }
- return output;
+ return new CloningEventSink(
+ [output, createSourceFileSink(name, extension)]);
}
}
@@ -56,17 +91,23 @@
class ProviderSourceFileManager implements SourceFileManager {
final SourceFileProvider sourceFileProvider;
+ final OutputProvider outputProvider;
- ProviderSourceFileManager(this.sourceFileProvider);
+ ProviderSourceFileManager(this.sourceFileProvider, this.outputProvider);
@override
SourceFile getSourceFile(uri) {
- return sourceFileProvider.getSourceFile(uri);
+ SourceFile sourceFile = sourceFileProvider.getSourceFile(uri);
+ if (sourceFile == null) {
+ sourceFile = outputProvider.getSourceFile(uri);
+ }
+ return sourceFile;
}
}
class RecordingPrintingContext extends LenientPrintingContext {
CodePositionListener listener;
+ Map<js.Node, CodePosition> codePositions = <js.Node, CodePosition>{};
RecordingPrintingContext(this.listener);
@@ -75,11 +116,163 @@
int startPosition,
int endPosition,
int closingPosition) {
+ codePositions[node] =
+ new CodePosition(startPosition, endPosition, closingPosition);
listener.onPositions(
node, startPosition, endPosition, closingPosition);
}
}
+/// A [SourceMapper] that records the source locations on each node.
+class RecordingSourceMapper implements SourceMapper {
+ final SourceMapper sourceMapper;
+ final _LocationRecorder nodeToSourceLocationsMap;
+
+ RecordingSourceMapper(this.sourceMapper, this.nodeToSourceLocationsMap);
+
+ @override
+ void register(js.Node node, int codeOffset, SourceLocation sourceLocation) {
+ nodeToSourceLocationsMap.register(node, codeOffset, sourceLocation);
+ sourceMapper.register(node, codeOffset, sourceLocation);
+ }
+}
+
+/// A wrapper of [SourceInformationProcessor] that records source locations and
+/// code positions.
+class RecordingSourceInformationProcessor
+ implements SourceInformationProcessor {
+ final RecordingSourceInformationStrategy wrapper;
+ final SourceInformationProcessor processor;
+ final CodePositionRecorder codePositions;
+ final LocationMap nodeToSourceLocationsMap;
+
+ RecordingSourceInformationProcessor(
+ this.wrapper,
+ this.processor,
+ this.codePositions,
+ this.nodeToSourceLocationsMap);
+
+ @override
+ void onPositions(js.Node node,
+ int startPosition,
+ int endPosition,
+ int closingPosition) {
+ codePositions.registerPositions(
+ node, startPosition, endPosition, closingPosition);
+ processor.onPositions(node, startPosition, endPosition, closingPosition);
+ }
+
+ @override
+ void process(js.Node node, BufferedCodeOutput code) {
+ processor.process(node, code);
+ wrapper.registerProcess(
+ node, code, codePositions, nodeToSourceLocationsMap);
+ }
+}
+
+/// Information recording for a use of [SourceInformationProcessor].
+class RecordedSourceInformationProcess {
+ final js.Node root;
+ final String code;
+ final CodePositionRecorder codePositions;
+ final LocationMap nodeToSourceLocationsMap;
+
+ RecordedSourceInformationProcess(
+ this.root,
+ this.code,
+ this.codePositions,
+ this.nodeToSourceLocationsMap);
+}
+
+
+/// A wrapper of [JavaScriptSourceInformationStrategy] that records
+/// [RecordedSourceInformationProcess].
+class RecordingSourceInformationStrategy
+ extends JavaScriptSourceInformationStrategy {
+ final JavaScriptSourceInformationStrategy strategy;
+ final Map<RecordedSourceInformationProcess, js.Node> processMap =
+ <RecordedSourceInformationProcess, js.Node>{};
+ final Map<js.Node, RecordedSourceInformationProcess> nodeMap =
+ <js.Node, RecordedSourceInformationProcess>{};
+
+ RecordingSourceInformationStrategy(this.strategy);
+
+ @override
+ SourceInformationBuilder createBuilderForContext(AstElement element) {
+ return strategy.createBuilderForContext(element);
+ }
+
+ @override
+ SourceInformationProcessor createProcessor(SourceMapper sourceMapper) {
+ LocationMap nodeToSourceLocationsMap =
+ new _LocationRecorder();
+ CodePositionRecorder codePositions = new CodePositionRecorder();
+ return new RecordingSourceInformationProcessor(
+ this,
+ strategy.createProcessor(new RecordingSourceMapper(
+ sourceMapper, nodeToSourceLocationsMap)),
+ codePositions, nodeToSourceLocationsMap);
+ }
+
+ void registerProcess(js.Node root,
+ BufferedCodeOutput code,
+ CodePositionRecorder codePositions,
+ LocationMap nodeToSourceLocationsMap) {
+ RecordedSourceInformationProcess subProcess =
+ new RecordedSourceInformationProcess(
+ root, code.getText(), codePositions, nodeToSourceLocationsMap);
+ processMap[subProcess] = root;
+ }
+
+ RecordedSourceInformationProcess subProcessForNode(js.Node node) {
+ return nodeMap.putIfAbsent(node, () {
+ for (RecordedSourceInformationProcess subProcess in processMap.keys) {
+ js.Node root = processMap[subProcess];
+ FindVisitor visitor = new FindVisitor(node);
+ root.accept(visitor);
+ if (visitor.found) {
+ return new RecordedSourceInformationProcess(
+ node,
+ subProcess.code,
+ subProcess.codePositions,
+ new _FilteredLocationMap(
+ visitor.nodes, subProcess.nodeToSourceLocationsMap));
+ }
+ return null;
+ }
+ });
+ }
+}
+
+/// Visitor that collects all nodes that are within a function. Used by the
+/// [RecordingSourceInformationStrategy] to filter what is recorded in a
+/// [RecordedSourceInformationProcess].
+class FindVisitor extends js.BaseVisitor {
+ final js.Node soughtNode;
+ bool found = false;
+ bool add = false;
+ final Set<js.Node> nodes = new Set<js.Node>();
+
+ FindVisitor(this.soughtNode);
+
+ visitNode(js.Node node) {
+ if (node == soughtNode) {
+ found = true;
+ add = true;
+ }
+ if (add) {
+ nodes.add(node);
+ }
+ node.visitChildren(this);
+ if (node == soughtNode) {
+ add = false;
+ }
+ }
+}
+
+const String USE_NEW_SOURCE_INFO = '--use-new-source-info';
+const String DISABLE_INLINING = '--disable-inlining';
+
/// Processor that computes [SourceMapInfo] for the JavaScript compiled for a
/// given Dart file.
class SourceMapProcessor {
@@ -112,11 +305,12 @@
/// Computes the [SourceMapInfo] for the compiled elements.
Future<List<SourceMapInfo>> process(
List<String> options,
- {bool verbose: true}) async {
+ {bool verbose: true,
+ bool perElement: true}) async {
OutputProvider outputProvider = outputToFile
- ? new OutputProvider()
- : new CloningOutputProvider(targetUri, sourceMapFileUri);
- if (options.contains('--use-new-source-info')) {
+ ? new CloningOutputProvider(targetUri, sourceMapFileUri)
+ : new OutputProvider();
+ if (options.contains(USE_NEW_SOURCE_INFO)) {
if (verbose) print('Using the new source information system.');
useNewSourceInfo = true;
}
@@ -125,7 +319,7 @@
// TODO(johnniwinther): Use [verbose] to avoid showing diagnostics.
options: ['--out=$targetUri', '--source-map=$sourceMapFileUri']
..addAll(options));
- if (options.contains('--disable-inlining')) {
+ if (options.contains(DISABLE_INLINING)) {
if (verbose) print('Inlining disabled');
compiler.disableInlining = true;
}
@@ -133,30 +327,58 @@
JavaScriptBackend backend = compiler.backend;
var handler = compiler.handler;
SourceFileProvider sourceFileProvider = handler.provider;
- sourceFileManager = new ProviderSourceFileManager(sourceFileProvider);
+ sourceFileManager = new ProviderSourceFileManager(
+ sourceFileProvider,
+ outputProvider);
+ RecordingSourceInformationStrategy strategy =
+ new RecordingSourceInformationStrategy(backend.sourceInformationStrategy);
+ backend.sourceInformationStrategy = strategy;
await compiler.run(inputUri);
List<SourceMapInfo> infoList = <SourceMapInfo>[];
- backend.generatedCode.forEach((Element element, js.Expression node) {
- js.JavaScriptPrintingOptions options =
- new js.JavaScriptPrintingOptions();
- JavaScriptSourceInformationStrategy sourceInformationStrategy =
- compiler.backend.sourceInformationStrategy;
- NodeToSourceLocationsMap nodeMap = new NodeToSourceLocationsMap();
- SourceInformationProcessor sourceInformationProcessor =
- sourceInformationStrategy.createProcessor(nodeMap);
- RecordingPrintingContext printingContext =
- new RecordingPrintingContext(sourceInformationProcessor);
- new js.Printer(options, printingContext).visit(node);
- sourceInformationProcessor.process(node);
-
- String code = printingContext.getText();
+ if (perElement) {
+ backend.generatedCode.forEach((Element element, js.Expression node) {
+ RecordedSourceInformationProcess subProcess =
+ strategy.subProcessForNode(node);
+ if (subProcess == null) {
+ // TODO(johnniwinther): Find out when this is happening and if it
+ // is benign. (Known to happen for `bool#fromString`)
+ print('No subProcess found for $element');
+ return;
+ }
+ LocationMap nodeMap = subProcess.nodeToSourceLocationsMap;
+ String code = subProcess.code;
+ CodePositionRecorder codePositions = subProcess.codePositions;
+ CodePointComputer visitor =
+ new CodePointComputer(sourceFileManager, code, nodeMap);
+ visitor.apply(node);
+ List<CodePoint> codePoints = visitor.codePoints;
+ infoList.add(new SourceMapInfo(
+ element, code, node,
+ codePoints,
+ codePositions/*strategy.codePositions*/,
+ nodeMap));
+ });
+ } else {
+ // TODO(johnniwinther): Supported multiple output units.
+ RecordedSourceInformationProcess process = strategy.processMap.keys.first;
+ js.Node node = strategy.processMap[process];
+ String code;
+ LocationMap nodeMap;
+ CodePositionRecorder codePositions;
+ nodeMap = process.nodeToSourceLocationsMap;
+ code = process.code;
+ codePositions = process.codePositions;
CodePointComputer visitor =
new CodePointComputer(sourceFileManager, code, nodeMap);
visitor.apply(node);
List<CodePoint> codePoints = visitor.codePoints;
- infoList.add(new SourceMapInfo(element, code, node, codePoints, nodeMap));
- });
+ infoList.add(new SourceMapInfo(
+ null, code, node,
+ codePoints,
+ codePositions,
+ nodeMap));
+ }
return infoList;
}
@@ -167,19 +389,43 @@
final String name;
final Element element;
final String code;
- final js.Expression node;
+ final js.Node node;
final List<CodePoint> codePoints;
- final NodeToSourceLocationsMap nodeMap;
+ final CodePositionMap jsCodePositions;
+ final LocationMap nodeMap;
SourceMapInfo(
- Element element, this.code, this.node, this.codePoints, this.nodeMap)
- : this.name = computeElementNameForSourceMaps(element),
+ Element element,
+ this.code,
+ this.node,
+ this.codePoints,
+ this.jsCodePositions,
+ this.nodeMap)
+ : this.name =
+ element != null ? computeElementNameForSourceMaps(element) : '',
this.element = element;
+
+ String toString() {
+ return '$name:$element';
+ }
}
/// Collection of JavaScript nodes with their source mapped target offsets
/// and source locations.
-class NodeToSourceLocationsMap implements SourceMapper {
+abstract class LocationMap {
+ Iterable<js.Node> get nodes;
+
+ Map<int, List<SourceLocation>> operator[] (js.Node node);
+
+ factory LocationMap.recorder() = _LocationRecorder;
+
+ factory LocationMap.filter(Set<js.Node> nodes, LocationMap map) =
+ _FilteredLocationMap;
+
+}
+
+class _LocationRecorder
+ implements SourceMapper, LocationMap {
final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {};
@override
@@ -196,11 +442,25 @@
}
}
+class _FilteredLocationMap implements LocationMap {
+ final Set<js.Node> _nodes;
+ final LocationMap map;
+
+ _FilteredLocationMap(this._nodes, this.map);
+
+ Iterable<js.Node> get nodes => map.nodes.where((n) => _nodes.contains(n));
+
+ Map<int, List<SourceLocation>> operator[] (js.Node node) {
+ return map[node];
+ }
+}
+
+
/// Visitor that computes the [CodePoint]s for source mapping locations.
class CodePointComputer extends js.BaseVisitor {
final SourceFileManager sourceFileManager;
final String code;
- final NodeToSourceLocationsMap nodeMap;
+ final LocationMap nodeMap;
List<CodePoint> codePoints = [];
CodePointComputer(this.sourceFileManager, this.code, this.nodeMap);
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
index 4227fee..52e871d 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
@@ -8,6 +8,7 @@
library sourcemap.html.helper;
import 'dart:convert';
+import 'dart:math' as Math;
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/io/source_information.dart';
@@ -40,9 +41,14 @@
return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})';
}
-/// Return the html for the [index] line number.
-String lineNumber(int index) {
- return '<span class="lineNumber">${index + 1} </span>';
+/// Return the html for the [index] line number. If [width] is provided, shorter
+/// line numbers will be prefixed with spaces to match the width.
+String lineNumber(int index, [int width]) {
+ String text = '${index + 1}';
+ if (width != null && text.length < width) {
+ text = (' ' * (width - text.length)) + text;
+ }
+ return '<span class="lineNumber">$text </span>';
}
/// Return the html escaped [text].
@@ -59,6 +65,10 @@
SourceMapHtmlInfo(this.sourceMapInfo,
this.codeProcessor,
this.sourceLocationCollection);
+
+ String toString() {
+ return sourceMapInfo.toString();
+ }
}
/// A collection of source locations.
@@ -84,16 +94,98 @@
}
}
+abstract class CssColorScheme {
+ String singleLocationToCssColor(var id);
+
+ String multiLocationToCssColor(List ids);
+
+ bool get showLocationAsSpan;
+}
+
+class CustomColorScheme implements CssColorScheme {
+ final bool showLocationAsSpan;
+ final Function single;
+ final Function multi;
+
+ CustomColorScheme(
+ {this.showLocationAsSpan: false,
+ String this.single(var id),
+ String this.multi(List ids)});
+
+ String singleLocationToCssColor(var id) => single != null ? single(id) : null;
+
+ String multiLocationToCssColor(List ids) => multi != null ? multi(ids) : null;
+}
+
+class PatternCssColorScheme implements CssColorScheme {
+ const PatternCssColorScheme();
+
+ bool get showLocationAsSpan => true;
+
+ String singleLocationToCssColor(int index) {
+ return "background:${toPattern(index)};";
+ }
+
+ String multiLocationToCssColor(List<int> indices) {
+
+ StringBuffer sb = new StringBuffer();
+ double delta = 100.0 / (indices.length);
+ double position = 0.0;
+
+ void addColor(String color) {
+ sb.write(', ${color} ${position.toInt()}%');
+ position += delta;
+ sb.write(', ${color} ${position.toInt()}%');
+ }
+
+ for (int index in indices) {
+ addColor('${toColorCss(index)}');
+ }
+ return 'background: linear-gradient(to right${sb}); '
+ 'background-size: 10px 10px;';
+ }
+}
+
+class SingleColorScheme implements CssColorScheme {
+ const SingleColorScheme();
+
+ bool get showLocationAsSpan => false;
+
+ String singleLocationToCssColor(int index) {
+ return "background:${toColorCss(index)};";
+ }
+
+ String multiLocationToCssColor(List<int> indices) {
+ StringBuffer sb = new StringBuffer();
+ double delta = 100.0 / (indices.length);
+ double position = 0.0;
+
+ void addColor(String color) {
+ sb.write(', ${color} ${position.toInt()}%');
+ position += delta;
+ sb.write(', ${color} ${position.toInt()}%');
+ }
+
+ for (int index in indices) {
+ addColor('${toColorCss(index)}');
+ }
+ return 'background: linear-gradient(to bottom${sb}); '
+ 'background-size: 10px 3px;';
+ }
+}
+
/// Processor that computes the HTML representation of a block of JavaScript
/// code and collects the source locations mapped in the code.
class CodeProcessor {
int lineIndex = 0;
- final String onclick;
+ final String name;
int currentJsSourceOffset = 0;
final SourceLocationCollection collection;
final Map<int, List<SourceLocation>> codeLocations = {};
+ final CssColorScheme colorScheme;
- CodeProcessor(this.onclick, this.collection);
+ CodeProcessor(this.name, this.collection,
+ {this.colorScheme: const PatternCssColorScheme()});
void addSourceLocation(int targetOffset, SourceLocation sourceLocation) {
codeLocations.putIfAbsent(targetOffset, () => []).add(sourceLocation);
@@ -101,102 +193,275 @@
}
String convertToHtml(String text) {
- StringBuffer htmlBuffer = new StringBuffer();
- int offset = 0;
- int lineIndex = 0;
- bool pendingSourceLocationsEnd = false;
- htmlBuffer.write(lineNumber(lineIndex));
- SourceLocation currentLocation;
-
- void endCurrentLocation() {
- if (currentLocation != null) {
- htmlBuffer.write('</a>');
- }
- currentLocation = null;
- }
-
- void addSubstring(int until) {
- if (until <= offset) return;
-
- String substring = text.substring(offset, until);
- offset = until;
- bool first = true;
- for (String line in substring.split('\n')) {
- if (!first) {
- endCurrentLocation();
- htmlBuffer.write('\n');
- lineIndex++;
- htmlBuffer.write(lineNumber(lineIndex));
+ List<Annotation> annotations = <Annotation>[];
+ codeLocations.forEach((int codeOffset, List<SourceLocation> locations) {
+ for (SourceLocation location in locations) {
+ if (location != null) {
+ annotations.add(new Annotation(
+ collection.getIndex(location),
+ codeOffset,
+ location.shortText));
}
- htmlBuffer.write(escape(line));
- first = false;
}
- }
-
- void insertSourceLocations(List<SourceLocation> lastSourceLocations) {
- endCurrentLocation();
-
- String color;
- int index;
- String title;
- if (lastSourceLocations.length == 1) {
- SourceLocation sourceLocation = lastSourceLocations.single;
- if (sourceLocation != null) {
- index = collection.getIndex(sourceLocation);
- color = "background:${toPattern(index)};";
- title = sourceLocation.shortText;
- currentLocation = sourceLocation;
- }
- } else {
-
- index = collection.getIndex(lastSourceLocations.first);
- StringBuffer sb = new StringBuffer();
- double delta = 100.0 / (lastSourceLocations.length);
- double position = 0.0;
-
- void addColor(String color) {
- sb.write(', ${color} ${position.toInt()}%');
- position += delta;
- sb.write(', ${color} ${position.toInt()}%');
- }
-
- for (SourceLocation sourceLocation in lastSourceLocations) {
- if (sourceLocation == null) continue;
- int colorIndex = collection.getIndex(sourceLocation);
- addColor('${toColorCss(colorIndex)}');
- currentLocation = sourceLocation;
- }
- color = 'background: linear-gradient(to right${sb}); '
- 'background-size: 10px 10px;';
- title = lastSourceLocations.map((l) => l.shortText).join(',');
- }
- if (index != null) {
- Set<int> indices =
- lastSourceLocations.map((l) => collection.getIndex(l)).toSet();
- String onmouseover = indices.map((i) => '\'$i\'').join(',');
- htmlBuffer.write(
- '<a name="js$index" href="#${index}" style="$color" title="$title" '
- 'onclick="${onclick}" onmouseover="highlight([${onmouseover}]);"'
- 'onmouseout="highlight([]);">');
- pendingSourceLocationsEnd = true;
- }
- if (lastSourceLocations.last == null) {
- endCurrentLocation();
- }
- }
-
- for (int targetOffset in codeLocations.keys.toList()..sort()) {
- List<SourceLocation> sourceLocations = codeLocations[targetOffset];
- addSubstring(targetOffset);
- insertSourceLocations(sourceLocations);
- }
-
- addSubstring(text.length);
- endCurrentLocation();
- return htmlBuffer.toString();
+ });
+ return convertAnnotatedCodeToHtml(
+ text, annotations, colorScheme: colorScheme,
+ elementScheme: new HighlightLinkScheme(name),
+ windowSize: 3);
}
}
+class Annotation {
+ final id;
+ final int codeOffset;
+ final String title;
+
+ Annotation(this.id, this.codeOffset, this.title);
+}
+
+class ElementScheme {
+ const ElementScheme();
+
+ String getName(var id, Set ids) => null;
+ String getHref(var id, Set ids) => null;
+ String onClick(var id, Set ids) => null;
+ String onMouseOver(var id, Set ids) => null;
+ String onMouseOut(var id, Set ids) => null;
+}
+
+class HighlightLinkScheme implements ElementScheme {
+ final String name;
+
+ HighlightLinkScheme(this.name);
+
+ @override
+ String getName(int id, Set<int> indices) {
+ return 'js$id';
+ }
+
+ @override
+ String getHref(int id, Set<int> indices) {
+ return "#${id}";
+ }
+
+ @override
+ String onClick(int id, Set<int> indices) {
+ return "show(\'$name\');";
+ }
+
+ @override
+ String onMouseOut(int id, Set<int> indices) {
+ String onmouseover = indices.map((i) => '\'$i\'').join(',');
+ return "highlight([${onmouseover}]);";
+ }
+
+ @override
+ String onMouseOver(int id, Set<int> indices) {
+ return "highlight([]);";
+ }
+}
+
+String convertAnnotatedCodeToHtml(
+ String code,
+ Iterable<Annotation> annotations,
+ {CssColorScheme colorScheme: const SingleColorScheme(),
+ ElementScheme elementScheme: const ElementScheme(),
+ int windowSize}) {
+ StringBuffer htmlBuffer = new StringBuffer();
+ List<CodeLine> lines = convertAnnotatedCodeToCodeLines(
+ code, annotations,
+ colorScheme: colorScheme,
+ elementScheme: elementScheme,
+ windowSize: windowSize);
+ int lineNoWidth;
+ if (lines.isNotEmpty) {
+ lineNoWidth = '${lines.last.lineNo + 1}'.length;
+ }
+ for (CodeLine line in lines) {
+ line.printHtmlOn(htmlBuffer, lineNoWidth);
+ }
+ return htmlBuffer.toString();
+}
+
+List<CodeLine> convertAnnotatedCodeToCodeLines(
+ String code,
+ Iterable<Annotation> annotations,
+ {CssColorScheme colorScheme: const SingleColorScheme(),
+ ElementScheme elementScheme: const ElementScheme(),
+ int windowSize}) {
+
+ List<CodeLine> lines = <CodeLine>[];
+ CodeLine currentLine;
+ int offset = 0;
+ int lineIndex = 0;
+ int firstLine;
+ int lastLine;
+ bool pendingSourceLocationsEnd = false;
+
+ void write(String code, String html) {
+ if (currentLine != null) {
+ currentLine.codeBuffer.write(code);
+ currentLine.htmlParts.add(html);
+ }
+ }
+
+ void startLine() {
+ lines.add(currentLine = new CodeLine(lines.length));
+ }
+
+ void endCurrentLocation() {
+ if (pendingSourceLocationsEnd) {
+ write('', '</a>');
+ }
+ pendingSourceLocationsEnd = false;
+ }
+
+ void addSubstring(int until, {bool isFirst: false, bool isLast: false}) {
+ if (until <= offset) return;
+ if (offset >= code.length) return;
+
+ String substring = code.substring(offset, until);
+ offset = until;
+ bool first = true;
+
+ if (isLast) {
+ lastLine = lineIndex;
+ }
+ if (isFirst) {
+ startLine();
+ }
+ for (String line in substring.split('\n')) {
+ if (!first) {
+ endCurrentLocation();
+ write('', '\n');
+ lineIndex++;
+ startLine();
+ }
+ if (pendingSourceLocationsEnd && !colorScheme.showLocationAsSpan) {
+ if (line.isNotEmpty) {
+ String before = line.substring(0, 1);
+ write(before, escape(before));
+ endCurrentLocation();
+ String after = line.substring(1);
+ write(after, escape(after));
+ }
+ } else {
+ write(line, escape(line));
+ }
+ first = false;
+ }
+ if (isFirst) {
+ firstLine = lineIndex;
+ }
+ }
+
+ void insertAnnotations(List<Annotation> annotations) {
+ endCurrentLocation();
+
+ String color;
+ var id;
+ String title;
+ if (annotations.length == 1) {
+ Annotation annotation = annotations.single;
+ if (annotation != null) {
+ id = annotation.id;
+ color = colorScheme.singleLocationToCssColor(id);
+ title = annotation.title;
+ }
+ } else {
+ id = annotations.first.id;
+ List ids = [];
+ for (Annotation annotation in annotations) {
+ ids.add(annotation.id);
+ }
+ color = colorScheme.multiLocationToCssColor(ids);
+ title = annotations.map((l) => l.title).join(',');
+ }
+ if (id != null) {
+ Set ids = annotations.map((l) => l.id).toSet();
+ String name = elementScheme.getName(id, ids);
+ String href = elementScheme.getHref(id, ids);
+ String onclick = elementScheme.onClick(id, ids);
+ String onmouseover = elementScheme.onMouseOver(id, ids);
+ String onmouseout = elementScheme.onMouseOut(id, ids);
+ write('', '<a');
+ if (href != null) {
+ write('', ' href="${href}"');
+ }
+ if (name != null) {
+ write('', ' name="${name}"');
+ }
+ if (title != null) {
+ write('', ' title="${escape(title)}"');
+ }
+ write('', ' style="${color}"');
+ if (onclick != null) {
+ write('', ' onclick="${onclick}"');
+ }
+ if (onmouseover != null) {
+ write('', ' onmouseover="${onmouseover}"');
+ }
+ if (onmouseout != null) {
+ write('', ' onmouseout="${onmouseout}"');
+ }
+ write('', '>');
+ pendingSourceLocationsEnd = true;
+ }
+ if (annotations.last == null) {
+ endCurrentLocation();
+ }
+ }
+
+ Map<int, List<Annotation>> annotationMap = <int, List<Annotation>>{};
+ for (Annotation annotation in annotations) {
+ annotationMap.putIfAbsent(annotation.codeOffset, () => <Annotation>[])
+ .add(annotation);
+ }
+
+ bool first = true;
+ for (int codeOffset in annotationMap.keys.toList()..sort()) {
+ List<Annotation> annotationList = annotationMap[codeOffset];
+ addSubstring(codeOffset, isFirst: first);
+ insertAnnotations(annotationList);
+ first = false;
+ }
+
+ addSubstring(code.length, isFirst: first, isLast: true);
+ endCurrentLocation();
+
+ int start = 0;
+ int end = lines.length - 1;
+ if (windowSize != null) {
+ start = Math.max(firstLine - windowSize, start);
+ end = Math.min(lastLine + windowSize, end);
+ }
+ return lines.sublist(start, end);
+}
+
+class CodeLine {
+ final int lineNo;
+ final StringBuffer codeBuffer = new StringBuffer();
+ final List<String> htmlParts = <String>[];
+ String _code;
+
+ CodeLine(this.lineNo);
+
+ String get code {
+ if (_code == null) {
+ _code = codeBuffer.toString();
+ }
+ return _code;
+ }
+
+ void printHtmlOn(StringBuffer htmlBuffer, [int lineNoWidth]) {
+ htmlBuffer.write(lineNumber(lineNo, lineNoWidth));
+ for (String part in htmlParts) {
+ htmlBuffer.write(part);
+ }
+ }
+}
+
+
/// Computes the HTML representation for a collection of JavaScript code blocks.
String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) {
@@ -240,10 +505,10 @@
js.Node node = info.node;
String code = info.code;
String name = info.name;
- String onclick = 'show(\'$name\');';
SourceLocationCollection subcollection =
new SourceLocationCollection(collection);
- CodeProcessor codeProcessor = new CodeProcessor(onclick, subcollection);
+ CodeProcessor codeProcessor = new CodeProcessor(name, subcollection);
+ //print('${info.element}:${info.nodeMap.nodes.length}');
for (js.Node node in info.nodeMap.nodes) {
info.nodeMap[node].forEach(
(int targetOffset, List<SourceLocation> sourceLocations) {
@@ -312,6 +577,11 @@
int firstLineIndex;
int lastLineIndex;
+ List<int> lineIndices = uriMap.keys.toList()..sort();
+ int lineNoWidth;
+ if (lineIndices.isNotEmpty) {
+ lineNoWidth = '${lineIndices.last + windowSize + 1}'.length;
+ }
void flush() {
if (firstLineIndex != null && lastLineIndex != null) {
@@ -325,7 +595,7 @@
line < firstLineIndex;
line++) {
if (line >= 0) {
- dartCodeBuffer.write(lineNumber(line));
+ dartCodeBuffer.write(lineNumber(line, lineNoWidth));
dartCodeBuffer.write(sourceFile.getLineText(line));
}
}
@@ -334,7 +604,7 @@
line <= lastLineIndex + windowSize;
line++) {
if (line < sourceFile.lines) {
- dartCodeBuffer.write(lineNumber(line));
+ dartCodeBuffer.write(lineNumber(line, lineNoWidth));
dartCodeBuffer.write(sourceFile.getLineText(line));
}
}
@@ -345,7 +615,6 @@
codeBuffer.clear();
}
- List<int> lineIndices = uriMap.keys.toList()..sort();
lineIndices.forEach((int lineIndex) {
List<SourceLocation> locations = uriMap[lineIndex];
if (lastLineIndex != null &&
@@ -356,7 +625,7 @@
firstLineIndex = lineIndex;
} else {
for (int line = lastLineIndex + 1; line < lineIndex; line++) {
- codeBuffer.write(lineNumber(line));
+ codeBuffer.write(lineNumber(line, lineNoWidth));
codeBuffer.write(sourceFile.getLineText(line));
}
}
@@ -371,7 +640,7 @@
end = locations[i + 1].column;
}
if (i == 0) {
- codeBuffer.write(lineNumber(lineIndex));
+ codeBuffer.write(lineNumber(lineIndex, lineNoWidth));
codeBuffer.write(line.substring(0, start));
}
codeBuffer.write(
diff --git a/tests/compiler/dart2js/sourcemaps/trace_graph.dart b/tests/compiler/dart2js/sourcemaps/trace_graph.dart
new file mode 100644
index 0000000..b21014b
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/trace_graph.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library sourcemap.trace_graph;
+
+import 'dart:collection';
+
+import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/io/position_information.dart';
+
+import 'sourcemap_html_helper.dart';
+
+class TraceGraph {
+ List<TraceStep> steps = <TraceStep>[];
+ TraceStep entry;
+ Queue stack = new Queue();
+
+ void addStep(TraceStep step) {
+ steps.add(step);
+ step.stack = stack.toList();
+ }
+
+ void pushBranch(branch) {
+ stack.addLast(branch);
+ }
+
+ void popBranch() {
+ stack.removeLast();
+ }
+}
+
+class TraceStep {
+ final int id;
+ final node;
+ final Offset offset;
+ final List text;
+ final SourceLocation sourceLocation;
+
+ TraceStep next;
+ Map<dynamic, TraceStep> branchMap;
+
+ List stack;
+
+ TraceStep(
+ this.id,
+ this.node,
+ this.offset,
+ this.text,
+ [this.sourceLocation]);
+
+ String toString() => '<span style="background:${toColorCss(id)}">$id</span>';
+}
+
diff --git a/tests/compiler/dart2js/type_mask_disjoint_test.dart b/tests/compiler/dart2js/type_mask_disjoint_test.dart
new file mode 100644
index 0000000..4cc7a00
--- /dev/null
+++ b/tests/compiler/dart2js/type_mask_disjoint_test.dart
@@ -0,0 +1,184 @@
+// 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:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/src/types/types.dart';
+
+import 'compiler_helper.dart';
+
+const String CODE = """
+class A {}
+class B extends A {}
+class C extends A {}
+
+class D implements A {}
+
+class E {}
+class F extends E {}
+class G implements E {}
+
+class H {}
+class I implements H {}
+class J extends D implements I {}
+
+class K {}
+class M extends K with A {}
+
+main() {
+ print([new A(), new B(), new C(), new D(), new E(), new F(), new G(),
+ new H(), new I(), new J(), new K(), new M()]);
+}
+""";
+
+Uri uri = new Uri(scheme: 'source');
+var compiler = compilerFor(CODE, uri);
+var world = compiler.world;
+
+main() {
+ asyncTest(() => compiler.run(uri).then((_) {
+
+ // Empty
+ check(' ! ', ' ! '); // both non-null
+ check(' ! ', ' '); // one non-null
+ check(' ', ' ! '); // one non-null
+ check(' ', ' ', areDisjoint: false); // null is common
+
+ // Exact
+ check('A!=', 'A!=', areDisjoint: false);
+ check('A!=', 'B!=');
+ check('A!=', 'E!=');
+ check('A =', 'E =', areDisjoint: false); // null is common
+ check('M!=', 'K!=');
+ check('M!=', 'A!=');
+
+ // Exact with subclass
+ check('A!=', 'A!<', areDisjoint: false);
+ check('B!=', 'A!<', areDisjoint: false);
+ check('A!=', 'B!<');
+ check('A!=', 'E!<');
+ check('A =', 'E!<');
+ check('A =', 'E <', areDisjoint: false);
+ check('M!=', 'K!<', areDisjoint: false);
+ check('M!=', 'A!<');
+
+ // Exact with subtype
+ check('A!=', 'A!*', areDisjoint: false);
+ check('B!=', 'A!*', areDisjoint: false);
+ check('A!=', 'B!*');
+ check('A!=', 'E!*');
+ check('A!=', 'I!*');
+ check('J!=', 'H!*', areDisjoint: false);
+ check('M!=', 'K!*', areDisjoint: false);
+ check('M!=', 'A!*', areDisjoint: false);
+
+ // Subclass with subclass
+ check('A!<', 'A!<', areDisjoint: false);
+ check('A!<', 'B!<', areDisjoint: false);
+ check('A!<', 'E!<');
+ check('A!<', 'H!<');
+ check('D!<', 'I!<');
+
+ // Subclass with subtype
+ check('A!<', 'A!*', areDisjoint: false);
+ check('A!<', 'B!*', areDisjoint: false);
+ check('A!<', 'E!*');
+ check('A!<', 'H!*');
+ check('D!<', 'I!*', areDisjoint: false);
+
+ // Subtype with subtype
+ check('A!*', 'A!*', areDisjoint: false);
+ check('A!*', 'B!*', areDisjoint: false);
+ check('A!*', 'E!*');
+ check('A!*', 'H!*', areDisjoint: false);
+ check('D!*', 'I!*', areDisjoint: false);
+
+ // Unions!
+ checkUnions(['B!=', 'C!='], ['A!=']);
+ checkUnions(['B!=', 'C!='], ['A =']);
+ checkUnions(['B!=', 'C ='], ['A ='], areDisjoint: false);
+
+ checkUnions(['B!=', 'C!='], ['A!<'], areDisjoint: false);
+ checkUnions(['B!=', 'C!='], ['B!='], areDisjoint: false);
+ checkUnions(['A!<', 'E!<'], ['C!='], areDisjoint: false);
+ checkUnions(['A!<', 'E!<'], ['F!='], areDisjoint: false);
+
+ checkUnions(['A!=', 'E!='], ['C!=', 'F!=']);
+ checkUnions(['A!=', 'E!='], ['A!=', 'F!='], areDisjoint: false);
+ checkUnions(['B!=', 'E!='], ['A!<', 'F!='], areDisjoint: false);
+ checkUnions(['A!<', 'E!<'], ['C!=', 'F!='], areDisjoint: false);
+ checkUnions(['A!=', 'E!='], ['C!=', 'F!=']);
+ }));
+}
+
+/// Checks the expectation of `isDisjoint` for two mask. Also checks that the
+/// result is consistent with an equivalent (but slower) implementation based on
+/// intersection.
+checkMask(TypeMask m1, TypeMask m2, {areDisjoint: false}) {
+ print('masks: $m1 $m2');
+ Expect.equals(areDisjoint, m1.isDisjoint(m2, world));
+ Expect.equals(areDisjoint, m2.isDisjoint(m1, world));
+ var i1 = m1.intersection(m2, world);
+ Expect.equals(areDisjoint, i1.isEmpty && !i1.isNullable);
+ var i2 = m2.intersection(m1, world);
+ Expect.equals(areDisjoint, i2.isEmpty && !i2.isNullable);
+}
+
+/// Checks the expectation of `isDisjoint` for two mask descriptors (see
+/// [maskOf] for details).
+check(String typeMaskDescriptor1, String typeMaskDescriptor2,
+ {areDisjoint: true}) {
+ print('[$typeMaskDescriptor1] & [$typeMaskDescriptor2]');
+ checkMask(maskOf(typeMaskDescriptor1), maskOf(typeMaskDescriptor2),
+ areDisjoint: areDisjoint);
+}
+
+
+checkUnions(List descriptors1, List descriptors2, {areDisjoint: true}) {
+ print('[$descriptors1] & [$descriptors2]');
+ var m1 = new TypeMask.unionOf(descriptors1.map(maskOf).toList(), world);
+ var m2 = new TypeMask.unionOf(descriptors2.map(maskOf).toList(), world);
+ checkMask(m1, m2, areDisjoint: areDisjoint);
+}
+
+Map _maskCache = {};
+Map _elementCache = {};
+
+/// Parses a descriptor of a flat mask. A descriptor is of the form "AXY" where:
+/// A: either a type T or " " (base class or empty)
+/// X: can be either ! or " " (nullable/nonnullable)
+/// Y: can be either " " (no flag), = (exact), < (subclass), * (subtype)
+///
+/// Examples:
+/// "-! " - empty, non-null
+/// "- " - null
+/// "Type!=" - non-null exact Type
+/// "Type =" - nullable exact Type
+/// "Type!<" - non-null subclass of Type
+/// "Type!*" - non-null subtype of Type
+TypeMask maskOf(String descriptor) =>
+ _maskCache.putIfAbsent(descriptor, () {
+ Expect.isTrue(descriptor.length >= 3);
+ var type = descriptor.substring(0, descriptor.length - 2);
+ bool isNullable = descriptor[descriptor.length - 2] != '!';
+ bool isExact = descriptor[descriptor.length - 1] == '=';
+ bool isSubclass = descriptor[descriptor.length - 1] == '<';
+ bool isSubtype = descriptor[descriptor.length - 1] == '*';
+
+ if (type == " ") {
+ Expect.isFalse(isExact || isSubclass || isSubtype);
+ return isNullable ? new TypeMask.empty() : new TypeMask.nonNullEmpty();
+ }
+
+ Expect.isTrue(isExact || isSubclass || isSubtype);
+ var element = _elementCache.putIfAbsent(type,
+ () => type == " " ? null : findElement(compiler, type));
+
+ var mask = isExact
+ ? new TypeMask.nonNullExact(element, world)
+ : (isSubclass
+ ? new TypeMask.nonNullSubclass(element, world)
+ : new TypeMask.nonNullSubtype(element, world));
+ return isNullable ? mask.nullable() : mask;
+ });
diff --git a/tests/compiler/dart2js/type_representation_test.dart b/tests/compiler/dart2js/type_representation_test.dart
index 0a2d4e0..ce4f3c8 100644
--- a/tests/compiler/dart2js/type_representation_test.dart
+++ b/tests/compiler/dart2js/type_representation_test.dart
@@ -50,7 +50,7 @@
}
String stringify(Expression expression) {
- return prettyPrint(expression, env.compiler).buffer.toString();
+ return prettyPrint(expression, env.compiler);
}
void expect(DartType type,
diff --git a/tests/compiler/dart2js/world_test.dart b/tests/compiler/dart2js/world_test.dart
index 13a0821..0109f8d 100644
--- a/tests/compiler/dart2js/world_test.dart
+++ b/tests/compiler/dart2js/world_test.dart
@@ -7,13 +7,22 @@
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'type_test_helper.dart';
+import 'package:compiler/src/common.dart';
import 'package:compiler/src/elements/elements.dart'
show Element, ClassElement;
+import 'package:compiler/src/universe/class_set.dart';
import 'package:compiler/src/world.dart' show ClassWorld;
void main() {
- asyncTest(() => TypeEnvironment.create(r"""
- class A {}
+ asyncTest(() async {
+ await testClassSets();
+ await testProperties();
+ });
+}
+
+testClassSets() async {
+ var env = await TypeEnvironment.create(r"""
+ class A implements X {}
class B {}
class C_Super extends A {}
class C extends C_Super {}
@@ -21,6 +30,7 @@
class E extends B implements A {}
class F extends Object with A implements B {}
class G extends Object with A, B {}
+ class X {}
""",
mainSource: r"""
main() {
@@ -33,120 +43,283 @@
new G();
}
""",
- useMockCompiler: false).then((env) {
- ClassWorld classWorld = env.compiler.world;
+ useMockCompiler: false);
+ ClassWorld classWorld = env.compiler.world;
- ClassElement Object_ = env.getElement("Object");
- ClassElement A = env.getElement("A");
- ClassElement B = env.getElement("B");
- ClassElement C = env.getElement("C");
- ClassElement D = env.getElement("D");
- ClassElement E = env.getElement("E");
- ClassElement F = env.getElement("F");
- ClassElement G = env.getElement("G");
+ ClassElement Object_ = env.getElement("Object");
+ ClassElement A = env.getElement("A");
+ ClassElement B = env.getElement("B");
+ ClassElement C = env.getElement("C");
+ ClassElement D = env.getElement("D");
+ ClassElement E = env.getElement("E");
+ ClassElement F = env.getElement("F");
+ ClassElement G = env.getElement("G");
+ ClassElement X = env.getElement("X");
- void check(
- String property,
- ClassElement cls,
- Iterable<ClassElement> foundClasses,
- List<ClassElement> expectedClasses,
- {bool exact: true}) {
- for (ClassElement expectedClass in expectedClasses) {
- Expect.isTrue(foundClasses.contains(expectedClass),
- "Expect $expectedClass in '$property' on $cls. "
- "Found:\n ${foundClasses.join('\n ')}");
+ void checkClasses(
+ String property,
+ ClassElement cls,
+ Iterable<ClassElement> foundClasses,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+
+ for (ClassElement expectedClass in expectedClasses) {
+ Expect.isTrue(foundClasses.contains(expectedClass),
+ "Expect $expectedClass in '$property' on $cls. "
+ "Found:\n ${foundClasses.join('\n ')}\n"
+ "${env.compiler.world.dump(cls)}");
+ }
+ if (exact) {
+ Expect.equals(expectedClasses.length, foundClasses.length,
+ "Unexpected classes "
+ "${foundClasses.where((c) => !expectedClasses.contains(c))} "
+ "in '$property' on $cls.\n"
+ "${env.compiler.world.dump(cls)}");
+ }
+ }
+
+ void check(
+ String property,
+ ClassElement cls,
+ Iterable<ClassElement> foundClasses,
+ List<ClassElement> expectedClasses,
+ {bool exact: true,
+ void forEach(ClassElement cls, ForEachFunction f),
+ int getCount(ClassElement cls)}) {
+ checkClasses(property, cls, foundClasses, expectedClasses, exact: exact);
+
+ if (forEach != null) {
+ List<ClassElement> visited = <ClassElement>[];
+ forEach(cls, (ClassElement c) {
+ visited.add(c);
+ });
+ checkClasses(
+ 'forEach($property)', cls, visited, expectedClasses, exact: exact);
+ }
+
+ if (getCount != null && exact) {
+ int count = getCount(cls);
+ Expect.equals(expectedClasses.length, count,
+ "Unexpected class count in '$property' on $cls.\n"
+ "${env.compiler.world.dump(cls)}");
+ }
+
+ }
+
+ void testSubclasses(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'subclassesOf',
+ cls,
+ classWorld.subclassesOf(cls),
+ expectedClasses,
+ exact: exact);
+ }
+
+ void testStrictSubclasses(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'strictSubclassesOf',
+ cls,
+ classWorld.strictSubclassesOf(cls),
+ expectedClasses,
+ exact: exact,
+ forEach: classWorld.forEachStrictSubclassOf,
+ getCount: classWorld.strictSubclassCount);
+ }
+
+ void testStrictSubtypes(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'strictSubtypesOf',
+ cls,
+ classWorld.strictSubtypesOf(cls),
+ expectedClasses,
+ exact: exact,
+ forEach: classWorld.forEachStrictSubtypeOf,
+ getCount: classWorld.strictSubtypeCount);
+ }
+
+ void testMixinUses(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'mixinUsesOf',
+ cls,
+ classWorld.mixinUsesOf(cls),
+ expectedClasses,
+ exact: exact);
+ }
+
+ testSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
+ testSubclasses(A, [A, C]);
+ testSubclasses(B, [B, E]);
+ testSubclasses(C, [C]);
+ testSubclasses(D, [D]);
+ testSubclasses(E, [E]);
+ testSubclasses(F, [F]);
+ testSubclasses(G, [G]);
+ testSubclasses(X, []);
+
+ testStrictSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
+ testStrictSubclasses(A, [C]);
+ testStrictSubclasses(B, [E]);
+ testStrictSubclasses(C, []);
+ testStrictSubclasses(D, []);
+ testStrictSubclasses(E, []);
+ testStrictSubclasses(F, []);
+ testStrictSubclasses(G, []);
+ testStrictSubclasses(X, []);
+
+ testStrictSubtypes(Object_, [A, B, C, D, E, F, G], exact: false);
+ testStrictSubtypes(A, [C, D, E, F, G]);
+ testStrictSubtypes(B, [E, F, G]);
+ testStrictSubtypes(C, []);
+ testStrictSubtypes(D, []);
+ testStrictSubtypes(E, []);
+ testStrictSubtypes(F, []);
+ testStrictSubtypes(G, []);
+ testStrictSubtypes(X, [A, C, D, E, F, G]);
+
+ testMixinUses(Object_, []);
+ testMixinUses(A, [F.superclass, G.superclass.superclass]);
+ testMixinUses(B, [G.superclass]);
+ testMixinUses(C, []);
+ testMixinUses(D, []);
+ testMixinUses(E, []);
+ testMixinUses(F, []);
+ testMixinUses(G, []);
+ testMixinUses(X, []);
+}
+
+testProperties() async {
+ var env = await TypeEnvironment.create(r"""
+ class A {}
+ class A1 extends A {}
+ class A2 implements A {}
+ class A3 extends Object with A {}
+
+ class B {}
+ class B1 extends B {}
+ class B2 implements B {}
+ class B3 extends Object with B {}
+
+ class C {}
+ class C1 extends C {}
+ class C2 implements C {}
+ class C3 extends Object with C {}
+
+ class D {}
+ class D1 extends D {}
+ class D2 implements D {}
+ class D3 extends Object with D {}
+
+ class E {}
+ class E1 extends E {}
+ class E2 implements E {}
+ class E3 extends Object with E {}
+
+ class F {}
+ class F1 extends F {}
+ class F2 implements F {}
+ class F3 extends Object with F {}
+
+ class G {}
+ class G1 extends G {}
+ class G2 extends G1 {}
+ class G3 extends G2 implements G {}
+ class G4 extends G2 with G {}
+
+ class H {}
+ class H1 extends H {}
+ class H2 extends H1 {}
+ class H3 extends H2 implements H {}
+ class H4 extends H2 with H {}
+ """,
+ mainSource: r"""
+ main() {
+ new B();
+ new C1();
+ new D2();
+ new E3();
+ new F1();
+ new F2();
+ new G2();
+ new G3();
+ new H4();
}
- if (exact) {
- Expect.equals(expectedClasses.length, foundClasses.length,
- "Unexpected classes "
- "${foundClasses.where((c) => !expectedClasses.contains(c))} "
- "in '$property' on $cls.");
- }
- }
+ """,
+ useMockCompiler: false);
+ ClassWorld classWorld = env.compiler.world;
- void testSubclasses(
- ClassElement cls,
- List<ClassElement> expectedClasses,
- {bool exact: true}) {
- check(
- 'subclassesOf',
- cls,
- classWorld.subclassesOf(cls),
- expectedClasses,
- exact: exact);
- }
+ check(String name,
+ {bool hasStrictSubtype,
+ bool hasOnlySubclasses}) {
+ ClassElement cls = env.getElement(name);
+ Expect.equals(hasStrictSubtype, classWorld.hasAnyStrictSubtype(cls),
+ "Unexpected hasAnyStrictSubtype property on $cls.");
+ Expect.equals(hasOnlySubclasses, classWorld.hasOnlySubclasses(cls),
+ "Unexpected hasOnlySubclasses property on $cls.");
+ }
- void testStrictSubclasses(
- ClassElement cls,
- List<ClassElement> expectedClasses,
- {bool exact: true}) {
- check(
- 'strictSubclassesOf',
- cls,
- classWorld.strictSubclassesOf(cls),
- expectedClasses,
- exact: exact);
- }
+ check("Object", hasStrictSubtype: true, hasOnlySubclasses: true);
- void testStrictSubtypes(
- ClassElement cls,
- List<ClassElement> expectedClasses,
- {bool exact: true}) {
- check(
- 'strictSubtypesOf',
- cls,
- classWorld.strictSubtypesOf(cls),
- expectedClasses,
- exact: exact);
- }
+ // No instantiated Ax classes.
+ check("A", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("A1", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("A2", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("A3", hasStrictSubtype: false, hasOnlySubclasses: true);
- void testMixinUses(
- ClassElement cls,
- List<ClassElement> expectedClasses,
- {bool exact: true}) {
- check(
- 'mixinUsesOf',
- cls,
- classWorld.mixinUsesOf(cls),
- expectedClasses,
- exact: exact);
- }
+ // class B instantiated
+ check("B", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("B1", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("B2", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("B3", hasStrictSubtype: false, hasOnlySubclasses: true);
- testSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
- testSubclasses(A, [A, C]);
- testSubclasses(B, [B, E]);
- testSubclasses(C, [C]);
- testSubclasses(D, [D]);
- testSubclasses(E, [E]);
- testSubclasses(F, [F]);
- testSubclasses(G, [G]);
+ // class C1 extends C instantiated
+ check("C", hasStrictSubtype: true, hasOnlySubclasses: true);
+ check("C1", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("C2", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("C3", hasStrictSubtype: false, hasOnlySubclasses: true);
- testStrictSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
- testStrictSubclasses(A, [C]);
- testStrictSubclasses(B, [E]);
- testStrictSubclasses(C, []);
- testStrictSubclasses(D, []);
- testStrictSubclasses(E, []);
- testStrictSubclasses(F, []);
- testStrictSubclasses(G, []);
+ // class D2 implements D instantiated
+ check("D", hasStrictSubtype: true, hasOnlySubclasses: false);
+ check("D1", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("D2", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("D3", hasStrictSubtype: false, hasOnlySubclasses: true);
- testStrictSubtypes(Object_, [A, B, C, D, E, F, G], exact: false);
- testStrictSubtypes(A, [C, D, E, F, G]);
- testStrictSubtypes(B, [E, F, G]);
- testStrictSubtypes(C, []);
- testStrictSubtypes(D, []);
- testStrictSubtypes(E, []);
- testStrictSubtypes(F, []);
- testStrictSubtypes(G, []);
+ // class E2 extends Object with E instantiated
+ check("E", hasStrictSubtype: true, hasOnlySubclasses: false);
+ check("E1", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("E2", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("E3", hasStrictSubtype: false, hasOnlySubclasses: true);
- testMixinUses(Object_, []);
- testMixinUses(A, [F.superclass, G.superclass.superclass]);
- testMixinUses(B, [G.superclass]);
- testMixinUses(C, []);
- testMixinUses(D, []);
- testMixinUses(E, []);
- testMixinUses(F, []);
- testMixinUses(G, []);
+ // class F1 extends F instantiated
+ // class F2 implements F instantiated
+ check("F", hasStrictSubtype: true, hasOnlySubclasses: false);
+ check("F1", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("F2", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("F3", hasStrictSubtype: false, hasOnlySubclasses: true);
- }));
+ // class G2 extends G1 extends G instantiated
+ // class G3 extends G2 extends G1 extends G instantiated
+ check("G", hasStrictSubtype: true, hasOnlySubclasses: true);
+ check("G1", hasStrictSubtype: true, hasOnlySubclasses: true);
+ check("G2", hasStrictSubtype: true, hasOnlySubclasses: true);
+ check("G3", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("G4", hasStrictSubtype: false, hasOnlySubclasses: true);
+
+ // class H4 extends H2 with H extends H1 extends H instantiated
+ check("H", hasStrictSubtype: true, hasOnlySubclasses: true);
+ check("H1", hasStrictSubtype: true, hasOnlySubclasses: true);
+ check("H2", hasStrictSubtype: true, hasOnlySubclasses: true);
+ check("H3", hasStrictSubtype: false, hasOnlySubclasses: true);
+ check("H4", hasStrictSubtype: false, hasOnlySubclasses: true);
}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 3d00167..2cb3918 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -3,7 +3,6 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2js ]
-16407_test: Fail # Issue 16407
class_test: Fail
statements_test: Fail
typed_locals_test: Fail
@@ -68,6 +67,4 @@
big_allocation_expression_test: Crash # Issue 24635
[ $compiler == dart2js && $cps_ir ]
-16407_test: Pass # Please triage this failure.
async_stacktrace_test/asyncStar: Crash # (foo()async*{try {tr... cannot handle sync*/async* functions
-switch_test/none: Crash # (switch (val){foo:ba... continue to a labeled switch case
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 88b3ccd..407ea29 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -189,16 +189,6 @@
[ $compiler == dart2js && $cps_ir ]
data_resource_test: Crash # (await for(var byteSlice in resource.openRead()){streamBytes.addAll(byteSlice);}): await for
error_stack_trace1_test: Pass # H.unwrapException(...).get$stackTrace is not a function
-growable_list_test: RuntimeError # Typed lists
-iterable_empty_test: RuntimeError # Please triage this failure.
-iterable_return_type_test/none: RuntimeError # Please triage this failure.
-iterable_to_list_test: RuntimeError # Please triage this failure.
-iterable_to_set_test: RuntimeError # Please triage this failure.
-list_filled_type_argument_test: RuntimeError # Please triage this failure.
-list_unmodifiable_test: RuntimeError # Please triage this failure.
-map_values2_test: RuntimeError # Please triage this failure.
-map_values3_test: RuntimeError # Please triage this failure.
-map_values4_test: RuntimeError # Please triage this failure.
package_resource_test: Crash # (await for(var byteSlice in resource.openRead()){streamBytes.addAll(byteSlice);}): await for
regexp/pcre_test: Crash # Stack Overflow in LoopHierarchy.
symbol_operator_test/03: RuntimeError # Issue 24878
diff --git a/tests/corelib/expando_test.dart b/tests/corelib/expando_test.dart
index d55aecf..a7fb1c4 100644
--- a/tests/corelib/expando_test.dart
+++ b/tests/corelib/expando_test.dart
@@ -18,7 +18,7 @@
testUnnamedExpando(object);
}
for (var object in legal) {
- Expect.equals(2, visits[object]);
+ Expect.equals(2, visits[object], "$object");
}
testIllegal();
testIdentity();
@@ -65,19 +65,19 @@
static testIllegal() {
Expando<int> expando = new Expando<int>();
Expect.throws(() => expando[null], (exception)
- => exception is ArgumentError);
+ => exception is ArgumentError, "null");
Expect.throws(() => expando['string'], (exception)
- => exception is ArgumentError);
+ => exception is ArgumentError, "'string'");
Expect.throws(() => expando['string'], (exception)
- => exception is ArgumentError);
+ => exception is ArgumentError, "'string'");
Expect.throws(() => expando[42], (exception)
- => exception is ArgumentError);
+ => exception is ArgumentError, "42");
Expect.throws(() => expando[42.87], (exception)
- => exception is ArgumentError);
+ => exception is ArgumentError, "42.87");
Expect.throws(() => expando[true], (exception)
- => exception is ArgumentError);
+ => exception is ArgumentError, "true");
Expect.throws(() => expando[false], (exception)
- => exception is ArgumentError);
+ => exception is ArgumentError, "false");
}
static testIdentity() {
diff --git a/tests/corelib/uri_parameters_all_test.dart b/tests/corelib/uri_parameters_all_test.dart
new file mode 100644
index 0000000..ea40ad8
--- /dev/null
+++ b/tests/corelib/uri_parameters_all_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+main() {
+ testAll(["a", "b", "c"]);
+ testAll([""]);
+ testAll(["a"]);
+ testAll(["",""]);
+ testAll(["baz"]);
+
+ testParse("z&y&w&z", {"z": ["", ""], "y": [""], "w": [""]});
+ testParse("x=42&y=42&x=37&y=37", {"x": ["42", "37"], "y": ["42", "37"]});
+ testParse("x&x&x&x&x", {"x": ["", "", "", "", ""]});
+ testParse("x=&&y", {"x": [""], "y": [""]});
+}
+
+testAll(List values) {
+ var uri = new Uri(scheme: "foo", path: "bar",
+ queryParameters: {"baz": values});
+ var list = uri.queryParametersAll["baz"];
+ Expect.listEquals(values, list);
+}
+
+testParse(query, results) {
+ var uri = new Uri(scheme: "foo", path: "bar", query: query);
+ var params = uri.queryParametersAll;
+ for (var k in results.keys) {
+ Expect.listEquals(results[k], params[k]);
+ }
+ uri = new Uri(scheme: "foo", path: "bar", queryParameters: results);
+ params = uri.queryParametersAll;
+ for (var k in results.keys) {
+ Expect.listEquals(results[k], params[k]);
+ }
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index cf5e043..402fe6e 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -429,3 +429,33 @@
[ $compiler == dart2js && $cps_ir ]
resource_http_test: Crash # (await for(var b in r.openRead()){bytes.addAll(b);}): await for
+
+[ $compiler == dart2js && $cps_ir && $browser ]
+custom/element_upgrade_test: RuntimeError # Please triage
+js_dart_to_string_test: RuntimeError # Please triage
+custom_elements_23127_test/c2t: RuntimeError # Please triage
+custom_elements_23127_test/c2: RuntimeError # Please triage
+custom_elements_23127_test/baseline: RuntimeError # Please triage
+keyboard_event_test: RuntimeError # Please triage
+js_typed_interop_test: RuntimeError # Please triage
+js_typed_interop_side_cast_test: RuntimeError # Please triage
+js_typed_interop_anonymous_exp_test: RuntimeError # Please triage
+custom_elements_test/register: RuntimeError # Please triage
+js_typed_interop_anonymous2_test: RuntimeError # Please triage
+js_typed_interop_anonymous_test: RuntimeError # Please triage
+js_array_test: RuntimeError # Please triage
+js_function_getter_test/call: RuntimeError # Please triage
+custom/mirrors_test: RuntimeError # Please triage
+custom/constructor_calls_created_synchronously_test: RuntimeError # Please triage
+input_element_test/attributes: Pass # Please triage
+js_function_getter_trust_types_test: RuntimeError # Please triage
+js_typed_interop_side_cast_exp_test: RuntimeError # Please triage
+js_typed_interop_anonymous2_exp_test: RuntimeError # Please triage
+mirrors_js_typed_interop_test: RuntimeError # Please triage
+js_function_getter_test: RuntimeError # Please triage
+custom_elements_23127_test/c1t: RuntimeError # Please triage
+custom_elements_test/innerHtml: RuntimeError # Please triage
+mouse_event_test: RuntimeError # Please triage
+js_test/JsObject_methods: RuntimeError # Please triage
+js_test/Dart_functions: RuntimeError # Please triage
+js_test/new_JsObject: RuntimeError # Please triage
diff --git a/tests/html/js_test.dart b/tests/html/js_test.dart
index 37c73ab..a902d59 100644
--- a/tests/html/js_test.dart
+++ b/tests/html/js_test.dart
@@ -322,7 +322,7 @@
});
- group('new JsObject()', () {
+ group('new_JsObject', () {
test('new Foo()', () {
var foo = new JsObject(context['Foo'], [42]);
@@ -649,7 +649,7 @@
});
- group('Dart functions', () {
+ group('Dart_functions', () {
test('invoke Dart callback from JS', () {
expect(() => context.callMethod('invokeCallback'), throws);
@@ -752,7 +752,7 @@
});
});
- group('JsObject methods', () {
+ group('JsObject_methods', () {
test('hashCode and ==', () {
final o1 = context['Object'];
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index e11f91a..7e51060 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -56,9 +56,6 @@
browser/issue_12474_test: CompileTimeError # Issue 22529
enum_const_test/02: RuntimeError # Issue 21817
-[ $compiler == dart2js && $cps_ir ]
-isolate_current_test: RuntimeError # Please triage this failure.
-
[ $compiler == dart2js && $runtime != d8 ]
error_exit_at_spawn_test: Skip # Issue 23876
error_at_spawn_test: Skip # Issue 23876
diff --git a/tests/language/built_in_identifier_prefix_test.dart b/tests/language/built_in_identifier_prefix_test.dart
deleted file mode 100644
index de995c9..0000000
--- a/tests/language/built_in_identifier_prefix_test.dart
+++ /dev/null
@@ -1,216 +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.
-
-// Test that built-in identifiers can be used as library prefixes.
-
-// From The Dart Programming Language Specification, section 11.30
-// "Identifier Reference":
-//
-// "A built-in identifier is one of the identifiers produced by the
-// production BUILT IN IDENTIFIER. It is a compile-time error if a
-// built-in identifier is used as the declared name of a class, type
-// parameter or type alias. It is a compile-time error to use a
-// built-in identifier other than dynamic as a type annotation."
-//
-// Observation: it is not illegal to use a built-in identifier as a library
-// prefix.
-//
-// Observation: it is not legal to use a built-in identifer as a type
-// annotation. A type annotation is not fully defined in the
-// specification, so we assume this means that the grammar production
-// "type" cannot match a built-in identifier. Unfortunately, this
-// doesn't prevent us from using built-in identifiers *in* type
-// annotations. For example, "final abstract foo;" is illegal as
-// "abstract" is used as a type annotation. However, "final
-// abstract<dynamic> foo;" is not illegal because "abstract" is used
-// as a typeName.
-
-import "package:expect/expect.dart";
-import 'built_in_identifier_prefix_library_abstract.dart' as abstract;
-import 'built_in_identifier_prefix_library_as.dart' as as;
-import 'built_in_identifier_prefix_library_dynamic.dart' as dynamic;
-import 'built_in_identifier_prefix_library_export.dart' as export;
-import 'built_in_identifier_prefix_library_external.dart' as external;
-import 'built_in_identifier_prefix_library_factory.dart' as factory;
-import 'built_in_identifier_prefix_library_get.dart' as get;
-import 'built_in_identifier_prefix_library_implements.dart' as implements;
-import 'built_in_identifier_prefix_library_import.dart' as import;
-import 'built_in_identifier_prefix_library_library.dart' as library;
-import 'built_in_identifier_prefix_library_operator.dart' as operator;
-import 'built_in_identifier_prefix_library_part.dart' as part;
-import 'built_in_identifier_prefix_library_set.dart' as set;
-import 'built_in_identifier_prefix_library_static.dart' as static;
-import 'built_in_identifier_prefix_library_typedef.dart' as typedef;
-
-abstract.A _abstract = new abstract.A();
-as.A _as = new as.A();
-dynamic.A _dynamic = new dynamic.A();
-export.A _export = new export.A();
-external.A _external = new external.A();
-factory.A _factory = new factory.A();
-get.A _get = new get.A();
-implements.A _implements = new implements.A();
-import.A _import = new import.A();
-library.A _library = new library.A();
-operator.A _operator = new operator.A();
-part.A _part = new part.A();
-set.A _set = new set.A();
-static.A _static = new static.A();
-typedef.A _typedef = new typedef.A();
-
-abstract<dynamic> generic_abstract = new abstract.A();
-as<dynamic> generic_as = new as.A();
-dynamic<dynamic> generic_dynamic = new dynamic.A();
-export<dynamic> generic_export = new export.A();
-external<dynamic> generic_external = new external.A();
-factory<dynamic> generic_factory = new factory.A();
-get<dynamic> generic_get = new get.A();
-implements<dynamic> generic_implements = new implements.A();
-import<dynamic> generic_import = new import.A();
-library<dynamic> generic_library = new library.A();
-operator<dynamic> generic_operator = new operator.A();
-part<dynamic> generic_part = new part.A();
-set<dynamic> generic_set = new set.A();
-static<dynamic> generic_static = new static.A();
-typedef<dynamic> generic_typedef = new typedef.A();
-
-abstract.B<dynamic> dynamic_B_abstract = new abstract.B();
-as.B<dynamic> dynamic_B_as = new as.B();
-dynamic.B<dynamic> dynamic_B_dynamic = new dynamic.B();
-export.B<dynamic> dynamic_B_export = new export.B();
-external.B<dynamic> dynamic_B_external = new external.B();
-factory.B<dynamic> dynamic_B_factory = new factory.B();
-get.B<dynamic> dynamic_B_get = new get.B();
-implements.B<dynamic> dynamic_B_implements = new implements.B();
-import.B<dynamic> dynamic_B_import = new import.B();
-library.B<dynamic> dynamic_B_library = new library.B();
-operator.B<dynamic> dynamic_B_operator = new operator.B();
-part.B<dynamic> dynamic_B_part = new part.B();
-set.B<dynamic> dynamic_B_set = new set.B();
-static.B<dynamic> dynamic_B_static = new static.B();
-typedef.B<dynamic> dynamic_B_typedef = new typedef.B();
-
-abstract.B<abstract<dynamic>> parameterized_B_abstract = new abstract.B();
-as.B<as<dynamic>> parameterized_B_as = new as.B();
-dynamic.B<dynamic<dynamic>> parameterized_B_dynamic = new dynamic.B();
-export.B<export<dynamic>> parameterized_B_export = new export.B();
-external.B<external<dynamic>> parameterized_B_external = new external.B();
-factory.B<factory<dynamic>> parameterized_B_factory = new factory.B();
-get.B<get<dynamic>> parameterized_B_get = new get.B();
-implements.B<implements<dynamic>> parameterized_B_implements =
- new implements.B();
-import.B<import<dynamic>> parameterized_B_import = new import.B();
-library.B<library<dynamic>> parameterized_B_library = new library.B();
-operator.B<operator<dynamic>> parameterized_B_operator = new operator.B();
-part.B<part<dynamic>> parameterized_B_part = new part.B();
-set.B<set<dynamic>> parameterized_B_set = new set.B();
-static.B<static<dynamic>> parameterized_B_static = new static.B();
-typedef.B<typedef<dynamic>> parameterized_B_typedef = new typedef.B();
-
-class UseA {
- abstract.A abstract = new abstract.A();
- as.A as = new as.A();
- dynamic.A dynamic = new dynamic.A();
- export.A export = new export.A();
- external.A external = new external.A();
- factory.A factory = new factory.A();
- get.A get = new get.A();
- implements.A implements = new implements.A();
- import.A import = new import.A();
- library.A library = new library.A();
- operator.A operator = new operator.A();
- part.A part = new part.A();
- set.A set = new set.A();
- static.A static = new static.A();
- typedef.A typedef = new typedef.A();
-}
-
-main() {
- bool assertionsEnabled = false;
- assert(assertionsEnabled = true);
-
- Expect.isTrue(_abstract is abstract.A);
- Expect.isTrue(_as is as.A);
- Expect.isTrue(_dynamic is dynamic.A);
- Expect.isTrue(_export is export.A);
- Expect.isTrue(_external is external.A);
- Expect.isTrue(_factory is factory.A);
- Expect.isTrue(_get is get.A);
- Expect.isTrue(_implements is implements.A);
- Expect.isTrue(_import is import.A);
- Expect.isTrue(_library is library.A);
- Expect.isTrue(_operator is operator.A);
- Expect.isTrue(_part is part.A);
- Expect.isTrue(_set is set.A);
- Expect.isTrue(_static is static.A);
- Expect.isTrue(_typedef is typedef.A);
-
- Expect.isTrue(dynamic_B_abstract is abstract.B);
- Expect.isTrue(dynamic_B_as is as.B);
- Expect.isTrue(dynamic_B_dynamic is dynamic.B);
- Expect.isTrue(dynamic_B_export is export.B);
- Expect.isTrue(dynamic_B_external is external.B);
- Expect.isTrue(dynamic_B_factory is factory.B);
- Expect.isTrue(dynamic_B_get is get.B);
- Expect.isTrue(dynamic_B_implements is implements.B);
- Expect.isTrue(dynamic_B_import is import.B);
- Expect.isTrue(dynamic_B_library is library.B);
- Expect.isTrue(dynamic_B_operator is operator.B);
- Expect.isTrue(dynamic_B_part is part.B);
- Expect.isTrue(dynamic_B_set is set.B);
- Expect.isTrue(dynamic_B_static is static.B);
- Expect.isTrue(dynamic_B_typedef is typedef.B);
-
- var x = new UseA();
- Expect.isTrue(x.abstract is abstract.A);
- Expect.isTrue(x.as is as.A);
- Expect.isTrue(x.dynamic is dynamic.A);
- Expect.isTrue(x.export is export.A);
- Expect.isTrue(x.external is external.A);
- Expect.isTrue(x.factory is factory.A);
- Expect.isTrue(x.get is get.A);
- Expect.isTrue(x.implements is implements.A);
- Expect.isTrue(x.import is import.A);
- Expect.isTrue(x.library is library.A);
- Expect.isTrue(x.operator is operator.A);
- Expect.isTrue(x.part is part.A);
- Expect.isTrue(x.set is set.A);
- Expect.isTrue(x.static is static.A);
- Expect.isTrue(x.typedef is typedef.A);
-
- // Most of the following variables have malformed type annotations.
- if (assertionsEnabled) return;
-
- Expect.isTrue(generic_abstract is abstract.A);
- Expect.isTrue(generic_as is as.A);
- Expect.isTrue(generic_dynamic is dynamic.A);
- Expect.isTrue(generic_export is export.A);
- Expect.isTrue(generic_external is external.A);
- Expect.isTrue(generic_factory is factory.A);
- Expect.isTrue(generic_get is get.A);
- Expect.isTrue(generic_implements is implements.A);
- Expect.isTrue(generic_import is import.A);
- Expect.isTrue(generic_library is library.A);
- Expect.isTrue(generic_operator is operator.A);
- Expect.isTrue(generic_part is part.A);
- Expect.isTrue(generic_set is set.A);
- Expect.isTrue(generic_static is static.A);
- Expect.isTrue(generic_typedef is typedef.A);
-
- Expect.isTrue(parameterized_B_abstract is abstract.B);
- Expect.isTrue(parameterized_B_as is as.B);
- Expect.isTrue(parameterized_B_dynamic is dynamic.B);
- Expect.isTrue(parameterized_B_export is export.B);
- Expect.isTrue(parameterized_B_external is external.B);
- Expect.isTrue(parameterized_B_factory is factory.B);
- Expect.isTrue(parameterized_B_get is get.B);
- Expect.isTrue(parameterized_B_implements is implements.B);
- Expect.isTrue(parameterized_B_import is import.B);
- Expect.isTrue(parameterized_B_library is library.B);
- Expect.isTrue(parameterized_B_operator is operator.B);
- Expect.isTrue(parameterized_B_part is part.B);
- Expect.isTrue(parameterized_B_set is set.B);
- Expect.isTrue(parameterized_B_static is static.B);
- Expect.isTrue(parameterized_B_typedef is typedef.B);
-}
diff --git a/tests/language/conflicting_type_variable_and_setter_test.dart b/tests/language/conflicting_type_variable_and_setter_test.dart
new file mode 100644
index 0000000..2aca0c3
--- /dev/null
+++ b/tests/language/conflicting_type_variable_and_setter_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class C<D> {
+ void set D(int value) {
+ field = value;
+ }
+
+ int field;
+}
+
+main() {
+ C<int> c = new C<int>();
+ c.D = 1;
+ Expect.equals(c.field, 1);
+}
diff --git a/tests/language/deep_nesting1_negative_test.dart b/tests/language/deep_nesting1_negative_test.dart
new file mode 100644
index 0000000..e85c11c
--- /dev/null
+++ b/tests/language/deep_nesting1_negative_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2016, 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.
+
+// Deeply nested expression must not crash compiler due to stack overflow.
+
+main() {
+ var x =
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]];
+ print('okay');
+}
diff --git a/tests/language/deep_nesting2_negative_test.dart b/tests/language/deep_nesting2_negative_test.dart
new file mode 100644
index 0000000..cd49a07
--- /dev/null
+++ b/tests/language/deep_nesting2_negative_test.dart
@@ -0,0 +1,10012 @@
+// Copyright (c) 2016, 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.
+
+// Deeply nested statements must not crash compiler due to stack overflow.
+
+var x = 0;
+
+main() {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ if (x == 0) {
+ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ print("survived!");
+}
diff --git a/tests/language/deferred_import_core_test.dart b/tests/language/deferred_import_core_test.dart
new file mode 100644
index 0000000..f3d6644
--- /dev/null
+++ b/tests/language/deferred_import_core_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, 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.
+
+// Nothing in the language spec explicitly prohibits a deferred import of
+// 'dart:core'. Make sure it doesn't lead to any strange behavior.
+
+import "dart:core" deferred as core;
+
+main() {
+ core.loadLibrary().then((_) => null);
+}
diff --git a/tests/language/export_not_shadowed_by_prefix_helper.dart b/tests/language/export_not_shadowed_by_prefix_helper.dart
new file mode 100644
index 0000000..3dcd016
--- /dev/null
+++ b/tests/language/export_not_shadowed_by_prefix_helper.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, 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.
+
+export "export_not_shadowed_by_prefix_helper2.dart";
+import "dart:core" as f;
diff --git a/tests/language/export_not_shadowed_by_prefix_helper2.dart b/tests/language/export_not_shadowed_by_prefix_helper2.dart
new file mode 100644
index 0000000..ae2dca5
--- /dev/null
+++ b/tests/language/export_not_shadowed_by_prefix_helper2.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, 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.
+
+void f() {
+ f_called = true;
+}
+
+bool f_called = false;
diff --git a/tests/language/export_not_shadowed_by_prefix_test.dart b/tests/language/export_not_shadowed_by_prefix_test.dart
new file mode 100644
index 0000000..3af1b48
--- /dev/null
+++ b/tests/language/export_not_shadowed_by_prefix_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, 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.
+
+// Verify that import prefixes within an imported library don't shadow
+// names re-exported by that library.
+
+import "package:expect/expect.dart";
+import "export_not_shadowed_by_prefix_helper.dart";
+
+main() {
+ f();
+ Expect.isTrue(f_called);
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 65a750e..319fdb8 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -6,9 +6,13 @@
# current state of the language.
[ ($compiler == none || $compiler == precompiler) ]
-built_in_identifier_prefix_test: Fail # Issue 6970
tearoff_constructor_basic_test: Skip # Crashes in checked mode -- hausner investigating
-const_qq_test: Fail
+
+# These tests are skipped in the VM because it has "--supermixin"
+# functionality enabled unconditionally. The tests should be removed
+# once the same is true for analyzer (#24478) and dart2js (#23773)
+mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
+mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
# These bugs refer currently ongoing language discussions.
constructor5_test: Fail # Issue 6422
@@ -38,7 +42,10 @@
async_star_cancel_while_paused_test: RuntimeError
async_star_await_pauses_test: Skip # Times out. Issue 23996
+library_env_test: RuntimeError
+
[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) ]
+
class_keyword_test/02: MissingCompileTimeError # Issue 13627
unicode_bom_test: Fail # Issue 16067
vm/debug_break_enabled_vm_test/01: Crash, OK # Expected to hit breakpoint.
@@ -101,7 +108,7 @@
[ ($compiler == none || $compiler == precompiler) && $runtime == ContentShellOnAndroid ]
gc_test: SkipSlow # Times out flakily. Issue 20956
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ( $arch == simarm || $arch == arm || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
+[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ( $arch == simarm || $arch == arm || $arch == simarmv6 || $arch == armv6 || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
[ ($compiler == none || $compiler == precompiler) && $runtime == dartium ]
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 5ea3d0a..f549de2 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -7,9 +7,15 @@
# Runtime negative test. No static errors or warnings.
closure_call_wrong_argument_count_negative_test: skip
+deep_nesting1_negative_test: Crash # Issue 25558
+deep_nesting2_negative_test: Crash # Issue 25558
+
enum_syntax_test/05: Fail # 21649
enum_syntax_test/06: Fail # 21649
+mixin_illegal_constructor_test/20: MissingCompileTimeError # 25588
+mixin_illegal_constructor_test/21: MissingCompileTimeError # 25588
+
tearoff_basic_test: Skip # Tear-off not supported
tearoff_constructor_basic_test: Skip # Tear-off not supported
@@ -19,7 +25,6 @@
getter_setter_in_lib_test: Fail # issue 23286
# Test issue 12694 (was analyzer issue), (1) when "abstract" is import prefix using it as type is warning; (2) currently analyzer resolves prefix as field (don't ask)
-built_in_identifier_prefix_test: CompileTimeError # Issue 12694
# TBF: we should check conflicts not only for methods, but for accessors too
override_field_test/03: fail
@@ -305,11 +310,6 @@
mixin_invalid_bound_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
mixin_invalid_bound2_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
mixin_super_bound_test: StaticWarning # legitimate StaticWarning, cannot be annotated
-mixin_super_bound2_test: CompileTimeError # Issue 24478
-mixin_super_test: CompileTimeError # Issue 24478
-mixin_super_2_test: CompileTimeError # Issue 24478
-mixin_super_use_test: CompileTimeError # Issue 24478
-mixin_superclass_test: CompileTimeError # Issue 24478
named_constructor_test/01: StaticWarning
named_constructor_test/03: StaticWarning
named_parameters2_test: StaticWarning
@@ -483,4 +483,4 @@
# intentionally referring to a variable that's not in scope.
transitive_private_library_access_test: StaticWarning
-const_qq_test: Fail
+conflicting_type_variable_and_setter_test: CompileTimeError # Issue 25525
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 2dbad85..a1bb9e3 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -4,6 +4,7 @@
[ $compiler == dart2js ]
getter_setter_in_lib_test: Fail # Issue 23288
+method_name_test: Fail # issue 25574
async_star_cancel_while_paused_test: RuntimeError # Issue 22853
async_star_await_pauses_test: Fail, Timeout # Issue 22853
@@ -13,8 +14,21 @@
try_catch_on_syntax_test/10: Fail # Issue 19823
try_catch_on_syntax_test/11: Fail # Issue 19823
+mixin_illegal_constructor_test/20: MissingCompileTimeError # 25587
+mixin_illegal_constructor_test/21: MissingCompileTimeError # 25587
+
+deep_nesting1_negative_test: Crash # Issue 25557
+deep_nesting2_negative_test: Crash # Issue 25557
+
call_function_apply_test: RuntimeError # Issue 23873
+# The following tests are supposed to fail.
+# When run for testing dart2js supports all dart:X libraries (because it
+# uses '--categories=all').
+library_env_test/has_no_html_support: RuntimeError, OK
+library_env_test/has_no_io_support: RuntimeError, OK
+library_env_test/has_no_mirror_support: RuntimeError, OK
+
[ $compiler == dart2js && $runtime == jsshell ]
await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
async_star_test: RuntimeError # Jsshell does not provide non-zero timers, Issue 7728
@@ -138,7 +152,6 @@
branch_canonicalization_test: RuntimeError # Issue 638.
identical_closure2_test: RuntimeError # Issue 1533, Issue 12596
integer_division_by_zero_test: RuntimeError # Issue 8301
-built_in_identifier_prefix_test: CompileTimeError # Issue 6972
number_identity2_test: RuntimeError # Issue 12596
double_int_to_string_test: RuntimeError # Issue 1533
mint_arithmetic_test: RuntimeError # Issue 1533
@@ -241,9 +254,9 @@
async_await_syntax_test/d06a: Crash # (await for(var o in st){}): await for
async_await_syntax_test/d09a: Crash # (()async*{yield 0;}): cannot handle sync*/async* functions
async_await_syntax_test/d10a: Crash # (()async*{yield* [] ;}): cannot handle sync*/async* functions
-async_await_test/02: Crash # (switch (v){label:ca... continue to a labeled switch case
-async_await_test/03: Crash # (switch (v){label:ca... continue to a labeled switch case
-async_await_test/none: Crash # (switch (v){label:ca... continue to a labeled switch case
+async_await_test/02: Crash # bailout: (await for
+async_await_test/03: Crash # bailout: (await for
+async_await_test/none: Crash # bailout: (await for
async_or_generator_return_type_stacktrace_test/02: Crash # (void badReturnTypeAsyncStar()async*{}): cannot handle sync*/async* functions
async_return_types_test/nestedFuture: Crash # cannot handle sync*/async* functions
async_return_types_test/none: Crash # cannot handle sync*/async* functions
@@ -267,26 +280,12 @@
await_for_test: Crash # (await for(var x in infiniteStream()){i++ ;if(i>10)break;t4.record(x);}): await for
await_for_use_local_test: Crash # (await for(var v in s){accum+= v;}): await for
call_closurization_test: RuntimeError # Bad type inference for ".call" tear-off.
-closure_in_constructor_test: RuntimeError # Please triage this failure.
-closures_initializer_test: RuntimeError # Please triage this failure.
-constructor12_test: RuntimeError # Please triage this failure.
deferred_super_dependency_test/01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
field3a_negative_test: Fail # Bogus result from type inference in case of invalid program.
-first_class_types_test: RuntimeError # Please triage this failure.
-generic2_test: RuntimeError # Please triage this failure.
-generic_instanceof_test: RuntimeError # Please triage this failure.
-generic_native_test: RuntimeError # Please triage this failure.
gc_test: Crash # Internal Error: Pending statics (see above).
-infinite_switch_label_test: Crash # (switch (target){l0:... continue to a labeled switch case
-instanceof2_test: RuntimeError # Please triage this failure.
-instanceof4_test/01: RuntimeError # Please triage this failure.
invocation_mirror_test: Crash # (super[37]=42): visitUnresolvedSuperIndexSet
-list_is_test: RuntimeError # Please triage this failure.
-list_test: RuntimeError # Please triage this failure.
-many_generic_instanceof_test: RuntimeError # Please triage this failure.
-nested_switch_label_test: Crash # (switch (target){out... continue to a labeled switch case
regress_23500_test/01: Crash # (await for(var c in new Stream.fromIterable([] )){}): await for
-stack_trace_test: Fail # Stack trace not preserved when inlining?
+savannah_test: RuntimeError # Success depends on the variable hints.
super_call4_test: RuntimeError # Please triage this failure.
super_getter_setter_test: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
super_operator_index5_test: Crash # (super[0]=42): visitUnresolvedSuperIndexSet
@@ -294,14 +293,7 @@
super_operator_index8_test: Crash # (super[f()]=g()): visitUnresolvedSuperIndexSet
super_operator_index_test/03: Crash # (super[4]=42): visitUnresolvedSuperIndexSet
super_operator_index_test/05: Crash # (super[4]=42): visitUnresolvedSuperIndexSet
-switch_label2_test: Crash # (switch (target){cas... continue to a labeled switch case
-switch_label_test: Crash # (switch (animal){cas... continue to a labeled switch case
-switch_try_catch_test: Crash # (switch (0){_0:case ... continue to a labeled switch case
-type_variable_closure2_test: RuntimeError # Issue 25309: T lost in List<T>
-type_variable_closure4_test: RuntimeError # T lost in <T,T>{}
-type_variable_field_initializer_closure_test: RuntimeError # Issue 25309: T lost in List<T>
-type_variable_field_initializer_test: RuntimeError # Issue 25309: T lost in List<T>
-type_variable_nested_test: RuntimeError # Issue 25309: T lost in List<T>
+switch8_test: Crash # Pending statics: JSArray
[ $compiler == dart2js && $cps_ir && $host_checked == false ]
regress_21795_test: Pass, RuntimeError # Due to inlining?
diff --git a/tests/language/library_env_test.dart b/tests/language/library_env_test.dart
new file mode 100644
index 0000000..d076ede
--- /dev/null
+++ b/tests/language/library_env_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+main() {
+ const NOT_PRESENT = null;
+
+ Expect.isTrue(const bool.fromEnvironment("dart.library.async"));
+ Expect.isTrue(const bool.fromEnvironment("dart.library.collection"));
+ Expect.isTrue(const bool.fromEnvironment("dart.library.convert"));
+ Expect.isTrue(const bool.fromEnvironment("dart.library.core"));
+ Expect.isTrue(const bool.fromEnvironment("dart.library.typed_data"));
+
+
+ bool hasHtmlSupport;
+ hasHtmlSupport = true; /// has_html_support: ok
+ hasHtmlSupport = false; /// has_no_html_support: ok
+
+ if (hasHtmlSupport != null) {
+ bool expectedResult = hasHtmlSupport ? true : NOT_PRESENT;
+
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.html",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.indexed_db",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.svg",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.web_audio",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.web_gl",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.web_sql",
+ defaultValue: NOT_PRESENT));
+ }
+
+ bool hasIoSupport;
+ hasIoSupport = true; /// has_io_support: ok
+ hasIoSupport = false; /// has_no_io_support: ok
+
+ if (hasIoSupport != null) {
+ bool expectedResult = hasIoSupport ? true : NOT_PRESENT;
+
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.io",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.developer",
+ defaultValue: NOT_PRESENT));
+ }
+
+ bool hasMirrorSupport;
+ hasMirrorSupport = true; /// has_mirror_support: ok
+ hasMirrorSupport = false; /// has_no_mirror_support: ok
+
+ if (hasMirrorSupport != null) {
+ bool expectedResult = hasMirrorSupport ? true : NOT_PRESENT;
+
+ Expect.equals(expectedResult,
+ const bool.fromEnvironment("dart.library.mirrors",
+ defaultValue: NOT_PRESENT));
+ }
+
+ Expect.equals(NOT_PRESENT,
+ const bool.fromEnvironment("dart.library.XYZ",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(NOT_PRESENT,
+ const bool.fromEnvironment("dart.library.Collection",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(NOT_PRESENT,
+ const bool.fromEnvironment("dart.library.converT",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(NOT_PRESENT,
+ const bool.fromEnvironment("dart.library.",
+ defaultValue: NOT_PRESENT));
+ Expect.equals(NOT_PRESENT,
+ const bool.fromEnvironment("dart.library.core ",
+ defaultValue: NOT_PRESENT));
+
+}
diff --git a/tests/language/method_name_test.dart b/tests/language/method_name_test.dart
index b0199cf..ea9c7d2 100644
--- a/tests/language/method_name_test.dart
+++ b/tests/language/method_name_test.dart
@@ -12,6 +12,7 @@
int get() {return 1;}
int set() {return 2;}
int operator() {return 3;}
+ int factory() { return 4; }
}
// Without return types.
@@ -19,6 +20,7 @@
get() {return 1;}
set() {return 2;}
operator() {return 3;}
+ factory() { return 4; }
}
main() {
@@ -27,11 +29,13 @@
Expect.equals(1, a.get());
Expect.equals(2, a.set());
Expect.equals(3, a.operator());
+ Expect.equals(4, a.factory());
}
{
B b = new B();
Expect.equals(1, b.get());
Expect.equals(2, b.set());
Expect.equals(3, b.operator());
+ Expect.equals(4, b.factory());
}
}
diff --git a/tests/language/mixin_illegal_constructor_test.dart b/tests/language/mixin_illegal_constructor_test.dart
index d0a59fb..8884084 100644
--- a/tests/language/mixin_illegal_constructor_test.dart
+++ b/tests/language/mixin_illegal_constructor_test.dart
@@ -15,7 +15,7 @@
M2.named();
}
-class C0 = Object with M0;
+class C0 = Object with M0; /// 20: compile-time error
class C1 = Object with M1; /// 01: compile-time error
class C2 = Object with M2; /// 02: compile-time error
class C3 = Object with M0, M1; /// 03: compile-time error
@@ -23,7 +23,7 @@
class C5 = Object with M0, M2; /// 05: compile-time error
class C6 = Object with M2, M0; /// 06: compile-time error
-class D0 extends Object with M0 { }
+class D0 extends Object with M0 { } /// 21: compile-time error
class D1 extends Object with M1 { } /// 07: compile-time error
class D2 extends Object with M2 { } /// 08: compile-time error
class D3 extends Object with M0, M1 { } /// 09: compile-time error
@@ -32,7 +32,7 @@
class D6 extends Object with M2, M0 { } /// 12: compile-time error
main() {
- new C0();
+ new C0(); /// 20: continued
new C1(); /// 01: continued
new C2(); /// 02: continued
new C3(); /// 03: continued
@@ -40,16 +40,11 @@
new C5(); /// 05: continued
new C6(); /// 06: continued
- new D0();
+ new D0(); /// 21: continued
new D1(); /// 07: continued
new D2(); /// 08: continued
new D3(); /// 09: continued
new D4(); /// 10: continued
new D5(); /// 11: continued
new D6(); /// 12: continued
-
- new C0(1,2,3); /// 13: static type warning, runtime error
- new C0.named(); /// 14: static type warning, runtime error
- new D0(1,2,3); /// 15: static type warning, runtime error
- new D0.named(); /// 16: static type warning, runtime error
}
diff --git a/tests/language/mixin_illegal_super_use_test.dart b/tests/language/mixin_illegal_super_use_test.dart
new file mode 100644
index 0000000..7f0d64a
--- /dev/null
+++ b/tests/language/mixin_illegal_super_use_test.dart
@@ -0,0 +1,71 @@
+// 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:expect/expect.dart";
+
+class M {
+}
+
+class P0 {
+ foo() {
+ super.toString(); /// 01: compile-time error
+ super.foo(); /// 02: compile-time error
+ super.bar = 100; /// 03: compile-time error
+
+ void inner() {
+ super.toString(); /// 04: compile-time error
+ super.foo(); /// 05: compile-time error
+ super.bar = 100; /// 06: compile-time error
+ }
+ inner();
+
+ (() {
+ super.toString(); /// 07: compile-time error
+ super.foo(); /// 08: compile-time error
+ super.bar = 100; /// 09: compile-time error
+ })();
+
+ return 42;
+ }
+}
+
+class P1 {
+ bar() {
+ super.toString(); /// 10: compile-time error
+ return 87;
+ }
+
+ // The test method is strategically placed here to try to force the
+ // P1 class and its bar method to be resolved before resolving the
+ // mixin applications.
+ test() {
+ new C();
+ var d = new D();
+ var e = new E();
+ var f = new F();
+ Expect.equals(42, d.foo());
+ Expect.equals(87, e.bar());
+ Expect.equals(99, f.baz());
+ }
+}
+
+class P2 {
+ baz() {
+ super.toString(); /// 11: compile-time error
+ return 99;
+ }
+}
+
+class C = Object with M;
+class D = Object with P0;
+class E = Object with M, P1;
+class F = Object with P2, M;
+
+main() {
+ var p1 = new P1();
+ var p2 = new P2();
+ Expect.equals(87, p1.bar());
+ p1.test();
+ Expect.equals(99, p2.baz());
+}
diff --git a/tests/language/mixin_illegal_superclass_test.dart b/tests/language/mixin_illegal_superclass_test.dart
new file mode 100644
index 0000000..03d2e6a
--- /dev/null
+++ b/tests/language/mixin_illegal_superclass_test.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.
+
+class S0 { }
+class S1 extends Object { }
+class S2 extends S0 { }
+
+class M0 { }
+class M1 extends Object { }
+class M2 extends M0 { }
+
+class C00 = S0 with M0;
+class C01 = S0 with M1;
+class C02 = S0 with M2; /// 01: compile-time error
+class C03 = S0 with M0, M1;
+class C04 = S0 with M0, M2; /// 02: compile-time error
+class C05 = S0 with M2, M0; /// 03: compile-time error
+class C06 = S0 with M1, M2; /// 04: compile-time error
+class C07 = S0 with M2, M1; /// 05: compile-time error
+
+class C10 = S1 with M0;
+class C11 = S1 with M1;
+class C12 = S1 with M2; /// 06: compile-time error
+class C13 = S1 with M0, M1;
+class C14 = S1 with M0, M2; /// 07: compile-time error
+class C15 = S1 with M2, M0; /// 08: compile-time error
+class C16 = S1 with M1, M2; /// 09: compile-time error
+class C17 = S1 with M2, M1; /// 10: compile-time error
+
+class C20 = S2 with M0;
+class C21 = S2 with M1;
+class C22 = S2 with M2; /// 11: compile-time error
+class C23 = S2 with M0, M1;
+class C24 = S2 with M0, M2; /// 12: compile-time error
+class C25 = S2 with M2, M0; /// 13: compile-time error
+class C26 = S2 with M1, M2; /// 14: compile-time error
+class C27 = S2 with M2, M1; /// 15: compile-time error
+
+class D00 extends S0 with M0 { }
+class D01 extends S0 with M1 { }
+class D02 extends S0 with M2 { } /// 16: compile-time error
+class D03 extends S0 with M0, M1 { }
+class D04 extends S0 with M0, M2 { } /// 17: compile-time error
+class D05 extends S0 with M2, M0 { } /// 18: compile-time error
+class D06 extends S0 with M1, M2 { } /// 19: compile-time error
+class D07 extends S0 with M2, M1 { } /// 20: compile-time error
+
+class D10 extends S1 with M0 { }
+class D11 extends S1 with M1 { }
+class D12 extends S1 with M2 { } /// 21: compile-time error
+class D13 extends S1 with M0, M1 { }
+class D14 extends S1 with M0, M2 { } /// 22: compile-time error
+class D15 extends S1 with M2, M0 { } /// 23: compile-time error
+class D16 extends S1 with M1, M2 { } /// 24: compile-time error
+class D17 extends S1 with M2, M1 { } /// 25: compile-time error
+
+class D20 extends S2 with M0 { }
+class D21 extends S2 with M1 { }
+class D22 extends S2 with M2 { } /// 26: compile-time error
+class D23 extends S2 with M0, M1 { }
+class D24 extends S2 with M0, M2 { } /// 27: compile-time error
+class D25 extends S2 with M2, M0 { } /// 28: compile-time error
+class D26 extends S2 with M1, M2 { } /// 29: compile-time error
+class D27 extends S2 with M2, M1 { } /// 30: compile-time error
+
+main() {
+ new C00();
+ new C01();
+ new C02(); /// 01: continued
+ new C03();
+ new C04(); /// 02: continued
+ new C05(); /// 03: continued
+ new C06(); /// 04: continued
+ new C07(); /// 05: continued
+
+ new C10();
+ new C11();
+ new C12(); /// 06: continued
+ new C13();
+ new C14(); /// 07: continued
+ new C15(); /// 08: continued
+ new C16(); /// 09: continued
+ new C17(); /// 10: continued
+
+ new C20();
+ new C21();
+ new C22(); /// 11: continued
+ new C23();
+ new C24(); /// 12: continued
+ new C25(); /// 13: continued
+ new C26(); /// 14: continued
+ new C27(); /// 15: continued
+
+ new D00();
+ new D01();
+ new D02(); /// 16: continued
+ new D03();
+ new D04(); /// 17: continued
+ new D05(); /// 18: continued
+ new D06(); /// 19: continued
+ new D07(); /// 20: continued
+
+ new D10();
+ new D11();
+ new D12(); /// 21: continued
+ new D13();
+ new D14(); /// 22: continued
+ new D15(); /// 23: continued
+ new D16(); /// 24: continued
+ new D17(); /// 25: continued
+
+ new D20();
+ new D21();
+ new D22(); /// 26: continued
+ new D23();
+ new D24(); /// 27: continued
+ new D25(); /// 28: continued
+ new D26(); /// 29: continued
+ new D27(); /// 30: continued
+}
diff --git a/tests/language/mixin_super_2_test.dart b/tests/language/mixin_super_2_test.dart
index ad86c08..91d68c6 100644
--- a/tests/language/mixin_super_2_test.dart
+++ b/tests/language/mixin_super_2_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
import "package:expect/expect.dart";
diff --git a/tests/language/mixin_super_bound2_test.dart b/tests/language/mixin_super_bound2_test.dart
index c6fcd7a..87e8b7a 100644
--- a/tests/language/mixin_super_bound2_test.dart
+++ b/tests/language/mixin_super_bound2_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
import "package:expect/expect.dart";
diff --git a/tests/language/mixin_super_test.dart b/tests/language/mixin_super_test.dart
index 6a5d5a3..8a4ee98 100644
--- a/tests/language/mixin_super_test.dart
+++ b/tests/language/mixin_super_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
import "package:expect/expect.dart";
diff --git a/tests/language/mixin_super_use_test.dart b/tests/language/mixin_super_use_test.dart
index cd95846..614bb632c 100644
--- a/tests/language/mixin_super_use_test.dart
+++ b/tests/language/mixin_super_use_test.dart
@@ -1,6 +1,7 @@
// 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.
+// SharedOptions=--supermixin
import "package:expect/expect.dart";
diff --git a/tests/language/mixin_superclass_test.dart b/tests/language/mixin_superclass_test.dart
index ade41da..1e658e8 100644
--- a/tests/language/mixin_superclass_test.dart
+++ b/tests/language/mixin_superclass_test.dart
@@ -1,6 +1,7 @@
// 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.
+// SharedOptions=--supermixin
class S0 { }
class S1 extends Object { }
diff --git a/tests/language/proxy4_test.dart b/tests/language/proxy4_test.dart
new file mode 100644
index 0000000..a7d44b5
--- /dev/null
+++ b/tests/language/proxy4_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for static warnings for member access on classes that inherit a
+// user defined noSuchMethod.
+
+class Mock {
+ noSuchMethod(i) => 42;
+}
+
+abstract class Foo { int foo(); }
+
+class DontWarnMe extends Mock implements Foo {}
+
+main() {
+ print(new DontWarnMe().foo());
+}
\ No newline at end of file
diff --git a/tests/language/proxy5_test.dart b/tests/language/proxy5_test.dart
new file mode 100644
index 0000000..41e63e6
--- /dev/null
+++ b/tests/language/proxy5_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for static warnings for member access on classes that inherit a
+// user defined noSuchMethod, even if it is abstract.
+
+import 'package:expect/expect.dart';
+
+abstract class Mock {
+ noSuchMethod(i);
+}
+
+abstract class Foo { int foo(); }
+
+class DontWarnMe extends Mock implements Foo {}
+
+main() {
+ Expect.throws(() => new DontWarnMe().foo());
+}
\ No newline at end of file
diff --git a/tests/language/regress_24567_test.dart b/tests/language/regress_24567_test.dart
new file mode 100644
index 0000000..e72750a
--- /dev/null
+++ b/tests/language/regress_24567_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:math' as math;
+
+class Random { }
+
+typedef F(Random r);
+
+main() {
+ f(Random r) { }
+ g(math.Random r) { }
+ Expect.isTrue(f is F);
+ Expect.isFalse(g is F);
+}
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index 4016986..3288d18 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -24,5 +24,5 @@
lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError # Issue 21647
lib/web_audio/dartium/web_audio_dartium: CompileTimeError # Issue 21647
lib/svg/dartium/svg_dartium: CompileTimeError # Issue 21647
-lib/_blink/dartium/_blink_dartium: CompileTimeError # Dartium JsInterop roll (js.JsObjectImpl)
-lib/js/dartium/js_dartium: CompileTimeError # Dartium JsInterop roll (js.JsObjectImpl)
+lib/_blink/dartium/_blink_dartium: CompileTimeError # Undefined Creates and Returns classes
+lib/js/dartium/js_dartium: CompileTimeError # Undefined Creates and Returns classes
\ No newline at end of file
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index d4cdafe..f5d5af2 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -170,7 +170,6 @@
[ $compiler == dart2js && $checked ]
convert/utf85_test: Pass, Slow # Issue 12029.
-mirrors/list_constructor_test/01: RuntimeError # Issue 19635.
[ $compiler == dart2js ]
convert/chunked_conversion_utf88_test: Slow, Pass
@@ -292,9 +291,6 @@
profiler/metrics_test: Fail # Issue 20309
profiler/metrics_num_test: Fail # Issue 20309
-[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
-mirrors/metadata_allowed_values_test/29: Crash # Issue 25287
-
[ ($compiler == dartanalyzer || $compiler == dart2analyzer) && $checked ]
mirrors/regress_16321_test/01: MissingCompileTimeError # Issue 16391
@@ -308,7 +304,7 @@
[ ($compiler == none || $compiler == precompiler) && $arch == mips ]
async/timer_regress22626_test: Pass, RuntimeError # Issue 22626
-[ $arch == simarm || $arch == simarmv5te ]
+[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te ]
convert/chunked_conversion_utf88_test: Skip # Pass, Slow Issue 12644.
convert/utf85_test: Skip # Pass, Slow Issue 12644.
@@ -331,7 +327,7 @@
[ ($runtime == vm || $runtime == dart_precompiled) && $mode == release && $arch == ia32 && $system == windows ]
convert/json_test: RuntimeError # Issue 24908
-[ $mode == debug && $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv5te ]
+[ $mode == debug && $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv6 && $arch != simarmv5te ]
convert/streamed_conversion_json_utf8_decode_test: Skip # Verification not yet implemented.
[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $builder_tag == asan ]
@@ -341,6 +337,7 @@
[ $compiler == dart2js && $cps_ir ]
async/async_await_zones_test: Crash # (await for(var x in bar().take(100)){sum+= x;}): await for
async/stream_iterator_test: Crash # (Stream createCancel... cannot handle sync*/async* functions
+mirrors/parameter_annotation_mirror_test: Pass, Fail # Issue 25501. Depends on inlining.
mirrors/symbol_validation_test/none: RuntimeError # Please triage this failure.
[ $compiler == dart2js && $cps_ir && $host_checked ]
diff --git a/tests/lib/mirrors/constructor_optional_args_test.dart b/tests/lib/mirrors/constructor_optional_args_test.dart
new file mode 100644
index 0000000..f9d9657
--- /dev/null
+++ b/tests/lib/mirrors/constructor_optional_args_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2016, 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.constructor_test;
+
+@MirrorsUsed(targets: const [A])
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class A {
+ factory A([x, y]) = B;
+ factory A.more([x, y]) = B.more;
+ factory A.oneMore(x, [y]) = B.more;
+}
+
+class B implements A {
+ final _x, _y, _z;
+
+ B([x = 'x', y = 'y']) : _x = x, _y = y, _z = null;
+
+ B.more([x = 'x', y = 'y', z = 'z']) : _x = x, _y = y, _z = z;
+
+ toString() => 'B(x=$_x, y=$_y, z=$_z)';
+}
+
+
+main() {
+ var d1 = new A(1);
+ Expect.equals('B(x=1, y=y, z=null)', '$d1', 'direct 1');
+
+ var d2 = new A.more(1);
+ Expect.equals('B(x=1, y=y, z=z)', '$d2', 'direct 2');
+
+ ClassMirror cm = reflectClass(A);
+
+ var v1 = cm.newInstance(const Symbol(''), []).reflectee;
+ var v2 = cm.newInstance(const Symbol(''), [1]).reflectee;
+ var v3 = cm.newInstance(const Symbol(''), [2, 3]).reflectee;
+
+ Expect.equals('B(x=x, y=y, z=null)', '$v1', 'unnamed 1');
+ Expect.equals('B(x=1, y=y, z=null)', '$v2', 'unnamed 2');
+ Expect.equals('B(x=2, y=3, z=null)', '$v3', 'unnamed 3');
+
+ var m1 = cm.newInstance(const Symbol('more'), []).reflectee;
+ var m2 = cm.newInstance(const Symbol('more'), [1]).reflectee;
+ var m3 = cm.newInstance(const Symbol('more'), [2, 3]).reflectee;
+
+ Expect.equals('B(x=x, y=y, z=z)', '$m1', 'more 1');
+ Expect.equals('B(x=1, y=y, z=z)', '$m2', 'more 2');
+ Expect.equals('B(x=2, y=3, z=z)', '$m3', 'more 3');
+
+ var o1 = cm.newInstance(const Symbol('oneMore'), [1]).reflectee;
+ var o2 = cm.newInstance(const Symbol('oneMore'), [2, 3]).reflectee;
+
+ Expect.equals('B(x=1, y=y, z=z)', '$o1', 'oneMore one arg');
+ Expect.equals('B(x=2, y=3, z=z)', '$o2', 'oneMore two args');
+}
diff --git a/tests/standalone/io/web_socket_compression_test.dart b/tests/standalone/io/web_socket_compression_test.dart
index 912b855..e25bc1b 100644
--- a/tests/standalone/io/web_socket_compression_test.dart
+++ b/tests/standalone/io/web_socket_compression_test.dart
@@ -130,6 +130,43 @@
});
}
+ void testContextSupport({CompressionOptions serverOpts,
+ CompressionOptions clientOpts,
+ int messages}) {
+ asyncStart();
+
+ createServer().then((server) {
+ server.listen((request) {
+ Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request));
+ WebSocketTransformer.upgrade(request, compression: serverOpts)
+ .then((webSocket) {
+ webSocket.listen((message) {
+ Expect.equals("Hello World", message);
+ webSocket.add(message);
+ });
+ });
+ });
+
+ var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/';
+ WebSocket.connect(url, compression: clientOpts).then((websocket) {
+ var i = 1;
+ websocket.listen((message) {
+ Expect.equals("Hello World", message);
+ if (i == messages) {
+ websocket.close();
+ return;
+ }
+ websocket.add("Hello World");
+ i++;
+ }, onDone: () {
+ server.close();
+ asyncEnd();
+ });
+ websocket.add("Hello World");
+ });
+ });
+ }
+
void testCompressionHeaders() {
asyncStart();
createServer().then((server) {
@@ -271,6 +308,31 @@
// Compression on server but not client.
testCompressionSupport(server: true);
+ // Test Multiple messages with various context takeover configurations.
+ // no context takeover on the server.
+ var serverComp = new CompressionOptions(serverNoContextTakeover: true);
+ testContextSupport(serverOpts: serverComp,
+ clientOpts: serverComp,
+ messages: 5);
+ // no contexttakeover on the client.
+ var clientComp = new CompressionOptions(clientNoContextTakeover: true);
+ testContextSupport(serverOpts: clientComp,
+ clientOpts: clientComp,
+ messages: 5);
+ // no context takeover enabled for both.
+ var compression = new CompressionOptions(serverNoContextTakeover: true,
+ clientNoContextTakeover: true);
+ testContextSupport(serverOpts: compression,
+ clientOpts: compression,
+ messages: 5);
+ // no context take over for opposing configurations.
+ testContextSupport(serverOpts: serverComp,
+ clientOpts: clientComp,
+ messages: 5);
+ testContextSupport(serverOpts: clientComp,
+ clientOpts: serverComp,
+ messages: 5);
+
testCompressionHeaders();
// Chrome headers
testReturnHeaders('permessage-deflate; client_max_window_bits',
@@ -289,7 +351,7 @@
'client_no_context_takeover',
'permessage-deflate; client_max_window_bits=15');
// Enable context Takeover and provide if requested.
- var compression = new CompressionOptions(clientNoContextTakeover: true,
+ compression = new CompressionOptions(clientNoContextTakeover: true,
serverNoContextTakeover: true);
testReturnHeaders('permessage-deflate; client_max_window_bits; '
'client_no_context_takeover',
diff --git a/tests/standalone/precompilation_dart2js_test.dart b/tests/standalone/precompilation_dart2js_test.dart
index 5d3900e..d7a8b71 100644
--- a/tests/standalone/precompilation_dart2js_test.dart
+++ b/tests/standalone/precompilation_dart2js_test.dart
@@ -87,7 +87,7 @@
var ld_library_path = new String.fromEnvironment("LD_LIBRARY_PATH");
ld_library_path = "${ld_library_path}:${tmp.path}";
- exec = "${dart_executable}_precompiled";
+ exec = "${dart_executable}_precompiled_runtime";
args = ["--run-precompiled-snapshot", "ignored_script", "--version"];
print("LD_LIBRARY_PATH=$ld_library_path $exec ${args.join(' ')}");
result = Process.runSync(exec, args,
diff --git a/tests/standalone/precompilation_test.dart b/tests/standalone/precompilation_test.dart
index 751682e..e58c5fe 100644
--- a/tests/standalone/precompilation_test.dart
+++ b/tests/standalone/precompilation_test.dart
@@ -86,7 +86,7 @@
ld_library_path = "${ld_library_path}:${tmp.path}";
result = Process.runSync(
- "${dart_executable}_precompiled",
+ "${dart_executable}_precompiled_runtime",
["--run-precompiled-snapshot", "ignored_script", "--hello"],
workingDirectory: tmp.path,
environment: {"LD_LIBRARY_PATH": ld_library_path});
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 590489e..8b09928 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -140,7 +140,7 @@
[ $compiler == dart2js && $browser ]
*: Skip
-[ $arch == simarm || $arch == simarmv5te || $arch == simmips ]
+[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simmips ]
out_of_memory_test: Skip # passes on Mac, crashes on Linux
oom_error_stacktrace_test: Skip # Fails on Linux
@@ -268,4 +268,4 @@
io/test_extension_test: RuntimeError # Platform.executable
io/regress_7679_test: RuntimeError # Platform.executable
-io/process_*: Skip # Most use Platform.executable
\ No newline at end of file
+io/process_*: Skip # Most use Platform.executable
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index bf69360..e81c804 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -5,8 +5,10 @@
[ $compiler == dart2js && $host_checked ]
dummy_compiler_test: Crash # Issue 22809
-[ $compiler == dart2js ]
+[ $compiler == dart2js && $host_checked == false ]
dummy_compiler_test: Slow, Pass
+
+[ $compiler == dart2js ]
recursive_import_test: Slow, Pass
source_mirrors_test: Slow, Pass
@@ -25,10 +27,5 @@
recursive_import_test: Pass, RuntimeError # Issue 17662
source_mirrors_test: Pass, RuntimeError # Issue 17662
-[ $compiler == dart2js && $cps_ir ]
-dummy_compiler_test: Crash # (switch (function.na... continue to a labeled switch case
-recursive_import_test: Crash # (switch (function.na... continue to a labeled switch case
-source_mirrors_test: Crash, Slow # (switch (function.na... continue to a labeled switch case
-
[ ($noopt || $compiler == precompiler) ]
source_mirrors_test: SkipByDesign # Imports dart:mirrors
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 3f481f1..074f02f 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -11,4 +11,5 @@
!7zip.tar.gz.sha1
!firefox_jsshell
!gsutil.tar.gz.sha1
-!clang.tar.gz.sha1
\ No newline at end of file
+!clang.tar.gz.sha1
+!unittest.tar.gz.sha1
diff --git a/third_party/boringssl/boringssl_configurations.gypi b/third_party/boringssl/boringssl_configurations.gypi
index 91c76c1..0a82431 100644
--- a/third_party/boringssl/boringssl_configurations.gypi
+++ b/third_party/boringssl/boringssl_configurations.gypi
@@ -66,6 +66,27 @@
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO', # -Werror off
},
},
+ # Disable hand-coded assembly routines on ARMv6 and ARMv5TE.
+ 'Dart_armv6_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'OPENSSL_NO_ASM',
+ ],
+ },
+ 'Dart_armv5te_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'OPENSSL_NO_ASM',
+ ],
+ },
+ # TODO(24321): Also disable temporarily on arm64. Reenable after the next
+ # roll.
+ 'Dart_arm64_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'OPENSSL_NO_ASM',
+ ],
+ },
# When being built for Android nss expects __linux__ to be defined.
'Dart_Android_Base': {
'target_conditions': [
@@ -96,4 +117,4 @@
},
},
},
-}
\ No newline at end of file
+}
diff --git a/third_party/pkg/unittest.tar.gz.sha1 b/third_party/pkg/unittest.tar.gz.sha1
new file mode 100644
index 0000000..2a8a5c2
--- /dev/null
+++ b/third_party/pkg/unittest.tar.gz.sha1
@@ -0,0 +1 @@
+fc9b8ccbfbecf20257255d69693d5a50f8692757
\ No newline at end of file
diff --git a/third_party/pkg_tested/pkg_tested.status b/third_party/pkg_tested/pkg_tested.status
index 031b82b..9a58476 100644
--- a/third_party/pkg_tested/pkg_tested.status
+++ b/third_party/pkg_tested/pkg_tested.status
@@ -23,7 +23,7 @@
pub/test/run/app_can_read_from_stdin_test: Fail # Issue 19448
pub/test/run/forwards_signal_posix_test: SkipByDesign
-[ $runtime == vm && ($mode == debug || $arch == mips || $arch == simmips || $arch == simarm || $arch == simarmv5te || $arch == simarm64 || $builder_tag == asan) ]
+[ $runtime == vm && ($mode == debug || $arch == mips || $arch == simmips || $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $builder_tag == asan) ]
dart_style/test/command_line_test: Skip # The test controller does not take into account that tests take much longer in debug mode or on simulators/mips.
dart_style/test/formatter_test: Skip # The test controller does not take into account that tests take much longer in debug mode or on simulators/mips.
diff --git a/tools/VERSION b/tools/VERSION
index 4c7a8a0..a14f088 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
#
CHANNEL dev
MAJOR 1
-MINOR 14
+MINOR 15
PATCH 0
-PRERELEASE 7
-PRERELEASE_PATCH 2
+PRERELEASE 0
+PRERELEASE_PATCH 0
diff --git a/tools/build.py b/tools/build.py
index dac178f..91d6864 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -55,8 +55,8 @@
default=False, action="store_true")
result.add_option("-a", "--arch",
help='Target architectures (comma-separated).',
- metavar='[all,ia32,x64,simarm,arm,simarmv5te,armv5te,simmips,mips'
- ',simarm64,arm64,]',
+ metavar='[all,ia32,x64,simarm,arm,simarmv6,armv6,simarmv5te,armv5te,'
+ 'simmips,mips,simarm64,arm64,]',
default=utils.GuessArchitecture())
result.add_option("--os",
help='Target OSs (comma-separated).',
@@ -101,8 +101,8 @@
print "Unknown mode %s" % mode
return False
for arch in options.arch:
- archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv5te', 'armv5te', 'simmips',
- 'mips', 'simarm64', 'arm64',]
+ archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv6', 'armv6',
+ 'simarmv5te', 'armv5te', 'simmips', 'mips', 'simarm64', 'arm64',]
if not arch in archs:
print "Unknown arch %s" % arch
return False
@@ -119,7 +119,7 @@
print ("Cross-compilation to %s is not supported on host os %s."
% (os_name, HOST_OS))
return False
- if not arch in ['ia32', 'arm', 'armv5te', 'arm64', 'mips']:
+ if not arch in ['ia32', 'arm', 'armv6', 'armv5te', 'arm64', 'mips']:
print ("Cross-compilation to %s is not supported for architecture %s."
% (os_name, arch))
return False
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index fbb0e6b..accf568 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -14,7 +14,7 @@
"dartium_chromium_commit": "62a7524d4f71c9e0858d24b0aa1bbff3a2d09bff",
"chromium_base_revision": "297060",
"dartium_webkit_branch": "/blink/branches/dart/dartium",
- "dartium_webkit_revision": "202748",
+ "dartium_webkit_revision": "202760",
# We use mirrors of all github repos to guarantee reproducibility and
# consistency between what users see and what the bots see.
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 92a5ed0..6d235b81 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -546,14 +546,10 @@
if (wrap_unwrap_type_blink(type_id, type_registry)):
type_is_callback = self.isCallback(type_registry, type_id)
if (dart_js_interop and type_id == 'EventListener' and
- (self.name == 'addEventListener')):
+ self.name in ['addEventListener', 'removeEventListener']):
# Events fired need use a JsFunction not a anonymous closure to
# insure the event can really be removed.
- parameters.append('wrap_event_listener(this, %s)' % p.name)
- elif (dart_js_interop and type_id == 'EventListener' and
- (self.name == 'removeEventListener')):
- # Find the JsFunction that corresponds to this Dart function.
- parameters.append('_knownListeners[this.hashCode][identityHashCode(%s)]' % p.name)
+ parameters.append('unwrap_jso(js.allowInterop(%s))' % p.name)
elif dart_js_interop and type_id == 'FontFaceSetForEachCallback':
# forEach is supported in the DOM for FontFaceSet as it iterates
# over the Javascript Object the callback parameters are also
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 24ecbb8..09c242d 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -614,9 +614,7 @@
return new {0}._internalWrap();
}}
- factory {0}._internalWrap() {{
- return new {0}.internal_();
- }}
+ external factory {0}._internalWrap();
@Deprecated("Internal Use Only")
{0}.internal_() : super.internal_();
diff --git a/tools/dom/src/dartium_CustomElementSupport.dart b/tools/dom/src/dartium_CustomElementSupport.dart
index aec7b4a..e769e88 100644
--- a/tools/dom/src/dartium_CustomElementSupport.dart
+++ b/tools/dom/src/dartium_CustomElementSupport.dart
@@ -44,7 +44,7 @@
throw new UnsupportedError('$tag is not registered.');
}
jsObject = unwrap_jso(element);
- } else if (element.runtimeType == js.JsObjectImpl) {
+ } else if (element.runtimeType == js.JsObject) {
// It's a Polymer core element (written in JS).
jsObject = element;
} else if (isNativeElementExtension) {
@@ -56,7 +56,7 @@
} else if (tag != null && element.localName != tag) {
throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
} else if (tag == null) {
- throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
+ throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObject.');
}
// Remember Dart class to tagName for any upgrading done in wrap_jso.
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index c82e9b5..66a18e0 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -158,9 +158,9 @@
'_DOMWindowCrossFrame': () => _DOMWindowCrossFrame,
// FIXME: Move these to better locations.
'DateTime': () => DateTime,
- 'JsObject': () => js.JsObjectImpl,
- 'JsFunction': () => js.JsFunctionImpl,
- 'JsArray': () => js.JsArrayImpl,
+ 'JsObject': () => js.JsObject,
+ 'JsFunction': () => js.JsFunction,
+ 'JsArray': () => js.JsArray,
$!TYPE_MAP
};
@@ -373,7 +373,7 @@
} else if (runtimeType == TemplateElement) {
// Data binding with a Dart class.
tag = element.attributes['is'];
- } else if (runtimeType == js.JsObjectImpl) {
+ } else if (runtimeType == js.JsObject) {
// It's a Polymer core element (written in JS).
// Make sure it's an element anything else we can ignore.
if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
@@ -386,7 +386,7 @@
}
}
} else {
- throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+ throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
}
return tag;
@@ -394,15 +394,9 @@
/// An abstract class for all DOM objects we wrap in dart:html and related
/// libraries.
-///
-/// ** Internal Use Only **
@Deprecated("Internal Use Only")
-class DartHtmlDomObject {
-
- /// The underlying JS DOM object.
- @Deprecated("Internal Use Only")
- js.JsObject blink_jsObject;
-
+class DartHtmlDomObject extends js.JSObject {
+ DartHtmlDomObject() : super.internal();
}
@Deprecated("Internal Use Only")
@@ -418,24 +412,6 @@
}
}
-// TODO(terry): Manage JS interop JsFunctions for each listener used for add/
-// removeEventListener. These JsFunctions will leak look at
-// fixing with weak-refs in C++. The key are the hashcodes of the
-// user's this (this is needed for futures) and listener function.
-Map<int, Map<int, js.JsFunction>> _knownListeners = {};
-
-@Deprecated("Internal Use Only")
-js.JsFunction wrap_event_listener(theObject, Function listener) {
- var thisHashCode = theObject.hashCode;
- var listenerHashCode = identityHashCode(listener);
-
- _knownListeners.putIfAbsent(thisHashCode, () => new Map<int, js.JsFunction>());
- _knownListeners[thisHashCode].putIfAbsent(listenerHashCode, () =>
- new js.JsFunction.withThis((theObject, event) => listener(wrap_jso(event))));
-
- return _knownListeners[thisHashCode][listenerHashCode];
-}
-
@Deprecated("Internal Use Only")
Map<String, dynamic> convertNativeObjectToDartMap(js.JsObject jsObject) {
var result = new Map();
diff --git a/tools/dom/templates/html/impl/impl_DOMException.darttemplate b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
index 9bbae84..498349b 100644
--- a/tools/dom/templates/html/impl/impl_DOMException.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
@@ -52,12 +52,7 @@
return new DomException._internalWrap();
}
- @Deprecated("Internal Use Only")
- js.JsObject blink_jsObject;
-
- factory DomException._internalWrap() {
- return new DomException.internal_();
- }
+ external factory DomException._internalWrap();
@Deprecated("Internal Use Only")
DomException.internal_() { }
diff --git a/tools/gyp/configurations.gypi b/tools/gyp/configurations.gypi
index 5b55362..ddf4647 100644
--- a/tools/gyp/configurations.gypi
+++ b/tools/gyp/configurations.gypi
@@ -17,9 +17,11 @@
['"<(target_arch)"=="ia32"', { 'dart_target_arch': 'IA32', }],
['"<(target_arch)"=="x64"', { 'dart_target_arch': 'X64', }],
['"<(target_arch)"=="arm"', { 'dart_target_arch': 'ARM', }],
+ ['"<(target_arch)"=="armv6"', { 'dart_target_arch': 'ARMV6', }],
['"<(target_arch)"=="armv5te"', { 'dart_target_arch': 'ARMV5TE', }],
['"<(target_arch)"=="arm64"', { 'dart_target_arch': 'ARM64', }],
['"<(target_arch)"=="simarm"', { 'dart_target_arch': 'SIMARM', }],
+ ['"<(target_arch)"=="simarmv6"', { 'dart_target_arch': 'SIMARMV6', }],
['"<(target_arch)"=="simarmv5te"', { 'dart_target_arch': 'SIMARMV5TE', }],
['"<(target_arch)"=="simarm64"', { 'dart_target_arch': 'SIMARM64', }],
['"<(target_arch)"=="mips"', { 'dart_target_arch': 'MIPS', }],
@@ -63,6 +65,14 @@
]
},
+ 'Dart_simarmv6_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'TARGET_ARCH_ARM',
+ 'TARGET_ARCH_ARM_6',
+ ]
+ },
+
'Dart_simarmv5te_Base': {
'abstract': 1,
'defines': [
@@ -78,6 +88,14 @@
],
},
+ 'Dart_armv6_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'TARGET_ARCH_ARM',
+ 'TARGET_ARCH_ARM_6',
+ ],
+ },
+
'Dart_armv5te_Base': {
'abstract': 1,
'defines': [
@@ -184,6 +202,27 @@
],
},
+ 'DebugSIMARMV6': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simarmv6_Base', 'Dart_Debug',
+ 'Dart_<(dart_target_os)_Base',
+ 'Dart_<(dart_target_os)_simarmv6_Base',
+ 'Dart_<(dart_target_os)_Debug',
+ ],
+ 'defines': [
+ 'DEBUG',
+ ],
+ },
+
+ 'ReleaseSIMARMV6': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simarmv6_Base', 'Dart_Release',
+ 'Dart_<(dart_target_os)_Base',
+ 'Dart_<(dart_target_os)_simarmv6_Base',
+ 'Dart_<(dart_target_os)_Release',
+ ],
+ },
+
'DebugSIMARMV5TE': {
'inherit_from': [
'Dart_Base', 'Dart_simarmv5te_Base', 'Dart_Debug',
@@ -285,6 +324,42 @@
],
},
+ 'DebugXARMV6': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv6_Base', 'Dart_Debug',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_xarmv6_Base',
+ 'Dart_Linux_Debug',
+ ],
+ },
+
+ 'ReleaseXARMV6': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv6_Base', 'Dart_Release',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_xarmv6_Base',
+ 'Dart_Linux_Release',
+ ],
+ },
+
+ 'DebugARMV6': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv6_Base', 'Dart_Debug',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_armv6_Base',
+ 'Dart_Linux_Debug',
+ ],
+ },
+
+ 'ReleaseARMV6': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv6_Base', 'Dart_Release',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_armv6_Base',
+ 'Dart_Linux_Release',
+ ],
+ },
+
'DebugXARMV5TE': {
'inherit_from': [
'Dart_Base', 'Dart_armv5te_Base', 'Dart_Debug',
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index ebaf935..307b1c2 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -76,6 +76,12 @@
'ldflags': [ '-m32', ],
},
+ 'Dart_Linux_simarmv6_Base': {
+ 'abstract': 1,
+ 'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
+ 'ldflags': [ '-m32', ],
+ },
+
'Dart_Linux_simarmv5te_Base': {
'abstract': 1,
'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
@@ -117,6 +123,35 @@
],
},
+ # ARMv6 cross-build
+ 'Dart_Linux_xarmv6_Base': {
+ 'abstract': 1,
+ 'target_conditions': [
+ ['_toolset=="target"', {
+ 'cflags': [
+ '-march=armv6',
+ '-mfpu=vfp',
+ '-Wno-psabi', # suppresses va_list warning
+ '-fno-strict-overflow',
+ ],
+ }],
+ ['_toolset=="host"', {
+ 'cflags': ['-m32', '-msse2', '-mfpmath=sse' ],
+ 'ldflags': ['-m32'],
+ }]]
+ },
+
+ # ARMv6 native build
+ 'Dart_Linux_armv6_Base': {
+ 'abstract': 1,
+ 'cflags': [
+ '-march=armv6',
+ '-mfpu=vfp',
+ '-Wno-psabi', # suppresses va_list warning
+ '-fno-strict-overflow',
+ ],
+ },
+
# ARMv5 cross-build
'Dart_Linux_xarmv5te_Base': {
'abstract': 1,
diff --git a/tools/gyp/configurations_msvs.gypi b/tools/gyp/configurations_msvs.gypi
index 3c859ce..c8b0fd3 100644
--- a/tools/gyp/configurations_msvs.gypi
+++ b/tools/gyp/configurations_msvs.gypi
@@ -24,6 +24,9 @@
'Dart_Win_simarm_Base': {
'abstract': 1,
},
+ 'Dart_Win_simarmv6_Base': {
+ 'abstract': 1,
+ },
'Dart_Win_simarmv5te_Base': {
'abstract': 1,
},
diff --git a/tools/gyp/configurations_xcode.gypi b/tools/gyp/configurations_xcode.gypi
index f709727..e3d04b6 100644
--- a/tools/gyp/configurations_xcode.gypi
+++ b/tools/gyp/configurations_xcode.gypi
@@ -78,6 +78,9 @@
'Dart_Macos_simarm_Base': {
'abstract': 1,
},
+ 'Dart_Macos_simarmv6_Base': {
+ 'abstract': 1,
+ },
'Dart_Macos_simarmv5te_Base': {
'abstract': 1,
},
diff --git a/tools/precompilation/test_linux.sh b/tools/precompilation/test_linux.sh
index 553dc18b..93de570 100755
--- a/tools/precompilation/test_linux.sh
+++ b/tools/precompilation/test_linux.sh
@@ -12,4 +12,4 @@
gcc -m64 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart_precompiled_runtime --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_linux_simarm.sh b/tools/precompilation/test_linux_simarm.sh
index e61b58b..8a8f36c 100755
--- a/tools/precompilation/test_linux_simarm.sh
+++ b/tools/precompilation/test_linux_simarm.sh
@@ -12,4 +12,4 @@
gcc -m32 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart_precompiled --run-precompiled-snapshot not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart_precompiled_runtime --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_macos.sh b/tools/precompilation/test_macos.sh
index 57e02dc..e853b1b 100755
--- a/tools/precompilation/test_macos.sh
+++ b/tools/precompilation/test_macos.sh
@@ -12,4 +12,4 @@
clang -m64 -dynamiclib -o libprecompiled.dylib precompiled.S
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart_precompiled_runtime --run-precompiled-snapshot not_used.dart
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 55810eb..2978003 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -172,6 +172,8 @@
switch (arch) {
case 'simarm':
case 'arm':
+ case 'simarmv6':
+ case 'armv6':
case' simarmv5te':
case 'armv5te':
case 'simmips':
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 92514fe..852e86d 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -108,8 +108,8 @@
'arch',
'The architecture to run tests for',
['-a', '--arch'],
- ['all', 'ia32', 'x64', 'arm', 'armv5te', 'arm64', 'mips',
- 'simarm', 'simarmv5te', 'simarm64', 'simmips'],
+ ['all', 'ia32', 'x64', 'arm', 'armv6', 'armv5te', 'arm64', 'mips',
+ 'simarm', 'simarmv6', 'simarmv5te', 'simarm64', 'simmips'],
'x64'),
new _TestOptionSpecification(
'system',
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 533c01c..fd67ebf 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -218,7 +218,7 @@
if (dartExecutable == null || dartExecutable == '') {
String suffix = executableBinarySuffix;
- dartExecutable = '$buildDir/dart_precompiled$suffix';
+ dartExecutable = '$buildDir/dart_precompiled_runtime$suffix';
}
TestUtils.ensureExists(dartExecutable, configuration);
diff --git a/tools/utils.py b/tools/utils.py
index aaef94c..f2f0704 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -52,6 +52,8 @@
os_id = platform.machine()
if os_id.startswith('armv5te'):
return 'armv5te'
+ elif os_id.startswith('armv6'):
+ return 'armv6'
elif os_id.startswith('arm'):
return 'arm'
elif os_id.startswith('aarch64'):
@@ -228,10 +230,12 @@
'ia32': 'ia32',
'x64': 'ia32',
'arm': 'arm',
+ 'armv6': 'arm',
'armv5te': 'arm',
'arm64': 'arm',
'mips': 'mips',
'simarm': 'ia32',
+ 'simarmv6': 'ia32',
'simarmv5te': 'ia32',
'simmips': 'ia32',
'simarm64': 'ia32',
@@ -581,6 +585,9 @@
# TODO(zra): This binary does not exist, yet. Check one in once we have
# sufficient stability.
return os.path.join(dart_binary_prefix, system, 'dart-armv5te')
+ elif arch == 'armv6':
+ # TODO(zra): Ditto.
+ return os.path.join(dart_binary_prefix, system, 'dart-armv6')
elif arch == 'arm':
return os.path.join(dart_binary_prefix, system, 'dart-arm')
elif arch == 'arm64':