Version 1.19.0-dev.3.0
Merge 59489091200e9739e8fcddcc0e5dfe63fef89a21 into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26425b5..3c62bf5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,59 @@
+## 1.19.0
+
+### Tool Changes
+
+* `dartfmt` - upgraded to v0.2.9
+ * Support trailing commas in argument and parameter lists.
+ * Gracefully handle read-only files.
+ * About a dozen other bug fixes.
+
+* Pub
+ * Added the ability for packages to declare a constraint on the [Flutter][]
+ SDK:
+
+ environment:
+ flutter: ^0.1.2
+ sdk: >=1.19.0 <2.0.0
+
+ A Flutter constraint will only be satisfiable when pub is running in the
+ context of the `flutter` executable, and when the Flutter SDK version
+ matches the constraint.
+
+ * Added `sdk` as a new package source that fetches packages from a hard-coded
+ SDK. Currently only the `flutter` SDK is supported:
+
+ dependencies:
+ flutter_driver:
+ sdk: flutter
+ version: ^0.0.1
+
+ A Flutter `sdk` dependency will only be satisfiable when pub is running in
+ the context of the `flutter` executable, and when the Flutter SDK contains a
+ package with the given name whose version matches the constraint.
+
+ * Fixed a bug where packages from a hosted HTTP URL were considered the same
+ as packages from an otherwise-identical HTTPS URL.
+
+ * Fixed timer formatting for timers that lasted longer than a minute.
+
+ * Eliminate some false negatives when determining whether global executables
+ are on the user's executable path.
+
+[Flutter]: https://flutter.io/
+
+## 1.18.1 - 2016-08-02
+
+Patch release, resolves two issues and improves performance:
+
+* Debugger: Fixes a bug that crashes the VM
+(SDK issue [26941](https://github.com/dart-lang/sdk/issues/26941))
+
+* VM: Fixes an optimizer bug involving closures, try, and await
+(SDK issue [26948](https://github.com/dart-lang/sdk/issues/26948))
+
+* Dart2js: Speeds up generated code on Firefox
+(https://codereview.chromium.org/2180533002)
+
## 1.18.0 - 2016-07-27
### Core library changes
diff --git a/DEPS b/DEPS
index f7b6c5e..10ac7b8 100644
--- a/DEPS
+++ b/DEPS
@@ -35,8 +35,8 @@
"buildtools_revision": "@565d04e8741429fb1b4f26d102f2c6c3b849edeb",
# Revisions of /third_party/* dependencies.
- "args_tag": "@0.13.4",
- "async_tag": "@1.10.0",
+ "args_tag": "@0.13.5",
+ "async_tag": "@1.11.0",
"barback-0.13.0_rev": "@34853",
"barback-0.14.0_rev": "@36398",
"barback-0.14.1_rev": "@38525",
@@ -54,7 +54,7 @@
"csslib_tag" : "@0.12.0",
"dart2js_info_rev" : "@0a221eaf16aec3879c45719de656680ccb80d8a1",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
- "dart_style_tag": "@0.2.4",
+ "dart_style_tag": "@0.2.9",
"dartdoc_tag" : "@v0.9.6+2",
"dev_compiler_rev": "@9cc982b90f57c6132f648b0041c0b03bd23fcbfc",
"fixnum_tag": "@0.10.5",
@@ -79,7 +79,7 @@
"mime_rev": "@75890811d4af5af080351ba8a2853ad4c8df98dd",
"mustache4dart_rev" : "@5724cfd85151e5b6b53ddcd3380daf188fe47f92",
"oauth2_tag": "@1.0.0",
- "observatory_pub_packages_rev": "@e5e1e543bea10d4bed95b22ad3e7aa2b20a23584",
+ "observatory_pub_packages_rev": "@a01235b5b71df27b602dae4676d0bf771cbe7fa2",
"observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
"package_config_rev": "@1.0.0",
"path_tag": "@1.3.6",
@@ -88,8 +88,8 @@
"pool_tag": "@1.2.1",
"protobuf_tag": "@0.5.1+1",
"pub_cache_tag": "@v0.1.0",
- "pub_rev": "@488ab539770512a234f0a01b74882dcbb3f1a4da",
- "pub_semver_tag": "@1.2.1",
+ "pub_rev": "@391b445dc6b28958794658b18caedb69d8cf8719",
+ "pub_semver_tag": "@1.3.0",
"quiver_tag": "@0.21.4",
"resource_rev":"@a49101ba2deb29c728acba6fb86000a8f730f4b1",
"root_certificates_rev": "@aed07942ce98507d2be28cbd29e879525410c7fc",
@@ -103,7 +103,7 @@
"source_maps_tag": "@0.10.1",
"source_span_tag": "@1.2.0",
"stack_trace_tag": "@1.4.2",
- "stream_channel_tag": "@1.3.1",
+ "stream_channel_tag": "@1.5.0",
"string_scanner_tag": "@0.1.4",
"sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
"test_reflective_loader_tag": "@0.0.3",
diff --git a/pkg/analysis_server/.analysis_options b/pkg/analysis_server/.analysis_options
index 7b230dd..49fda46 100644
--- a/pkg/analysis_server/.analysis_options
+++ b/pkg/analysis_server/.analysis_options
@@ -1,3 +1,5 @@
+analyzer:
+ strong-mode: true
linter:
rules:
- unnecessary_brace_in_string_interp
diff --git a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
index ce6235d..c17b77b 100644
--- a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
@@ -51,10 +51,11 @@
}
@override
- Future<Response> sendRequest(Request request) {
+ Future<Response> sendRequest(Request request) async {
String id = request.id;
output.write(JSON.encode(request.toJson()) + '\n');
- return responseStream.firstWhere((Response response) => response.id == id);
+ return await responseStream
+ .firstWhere((Response response) => response.id == id);
}
}
diff --git a/pkg/analysis_server/lib/src/channel/web_socket_channel.dart b/pkg/analysis_server/lib/src/channel/web_socket_channel.dart
index 0368eb6..282b1f9 100644
--- a/pkg/analysis_server/lib/src/channel/web_socket_channel.dart
+++ b/pkg/analysis_server/lib/src/channel/web_socket_channel.dart
@@ -55,10 +55,11 @@
}
@override
- Future<Response> sendRequest(Request request) {
+ Future<Response> sendRequest(Request request) async {
String id = request.id;
socket.add(JSON.encode(request.toJson()));
- return responseStream.firstWhere((Response response) => response.id == id);
+ return await responseStream
+ .firstWhere((Response response) => response.id == id);
}
}
diff --git a/pkg/analysis_server/lib/src/services/index/index.dart b/pkg/analysis_server/lib/src/services/index/index.dart
index 7270ac2..aa06637 100644
--- a/pkg/analysis_server/lib/src/services/index/index.dart
+++ b/pkg/analysis_server/lib/src/services/index/index.dart
@@ -341,24 +341,39 @@
* [element] is not referenced in the [index].
*/
int findElementId(Element element) {
+ IndexElementInfo info = new IndexElementInfo(element);
+ element = info.element;
// Find the id of the element's unit.
int unitId = getUnitId(element);
if (unitId == -1) {
return -1;
}
// Prepare information about the element.
- ElementInfo info = PackageIndexAssembler.newElementInfo(unitId, element);
- // Find the first occurrence of an element with the same offset.
- int elementId = _findFirstOccurrence(index.elementOffsets, info.offset);
+ int unitMemberId = getElementUnitMemberId(element);
+ if (unitMemberId == -1) {
+ return -1;
+ }
+ int classMemberId = getElementClassMemberId(element);
+ if (classMemberId == -1) {
+ return -1;
+ }
+ int parameterId = getElementParameterId(element);
+ if (parameterId == -1) {
+ return -1;
+ }
+ // Try to find the element id using classMemberId, parameterId, and kind.
+ int elementId =
+ _findFirstOccurrence(index.elementNameUnitMemberIds, unitMemberId);
if (elementId == -1) {
return -1;
}
- // Try to find the element id using offset, unit and kind.
for (;
- elementId < index.elementOffsets.length &&
- index.elementOffsets[elementId] == info.offset;
+ elementId < index.elementNameUnitMemberIds.length &&
+ index.elementNameUnitMemberIds[elementId] == unitMemberId;
elementId++) {
if (index.elementUnits[elementId] == unitId &&
+ index.elementNameClassMemberIds[elementId] == classMemberId &&
+ index.elementNameParameterIds[elementId] == parameterId &&
index.elementKinds[elementId] == info.kind) {
return elementId;
}
@@ -383,6 +398,45 @@
}
/**
+ * Return the [element]'s class member name identifier, `null` is not a class
+ * member, or `-1` if the [element] is not referenced in the [index].
+ */
+ int getElementClassMemberId(Element element) {
+ for (; element != null; element = element.enclosingElement) {
+ if (element.enclosingElement is ClassElement) {
+ return getStringId(element.name);
+ }
+ }
+ return getStringId(PackageIndexAssembler.NULL_STRING);
+ }
+
+ /**
+ * Return the [element]'s class member name identifier, `null` is not a class
+ * member, or `-1` if the [element] is not referenced in the [index].
+ */
+ int getElementParameterId(Element element) {
+ for (; element != null; element = element.enclosingElement) {
+ if (element is ParameterElement) {
+ return getStringId(element.name);
+ }
+ }
+ return getStringId(PackageIndexAssembler.NULL_STRING);
+ }
+
+ /**
+ * Return the [element]'s top-level name identifier, `0` is the unit, or
+ * `-1` if the [element] is not referenced in the [index].
+ */
+ int getElementUnitMemberId(Element element) {
+ for (; element != null; element = element.enclosingElement) {
+ if (element.enclosingElement is CompilationUnitElement) {
+ return getStringId(element.name);
+ }
+ }
+ return getStringId(PackageIndexAssembler.NULL_STRING);
+ }
+
+ /**
* Complete with a list of locations where the given [element] has relation
* of the given [kind].
*/
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 47eb392..5b2b6e3 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -261,12 +261,10 @@
ParameterElement parameter) async {
List<SearchMatch> matches = <SearchMatch>[];
matches.addAll(await _searchReferences(parameter));
- matches.addAll(await _searchReferences_Local(
- parameter,
- (n) =>
- n is ConstructorDeclaration ||
- n is MethodDeclaration ||
- n is FunctionExpression));
+ matches.addAll(await _searchReferences_Local(parameter, (AstNode node) {
+ AstNode parent = node.parent;
+ return parent is ClassDeclaration || parent is CompilationUnit;
+ }));
return matches;
}
@@ -408,7 +406,7 @@
}
void _addMatch(AstNode node, MatchKind kind) {
- bool isQualified = node is SimpleIdentifier && node.isQualified;
+ bool isQualified = node.parent is Label;
matches.add(new SearchMatch(context, libraryUri, unitUri, kind,
rangeNode(node), true, isQualified));
}
diff --git a/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart b/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart
index 3d99622..1997bff 100644
--- a/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart
+++ b/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart
@@ -106,7 +106,8 @@
// Check for cached entry
Map entry = _cache[folder.path];
if (entry != null) {
- Map<String, int> modificationStamps = entry[modificationStampsKey];
+ Map<String, int> modificationStamps =
+ entry[modificationStampsKey] as Map<String, int>;
if (modificationStamps != null) {
//
// Check to see if any dependencies have changed
@@ -217,7 +218,7 @@
TimestampedData<String> data = source.contents;
Map map = JSON.decode(data.data);
if (map[cacheVersionKey] == cacheVersion) {
- _cache = map[cacheKey];
+ _cache = map[cacheKey] as Map<String, Map>;
_cacheModificationTime = data.modificationTime;
}
} catch (exception, stackTrace) {
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 13a149a..d9486dd 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -827,17 +827,17 @@
'<table style="border-collapse: separate; border-spacing: 10px 5px;">');
_writeRow(buffer, ['Name', 'Count'], header: true);
_writeRow(buffer, [
- 'Modified',
+ 'Changed',
PerformanceStatistics
- .cacheConsistencyValidationStatistics.numOfModified
+ .cacheConsistencyValidationStatistics.numOfChanged
], classes: [
null,
"right"
]);
_writeRow(buffer, [
- 'Deleted',
+ 'Removed',
PerformanceStatistics
- .cacheConsistencyValidationStatistics.numOfDeleted
+ .cacheConsistencyValidationStatistics.numOfRemoved
], classes: [
null,
"right"
@@ -1415,8 +1415,6 @@
_writeOption(
buffer, 'Enable strict call checks', options.enableStrictCallChecks);
_writeOption(buffer, 'Enable super mixins', options.enableSuperMixins);
- _writeOption(
- buffer, 'Enable trailing commas', options.enableTrailingCommas);
_writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint);
_writeOption(buffer, 'Generate errors in implicit files',
options.generateImplicitErrors);
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index cc09692..d35c631 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/services/correction/status.dart';
+import 'package:analyzer/src/generated/source.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@@ -265,15 +266,15 @@
expectedContextSearch: 'test(); // marker');
}
- test_checkFinalConditions_shadowed_inSubClass() async {
+ test_checkFinalConditions_shadowedBySub_MethodElement() async {
indexTestUnit('''
class A {
- newName() {} // marker
+ test() {}
}
class B extends A {
- test() {}
+ newName() {} // marker
main() {
- newName();
+ test();
}
}
''');
@@ -282,11 +283,12 @@
refactoring.newName = 'newName';
RefactoringStatus status = await refactoring.checkFinalConditions();
assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR,
- expectedMessage: "Renamed method will shadow method 'A.newName'.",
+ expectedMessage:
+ "Renamed method will be shadowed by method 'B.newName'.",
expectedContextSearch: 'newName() {} // marker');
}
- test_checkFinalConditions_shadowsSuper_inSubClass_FieldElement() async {
+ test_checkFinalConditions_shadowsSuper_FieldElement() async {
indexTestUnit('''
class A {
int newName; // marker
@@ -312,13 +314,10 @@
test_checkFinalConditions_shadowsSuper_MethodElement() async {
indexTestUnit('''
class A {
- test() {}
+ newName() {} // marker
}
class B extends A {
- newName() {} // marker
- main() {
- test();
- }
+ test() {}
}
''');
createRenameRefactoringAtString('test() {}');
@@ -326,11 +325,33 @@
refactoring.newName = 'newName';
RefactoringStatus status = await refactoring.checkFinalConditions();
assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR,
- expectedMessage:
- "Renamed method will be shadowed by method 'B.newName'.",
+ expectedMessage: "Renamed method will shadow method 'A.newName'.",
expectedContextSearch: 'newName() {} // marker');
}
+ test_checkFinalConditions_shadowsSuper_MethodElement_otherLib() async {
+ var libCode = r'''
+class A {
+ newName() {} // marker
+}
+''';
+ indexUnit('/lib.dart', libCode);
+ indexTestUnit('''
+import 'lib.dart';
+class B extends A {
+ test() {}
+}
+''');
+ createRenameRefactoringAtString('test() {}');
+ // check status
+ refactoring.newName = 'newName';
+ RefactoringStatus status = await refactoring.checkFinalConditions();
+ assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR,
+ expectedMessage: "Renamed method will shadow method 'A.newName'.",
+ expectedContextRange: new SourceRange(
+ libCode.indexOf('newName() {} // marker'), 'newName'.length));
+ }
+
test_checkInitialConditions_inSDK() async {
indexTestUnit('''
main() {
diff --git a/pkg/analyzer/.analysis_options b/pkg/analyzer/.analysis_options
index 2b11248..c952041 100644
--- a/pkg/analyzer/.analysis_options
+++ b/pkg/analyzer/.analysis_options
@@ -1,3 +1,5 @@
+analyzer:
+ strong-mode: true
linter:
rules:
# TODO(pq): re-enable once we have a bulk edit tool
diff --git a/pkg/analyzer/lib/dart/ast/token.dart b/pkg/analyzer/lib/dart/ast/token.dart
index 14ba3f9..687111a 100644
--- a/pkg/analyzer/lib/dart/ast/token.dart
+++ b/pkg/analyzer/lib/dart/ast/token.dart
@@ -409,6 +409,9 @@
static const TokenType AMPERSAND_AMPERSAND = const TokenType._(
'AMPERSAND_AMPERSAND', TokenClass.LOGICAL_AND_OPERATOR, '&&');
+ static const TokenType AMPERSAND_AMPERSAND_EQ = const TokenType._(
+ 'AMPERSAND_AMPERSAND_EQ', TokenClass.ASSIGNMENT_OPERATOR, '&&=');
+
static const TokenType AMPERSAND_EQ =
const TokenType._('AMPERSAND_EQ', TokenClass.ASSIGNMENT_OPERATOR, '&=');
@@ -426,6 +429,9 @@
static const TokenType BAR_BAR =
const TokenType._('BAR_BAR', TokenClass.LOGICAL_OR_OPERATOR, '||');
+ static const TokenType BAR_BAR_EQ =
+ const TokenType._('BAR_BAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, '||=');
+
static const TokenType BAR_EQ =
const TokenType._('BAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, '|=');
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 3755353..377e9b1 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -147,6 +147,9 @@
Map<String, List<Folder>> folderMap = new HashMap<String, List<Folder>>();
packages.asMap().forEach((String packagePath, Uri uri) {
String path = resourceProvider.pathContext.fromUri(uri);
+ if (path.endsWith(resourceProvider.pathContext.separator)) {
+ path = path.substring(0, path.length - 1);
+ }
folderMap[packagePath] = [resourceProvider.getFolder(path)];
});
return folderMap;
@@ -284,7 +287,7 @@
return embedderSdk;
});
return dartSdk;
- } else if (extFilePaths != null) {
+ } else if (extFilePaths != null && extFilePaths.isNotEmpty) {
//
// We have an extension file, but no embedder file.
//
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index efa8227..7b956a9 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -673,7 +673,7 @@
deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
_resultMap.remove(descriptor);
// Stop depending on other results.
- if (deltaResult != DeltaResult.KEEP_CONTINUE) {
+ {
TargetedResult thisResult = new TargetedResult(target, descriptor);
List<AnalysisCache> caches = _partition.containingCaches;
int cacheLength = caches.length;
@@ -697,10 +697,6 @@
// if (deltaResult == null) {
// String indent = ' ' * level;
// print('[$id]$indent invalidate $descriptor for $target');
-// if ('$descriptor for $target' ==
-// 'READY_LIBRARY_ELEMENT2 for /Users/scheglov/tmp/limited-invalidation/async/lib/async.dart') {
-// print('interesting');
-// }
// }
}
// Invalidate results that depend on this result.
@@ -714,8 +710,10 @@
_partition._removeIfSource(target);
}
// Notify controller.
- _partition.onResultInvalidated
- .add(new InvalidatedResult(this, descriptor, thisData.value));
+ if (deltaResult != DeltaResult.KEEP_CONTINUE) {
+ _partition.onResultInvalidated
+ .add(new InvalidatedResult(this, descriptor, thisData.value));
+ }
}
/**
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index ca3eebc..fe33e3a 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -292,6 +292,9 @@
? this._options.implicitCasts != options.implicitCasts
: false) ||
((options is AnalysisOptionsImpl)
+ ? this._options.nonnullableTypes != options.nonnullableTypes
+ : false) ||
+ ((options is AnalysisOptionsImpl)
? this._options.implicitDynamic != options.implicitDynamic
: false) ||
this._options.enableStrictCallChecks !=
@@ -326,6 +329,7 @@
if (options is AnalysisOptionsImpl) {
this._options.strongModeHints = options.strongModeHints;
this._options.implicitCasts = options.implicitCasts;
+ this._options.nonnullableTypes = options.nonnullableTypes;
this._options.implicitDynamic = options.implicitDynamic;
}
if (needsRecompute) {
@@ -2068,9 +2072,9 @@
@override
bool sourceModificationTimesComputed(List<Source> sources, List<int> times) {
- int consistencyCheckStart = JavaSystem.nanoTime();
+ Stopwatch timer = new Stopwatch()..start();
HashSet<Source> changedSources = new HashSet<Source>();
- HashSet<Source> missingSources = new HashSet<Source>();
+ HashSet<Source> removedSources = new HashSet<Source>();
for (int i = 0; i < sources.length; i++) {
Source source = sources[i];
// When a source is in the content cache,
@@ -2087,16 +2091,15 @@
// Compare with the modification time in the cache entry.
CacheEntry entry = context._privatePartition.get(source);
if (entry != null) {
- if (sourceTime != entry.modificationTime) {
- changedSources.add(source);
- PerformanceStatistics
- .cacheConsistencyValidationStatistics.numOfModified++;
- }
- if (entry.exception != null) {
+ if (entry.modificationTime != sourceTime) {
if (sourceTime == -1) {
- missingSources.add(source);
+ removedSources.add(source);
PerformanceStatistics
- .cacheConsistencyValidationStatistics.numOfModified++;
+ .cacheConsistencyValidationStatistics.numOfRemoved++;
+ } else {
+ changedSources.add(source);
+ PerformanceStatistics
+ .cacheConsistencyValidationStatistics.numOfChanged++;
}
}
}
@@ -2104,35 +2107,23 @@
for (Source source in changedSources) {
context._sourceChanged(source);
}
- int removalCount = 0;
- for (Source source in missingSources) {
- if (context.getLibrariesContaining(source).isEmpty &&
- context.getLibrariesDependingOn(source).isEmpty) {
- context._removeFromCache(source);
- removalCount++;
- }
+ for (Source source in removedSources) {
+ context._sourceRemoved(source);
}
- int consistencyCheckEnd = JavaSystem.nanoTime();
- if (changedSources.length > 0 || missingSources.length > 0) {
+ if (changedSources.length > 0 || removedSources.length > 0) {
StringBuffer buffer = new StringBuffer();
buffer.write("Consistency check took ");
- buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
+ buffer.write(timer.elapsedMilliseconds);
buffer.writeln(" ms and found");
buffer.write(" ");
buffer.write(changedSources.length);
- buffer.writeln(" inconsistent entries");
+ buffer.writeln(" changed sources");
buffer.write(" ");
- buffer.write(missingSources.length);
- buffer.write(" missing sources (");
- buffer.write(removalCount);
- buffer.writeln(" removed");
- for (Source source in missingSources) {
- buffer.write(" ");
- buffer.writeln(source.fullName);
- }
+ buffer.write(removedSources.length);
+ buffer.write(" removed sources.");
context._logInformation(buffer.toString());
}
- return changedSources.length > 0;
+ return changedSources.isNotEmpty || removedSources.isNotEmpty;
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 3b09bef..6eaaedb 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -976,7 +976,7 @@
SimpleIdentifier propertyNameNode = node.name;
String propertyName = propertyNameNode.name;
FieldElementImpl field =
- _currentHolder.getField(propertyName) as FieldElementImpl;
+ _currentHolder.getField(propertyName, synthetic: true) as FieldElementImpl;
if (field == null) {
field = new FieldElementImpl(node.name.name, -1);
field.final2 = true;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 7743244..ddb414e 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -7336,7 +7336,7 @@
DartType get type => setter.variable.type;
@override
- void set type(FunctionType type) {
+ void set type(DartType type) {
assert(false); // Should never be called.
}
}
@@ -7656,7 +7656,7 @@
}
@override
- DartType get type {
+ FunctionType get type {
return _type ??= new FunctionTypeImpl(this);
}
@@ -7699,7 +7699,7 @@
}
@override
- DartType get type {
+ FunctionType get type {
return _type ??= new FunctionTypeImpl(this);
}
@@ -8260,20 +8260,20 @@
abstract class UriReferencedElementImpl extends ElementImpl
implements UriReferencedElement {
/**
- * The offset of the URI in the file, may be `-1` if synthetic.
+ * The offset of the URI in the file, or `-1` if this node is synthetic.
*/
- int uriOffset = -1;
+ int _uriOffset = -1;
/**
* The offset of the character immediately following the last character of
- * this node's URI, may be `-1` if synthetic.
+ * this node's URI, or `-1` if this node is synthetic.
*/
- int uriEnd = -1;
+ int _uriEnd = -1;
/**
* The URI that is specified by this directive.
*/
- String uri;
+ String _uri;
/**
* Initialize a newly created import element to have the given [name] and
@@ -8286,6 +8286,44 @@
*/
UriReferencedElementImpl.forSerialized(ElementImpl enclosingElement)
: super.forSerialized(enclosingElement);
+
+ /**
+ * Return the URI that is specified by this directive.
+ */
+ String get uri => _uri;
+
+ /**
+ * Set the URI that is specified by this directive to be the given [uri].
+ */
+ void set uri(String uri) {
+ _uri = uri;
+ }
+
+ /**
+ * Return the offset of the character immediately following the last character
+ * of this node's URI, or `-1` if this node is synthetic.
+ */
+ int get uriEnd => _uriEnd;
+
+ /**
+ * Set the offset of the character immediately following the last character of
+ * this node's URI to the given [offset].
+ */
+ void set uriEnd(int offset) {
+ _uriEnd = offset;
+ }
+
+ /**
+ * Return the offset of the URI in the file, or `-1` if this node is synthetic.
+ */
+ int get uriOffset => _uriOffset;
+
+ /**
+ * Set the offset of the URI in the file to the given [offset].
+ */
+ void set uriOffset(int offset) {
+ _uriOffset = offset;
+ }
}
/**
diff --git a/pkg/analyzer/lib/src/dart/scanner/scanner.dart b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
index 7814eb7..0e60a90 100644
--- a/pkg/analyzer/lib/src/dart/scanner/scanner.dart
+++ b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:charcode/ascii.dart';
/**
* A state in a state machine used to scan keywords.
@@ -57,7 +58,7 @@
* [character], or `null` if there is no valid state reachable from this state
* with such a transition.
*/
- KeywordState next(int character) => _table[character - 0x61];
+ KeywordState next(int character) => _table[character - $a];
/**
* Create the next state in the state machine where we have already recognized
@@ -69,7 +70,7 @@
int start, List<String> strings, int offset, int length) {
List<KeywordState> result = new List<KeywordState>(26);
assert(length != 0);
- int chunk = 0x0;
+ int chunk = $nul;
int chunkStart = -1;
bool isLeaf = false;
for (int i = offset; i < offset + length; i++) {
@@ -80,7 +81,7 @@
int c = strings[i].codeUnitAt(start);
if (chunk != c) {
if (chunkStart != -1) {
- result[chunk - 0x61] = _computeKeywordStateTable(
+ result[chunk - $a] = _computeKeywordStateTable(
start + 1, strings, chunkStart, i - chunkStart);
}
chunkStart = i;
@@ -89,8 +90,8 @@
}
}
if (chunkStart != -1) {
- assert(result[chunk - 0x61] == null);
- result[chunk - 0x61] = _computeKeywordStateTable(
+ assert(result[chunk - $a] == null);
+ result[chunk - $a] = _computeKeywordStateTable(
start + 1, strings, chunkStart, offset + length - chunkStart);
} else {
assert(length == 1);
@@ -207,6 +208,12 @@
bool scanGenericMethodComments = false;
/**
+ * A flag indicating whether the lazy compound assignment operators '&&=' and
+ * '||=' are enabled.
+ */
+ bool scanLazyAssignmentOperators = false;
+
+ /**
* Initialize a newly created scanner to scan characters from the given
* [source]. The given character [_reader] will be used to read the characters
* in the source. The given [_errorListener] will be informed of any errors
@@ -260,175 +267,175 @@
int bigSwitch(int next) {
_beginToken();
- if (next == 0xD) {
+ if (next == $cr) {
// '\r'
next = _reader.advance();
- if (next == 0xA) {
+ if (next == $lf) {
// '\n'
next = _reader.advance();
}
recordStartOfLine();
return next;
- } else if (next == 0xA) {
+ } else if (next == $lf) {
// '\n'
next = _reader.advance();
recordStartOfLine();
return next;
- } else if (next == 0x9 || next == 0x20) {
+ } else if (next == $tab || next == $space) {
// '\t' || ' '
return _reader.advance();
}
- if (next == 0x72) {
+ if (next == $r) {
// 'r'
int peek = _reader.peek();
- if (peek == 0x22 || peek == 0x27) {
+ if (peek == $double_quote || peek == $single_quote) {
// '"' || "'"
int start = _reader.offset;
return _tokenizeString(_reader.advance(), start, true);
}
}
- if (0x61 <= next && next <= 0x7A) {
+ if ($a <= next && next <= $z) {
// 'a'-'z'
return _tokenizeKeywordOrIdentifier(next, true);
}
- if ((0x41 <= next && next <= 0x5A) || next == 0x5F || next == 0x24) {
+ if (($A <= next && next <= $Z) || next == $_ || next == $$) {
// 'A'-'Z' || '_' || '$'
return _tokenizeIdentifier(next, _reader.offset, true);
}
- if (next == 0x3C) {
+ if (next == $lt) {
// '<'
return _tokenizeLessThan(next);
}
- if (next == 0x3E) {
+ if (next == $gt) {
// '>'
return _tokenizeGreaterThan(next);
}
- if (next == 0x3D) {
+ if (next == $equal) {
// '='
return _tokenizeEquals(next);
}
- if (next == 0x21) {
+ if (next == $exclamation) {
// '!'
return _tokenizeExclamation(next);
}
- if (next == 0x2B) {
+ if (next == $plus) {
// '+'
return _tokenizePlus(next);
}
- if (next == 0x2D) {
+ if (next == $minus) {
// '-'
return _tokenizeMinus(next);
}
- if (next == 0x2A) {
+ if (next == $asterisk) {
// '*'
return _tokenizeMultiply(next);
}
- if (next == 0x25) {
+ if (next == $percent) {
// '%'
return _tokenizePercent(next);
}
- if (next == 0x26) {
+ if (next == $ampersand) {
// '&'
return _tokenizeAmpersand(next);
}
- if (next == 0x7C) {
+ if (next == $bar) {
// '|'
return _tokenizeBar(next);
}
- if (next == 0x5E) {
+ if (next == $caret) {
// '^'
return _tokenizeCaret(next);
}
- if (next == 0x5B) {
+ if (next == $open_bracket) {
// '['
return _tokenizeOpenSquareBracket(next);
}
- if (next == 0x7E) {
+ if (next == $tilde) {
// '~'
return _tokenizeTilde(next);
}
- if (next == 0x5C) {
+ if (next == $backslash) {
// '\\'
_appendTokenOfType(TokenType.BACKSLASH);
return _reader.advance();
}
- if (next == 0x23) {
+ if (next == $hash) {
// '#'
return _tokenizeTag(next);
}
- if (next == 0x28) {
+ if (next == $open_paren) {
// '('
_appendBeginToken(TokenType.OPEN_PAREN);
return _reader.advance();
}
- if (next == 0x29) {
+ if (next == $close_paren) {
// ')'
_appendEndToken(TokenType.CLOSE_PAREN, TokenType.OPEN_PAREN);
return _reader.advance();
}
- if (next == 0x2C) {
+ if (next == $comma) {
// ','
_appendTokenOfType(TokenType.COMMA);
return _reader.advance();
}
- if (next == 0x3A) {
+ if (next == $colon) {
// ':'
_appendTokenOfType(TokenType.COLON);
return _reader.advance();
}
- if (next == 0x3B) {
+ if (next == $semicolon) {
// ';'
_appendTokenOfType(TokenType.SEMICOLON);
return _reader.advance();
}
- if (next == 0x3F) {
+ if (next == $question) {
// '?'
return _tokenizeQuestion();
}
- if (next == 0x5D) {
+ if (next == $close_bracket) {
// ']'
_appendEndToken(
TokenType.CLOSE_SQUARE_BRACKET, TokenType.OPEN_SQUARE_BRACKET);
return _reader.advance();
}
- if (next == 0x60) {
+ if (next == $backquote) {
// '`'
_appendTokenOfType(TokenType.BACKPING);
return _reader.advance();
}
- if (next == 0x7B) {
+ if (next == $lbrace) {
// '{'
_appendBeginToken(TokenType.OPEN_CURLY_BRACKET);
return _reader.advance();
}
- if (next == 0x7D) {
+ if (next == $rbrace) {
// '}'
_appendEndToken(
TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET);
return _reader.advance();
}
- if (next == 0x2F) {
+ if (next == $slash) {
// '/'
return _tokenizeSlashOrComment(next);
}
- if (next == 0x40) {
+ if (next == $at) {
// '@'
_appendTokenOfType(TokenType.AT);
return _reader.advance();
}
- if (next == 0x22 || next == 0x27) {
+ if (next == $double_quote || next == $single_quote) {
// '"' || "'"
return _tokenizeString(next, _reader.offset, false);
}
- if (next == 0x2E) {
+ if (next == $dot) {
// '.'
return _tokenizeDotOrNumber(next);
}
- if (next == 0x30) {
+ if (next == $0) {
// '0'
return _tokenizeHexOrNumber(next);
}
- if (0x31 <= next && next <= 0x39) {
+ if ($1 <= next && next <= $9) {
// '1'-'9'
return _tokenizeNumber(next);
}
@@ -648,12 +655,12 @@
TokenType _matchGenericMethodCommentType(String value) {
if (scanGenericMethodComments) {
// Match /*< and >*/
- if (StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x3C) &&
- StringUtilities.endsWith3(value, 0x3E, 0x2A, 0x2F)) {
+ if (StringUtilities.startsWith3(value, 0, $slash, $asterisk, $lt) &&
+ StringUtilities.endsWith3(value, $gt, $asterisk, $slash)) {
return TokenType.GENERIC_METHOD_TYPE_LIST;
}
// Match /*=
- if (StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x3D)) {
+ if (StringUtilities.startsWith3(value, 0, $slash, $asterisk, $equal)) {
return TokenType.GENERIC_METHOD_TYPE_ASSIGN;
}
}
@@ -694,12 +701,17 @@
}
int _tokenizeAmpersand(int next) {
- // && &= &
+ // &&= && &= &
next = _reader.advance();
- if (next == 0x26) {
+ if (next == $ampersand) {
+ next = _reader.advance();
+ if (scanLazyAssignmentOperators && next == $equal) {
+ _appendTokenOfType(TokenType.AMPERSAND_AMPERSAND_EQ);
+ return _reader.advance();
+ }
_appendTokenOfType(TokenType.AMPERSAND_AMPERSAND);
- return _reader.advance();
- } else if (next == 0x3D) {
+ return next;
+ } else if (next == $equal) {
_appendTokenOfType(TokenType.AMPERSAND_EQ);
return _reader.advance();
} else {
@@ -709,12 +721,17 @@
}
int _tokenizeBar(int next) {
- // | || |=
+ // ||= || |= |
next = _reader.advance();
- if (next == 0x7C) {
+ if (next == $bar) {
+ next = _reader.advance();
+ if (scanLazyAssignmentOperators && next == $equal) {
+ _appendTokenOfType(TokenType.BAR_BAR_EQ);
+ return _reader.advance();
+ }
_appendTokenOfType(TokenType.BAR_BAR);
- return _reader.advance();
- } else if (next == 0x3D) {
+ return next;
+ } else if (next == $equal) {
_appendTokenOfType(TokenType.BAR_EQ);
return _reader.advance();
} else {
@@ -724,16 +741,16 @@
}
int _tokenizeCaret(int next) =>
- _select(0x3D, TokenType.CARET_EQ, TokenType.CARET);
+ _select($equal, TokenType.CARET_EQ, TokenType.CARET);
int _tokenizeDotOrNumber(int next) {
int start = _reader.offset;
next = _reader.advance();
- if (0x30 <= next && next <= 0x39) {
+ if ($0 <= next && next <= $9) {
return _tokenizeFractionPart(next, start);
- } else if (0x2E == next) {
+ } else if ($dot == next) {
return _select(
- 0x2E, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PERIOD);
+ $dot, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PERIOD);
} else {
_appendTokenOfType(TokenType.PERIOD);
return next;
@@ -743,10 +760,10 @@
int _tokenizeEquals(int next) {
// = == =>
next = _reader.advance();
- if (next == 0x3D) {
+ if (next == $equal) {
_appendTokenOfType(TokenType.EQ_EQ);
return _reader.advance();
- } else if (next == 0x3E) {
+ } else if (next == $gt) {
_appendTokenOfType(TokenType.FUNCTION);
return _reader.advance();
}
@@ -757,7 +774,7 @@
int _tokenizeExclamation(int next) {
// ! !=
next = _reader.advance();
- if (next == 0x3D) {
+ if (next == $equal) {
_appendTokenOfType(TokenType.BANG_EQ);
return _reader.advance();
}
@@ -766,12 +783,12 @@
}
int _tokenizeExponent(int next) {
- if (next == 0x2B || next == 0x2D) {
+ if (next == $plus || next == $minus) {
next = _reader.advance();
}
bool hasDigits = false;
while (true) {
- if (0x30 <= next && next <= 0x39) {
+ if ($0 <= next && next <= $9) {
hasDigits = true;
} else {
if (!hasDigits) {
@@ -787,9 +804,9 @@
bool done = false;
bool hasDigit = false;
LOOP: while (!done) {
- if (0x30 <= next && next <= 0x39) {
+ if ($0 <= next && next <= $9) {
hasDigit = true;
- } else if (0x65 == next || 0x45 == next) {
+ } else if ($e == next || $E == next) {
hasDigit = true;
next = _tokenizeExponent(_reader.advance());
done = true;
@@ -802,8 +819,8 @@
}
if (!hasDigit) {
_appendStringToken(TokenType.INT, _reader.getString(start, -2));
- if (0x2E == next) {
- return _selectWithOffset(0x2E, TokenType.PERIOD_PERIOD_PERIOD,
+ if ($dot == next) {
+ return _selectWithOffset($dot, TokenType.PERIOD_PERIOD_PERIOD,
TokenType.PERIOD_PERIOD, _reader.offset - 1);
}
_appendTokenOfTypeWithOffset(TokenType.PERIOD, _reader.offset - 1);
@@ -817,12 +834,12 @@
int _tokenizeGreaterThan(int next) {
// > >= >> >>=
next = _reader.advance();
- if (0x3D == next) {
+ if ($equal == next) {
_appendTokenOfType(TokenType.GT_EQ);
return _reader.advance();
- } else if (0x3E == next) {
+ } else if ($gt == next) {
next = _reader.advance();
- if (0x3D == next) {
+ if ($equal == next) {
_appendTokenOfType(TokenType.GT_GT_EQ);
return _reader.advance();
} else {
@@ -840,9 +857,9 @@
bool hasDigits = false;
while (true) {
next = _reader.advance();
- if ((0x30 <= next && next <= 0x39) ||
- (0x41 <= next && next <= 0x46) ||
- (0x61 <= next && next <= 0x66)) {
+ if (($0 <= next && next <= $9) ||
+ ($A <= next && next <= $F) ||
+ ($a <= next && next <= $f)) {
hasDigits = true;
} else {
if (!hasDigits) {
@@ -857,7 +874,7 @@
int _tokenizeHexOrNumber(int next) {
int x = _reader.peek();
- if (x == 0x78 || x == 0x58) {
+ if (x == $x || x == $X) {
_reader.advance();
return _tokenizeHex(x);
}
@@ -865,11 +882,11 @@
}
int _tokenizeIdentifier(int next, int start, bool allowDollar) {
- while ((0x61 <= next && next <= 0x7A) ||
- (0x41 <= next && next <= 0x5A) ||
- (0x30 <= next && next <= 0x39) ||
- next == 0x5F ||
- (next == 0x24 && allowDollar)) {
+ while (($a <= next && next <= $z) ||
+ ($A <= next && next <= $Z) ||
+ ($0 <= next && next <= $9) ||
+ next == $_ ||
+ (next == $$ && allowDollar)) {
next = _reader.advance();
}
_appendStringToken(
@@ -881,7 +898,7 @@
_appendBeginToken(TokenType.STRING_INTERPOLATION_EXPRESSION);
next = _reader.advance();
while (next != -1) {
- if (next == 0x7D) {
+ if (next == $rbrace) {
BeginToken begin =
_findTokenMatchingClosingBraceInInterpolationExpression();
if (begin == null) {
@@ -914,9 +931,9 @@
int _tokenizeInterpolatedIdentifier(int next, int start) {
_appendStringTokenWithOffset(
TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 0);
- if ((0x41 <= next && next <= 0x5A) ||
- (0x61 <= next && next <= 0x7A) ||
- next == 0x5F) {
+ if (($A <= next && next <= $Z) ||
+ ($a <= next && next <= $z) ||
+ next == $_) {
_beginToken();
next = _tokenizeKeywordOrIdentifier(next, false);
}
@@ -927,17 +944,17 @@
int _tokenizeKeywordOrIdentifier(int next, bool allowDollar) {
KeywordState state = KeywordState.KEYWORD_STATE;
int start = _reader.offset;
- while (state != null && 0x61 <= next && next <= 0x7A) {
+ while (state != null && $a <= next && next <= $z) {
state = state.next(next);
next = _reader.advance();
}
if (state == null || state.keyword() == null) {
return _tokenizeIdentifier(next, start, allowDollar);
}
- if ((0x41 <= next && next <= 0x5A) ||
- (0x30 <= next && next <= 0x39) ||
- next == 0x5F ||
- next == 0x24) {
+ if (($A <= next && next <= $Z) ||
+ ($0 <= next && next <= $9) ||
+ next == $_ ||
+ next == $$) {
return _tokenizeIdentifier(next, start, allowDollar);
} else if (next < 128) {
_appendKeywordToken(state.keyword());
@@ -950,11 +967,11 @@
int _tokenizeLessThan(int next) {
// < <= << <<=
next = _reader.advance();
- if (0x3D == next) {
+ if ($equal == next) {
_appendTokenOfType(TokenType.LT_EQ);
return _reader.advance();
- } else if (0x3C == next) {
- return _select(0x3D, TokenType.LT_LT_EQ, TokenType.LT_LT);
+ } else if ($lt == next) {
+ return _select($equal, TokenType.LT_LT_EQ, TokenType.LT_LT);
} else {
_appendTokenOfType(TokenType.LT);
return next;
@@ -964,10 +981,10 @@
int _tokenizeMinus(int next) {
// - -- -=
next = _reader.advance();
- if (next == 0x2D) {
+ if (next == $minus) {
_appendTokenOfType(TokenType.MINUS_MINUS);
return _reader.advance();
- } else if (next == 0x3D) {
+ } else if (next == $equal) {
_appendTokenOfType(TokenType.MINUS_EQ);
return _reader.advance();
} else {
@@ -985,9 +1002,9 @@
_appendCommentToken(
TokenType.MULTI_LINE_COMMENT, _reader.getString(_tokenStart, 0));
return next;
- } else if (0x2A == next) {
+ } else if ($asterisk == next) {
next = _reader.advance();
- if (0x2F == next) {
+ if ($slash == next) {
--nesting;
if (0 == nesting) {
_appendCommentToken(TokenType.MULTI_LINE_COMMENT,
@@ -997,19 +1014,19 @@
next = _reader.advance();
}
}
- } else if (0x2F == next) {
+ } else if ($slash == next) {
next = _reader.advance();
- if (0x2A == next) {
+ if ($asterisk == next) {
next = _reader.advance();
++nesting;
}
- } else if (next == 0xD) {
+ } else if (next == $cr) {
next = _reader.advance();
- if (next == 0xA) {
+ if (next == $lf) {
next = _reader.advance();
}
recordStartOfLine();
- } else if (next == 0xA) {
+ } else if (next == $lf) {
next = _reader.advance();
recordStartOfLine();
} else {
@@ -1024,13 +1041,13 @@
while (next != quoteChar) {
if (next == -1) {
break outer;
- } else if (next == 0xD) {
+ } else if (next == $cr) {
next = _reader.advance();
- if (next == 0xA) {
+ if (next == $lf) {
next = _reader.advance();
}
recordStartOfLine();
- } else if (next == 0xA) {
+ } else if (next == $lf) {
next = _reader.advance();
recordStartOfLine();
} else {
@@ -1057,7 +1074,7 @@
}
int next = _reader.advance();
while (next != -1) {
- if (next == 0x24) {
+ if (next == $$) {
_appendStringToken(TokenType.STRING, _reader.getString(start, -1));
next = _tokenizeStringInterpolation(start);
_beginToken();
@@ -1075,30 +1092,30 @@
}
continue;
}
- if (next == 0x5C) {
+ if (next == $backslash) {
next = _reader.advance();
if (next == -1) {
break;
}
- if (next == 0xD) {
+ if (next == $cr) {
next = _reader.advance();
- if (next == 0xA) {
+ if (next == $lf) {
next = _reader.advance();
}
recordStartOfLine();
- } else if (next == 0xA) {
+ } else if (next == $lf) {
recordStartOfLine();
next = _reader.advance();
} else {
next = _reader.advance();
}
- } else if (next == 0xD) {
+ } else if (next == $cr) {
next = _reader.advance();
- if (next == 0xA) {
+ if (next == $lf) {
next = _reader.advance();
}
recordStartOfLine();
- } else if (next == 0xA) {
+ } else if (next == $lf) {
recordStartOfLine();
next = _reader.advance();
} else {
@@ -1115,17 +1132,17 @@
}
int _tokenizeMultiply(int next) =>
- _select(0x3D, TokenType.STAR_EQ, TokenType.STAR);
+ _select($equal, TokenType.STAR_EQ, TokenType.STAR);
int _tokenizeNumber(int next) {
int start = _reader.offset;
while (true) {
next = _reader.advance();
- if (0x30 <= next && next <= 0x39) {
+ if ($0 <= next && next <= $9) {
continue;
- } else if (next == 0x2E) {
+ } else if (next == $dot) {
return _tokenizeFractionPart(_reader.advance(), start);
- } else if (next == 0x65 || next == 0x45) {
+ } else if (next == $e || next == $E) {
return _tokenizeFractionPart(next, start);
} else {
_appendStringToken(
@@ -1138,8 +1155,8 @@
int _tokenizeOpenSquareBracket(int next) {
// [ [] []=
next = _reader.advance();
- if (next == 0x5D) {
- return _select(0x3D, TokenType.INDEX_EQ, TokenType.INDEX);
+ if (next == $close_bracket) {
+ return _select($equal, TokenType.INDEX_EQ, TokenType.INDEX);
} else {
_appendBeginToken(TokenType.OPEN_SQUARE_BRACKET);
return next;
@@ -1147,15 +1164,15 @@
}
int _tokenizePercent(int next) =>
- _select(0x3D, TokenType.PERCENT_EQ, TokenType.PERCENT);
+ _select($equal, TokenType.PERCENT_EQ, TokenType.PERCENT);
int _tokenizePlus(int next) {
// + ++ +=
next = _reader.advance();
- if (0x2B == next) {
+ if ($plus == next) {
_appendTokenOfType(TokenType.PLUS_PLUS);
return _reader.advance();
- } else if (0x3D == next) {
+ } else if ($equal == next) {
_appendTokenOfType(TokenType.PLUS_EQ);
return _reader.advance();
} else {
@@ -1167,14 +1184,14 @@
int _tokenizeQuestion() {
// ? ?. ?? ??=
int next = _reader.advance();
- if (next == 0x2E) {
+ if (next == $dot) {
// '.'
_appendTokenOfType(TokenType.QUESTION_PERIOD);
return _reader.advance();
- } else if (next == 0x3F) {
+ } else if (next == $question) {
// '?'
next = _reader.advance();
- if (next == 0x3D) {
+ if (next == $equal) {
// '='
_appendTokenOfType(TokenType.QUESTION_QUESTION_EQ);
return _reader.advance();
@@ -1195,7 +1212,7 @@
_appendCommentToken(
TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, 0));
return next;
- } else if (0xA == next || 0xD == next) {
+ } else if ($lf == next || $cr == next) {
_appendCommentToken(
TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, -1));
return next;
@@ -1209,7 +1226,7 @@
if (next == quoteChar) {
_appendStringToken(TokenType.STRING, _reader.getString(start, 0));
return _reader.advance();
- } else if (next == 0xD || next == 0xA) {
+ } else if (next == $cr || next == $lf) {
_reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
_appendStringToken(TokenType.STRING, _reader.getString(start, -1));
return _reader.advance();
@@ -1223,16 +1240,16 @@
int _tokenizeSingleLineString(int next, int quoteChar, int start) {
while (next != quoteChar) {
- if (next == 0x5C) {
+ if (next == $backslash) {
next = _reader.advance();
- } else if (next == 0x24) {
+ } else if (next == $$) {
_appendStringToken(TokenType.STRING, _reader.getString(start, -1));
next = _tokenizeStringInterpolation(start);
_beginToken();
start = _reader.offset;
continue;
}
- if (next <= 0xD && (next == 0xA || next == 0xD || next == -1)) {
+ if (next <= $cr && (next == $lf || next == $cr || next == -1)) {
_reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
if (start == _reader.offset) {
_appendStringTokenWithOffset(TokenType.STRING, "", 1);
@@ -1251,11 +1268,11 @@
int _tokenizeSlashOrComment(int next) {
next = _reader.advance();
- if (0x2A == next) {
+ if ($asterisk == next) {
return _tokenizeMultiLineComment(next);
- } else if (0x2F == next) {
+ } else if ($slash == next) {
return _tokenizeSingleLineComment(next);
- } else if (0x3D == next) {
+ } else if ($equal == next) {
_appendTokenOfType(TokenType.SLASH_EQ);
return _reader.advance();
} else {
@@ -1288,7 +1305,7 @@
int _tokenizeStringInterpolation(int start) {
_beginToken();
int next = _reader.advance();
- if (next == 0x7B) {
+ if (next == $lbrace) {
return _tokenizeInterpolatedExpression(next, start);
} else {
return _tokenizeInterpolatedIdentifier(next, start);
@@ -1298,10 +1315,10 @@
int _tokenizeTag(int next) {
// # or #!.*[\n\r]
if (_reader.offset == 0) {
- if (_reader.peek() == 0x21) {
+ if (_reader.peek() == $exclamation) {
do {
next = _reader.advance();
- } while (next != 0xA && next != 0xD && next > 0);
+ } while (next != $lf && next != $cr && next > 0);
_appendStringToken(
TokenType.SCRIPT_TAG, _reader.getString(_tokenStart, 0));
return next;
@@ -1314,8 +1331,8 @@
int _tokenizeTilde(int next) {
// ~ ~/ ~/=
next = _reader.advance();
- if (next == 0x2F) {
- return _select(0x3D, TokenType.TILDE_SLASH_EQ, TokenType.TILDE_SLASH);
+ if (next == $slash) {
+ return _select($equal, TokenType.TILDE_SLASH_EQ, TokenType.TILDE_SLASH);
} else {
_appendTokenOfType(TokenType.TILDE);
return next;
@@ -1326,8 +1343,8 @@
* Checks if [value] is a single-line or multi-line comment.
*/
static bool _isDocumentationComment(String value) {
- return StringUtilities.startsWith3(value, 0, 0x2F, 0x2F, 0x2F) ||
- StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x2A);
+ return StringUtilities.startsWith3(value, 0, $slash, $slash, $slash) ||
+ StringUtilities.startsWith3(value, 0, $slash, $asterisk, $asterisk);
}
}
diff --git a/pkg/analyzer/lib/src/dart/sdk/sdk.dart b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
new file mode 100644
index 0000000..338a560
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
@@ -0,0 +1,708 @@
+// 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.generated.sdk2;
+
+import 'dart:collection';
+import 'dart:io' as io;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/java_engine_io.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
+import 'package:analyzer/src/summary/summary_sdk.dart';
+import 'package:path/path.dart' as pathos;
+import 'package:yaml/yaml.dart';
+
+/**
+ * An abstract implementation of a Dart SDK in which the available libraries are
+ * stored in a library map. Subclasses are responsible for populating the
+ * library map.
+ */
+abstract class AbstractDartSdk implements DartSdk {
+ /**
+ * The resource provider used to access the file system.
+ */
+ ResourceProvider resourceProvider;
+
+ /**
+ * A mapping from Dart library URI's to the library represented by that URI.
+ */
+ LibraryMap libraryMap = new LibraryMap();
+
+ /**
+ * The [AnalysisOptions] to use to create the [context].
+ */
+ AnalysisOptions _analysisOptions;
+
+ /**
+ * The flag that specifies whether an SDK summary should be used. This is a
+ * temporary flag until summaries are enabled by default.
+ */
+ bool _useSummary = false;
+
+ /**
+ * The [AnalysisContext] which is used for all of the sources in this SDK.
+ */
+ InternalAnalysisContext _analysisContext;
+
+ /**
+ * The mapping from Dart URI's to the corresponding sources.
+ */
+ Map<String, Source> _uriToSourceMap = new HashMap<String, Source>();
+
+ /**
+ * Set the [options] for this SDK analysis context. Throw [StateError] if the
+ * context has been already created.
+ */
+ void set analysisOptions(AnalysisOptions options) {
+ if (_analysisContext != null) {
+ throw new StateError(
+ 'Analysis options cannot be changed after context creation.');
+ }
+ _analysisOptions = options;
+ }
+
+ @override
+ AnalysisContext get context {
+ if (_analysisContext == null) {
+ _analysisContext = new SdkAnalysisContext(_analysisOptions);
+ SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
+ _analysisContext.sourceFactory = factory;
+ if (_useSummary) {
+ bool strongMode = _analysisOptions?.strongMode ?? false;
+ PackageBundle sdkBundle = getSummarySdkBundle(strongMode);
+ if (sdkBundle != null) {
+ _analysisContext.resultProvider = new SdkSummaryResultProvider(
+ _analysisContext, sdkBundle, strongMode);
+ }
+ }
+ }
+ return _analysisContext;
+ }
+
+ @override
+ List<SdkLibrary> get sdkLibraries => libraryMap.sdkLibraries;
+
+ /**
+ * Return the path separator used by the resource provider.
+ */
+ String get separator => resourceProvider.pathContext.separator;
+
+ @override
+ List<String> get uris => libraryMap.uris;
+
+ /**
+ * Return `true` if the SDK summary will be used when available.
+ */
+ bool get useSummary => _useSummary;
+
+ /**
+ * Specify whether SDK summary should be used.
+ */
+ void set useSummary(bool use) {
+ if (_analysisContext != null) {
+ throw new StateError(
+ 'The "useSummary" flag cannot be changed after context creation.');
+ }
+ _useSummary = use;
+ }
+
+ @override
+ Source fromFileUri(Uri uri) {
+ File file =
+ resourceProvider.getFile(resourceProvider.pathContext.fromUri(uri));
+ String path = _getPath(file);
+ if (path == null) {
+ return null;
+ }
+ try {
+ return file.createSource(parseUriWithException(path));
+ } on URISyntaxException catch (exception, stackTrace) {
+ AnalysisEngine.instance.logger.logInformation(
+ "Failed to create URI: $path",
+ new CaughtException(exception, stackTrace));
+ }
+ return null;
+ }
+
+ String getRelativePathFromFile(File file);
+
+ @override
+ SdkLibrary getSdkLibrary(String dartUri) => libraryMap.getLibrary(dartUri);
+
+ /**
+ * Return the [PackageBundle] for this SDK, if it exists, or `null` otherwise.
+ * This method should not be used outside of `analyzer` and `analyzer_cli`
+ * packages.
+ */
+ PackageBundle getSummarySdkBundle(bool strongMode);
+
+ Source internalMapDartUri(String dartUri) {
+ // TODO(brianwilkerson) Figure out how to unify the implementations in the
+ // two subclasses.
+ 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(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('/', separator);
+ try {
+ File file = resourceProvider.getFile(filePath);
+ return file.createSource(parseUriWithException(dartUri));
+ } on URISyntaxException {
+ return null;
+ }
+ }
+
+ @override
+ Source mapDartUri(String dartUri) {
+ Source source = _uriToSourceMap[dartUri];
+ if (source == null) {
+ source = internalMapDartUri(dartUri);
+ _uriToSourceMap[dartUri] = source;
+ }
+ return source;
+ }
+
+ String _getPath(File file) {
+ List<SdkLibrary> libraries = libraryMap.sdkLibraries;
+ int length = libraries.length;
+ List<String> paths = new List(length);
+ String filePath = getRelativePathFromFile(file);
+ if (filePath == null) {
+ return null;
+ }
+ for (int i = 0; i < length; i++) {
+ SdkLibrary library = libraries[i];
+ String libraryPath = library.path.replaceAll('/', separator);
+ if (filePath == libraryPath) {
+ return library.shortName;
+ }
+ paths[i] = libraryPath;
+ }
+ for (int i = 0; i < length; i++) {
+ SdkLibrary library = libraries[i];
+ String libraryPath = paths[i];
+ int index = libraryPath.lastIndexOf(separator);
+ if (index >= 0) {
+ String prefix = libraryPath.substring(0, index + 1);
+ if (filePath.startsWith(prefix)) {
+ String relPath =
+ filePath.substring(prefix.length).replaceAll(separator, '/');
+ return '${library.shortName}/$relPath';
+ }
+ }
+ }
+ return null;
+ }
+}
+
+/**
+ * An SDK backed by URI mappings derived from an `_embedder.yaml` file.
+ */
+class EmbedderSdk extends AbstractDartSdk {
+ static const String _DART_COLON_PREFIX = 'dart:';
+
+ static const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs';
+ final Map<String, String> _urlMappings = new HashMap<String, String>();
+
+ EmbedderSdk(
+ ResourceProvider resourceProvider, Map<Folder, YamlMap> embedderYamls) {
+ this.resourceProvider = resourceProvider;
+ embedderYamls?.forEach(_processEmbedderYaml);
+ }
+
+ @override
+ // TODO(danrubel) Determine SDK version
+ String get sdkVersion => '0';
+
+ /**
+ * The url mappings for this SDK.
+ */
+ Map<String, String> get urlMappings => _urlMappings;
+
+ @override
+ String getRelativePathFromFile(File file) => file.path;
+
+ @override
+ PackageBundle getSummarySdkBundle(bool strongMode) => null;
+
+ @override
+ Source internalMapDartUri(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(resourceProvider.pathContext.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('/', resourceProvider.pathContext.separator);
+ try {
+ File file = resourceProvider.getFile(filePath);
+ return file.createSource(parseUriWithException(dartUri));
+ } on URISyntaxException {
+ return null;
+ }
+ }
+
+ /**
+ * Install the mapping from [name] to [libDir]/[file].
+ */
+ void _processEmbeddedLibs(String name, String file, Folder libDir) {
+ if (!name.startsWith(_DART_COLON_PREFIX)) {
+ // SDK libraries must begin with 'dart:'.
+ return;
+ }
+ String libPath = libDir.canonicalizePath(file);
+ _urlMappings[name] = libPath;
+ SdkLibraryImpl library = new SdkLibraryImpl(name);
+ library.path = libPath;
+ libraryMap.setLibrary(name, library);
+ }
+
+ /**
+ * Given the 'embedderYamls' from [EmbedderYamlLocator] check each one for the
+ * top level key 'embedded_libs'. Under the 'embedded_libs' key are key value
+ * pairs. Each key is a 'dart:' library uri and each value is a path
+ * (relative to the directory containing `_embedder.yaml`) to a dart script
+ * for the given library. For example:
+ *
+ * embedded_libs:
+ * 'dart:io': '../../sdk/io/io.dart'
+ *
+ * If a key doesn't begin with `dart:` it is ignored.
+ */
+ void _processEmbedderYaml(Folder libDir, YamlMap map) {
+ YamlNode embedded_libs = map[_EMBEDDED_LIB_MAP_KEY];
+ if (embedded_libs is YamlMap) {
+ embedded_libs.forEach((k, v) => _processEmbeddedLibs(k, v, libDir));
+ }
+ }
+}
+
+/**
+ * A Dart SDK installed in a specified directory. Typical Dart SDK layout is
+ * something like...
+ *
+ * dart-sdk/
+ * bin/
+ * dart[.exe] <-- VM
+ * lib/
+ * core/
+ * core.dart
+ * ... other core library files ...
+ * ... other libraries ...
+ * util/
+ * ... Dart utilities ...
+ * Chromium/ <-- Dartium typically exists in a sibling directory
+ */
+class FolderBasedDartSdk extends AbstractDartSdk {
+ /**
+ * The name of the directory within the SDK directory that contains
+ * executables.
+ */
+ static String _BIN_DIRECTORY_NAME = "bin";
+
+ /**
+ * The name of the directory within the SDK directory that contains
+ * documentation for the libraries.
+ */
+ static String _DOCS_DIRECTORY_NAME = "docs";
+
+ /**
+ * The name of the directory within the SDK directory that contains the
+ * sdk_library_metadata directory.
+ */
+ static String _INTERNAL_DIR = "_internal";
+
+ /**
+ * The name of the sdk_library_metadata directory that contains the package
+ * holding the libraries.dart file.
+ */
+ static String _SDK_LIBRARY_METADATA_DIR = "sdk_library_metadata";
+
+ /**
+ * The name of the directory within the sdk_library_metadata that contains
+ * libraries.dart.
+ */
+ static String _SDK_LIBRARY_METADATA_LIB_DIR = "lib";
+
+ /**
+ * The name of the directory within the SDK directory that contains the
+ * libraries.
+ */
+ static String _LIB_DIRECTORY_NAME = "lib";
+
+ /**
+ * The name of the libraries file.
+ */
+ static String _LIBRARIES_FILE = "libraries.dart";
+
+ /**
+ * The name of the pub executable on windows.
+ */
+ static String _PUB_EXECUTABLE_NAME_WIN = "pub.bat";
+
+ /**
+ * The name of the pub executable on non-windows operating systems.
+ */
+ static String _PUB_EXECUTABLE_NAME = "pub";
+
+ /**
+ * The name of the file within the SDK directory that contains the version
+ * number of the SDK.
+ */
+ static String _VERSION_FILE_NAME = "version";
+
+ /**
+ * The directory containing the SDK.
+ */
+ Folder _sdkDirectory;
+
+ /**
+ * The directory within the SDK directory that contains the libraries.
+ */
+ Folder _libraryDirectory;
+
+ /**
+ * The revision number of this SDK, or `"0"` if the revision number cannot be
+ * discovered.
+ */
+ String _sdkVersion;
+
+ /**
+ * The file containing the pub executable.
+ */
+ File _pubExecutable;
+
+ /**
+ * Initialize a newly created SDK to represent the Dart SDK installed in the
+ * [sdkDirectory]. The flag [useDart2jsPaths] is `true` if the dart2js path
+ * should be used when it is available
+ */
+ FolderBasedDartSdk(ResourceProvider resourceProvider, this._sdkDirectory,
+ [bool useDart2jsPaths = false]) {
+ this.resourceProvider = resourceProvider;
+ libraryMap = initialLibraryMap(useDart2jsPaths);
+ }
+
+ /**
+ * Return the directory containing the SDK.
+ */
+ Folder get directory => _sdkDirectory;
+
+ /**
+ * Return the directory containing documentation for the SDK.
+ */
+ Folder get docDirectory =>
+ _sdkDirectory.getChildAssumingFolder(_DOCS_DIRECTORY_NAME);
+
+ /**
+ * Return the directory within the SDK directory that contains the libraries.
+ */
+ Folder get libraryDirectory {
+ if (_libraryDirectory == null) {
+ _libraryDirectory =
+ _sdkDirectory.getChildAssumingFolder(_LIB_DIRECTORY_NAME);
+ }
+ return _libraryDirectory;
+ }
+
+ /**
+ * Return the file containing the Pub executable, or `null` if it does not exist.
+ */
+ File get pubExecutable {
+ if (_pubExecutable == null) {
+ _pubExecutable = _sdkDirectory
+ .getChildAssumingFolder(_BIN_DIRECTORY_NAME)
+ .getChildAssumingFile(OSUtilities.isWindows()
+ ? _PUB_EXECUTABLE_NAME_WIN
+ : _PUB_EXECUTABLE_NAME);
+ }
+ return _pubExecutable;
+ }
+
+ /**
+ * Return the revision number of this SDK, or `"0"` if the revision number
+ * cannot be discovered.
+ */
+ @override
+ String get sdkVersion {
+ if (_sdkVersion == null) {
+ _sdkVersion = DartSdk.DEFAULT_VERSION;
+ File revisionFile =
+ _sdkDirectory.getChildAssumingFile(_VERSION_FILE_NAME);
+ try {
+ String revision = revisionFile.readAsStringSync();
+ if (revision != null) {
+ _sdkVersion = revision.trim();
+ }
+ } on FileSystemException {
+ // Fall through to return the default.
+ }
+ }
+ return _sdkVersion;
+ }
+
+ /**
+ * Determine the search order for trying to locate the [_LIBRARIES_FILE].
+ */
+ Iterable<File> get _libraryMapLocations sync* {
+ yield libraryDirectory
+ .getChildAssumingFolder(_INTERNAL_DIR)
+ .getChildAssumingFolder(_SDK_LIBRARY_METADATA_DIR)
+ .getChildAssumingFolder(_SDK_LIBRARY_METADATA_LIB_DIR)
+ .getChildAssumingFile(_LIBRARIES_FILE);
+ yield libraryDirectory
+ .getChildAssumingFolder(_INTERNAL_DIR)
+ .getChildAssumingFile(_LIBRARIES_FILE);
+ }
+
+ @override
+ String getRelativePathFromFile(File file) {
+ String filePath = file.path;
+ String libPath = libraryDirectory.path;
+ if (!filePath
+ .startsWith("$libPath${resourceProvider.pathContext.separator}")) {
+ return null;
+ }
+ return filePath.substring(libPath.length + 1);
+ }
+
+ /**
+ * Return the [PackageBundle] for this SDK, if it exists, or `null` otherwise.
+ * This method should not be used outside of `analyzer` and `analyzer_cli`
+ * packages.
+ */
+ PackageBundle getSummarySdkBundle(bool strongMode) {
+ String rootPath = directory.path;
+ String name = strongMode ? 'strong.sum' : 'spec.sum';
+ String path =
+ resourceProvider.pathContext.join(rootPath, 'lib', '_internal', name);
+ try {
+ File file = resourceProvider.getFile(path);
+ if (file.exists) {
+ List<int> bytes = file.readAsBytesSync();
+ return new PackageBundle.fromBuffer(bytes);
+ }
+ } catch (exception, stackTrace) {
+ AnalysisEngine.instance.logger.logError(
+ 'Failed to load SDK analysis summary from $path',
+ new CaughtException(exception, stackTrace));
+ }
+ return null;
+ }
+
+ /**
+ * Read all of the configuration files to initialize the library maps. The
+ * flag [useDart2jsPaths] is `true` if the dart2js path should be used when it
+ * is available. Return the initialized library map.
+ */
+ LibraryMap initialLibraryMap(bool useDart2jsPaths) {
+ List<String> searchedPaths = <String>[];
+ var lastStackTrace = null;
+ var lastException = null;
+ for (File librariesFile in _libraryMapLocations) {
+ try {
+ String contents = librariesFile.readAsStringSync();
+ return new SdkLibrariesReader(useDart2jsPaths)
+ .readFromFile(librariesFile, contents);
+ } catch (exception, stackTrace) {
+ searchedPaths.add(librariesFile.path);
+ lastException = exception;
+ lastStackTrace = stackTrace;
+ }
+ }
+ AnalysisEngine.instance.logger.logError(
+ "Could not initialize the library map from $searchedPaths",
+ new CaughtException(lastException, lastStackTrace));
+ return new LibraryMap();
+ }
+
+ @override
+ Source internalMapDartUri(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;
+ }
+ try {
+ File file = libraryDirectory.getChildAssumingFile(library.path);
+ if (!relativePath.isEmpty) {
+ file = file.parent.getChildAssumingFile(relativePath);
+ }
+ return file.createSource(parseUriWithException(dartUri));
+ } on URISyntaxException {
+ return null;
+ }
+ }
+
+ /**
+ * Return the default directory for the Dart SDK, or `null` if the directory
+ * cannot be determined (or does not exist). The default directory is provided
+ * by a system property named `com.google.dart.sdk`.
+ */
+ static Folder defaultSdkDirectory(ResourceProvider resourceProvider) {
+ // TODO(brianwilkerson) This is currently only being used in the analysis
+ // server's Driver class to find the default SDK. The command-line analyzer
+ // uses cli_utils to find the SDK. Not sure why they're different.
+ String sdkProperty = getSdkProperty(resourceProvider);
+ if (sdkProperty == null) {
+ return null;
+ }
+ Folder sdkDirectory = resourceProvider.getFolder(sdkProperty);
+ if (!sdkDirectory.exists) {
+ return null;
+ }
+ return sdkDirectory;
+ }
+
+ static String getSdkProperty(ResourceProvider resourceProvider) {
+ String exec = io.Platform.executable;
+ if (exec.length == 0) {
+ return null;
+ }
+ pathos.Context pathContext = resourceProvider.pathContext;
+ // Might be "xcodebuild/ReleaseIA32/dart" with "sdk" sibling
+ String outDir = pathContext.dirname(pathContext.dirname(exec));
+ String sdkPath = pathContext.join(pathContext.dirname(outDir), "sdk");
+ if (resourceProvider.getFolder(sdkPath).exists) {
+ return sdkPath;
+ }
+ // probably be "dart-sdk/bin/dart"
+ return pathContext.dirname(pathContext.dirname(exec));
+ }
+}
+
+/**
+ * An object used to read and parse the libraries file
+ * (dart-sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart) for information
+ * about the libraries in an SDK. The library information is represented as a
+ * Dart file containing a single top-level variable whose value is a const map.
+ * The keys of the map are the names of libraries defined in the SDK and the
+ * values in the map are info objects defining the library. For example, a
+ * subset of a typical SDK might have a libraries file that looks like the
+ * following:
+ *
+ * final Map<String, LibraryInfo> LIBRARIES = const <LibraryInfo> {
+ * // Used by VM applications
+ * "builtin" : const LibraryInfo(
+ * "builtin/builtin_runtime.dart",
+ * category: "Server",
+ * platforms: VM_PLATFORM),
+ *
+ * "compiler" : const LibraryInfo(
+ * "compiler/compiler.dart",
+ * category: "Tools",
+ * platforms: 0),
+ * };
+ */
+class SdkLibrariesReader {
+ /**
+ * A flag indicating whether the dart2js path should be used when it is
+ * available.
+ */
+ final bool _useDart2jsPaths;
+
+ /**
+ * Initialize a newly created library reader to use the dart2js path if
+ * [_useDart2jsPaths] is `true`.
+ */
+ SdkLibrariesReader(this._useDart2jsPaths);
+
+ /**
+ * Return the library map read from the given [file], given that the content
+ * of the file is already known to be [libraryFileContents].
+ */
+ LibraryMap readFromFile(File file, String libraryFileContents) =>
+ readFromSource(file.createSource(), libraryFileContents);
+
+ /**
+ * Return the library map read from the given [source], given that the content
+ * of the file is already known to be [libraryFileContents].
+ */
+ LibraryMap readFromSource(Source source, String libraryFileContents) {
+ BooleanErrorListener errorListener = new BooleanErrorListener();
+ Scanner scanner = new Scanner(
+ source, new CharSequenceReader(libraryFileContents), errorListener);
+ Parser parser = new Parser(source, errorListener);
+ CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
+ SdkLibrariesReader_LibraryBuilder libraryBuilder =
+ new SdkLibrariesReader_LibraryBuilder(_useDart2jsPaths);
+ // If any syntactic errors were found then don't try to visit the AST
+ // structure.
+ if (!errorListener.errorReported) {
+ unit.accept(libraryBuilder);
+ }
+ return libraryBuilder.librariesMap;
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index b2c10e2..029b5c6 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -156,7 +156,9 @@
Object visitAssignmentExpression(AssignmentExpression node) {
Token operator = node.operator;
TokenType operatorType = operator.type;
- if (operatorType != TokenType.EQ &&
+ if (operatorType != TokenType.AMPERSAND_AMPERSAND_EQ &&
+ operatorType != TokenType.BAR_BAR_EQ &&
+ operatorType != TokenType.EQ &&
operatorType != TokenType.QUESTION_QUESTION_EQ) {
operatorType = _operatorFromCompoundAssignment(operatorType);
Expression leftHandSide = node.leftHandSide;
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index bd08147..967095a 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1070,6 +1070,12 @@
bool get enableGenericMethods => null;
/**
+ * Return `true` to enable the lazy compound assignment operators '&&=' and
+ * '||='.
+ */
+ bool get enableLazyAssignmentOperators;
+
+ /**
* Return `true` to strictly follow the specification when generating
* warnings on "call" methods (fixes dartbug.com/21938).
*/
@@ -1185,6 +1191,11 @@
static const int ENABLE_SUPER_MIXINS_FLAG = 0x40;
/**
+ * The default list of non-nullable type names.
+ */
+ static const List<String> NONNULLABLE_TYPES = const <String>[];
+
+ /**
* A predicate indicating whether analysis is to parse and analyze function
* bodies.
*/
@@ -1219,6 +1230,9 @@
*/
bool enableGenericMethods = false;
+ @override
+ bool enableLazyAssignmentOperators = false;
+
/**
* A flag indicating whether analysis is to strictly follow the specification
* when generating warnings on "call" methods (fixes dartbug.com/21938).
@@ -1234,9 +1248,6 @@
@override
bool enableTiming = false;
- @override
- bool enableTrailingCommas = true;
-
/**
* A flag indicating whether errors, warnings and hints should be generated
* for sources that are implicitly being analyzed.
@@ -1306,6 +1317,12 @@
*/
bool implicitCasts = true;
+ /**
+ * A list of non-nullable type names, prefixed by the library URI they belong
+ * to, e.g., 'dart:core,int', 'dart:core,bool', 'file:///foo.dart,bar', etc.
+ */
+ List<String> nonnullableTypes = NONNULLABLE_TYPES;
+
@override
bool finerGrainedInvalidation = false;
@@ -1353,6 +1370,7 @@
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
implicitCasts = options.implicitCasts;
+ nonnullableTypes = options.nonnullableTypes;
implicitDynamic = options.implicitDynamic;
}
trackCacheDependencies = options.trackCacheDependencies;
@@ -1542,18 +1560,26 @@
*/
class CacheConsistencyValidationStatistics {
/**
- * Number of sources which were modified, but the context was not notified
+ * Number of sources which were changed, but the context was not notified
* about it, so this fact was detected only during cache consistency
* validation.
*/
- int numOfModified = 0;
+ int numOfChanged = 0;
/**
- * Number of sources which were deleted, but the context was not notified
+ * Number of sources which stopped existing, but the context was not notified
* about it, so this fact was detected only during cache consistency
* validation.
*/
- int numOfDeleted = 0;
+ int numOfRemoved = 0;
+
+ /**
+ * Reset all counters.
+ */
+ void reset() {
+ numOfChanged = 0;
+ numOfRemoved = 0;
+ }
}
/**
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 4a7cef1..e3cf73c7 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -13,7 +13,6 @@
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';
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index b111583..afa7cce 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -3143,14 +3143,14 @@
_typeParameters.add(element);
}
- FieldElement getField(String fieldName) {
+ FieldElement getField(String fieldName, {bool synthetic: false}) {
if (_fields == null) {
return null;
}
int length = _fields.length;
for (int i = 0; i < length; i++) {
FieldElement field = _fields[i];
- if (field.name == fieldName) {
+ if (field.name == fieldName && field.isSynthetic == synthetic) {
return field;
}
}
@@ -3434,7 +3434,10 @@
if (_nodeExits(leftHandSide)) {
return true;
}
- if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
+ TokenType operatorType = node.operator.type;
+ if (operatorType == TokenType.AMPERSAND_AMPERSAND_EQ ||
+ operatorType == TokenType.BAR_BAR_EQ ||
+ operatorType == TokenType.QUESTION_QUESTION_EQ) {
return false;
}
if (leftHandSide is PropertyAccess &&
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 19019da..f681471 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -255,6 +255,9 @@
// bound of the static types of the LHS and RHS.
_analyzeLeastUpperBound(node, node.leftHandSide, node.rightHandSide);
return null;
+ } else if (operator == TokenType.AMPERSAND_AMPERSAND_EQ ||
+ operator == TokenType.BAR_BAR_EQ) {
+ _recordStaticType(node, _typeProvider.boolType);
} else {
ExecutableElement staticMethodElement = node.staticElement;
DartType staticType = _computeStaticReturnType(staticMethodElement);
@@ -2008,7 +2011,11 @@
arguments.correspondingStaticParameters = ResolverVisitor
.resolveArgumentsToParameters(arguments, inferred.parameters, null);
inferConstructorName(constructor, inferred.returnType);
- // TODO(jmesserly): should we fix up the staticElement as well?
+ // Update the static element as well. This is used in some cases, such as
+ // computing constant values. It is stored in two places.
+ constructor.staticElement =
+ ConstructorMember.from(rawElement, inferred.returnType);
+ node.staticElement = constructor.staticElement;
}
}
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index f7efd79..9154132 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -31,7 +31,14 @@
*/
final bool implicitCasts;
- StrongTypeSystemImpl({this.implicitCasts: true});
+ /**
+ * A list of non-nullable type names (e.g., 'int', 'bool', etc.).
+ */
+ final List<String> nonnullableTypes;
+
+ StrongTypeSystemImpl(
+ {this.implicitCasts: true,
+ this.nonnullableTypes: AnalysisOptionsImpl.NONNULLABLE_TYPES});
bool anyParameterType(FunctionType ft, bool predicate(DartType t)) {
return ft.parameters.any((p) => predicate(p.type));
@@ -156,7 +163,7 @@
// subtypes (or supertypes) as necessary, and track the constraints that
// are implied by this.
var inferringTypeSystem =
- new _StrongInferenceTypeSystem(typeProvider, fnType.typeFormals);
+ new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals);
// Since we're trying to infer the instantiation, we want to ignore type
// formals as we check the parameters and return type.
@@ -209,7 +216,7 @@
// subtypes (or supertypes) as necessary, and track the constraints that
// are implied by this.
var inferringTypeSystem =
- new _StrongInferenceTypeSystem(typeProvider, fnType.typeFormals);
+ new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals);
// Special case inference for Future.then.
//
@@ -622,8 +629,9 @@
bool _isInterfaceSubtypeOf(
InterfaceType i1, InterfaceType i2, Set<Element> visited) {
// Guard recursive calls
- _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
- _guard(_isInterfaceSubtypeOf);
+ _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = _guard(
+ (DartType i1, DartType i2, Set<Element> visited) =>
+ _isInterfaceSubtypeOf(i1, i2, visited));
if (i1 == i2) {
return true;
@@ -755,6 +763,16 @@
return (t.isDynamic && !dynamicIsBottom) || t.isObject;
}
+ bool isNonNullableType(DartType type) {
+ return nonnullableTypes.contains(_getTypeFullyQualifiedName(type));
+ }
+
+ /// Given a type return its name prepended with the URI to its containing
+ /// library and separated by a comma.
+ String _getTypeFullyQualifiedName(DartType type) {
+ return "${type?.element?.library?.source?.uri},$type";
+ }
+
/**
* This currently just implements a simple least upper bound to
* handle some common cases. It also avoids some termination issues
@@ -1185,7 +1203,9 @@
static TypeSystem create(AnalysisContext context) {
var options = context.analysisOptions as AnalysisOptionsImpl;
return options.strongMode
- ? new StrongTypeSystemImpl(implicitCasts: options.implicitCasts)
+ ? new StrongTypeSystemImpl(
+ implicitCasts: options.implicitCasts,
+ nonnullableTypes: options.nonnullableTypes)
: new TypeSystemImpl();
}
}
@@ -1261,16 +1281,16 @@
/// Tracks upper and lower type bounds for a set of type parameters.
class _StrongInferenceTypeSystem extends StrongTypeSystemImpl {
final TypeProvider _typeProvider;
+
+ /// The outer strong mode type system, used for GLB and LUB, so we don't
+ /// recurse into our constraint solving code.
+ final StrongTypeSystemImpl _typeSystem;
final Map<TypeParameterType, _TypeParameterBound> _bounds;
- _StrongInferenceTypeSystem(
- this._typeProvider, Iterable<TypeParameterElement> typeFormals)
- : _bounds =
- new Map.fromIterable(typeFormals, key: (t) => t.type, value: (t) {
- _TypeParameterBound bound = new _TypeParameterBound();
- if (t.bound != null) bound.upper = t.bound;
- return bound;
- });
+ _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem,
+ Iterable<TypeParameterElement> typeFormals)
+ : _bounds = new Map.fromIterable(typeFormals,
+ key: (t) => t.type, value: (t) => new _TypeParameterBound());
/// Given the constraints that were given by calling [isSubtypeOf], find the
/// instantiation of the generic function that satisfies these constraints.
@@ -1278,26 +1298,19 @@
List<TypeParameterType> fnTypeParams =
TypeParameterTypeImpl.getTypes(fnType.typeFormals);
- var inferredTypes = new List<DartType>.from(fnTypeParams, growable: false);
+ // Initialize the inferred type array.
+ //
+ // They all start as `dynamic` to offer reasonable degradation for f-bounded
+ // type parameters.
+ var inferredTypes = new List<DartType>.filled(
+ fnTypeParams.length, DynamicTypeImpl.instance,
+ growable: false);
+
for (int i = 0; i < fnTypeParams.length; i++) {
TypeParameterType typeParam = fnTypeParams[i];
- _TypeParameterBound bound = _bounds[typeParam];
- // Now we've computed lower and upper bounds for each type parameter.
+ // Apply the `extends` clause for the type parameter, if any.
//
- // To decide on which type to assign, we look at the return type and see
- // if the type parameter occurs in covariant or contravariant positions.
- //
- // If the type is "passed in" at all, or if our lower bound was bottom,
- // we choose the upper bound as being the most useful.
- //
- // Otherwise we choose the more precise lower bound.
- _TypeParameterVariance variance =
- new _TypeParameterVariance.from(typeParam, fnType.returnType);
-
- inferredTypes[i] =
- variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower;
-
// Assumption: if the current type parameter has an "extends" clause
// that refers to another type variable we are inferring, it will appear
// before us or in this list position. For example:
@@ -1313,8 +1326,28 @@
// Or if the type parameter's bound depends on itself such as:
//
// <T extends Clonable<T>>
+ DartType declaredUpperBound = typeParam.element.bound;
+ if (declaredUpperBound != null) {
+ // Assert that the type parameter is a subtype of its bound.
+ _inferTypeParameterSubtypeOf(typeParam,
+ declaredUpperBound.substitute2(inferredTypes, fnTypeParams), null);
+ }
+
+ // Now we've computed lower and upper bounds for each type parameter.
+ //
+ // To decide on which type to assign, we look at the return type and see
+ // if the type parameter occurs in covariant or contravariant positions.
+ //
+ // If the type is "passed in" at all, or if our lower bound was bottom,
+ // we choose the upper bound as being the most useful.
+ //
+ // Otherwise we choose the more precise lower bound.
+ _TypeParameterVariance variance =
+ new _TypeParameterVariance.from(typeParam, fnType.returnType);
+
+ _TypeParameterBound bound = _bounds[typeParam];
inferredTypes[i] =
- inferredTypes[i].substitute2(inferredTypes, fnTypeParams);
+ variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower;
// See if the constraints on the type variable are satisfied.
//
@@ -1348,7 +1381,8 @@
// We already know T1 <: U, for some U.
// So update U to reflect the new constraint T1 <: GLB(U, T2)
//
- bound.upper = getGreatestLowerBound(_typeProvider, bound.upper, t2);
+ bound.upper =
+ _typeSystem.getGreatestLowerBound(_typeProvider, bound.upper, t2);
// Optimistically assume we will be able to satisfy the constraint.
return true;
}
@@ -1362,7 +1396,8 @@
// We already know L <: T2, for some L.
// So update L to reflect the new constraint LUB(L, T1) <: T2
//
- bound.lower = getLeastUpperBound(_typeProvider, bound.lower, t1);
+ bound.lower =
+ _typeSystem.getLeastUpperBound(_typeProvider, bound.lower, t1);
// Optimistically assume we will be able to satisfy the constraint.
return true;
}
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 1034bc5..bbed56e 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -2136,7 +2136,9 @@
class PackageIndexBuilder extends Object with _PackageIndexMixin implements idl.PackageIndex {
List<idl.IndexSyntheticElementKind> _elementKinds;
- List<int> _elementOffsets;
+ List<int> _elementNameClassMemberIds;
+ List<int> _elementNameParameterIds;
+ List<int> _elementNameUnitMemberIds;
List<int> _elementUnits;
List<String> _strings;
List<int> _unitLibraryUris;
@@ -2155,17 +2157,47 @@
}
@override
- List<int> get elementOffsets => _elementOffsets ??= <int>[];
+ List<int> get elementNameClassMemberIds => _elementNameClassMemberIds ??= <int>[];
/**
* Each item of this list corresponds to a unique referenced element. It is
- * the offset of the element name relative to the beginning of the file. The
- * list is sorted in ascending order, so that the client can quickly check
- * whether an element is referenced in this [PackageIndex].
+ * the identifier of the class member element name, or `null` if the element is
+ * a top-level element. The list is sorted in ascending order, so that the
+ * client can quickly check whether an element is referenced in this
+ * [PackageIndex].
*/
- void set elementOffsets(List<int> _value) {
+ void set elementNameClassMemberIds(List<int> _value) {
assert(_value == null || _value.every((e) => e >= 0));
- _elementOffsets = _value;
+ _elementNameClassMemberIds = _value;
+ }
+
+ @override
+ List<int> get elementNameParameterIds => _elementNameParameterIds ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the identifier of the named parameter name, or `null` if the element is not
+ * a named parameter. The list is sorted in ascending order, so that the
+ * client can quickly check whether an element is referenced in this
+ * [PackageIndex].
+ */
+ void set elementNameParameterIds(List<int> _value) {
+ assert(_value == null || _value.every((e) => e >= 0));
+ _elementNameParameterIds = _value;
+ }
+
+ @override
+ List<int> get elementNameUnitMemberIds => _elementNameUnitMemberIds ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the identifier of the top-level element name, or `null` if the element is
+ * the unit. The list is sorted in ascending order, so that the client can
+ * quickly check whether an element is referenced in this [PackageIndex].
+ */
+ void set elementNameUnitMemberIds(List<int> _value) {
+ assert(_value == null || _value.every((e) => e >= 0));
+ _elementNameUnitMemberIds = _value;
}
@override
@@ -2229,9 +2261,11 @@
_unitUnitUris = _value;
}
- PackageIndexBuilder({List<idl.IndexSyntheticElementKind> elementKinds, List<int> elementOffsets, List<int> elementUnits, List<String> strings, List<int> unitLibraryUris, List<UnitIndexBuilder> units, List<int> unitUnitUris})
+ PackageIndexBuilder({List<idl.IndexSyntheticElementKind> elementKinds, List<int> elementNameClassMemberIds, List<int> elementNameParameterIds, List<int> elementNameUnitMemberIds, List<int> elementUnits, List<String> strings, List<int> unitLibraryUris, List<UnitIndexBuilder> units, List<int> unitUnitUris})
: _elementKinds = elementKinds,
- _elementOffsets = elementOffsets,
+ _elementNameClassMemberIds = elementNameClassMemberIds,
+ _elementNameParameterIds = elementNameParameterIds,
+ _elementNameUnitMemberIds = elementNameUnitMemberIds,
_elementUnits = elementUnits,
_strings = strings,
_unitLibraryUris = unitLibraryUris,
@@ -2252,7 +2286,9 @@
fb.Offset finish(fb.Builder fbBuilder) {
fb.Offset offset_elementKinds;
- fb.Offset offset_elementOffsets;
+ fb.Offset offset_elementNameClassMemberIds;
+ fb.Offset offset_elementNameParameterIds;
+ fb.Offset offset_elementNameUnitMemberIds;
fb.Offset offset_elementUnits;
fb.Offset offset_strings;
fb.Offset offset_unitLibraryUris;
@@ -2261,8 +2297,14 @@
if (!(_elementKinds == null || _elementKinds.isEmpty)) {
offset_elementKinds = fbBuilder.writeListUint8(_elementKinds.map((b) => b.index).toList());
}
- if (!(_elementOffsets == null || _elementOffsets.isEmpty)) {
- offset_elementOffsets = fbBuilder.writeListUint32(_elementOffsets);
+ if (!(_elementNameClassMemberIds == null || _elementNameClassMemberIds.isEmpty)) {
+ offset_elementNameClassMemberIds = fbBuilder.writeListUint32(_elementNameClassMemberIds);
+ }
+ if (!(_elementNameParameterIds == null || _elementNameParameterIds.isEmpty)) {
+ offset_elementNameParameterIds = fbBuilder.writeListUint32(_elementNameParameterIds);
+ }
+ if (!(_elementNameUnitMemberIds == null || _elementNameUnitMemberIds.isEmpty)) {
+ offset_elementNameUnitMemberIds = fbBuilder.writeListUint32(_elementNameUnitMemberIds);
}
if (!(_elementUnits == null || _elementUnits.isEmpty)) {
offset_elementUnits = fbBuilder.writeListUint32(_elementUnits);
@@ -2283,8 +2325,14 @@
if (offset_elementKinds != null) {
fbBuilder.addOffset(5, offset_elementKinds);
}
- if (offset_elementOffsets != null) {
- fbBuilder.addOffset(1, offset_elementOffsets);
+ if (offset_elementNameClassMemberIds != null) {
+ fbBuilder.addOffset(7, offset_elementNameClassMemberIds);
+ }
+ if (offset_elementNameParameterIds != null) {
+ fbBuilder.addOffset(8, offset_elementNameParameterIds);
+ }
+ if (offset_elementNameUnitMemberIds != null) {
+ fbBuilder.addOffset(1, offset_elementNameUnitMemberIds);
}
if (offset_elementUnits != null) {
fbBuilder.addOffset(0, offset_elementUnits);
@@ -2324,7 +2372,9 @@
_PackageIndexImpl(this._bc, this._bcOffset);
List<idl.IndexSyntheticElementKind> _elementKinds;
- List<int> _elementOffsets;
+ List<int> _elementNameClassMemberIds;
+ List<int> _elementNameParameterIds;
+ List<int> _elementNameUnitMemberIds;
List<int> _elementUnits;
List<String> _strings;
List<int> _unitLibraryUris;
@@ -2338,9 +2388,21 @@
}
@override
- List<int> get elementOffsets {
- _elementOffsets ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 1, const <int>[]);
- return _elementOffsets;
+ List<int> get elementNameClassMemberIds {
+ _elementNameClassMemberIds ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 7, const <int>[]);
+ return _elementNameClassMemberIds;
+ }
+
+ @override
+ List<int> get elementNameParameterIds {
+ _elementNameParameterIds ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 8, const <int>[]);
+ return _elementNameParameterIds;
+ }
+
+ @override
+ List<int> get elementNameUnitMemberIds {
+ _elementNameUnitMemberIds ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 1, const <int>[]);
+ return _elementNameUnitMemberIds;
}
@override
@@ -2379,7 +2441,9 @@
Map<String, Object> toJson() {
Map<String, Object> _result = <String, Object>{};
if (elementKinds.isNotEmpty) _result["elementKinds"] = elementKinds.map((_value) => _value.toString().split('.')[1]).toList();
- if (elementOffsets.isNotEmpty) _result["elementOffsets"] = elementOffsets;
+ if (elementNameClassMemberIds.isNotEmpty) _result["elementNameClassMemberIds"] = elementNameClassMemberIds;
+ if (elementNameParameterIds.isNotEmpty) _result["elementNameParameterIds"] = elementNameParameterIds;
+ if (elementNameUnitMemberIds.isNotEmpty) _result["elementNameUnitMemberIds"] = elementNameUnitMemberIds;
if (elementUnits.isNotEmpty) _result["elementUnits"] = elementUnits;
if (strings.isNotEmpty) _result["strings"] = strings;
if (unitLibraryUris.isNotEmpty) _result["unitLibraryUris"] = unitLibraryUris;
@@ -2391,7 +2455,9 @@
@override
Map<String, Object> toMap() => {
"elementKinds": elementKinds,
- "elementOffsets": elementOffsets,
+ "elementNameClassMemberIds": elementNameClassMemberIds,
+ "elementNameParameterIds": elementNameParameterIds,
+ "elementNameUnitMemberIds": elementNameUnitMemberIds,
"elementUnits": elementUnits,
"strings": strings,
"unitLibraryUris": unitLibraryUris,
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index d08851c..329fe6b 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -1232,11 +1232,29 @@
/**
* Each item of this list corresponds to a unique referenced element. It is
- * the offset of the element name relative to the beginning of the file. The
- * list is sorted in ascending order, so that the client can quickly check
- * whether an element is referenced in this [PackageIndex].
+ * the identifier of the class member element name, or `null` if the element is
+ * a top-level element. The list is sorted in ascending order, so that the
+ * client can quickly check whether an element is referenced in this
+ * [PackageIndex].
*/
- elementOffsets:[uint] (id: 1);
+ elementNameClassMemberIds:[uint] (id: 7);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the identifier of the named parameter name, or `null` if the element is not
+ * a named parameter. The list is sorted in ascending order, so that the
+ * client can quickly check whether an element is referenced in this
+ * [PackageIndex].
+ */
+ elementNameParameterIds:[uint] (id: 8);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the identifier of the top-level element name, or `null` if the element is
+ * the unit. The list is sorted in ascending order, so that the client can
+ * quickly check whether an element is referenced in this [PackageIndex].
+ */
+ elementNameUnitMemberIds:[uint] (id: 1);
/**
* Each item of this list corresponds to a unique referenced element. It is
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 505ade8..60a0552 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -714,12 +714,32 @@
/**
* Each item of this list corresponds to a unique referenced element. It is
- * the offset of the element name relative to the beginning of the file. The
- * list is sorted in ascending order, so that the client can quickly check
- * whether an element is referenced in this [PackageIndex].
+ * the identifier of the class member element name, or `null` if the element is
+ * a top-level element. The list is sorted in ascending order, so that the
+ * client can quickly check whether an element is referenced in this
+ * [PackageIndex].
+ */
+ @Id(7)
+ List<int> get elementNameClassMemberIds;
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the identifier of the named parameter name, or `null` if the element is not
+ * a named parameter. The list is sorted in ascending order, so that the
+ * client can quickly check whether an element is referenced in this
+ * [PackageIndex].
+ */
+ @Id(8)
+ List<int> get elementNameParameterIds;
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the identifier of the top-level element name, or `null` if the element is
+ * the unit. The list is sorted in ascending order, so that the client can
+ * quickly check whether an element is referenced in this [PackageIndex].
*/
@Id(1)
- List<int> get elementOffsets;
+ List<int> get elementNameUnitMemberIds;
/**
* Each item of this list corresponds to a unique referenced element. It is
diff --git a/pkg/analyzer/lib/src/summary/index_unit.dart b/pkg/analyzer/lib/src/summary/index_unit.dart
index bc09ee3..c1bbae5 100644
--- a/pkg/analyzer/lib/src/summary/index_unit.dart
+++ b/pkg/analyzer/lib/src/summary/index_unit.dart
@@ -13,198 +13,15 @@
import 'package:analyzer/src/summary/idl.dart';
/**
- * Information about an element referenced in index.
+ * Information about an element that is actually put into index for some other
+ * related element. For example for a synthetic getter this is the corresponding
+ * non-synthetic field and [IndexSyntheticElementKind.getter] as the [kind].
*/
-class ElementInfo {
- /**
- * The identifier of the [CompilationUnitElement] containing this element.
- */
- final int unitId;
-
- /**
- * The name offset of the element.
- */
- final int offset;
-
- /**
- * The kind of the element.
- */
+class IndexElementInfo {
+ final Element element;
final IndexSyntheticElementKind kind;
- /**
- * The unique id of the element. It is set after indexing of the whole
- * package is done and we are assembling the full package index.
- */
- int id;
-
- ElementInfo(this.unitId, this.offset, this.kind) {
- assert(offset >= 0);
- }
-}
-
-/**
- * Object that gathers information about the whole package index and then uses
- * it to assemble a new [PackageIndexBuilder]. Call [index] on each compilation
- * unit to be indexed, then call [assemble] to retrieve the complete index for
- * the package.
- */
-class PackageIndexAssembler {
- /**
- * Map associating referenced elements with their [ElementInfo]s.
- */
- final Map<Element, ElementInfo> _elementMap = <Element, ElementInfo>{};
-
- /**
- * Map associating [CompilationUnitElement]s with their identifiers, which
- * are indices into [_unitLibraryUris] and [_unitUnitUris].
- */
- final Map<CompilationUnitElement, int> _unitMap =
- <CompilationUnitElement, int>{};
-
- /**
- * Each item of this list corresponds to the library URI of a unique
- * [CompilationUnitElement].
- */
- final List<_StringInfo> _unitLibraryUris = <_StringInfo>[];
-
- /**
- * Each item of this list corresponds to the unit URI of a unique
- * [CompilationUnitElement].
- */
- final List<_StringInfo> _unitUnitUris = <_StringInfo>[];
-
- /**
- * Map associating strings with their [_StringInfo]s.
- */
- final Map<String, _StringInfo> _stringMap = <String, _StringInfo>{};
-
- /**
- * List of information about each unit indexed in this index.
- */
- final List<_UnitIndexAssembler> _units = <_UnitIndexAssembler>[];
-
- /**
- * Assemble a new [PackageIndexBuilder] using the information gathered by
- * [indexDeclarations] or [indexUnit].
- */
- PackageIndexBuilder assemble() {
- // sort strings end set IDs
- List<_StringInfo> stringInfoList = _stringMap.values.toList();
- stringInfoList.sort((a, b) {
- return a.value.compareTo(b.value);
- });
- for (int i = 0; i < stringInfoList.length; i++) {
- stringInfoList[i].id = i;
- }
- // sort elements and set IDs
- List<ElementInfo> elementInfoList = _elementMap.values.toList();
- elementInfoList.sort((a, b) {
- return a.offset - b.offset;
- });
- for (int i = 0; i < elementInfoList.length; i++) {
- elementInfoList[i].id = i;
- }
- return new PackageIndexBuilder(
- unitLibraryUris: _unitLibraryUris.map((s) => s.id).toList(),
- unitUnitUris: _unitUnitUris.map((s) => s.id).toList(),
- elementUnits: elementInfoList.map((e) => e.unitId).toList(),
- elementOffsets: elementInfoList.map((e) => e.offset).toList(),
- elementKinds: elementInfoList.map((e) => e.kind).toList(),
- strings: stringInfoList.map((s) => s.value).toList(),
- units: _units.map((unit) => unit.assemble()).toList());
- }
-
- /**
- * Index declarations in the given partially resolved [unit].
- */
- void indexDeclarations(CompilationUnit unit) {
- int unitId = _getUnitId(unit.element);
- _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitId);
- _units.add(assembler);
- unit.accept(new _IndexDeclarationContributor(assembler));
- }
-
- /**
- * Index the given fully resolved [unit].
- */
- void indexUnit(CompilationUnit unit) {
- int unitId = _getUnitId(unit.element);
- _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitId);
- _units.add(assembler);
- unit.accept(new _IndexContributor(assembler));
- }
-
- /**
- * Return the unique [ElementInfo] corresponding the [element]. The field
- * [ElementInfo.id] is filled by [assemble] during final sorting.
- */
- ElementInfo _getElementInfo(Element element) {
- if (element is Member) {
- element = (element as Member).baseElement;
- }
- return _elementMap.putIfAbsent(element, () {
- CompilationUnitElement unitElement = getUnitElement(element);
- int unitId = _getUnitId(unitElement);
- return newElementInfo(unitId, element);
- });
- }
-
- /**
- * Return the unique [_StringInfo] corresponding the [str]. The field
- * [_StringInfo.id] is filled by [assemble] during final sorting.
- */
- _StringInfo _getStringInfo(String str) {
- return _stringMap.putIfAbsent(str, () {
- return new _StringInfo(str);
- });
- }
-
- /**
- * Add information about [unitElement] to [_unitUnitUris] and
- * [_unitLibraryUris] if necessary, and return the location in those
- * arrays representing [unitElement].
- */
- int _getUnitId(CompilationUnitElement unitElement) {
- return _unitMap.putIfAbsent(unitElement, () {
- assert(_unitLibraryUris.length == _unitUnitUris.length);
- int id = _unitUnitUris.length;
- _unitLibraryUris.add(_getUriInfo(unitElement.library.source.uri));
- _unitUnitUris.add(_getUriInfo(unitElement.source.uri));
- return id;
- });
- }
-
- /**
- * Return the unique [_StringInfo] corresponding [uri]. The field
- * [_StringInfo.id] is filled by [assemble] during final sorting.
- */
- _StringInfo _getUriInfo(Uri uri) {
- String str = uri.toString();
- return _getStringInfo(str);
- }
-
- /**
- * Return the [CompilationUnitElement] that should be used for [element].
- * Throw [StateError] if the [element] is not linked into a unit.
- */
- static CompilationUnitElement getUnitElement(Element element) {
- for (Element e = element; e != null; e = e.enclosingElement) {
- if (e is CompilationUnitElement) {
- return e;
- }
- if (e is LibraryElement) {
- return e.definingCompilationUnit;
- }
- }
- throw new StateError(element.toString());
- }
-
- /**
- * Return a new [ElementInfo] for the given [element] in the given [unitId].
- * This method is static, so it cannot add any information to the index.
- */
- static ElementInfo newElementInfo(int unitId, Element element) {
- int offset = null;
+ factory IndexElementInfo(Element element) {
IndexSyntheticElementKind kind = IndexSyntheticElementKind.notSynthetic;
if (element.isSynthetic) {
if (element is ConstructorElement) {
@@ -245,10 +62,222 @@
}
} else if (element is LibraryElement || element is CompilationUnitElement) {
kind = IndexSyntheticElementKind.unit;
- offset = 0;
}
- offset ??= element.nameOffset;
- return new ElementInfo(unitId, offset, kind);
+ return new IndexElementInfo._(element, kind);
+ }
+
+ IndexElementInfo._(this.element, this.kind);
+}
+
+/**
+ * Object that gathers information about the whole package index and then uses
+ * it to assemble a new [PackageIndexBuilder]. Call [indexUnit] on each
+ * compilation unit to be indexed, then call [assemble] to retrieve the
+ * complete index for the package.
+ */
+class PackageIndexAssembler {
+ /**
+ * The string to use place of the `null` string.
+ */
+ static const NULL_STRING = '--nullString--';
+
+ /**
+ * Map associating referenced elements with their [_ElementInfo]s.
+ */
+ final Map<Element, _ElementInfo> _elementMap = <Element, _ElementInfo>{};
+
+ /**
+ * Map associating [CompilationUnitElement]s with their identifiers, which
+ * are indices into [_unitLibraryUris] and [_unitUnitUris].
+ */
+ final Map<CompilationUnitElement, int> _unitMap =
+ <CompilationUnitElement, int>{};
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique
+ * [CompilationUnitElement].
+ */
+ final List<_StringInfo> _unitLibraryUris = <_StringInfo>[];
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique
+ * [CompilationUnitElement].
+ */
+ final List<_StringInfo> _unitUnitUris = <_StringInfo>[];
+
+ /**
+ * Map associating strings with their [_StringInfo]s.
+ */
+ final Map<String, _StringInfo> _stringMap = <String, _StringInfo>{};
+
+ /**
+ * List of information about each unit indexed in this index.
+ */
+ final List<_UnitIndexAssembler> _units = <_UnitIndexAssembler>[];
+
+ /**
+ * The [_StringInfo] to use for `null` strings.
+ */
+ _StringInfo _nullString;
+
+ PackageIndexAssembler() {
+ _nullString = _getStringInfo(NULL_STRING);
+ }
+
+ /**
+ * Assemble a new [PackageIndexBuilder] using the information gathered by
+ * [indexDeclarations] or [indexUnit].
+ */
+ PackageIndexBuilder assemble() {
+ // sort strings end set IDs
+ List<_StringInfo> stringInfoList = _stringMap.values.toList();
+ stringInfoList.sort((a, b) {
+ return a.value.compareTo(b.value);
+ });
+ for (int i = 0; i < stringInfoList.length; i++) {
+ stringInfoList[i].id = i;
+ }
+ // sort elements and set IDs
+ List<_ElementInfo> elementInfoList = _elementMap.values.toList();
+ elementInfoList.sort((a, b) {
+ int delta;
+ delta = a.nameIdUnitMember.id - b.nameIdUnitMember.id;
+ if (delta != null) {
+ return delta;
+ }
+ delta = a.nameIdClassMember.id - b.nameIdClassMember.id;
+ if (delta != null) {
+ return delta;
+ }
+ return a.nameIdParameter.id - b.nameIdParameter.id;
+ });
+ for (int i = 0; i < elementInfoList.length; i++) {
+ elementInfoList[i].id = i;
+ }
+ return new PackageIndexBuilder(
+ unitLibraryUris: _unitLibraryUris.map((s) => s.id).toList(),
+ unitUnitUris: _unitUnitUris.map((s) => s.id).toList(),
+ elementUnits: elementInfoList.map((e) => e.unitId).toList(),
+ elementNameUnitMemberIds:
+ elementInfoList.map((e) => e.nameIdUnitMember.id).toList(),
+ elementNameClassMemberIds:
+ elementInfoList.map((e) => e.nameIdClassMember.id).toList(),
+ elementNameParameterIds:
+ elementInfoList.map((e) => e.nameIdParameter.id).toList(),
+ elementKinds: elementInfoList.map((e) => e.kind).toList(),
+ strings: stringInfoList.map((s) => s.value).toList(),
+ units: _units.map((unit) => unit.assemble()).toList());
+ }
+
+ /**
+ * Index declarations in the given partially resolved [unit].
+ */
+ void indexDeclarations(CompilationUnit unit) {
+ int unitId = _getUnitId(unit.element);
+ _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitId);
+ _units.add(assembler);
+ unit.accept(new _IndexDeclarationContributor(assembler));
+ }
+
+ /**
+ * Index the given fully resolved [unit].
+ */
+ void indexUnit(CompilationUnit unit) {
+ int unitId = _getUnitId(unit.element);
+ _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitId);
+ _units.add(assembler);
+ unit.accept(new _IndexContributor(assembler));
+ }
+
+ /**
+ * Return the unique [_ElementInfo] corresponding the [element]. The field
+ * [_ElementInfo.id] is filled by [assemble] during final sorting.
+ */
+ _ElementInfo _getElementInfo(Element element) {
+ if (element is Member) {
+ element = (element as Member).baseElement;
+ }
+ return _elementMap.putIfAbsent(element, () {
+ CompilationUnitElement unitElement = getUnitElement(element);
+ int unitId = _getUnitId(unitElement);
+ return _newElementInfo(unitId, element);
+ });
+ }
+
+ /**
+ * Return the unique [_StringInfo] corresponding the [str]. The field
+ * [_StringInfo.id] is filled by [assemble] during final sorting.
+ */
+ _StringInfo _getStringInfo(String str) {
+ return _stringMap.putIfAbsent(str, () {
+ return new _StringInfo(str);
+ });
+ }
+
+ /**
+ * Add information about [unitElement] to [_unitUnitUris] and
+ * [_unitLibraryUris] if necessary, and return the location in those
+ * arrays representing [unitElement].
+ */
+ int _getUnitId(CompilationUnitElement unitElement) {
+ return _unitMap.putIfAbsent(unitElement, () {
+ assert(_unitLibraryUris.length == _unitUnitUris.length);
+ int id = _unitUnitUris.length;
+ _unitLibraryUris.add(_getUriInfo(unitElement.library.source.uri));
+ _unitUnitUris.add(_getUriInfo(unitElement.source.uri));
+ return id;
+ });
+ }
+
+ /**
+ * Return the unique [_StringInfo] corresponding [uri]. The field
+ * [_StringInfo.id] is filled by [assemble] during final sorting.
+ */
+ _StringInfo _getUriInfo(Uri uri) {
+ String str = uri.toString();
+ return _getStringInfo(str);
+ }
+
+ /**
+ * Return a new [_ElementInfo] for the given [element] in the given [unitId].
+ * This method is static, so it cannot add any information to the index.
+ */
+ _ElementInfo _newElementInfo(int unitId, Element element) {
+ IndexElementInfo info = new IndexElementInfo(element);
+ element = info.element;
+ // Prepare name identifiers.
+ _StringInfo nameIdParameter = _nullString;
+ _StringInfo nameIdClassMember = _nullString;
+ _StringInfo nameIdUnitMember = _nullString;
+ if (element is ParameterElement) {
+ nameIdParameter = _getStringInfo(element.name);
+ element = element.enclosingElement;
+ }
+ if (element?.enclosingElement is ClassElement) {
+ nameIdClassMember = _getStringInfo(element.name);
+ element = element.enclosingElement;
+ }
+ if (element?.enclosingElement is CompilationUnitElement) {
+ nameIdUnitMember = _getStringInfo(element.name);
+ }
+ return new _ElementInfo(unitId, nameIdUnitMember, nameIdClassMember,
+ nameIdParameter, info.kind);
+ }
+
+ /**
+ * Return the [CompilationUnitElement] that should be used for [element].
+ * Throw [StateError] if the [element] is not linked into a unit.
+ */
+ static CompilationUnitElement getUnitElement(Element element) {
+ for (Element e = element; e != null; e = e.enclosingElement) {
+ if (e is CompilationUnitElement) {
+ return e;
+ }
+ if (e is LibraryElement) {
+ return e.definingCompilationUnit;
+ }
+ }
+ throw new StateError(element.toString());
}
}
@@ -278,13 +307,55 @@
}
/**
+ * Information about an element referenced in index.
+ */
+class _ElementInfo {
+ /**
+ * The identifier of the [CompilationUnitElement] containing this element.
+ */
+ final int unitId;
+
+ /**
+ * The identifier of the top-level name, or `null` if the element is a
+ * reference to the unit.
+ */
+ final _StringInfo nameIdUnitMember;
+
+ /**
+ * The identifier of the class member name, or `null` if the element is not a
+ * class member or a named parameter of a class member.
+ */
+ final _StringInfo nameIdClassMember;
+
+ /**
+ * The identifier of the named parameter name, or `null` if the element is not
+ * a named parameter.
+ */
+ final _StringInfo nameIdParameter;
+
+ /**
+ * The kind of the element.
+ */
+ final IndexSyntheticElementKind kind;
+
+ /**
+ * The unique id of the element. It is set after indexing of the whole
+ * package is done and we are assembling the full package index.
+ */
+ int id;
+
+ _ElementInfo(this.unitId, this.nameIdUnitMember, this.nameIdClassMember,
+ this.nameIdParameter, this.kind);
+}
+
+/**
* Information about a single relation. Any [_ElementRelationInfo] is always
* part of a [_UnitIndexAssembler], so [offset] and [length] should be
* understood within the context of the compilation unit pointed to by the
* [_UnitIndexAssembler].
*/
class _ElementRelationInfo {
- final ElementInfo elementInfo;
+ final _ElementInfo elementInfo;
final IndexRelationKind kind;
final int offset;
final int length;
@@ -770,7 +841,7 @@
* compilation unit.
* - Call [addNameRelation] for each name relation found in the
* compilation unit.
- * - Assign ids to all the [ElementInfo] objects reachable from
+ * - Assign ids to all the [_ElementInfo] objects reachable from
* [elementRelations].
* - Call [assemble] to produce the final unit index.
*/
@@ -786,7 +857,7 @@
void addElementRelation(Element element, IndexRelationKind kind, int offset,
int length, bool isQualified) {
try {
- ElementInfo elementInfo = pkg._getElementInfo(element);
+ _ElementInfo elementInfo = pkg._getElementInfo(element);
elementRelations.add(new _ElementRelationInfo(
elementInfo, kind, offset, length, isQualified));
} on StateError {}
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 08cbde1..f76bdc2 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -347,7 +347,7 @@
@override
final CompilationUnitElementForLink enclosingElement;
- @override
+ /// TODO(brianwilkerson) This appears to be unused and might be removable.
bool hasBeenInferred;
ClassElementForLink(CompilationUnitElementForLink enclosingElement)
@@ -368,7 +368,7 @@
List<ConstructorElementForLink> get constructors;
@override
- CompilationUnitElementForLink get enclosingUnit => enclosingElement;
+ CompilationUnitElementImpl get enclosingUnit => enclosingElement;
@override
List<FieldElementForLink> get fields;
@@ -571,7 +571,7 @@
}
@override
- DartType get type =>
+ InterfaceType get type =>
_type ??= buildType((int i) => typeParameterTypes[i], null);
@override
@@ -740,7 +740,7 @@
InterfaceType get supertype => library._linker.typeProvider.objectType;
@override
- DartType get type => _type ??= new InterfaceTypeImpl(this);
+ InterfaceType get type => _type ??= new InterfaceTypeImpl(this);
@override
List<TypeParameterElement> get typeParameters => const [];
@@ -1198,7 +1198,7 @@
enclosingClass != null ? addReference(enclosingClass) : null,
dependency: enclosingClass != null
? null
- : library.addDependency(element.library),
+ : library.addDependency(element.library as LibraryElementForLink),
kind: kind);
} else if (element is FunctionElementForLink_Initializer) {
return addRawReference('',
@@ -1629,6 +1629,9 @@
ConstructorElementForLink get asConstructor => this;
@override
+ ClassElementImpl get enclosingElement => super.enclosingClass;
+
+ @override
bool get isCycleFree {
if (!_constNode.isEvaluated) {
new ConstDependencyWalker().walk(_constNode);
@@ -1852,7 +1855,6 @@
String _name;
String _displayName;
- @override
final CompilationUnitElementForLink compilationUnit;
ExecutableElementForLink(this.compilationUnit, this._unlinkedExecutable);
@@ -1929,7 +1931,7 @@
bool get isSynthetic => false;
@override
- LibraryElementForLink get library => enclosingElement.library;
+ LibraryElement get library => enclosingElement.library;
@override
String get name {
@@ -1975,7 +1977,7 @@
*/
DartType _computeDefaultReturnType() {
if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter &&
- library._linker.strongMode) {
+ (library as LibraryElementForLink)._linker.strongMode) {
// In strong mode, setters without an explicit return type are
// considered to return `void`.
return VoidTypeImpl.instance;
@@ -3728,6 +3730,9 @@
DartType get asStaticType => type;
@override
+ ClassElementImpl get enclosingElement => super.enclosingClass;
+
+ @override
String get identifier => name;
@override
@@ -3998,7 +4003,7 @@
* Mixin used by elements that can have parameters.
*/
abstract class ParameterParentElementForLink implements Element {
- List<ParameterElementForLink> _parameters;
+ List<ParameterElement> _parameters;
/**
* Get the appropriate integer list to store in
@@ -4012,11 +4017,11 @@
/**
* Get all the parameters of this element.
*/
- List<ParameterElementForLink> get parameters {
+ List<ParameterElement> get parameters {
if (_parameters == null) {
List<UnlinkedParam> unlinkedParameters = this.unlinkedParameters;
int numParameters = unlinkedParameters.length;
- _parameters = new List<ParameterElementForLink>(numParameters);
+ _parameters = new List<ParameterElement>(numParameters);
for (int i = 0; i < numParameters; i++) {
UnlinkedParam unlinkedParam = unlinkedParameters[i];
_parameters[i] = new ParameterElementForLink(
@@ -4142,7 +4147,7 @@
with ReferenceableElementForLink
implements PropertyAccessorElementForLink {
@override
- SyntheticVariableElementForLink variable;
+ PropertyInducingElement variable;
PropertyAccessorElementForLink_Executable(
CompilationUnitElementForLink enclosingUnit,
@@ -4175,7 +4180,8 @@
@override
ReferenceableElementForLink getContainedName(String name) {
- return new NonstaticMemberElementForLink(library, this, name);
+ return new NonstaticMemberElementForLink(
+ library as LibraryElementForLink, this, name);
}
@override
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index c2a625b..eeaef9d 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -641,7 +641,7 @@
bool isSemanticallyStatic = isTopLevel || isDeclaredStatic;
if (formalParameters != null) {
b.parameters = formalParameters.parameters
- .map((FormalParameter p) => p.accept(this))
+ .map((FormalParameter p) => p.accept(this) as UnlinkedParamBuilder)
.toList();
if (!isSemanticallyStatic) {
for (int i = 0; i < formalParameters.parameters.length; i++) {
@@ -751,7 +751,7 @@
b.type = serializedReturnType;
}
b.parameters = parameters.parameters
- .map((FormalParameter p) => p.accept(this))
+ .map((FormalParameter p) => p.accept(this) as UnlinkedParamBuilder)
.toList();
}
@@ -1042,7 +1042,7 @@
b.nameOffset = node.returnType.offset;
}
b.parameters = node.parameters.parameters
- .map((FormalParameter p) => p.accept(this))
+ .map((FormalParameter p) => p.accept(this) as UnlinkedParamBuilder)
.toList();
b.kind = UnlinkedExecutableKind.constructor;
if (node.factoryKeyword != null) {
@@ -1235,7 +1235,7 @@
b.returnType = serializedReturnType;
}
b.parameters = node.parameters.parameters
- .map((FormalParameter p) => p.accept(this))
+ .map((FormalParameter p) => p.accept(this) as UnlinkedParamBuilder)
.toList();
b.documentationComment = serializeDocumentation(node.documentationComment);
b.annotations = serializeAnnotations(node.metadata);
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 0d3981f..4ff2448 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -1344,6 +1344,7 @@
}
return null;
}
+
EnumDeclaration firstEnum = findFirstEnum();
if (firstEnum != null && firstEnum.element.accessors.isEmpty) {
EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider);
@@ -2228,6 +2229,7 @@
deps.addAll(l.units);
}
}
+
int length = component.length;
for (int i = 0; i < length; i++) {
LibraryElement library = component[i];
@@ -2633,6 +2635,14 @@
return true;
}
}
+ for (String name in references.names) {
+ ClassElementDelta classDelta = changedClasses[name];
+ if (classDelta != null && classDelta.hasAnnotationChanges) {
+ _log(() => '$refLibrary hints/verify errors are affected because '
+ '$name has a class delta with annotation changes');
+ return true;
+ }
+ }
return false;
}
@@ -4884,16 +4894,6 @@
}
}
- static String _getSimpleName(Identifier identifier) {
- if (identifier is SimpleIdentifier) {
- return identifier.name;
- }
- if (identifier is PrefixedIdentifier) {
- return identifier.identifier.name;
- }
- return null;
- }
-
@override
visitClassTypeAlias(ClassTypeAlias node) {
ReferencedNamesScope outerScope = scope;
@@ -4923,14 +4923,6 @@
}
@override
- visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- if (node.constructorName == null && enclosingSuperClassName != null) {
- names.extendedUsedUnnamedConstructorNames.add(enclosingSuperClassName);
- }
- super.visitSuperConstructorInvocation(node);
- }
-
- @override
visitConstructorName(ConstructorName node) {
if (node.parent is! ConstructorDeclaration) {
super.visitConstructorName(node);
@@ -5050,6 +5042,14 @@
}
@override
+ visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ if (node.constructorName == null && enclosingSuperClassName != null) {
+ names.extendedUsedUnnamedConstructorNames.add(enclosingSuperClassName);
+ }
+ super.visitSuperConstructorInvocation(node);
+ }
+
+ @override
visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
VariableDeclarationList variableList = node.variables;
// Prepare type dependencies.
@@ -5081,6 +5081,16 @@
void _addSuperNames(String className, List<TypeName> types) {
types?.forEach((type) => _addSuperName(className, type));
}
+
+ static String _getSimpleName(Identifier identifier) {
+ if (identifier is SimpleIdentifier) {
+ return identifier.name;
+ }
+ if (identifier is PrefixedIdentifier) {
+ return identifier.identifier.name;
+ }
+ return null;
+ }
}
class ReferencedNamesScope {
@@ -6134,6 +6144,8 @@
scanner.setSourceStart(fragment.line, fragment.column);
scanner.preserveComments = context.analysisOptions.preserveComments;
scanner.scanGenericMethodComments = context.analysisOptions.strongMode;
+ scanner.scanLazyAssignmentOperators =
+ context.analysisOptions.enableLazyAssignmentOperators;
LineInfo lineInfo = new LineInfo(scanner.lineStarts);
@@ -6149,6 +6161,8 @@
new Scanner(source, new CharSequenceReader(content), errorListener);
scanner.preserveComments = context.analysisOptions.preserveComments;
scanner.scanGenericMethodComments = context.analysisOptions.strongMode;
+ scanner.scanLazyAssignmentOperators =
+ context.analysisOptions.enableLazyAssignmentOperators;
LineInfo lineInfo = new LineInfo(scanner.lineStarts);
@@ -6255,7 +6269,9 @@
if (options.strongMode) {
CodeChecker checker = new CodeChecker(
typeProvider,
- new StrongTypeSystemImpl(implicitCasts: options.implicitCasts),
+ new StrongTypeSystemImpl(
+ implicitCasts: options.implicitCasts,
+ nonnullableTypes: options.nonnullableTypes),
errorListener,
options);
checker.visitCompilationUnit(unit);
diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
index 5d8496d..bd317cf 100644
--- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
+++ b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
@@ -29,6 +29,8 @@
final Set<ClassElementDelta> superDeltas = new Set<ClassElementDelta>();
+ bool hasAnnotationChanges = false;
+
final List<PropertyAccessorElement> addedAccessors =
<PropertyAccessorElement>[];
final List<PropertyAccessorElement> removedAccessors =
@@ -213,10 +215,19 @@
ElementHolder classElementHolder = new ElementHolder();
ClassElementDelta classDelta =
new ClassElementDelta(classElement, librarySource, classElement.name);
+ // Check for annotation changes.
+ {
+ String oldAnnotationsCode =
+ TokenUtils.getFullCodeOfList(oldClass.metadata);
+ String newAnnotationsCode =
+ TokenUtils.getFullCodeOfList(newClass.metadata);
+ classDelta.hasAnnotationChanges =
+ oldAnnotationsCode != newAnnotationsCode;
+ }
// Prepare all old member elements.
- var removedAccessors = new Set<PropertyAccessorElement>();
- var removedConstructors = new Set<ConstructorElement>();
- var removedMethods = new Set<MethodElement>();
+ var removedAccessors = new Set<PropertyAccessorElement>.identity();
+ var removedConstructors = new Set<ConstructorElement>.identity();
+ var removedMethods = new Set<MethodElement>.identity();
removedAccessors.addAll(classElement.accessors);
removedConstructors.addAll(classElement.constructors);
removedMethods.addAll(classElement.methods);
@@ -357,6 +368,7 @@
}
}
// Update ClassElement.
+ classElement.metadata = newElement.metadata;
classElement.accessors = newAccessors;
classElement.constructors = classElementHolder.constructors;
classElement.fields = newFields.values.toList();
@@ -637,7 +649,7 @@
}
/**
- * Return the token string of all the [node] tokens.
+ * Return the token string of all the [node].
*/
static String getFullCode(AstNode node) {
if (node == null) {
@@ -648,6 +660,16 @@
}
/**
+ * Return the token string of all the [nodes].
+ */
+ static String getFullCodeOfList(List<AstNode> nodes) {
+ if (nodes == null) {
+ return '';
+ }
+ return nodes.map(getFullCode).join(_SEPARATOR);
+ }
+
+ /**
* Returns all tokens (including comments) of the given [node].
*/
static List<Token> getTokens(AstNode node) {
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
index 7bc5fa1..14d127c 100644
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ b/pkg/analyzer/lib/src/task/inputs.dart
@@ -92,7 +92,9 @@
ListTaskInput/*<V>*/ toFlattenListOf/*<V>*/(
ListResultDescriptor/*<V>*/ subListResult) {
return new ListToFlattenListTaskInput<E, dynamic/*=V*/ >(
- this, subListResult.of as dynamic);
+ this,
+ (E element) =>
+ subListResult.of(element as AnalysisTarget) as TaskInput/*<V>*/);
}
ListTaskInput/*<V>*/ toList/*<V>*/(UnaryFunction<E, dynamic/*=V*/ > mapper) {
@@ -370,7 +372,7 @@
if (currentBuilder.moveNext()) {
return true;
}
- baseMap = currentBuilder.inputValue;
+ baseMap = currentBuilder.inputValue as dynamic/*=Map<K, List<V>>*/;
if (baseMap == null) {
// No base map could be computed due to a circular dependency. Use an
// empty map so that no further results will be computed.
@@ -386,7 +388,7 @@
return true;
}
// Add the result value for the current Map key/value.
- E resultValue = currentBuilder.inputValue;
+ E resultValue = currentBuilder.inputValue as dynamic/*=E*/;
if (resultValue != null) {
inputValue.add(resultValue);
}
@@ -444,20 +446,22 @@
ListTaskInput/*<V>*/ toFlattenListOf/*<V>*/(
ListResultDescriptor/*<V>*/ subListResult) {
return new ListToFlattenListTaskInput<E, dynamic/*=V*/ >(
- this, subListResult.of as dynamic);
+ this,
+ (E element) =>
+ subListResult.of(element as AnalysisTarget) as TaskInput/*<V>*/);
}
@override
ListTaskInput/*<V>*/ toListOf/*<V>*/(ResultDescriptor/*<V>*/ valueResult) {
return new ListToListTaskInput<E, dynamic/*=V*/ >(
- this, valueResult.of as dynamic);
+ this, (E element) => valueResult.of(element as AnalysisTarget));
}
@override
MapTaskInput<AnalysisTarget, dynamic/*=V*/ > toMapOf/*<V>*/(
ResultDescriptor/*<V>*/ valueResult) {
return new ListToMapTaskInput<AnalysisTarget, dynamic/*=V*/ >(
- this as dynamic, valueResult.of);
+ this as dynamic/*=TaskInput<List<AnalysisTarget>>*/, valueResult.of);
}
}
@@ -696,7 +700,8 @@
abstract class TaskInputImpl<V> implements TaskInput<V> {
@override
ListTaskInput/*<E>*/ mappedToList/*<E>*/(List/*<E>*/ mapper(V value)) {
- return new ObjectToListTaskInput(this, mapper);
+ return new ObjectToListTaskInput(
+ this, (Object element) => mapper(element as V));
}
}
@@ -967,7 +972,7 @@
if (_resultValue == null) {
// We have finished computing the list of values from which the results
// will be derived.
- _baseList = currentBuilder.inputValue;
+ _baseList = currentBuilder.inputValue as dynamic/*=List<B>*/;
if (_baseList == null) {
// No base list could be computed due to a circular dependency. Use an
// empty list so that no further results will be computed.
@@ -978,7 +983,8 @@
} else {
// We have finished computing one of the elements in the result list.
if (currentBuilder.inputValue != null) {
- _addResultElement(_baseListElement, currentBuilder.inputValue);
+ _addResultElement(
+ _baseListElement, currentBuilder.inputValue as dynamic/*=E*/);
}
_baseListIndex++;
}
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 98c4aa6..c074b79 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -9,6 +9,7 @@
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart' show TokenType;
+import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
@@ -20,6 +21,21 @@
import 'ast_properties.dart';
+bool isKnownFunction(Expression expression) {
+ Element element = null;
+ if (expression is FunctionExpression) {
+ return true;
+ } else if (expression is PropertyAccess) {
+ element = expression.propertyName.staticElement;
+ } else if (expression is Identifier) {
+ element = expression.staticElement;
+ }
+// First class functions and static methods, where we know the original
+// declaration, will have an exact type, so we know a downcast will fail.
+ return element is FunctionElement ||
+ element is MethodElement && element.isStatic;
+}
+
DartType _elementType(Element e) {
if (e == null) {
// Malformed code - just return dynamic.
@@ -28,6 +44,8 @@
return (e as dynamic).type;
}
+// Return the field on type corresponding to member, or null if none
+// exists or the "field" is actually a getter/setter.
PropertyInducingElement _getMemberField(
InterfaceType type, PropertyAccessorElement member) {
String memberName = member.name;
@@ -53,8 +71,6 @@
return field;
}
-// Return the field on type corresponding to member, or null if none
-// exists or the "field" is actually a getter/setter.
/// Looks up the declaration that matches [member] in [type] and returns it's
/// declared type.
FunctionType _getMemberType(InterfaceType type, ExecutableElement member) =>
@@ -147,6 +163,7 @@
checkAssignment(expr.expression, type);
} else {
_checkDowncast(expr, type);
+ _checkNonNullAssignment(expr, type);
}
}
@@ -176,13 +193,6 @@
}
@override
- void visitCompilationUnit(CompilationUnit node) {
- _hasImplicitCasts = false;
- node.visitChildren(this);
- setHasImplicitCasts(node, _hasImplicitCasts);
- }
-
- @override
void visitAsExpression(AsExpression node) {
// We could do the same check as the IsExpression below, but that is
// potentially too conservative. Instead, at runtime, we must fail hard
@@ -192,11 +202,16 @@
@override
void visitAssignmentExpression(AssignmentExpression node) {
- var token = node.operator;
- if (token.type == TokenType.EQ ||
- token.type == TokenType.QUESTION_QUESTION_EQ) {
+ Token operator = node.operator;
+ TokenType operatorType = operator.type;
+ if (operatorType == TokenType.EQ ||
+ operatorType == TokenType.QUESTION_QUESTION_EQ) {
DartType staticType = _getStaticType(node.leftHandSide);
checkAssignment(node.rightHandSide, staticType);
+ } else if (operatorType == TokenType.AMPERSAND_AMPERSAND_EQ ||
+ operatorType == TokenType.BAR_BAR_EQ) {
+ checkAssignment(node.leftHandSide, typeProvider.boolType);
+ checkAssignment(node.rightHandSide, typeProvider.boolType);
} else {
_checkCompoundAssignment(node);
}
@@ -259,6 +274,13 @@
}
@override
+ void visitCompilationUnit(CompilationUnit node) {
+ _hasImplicitCasts = false;
+ node.visitChildren(this);
+ setHasImplicitCasts(node, _hasImplicitCasts);
+ }
+
+ @override
void visitConditionalExpression(ConditionalExpression node) {
checkBoolean(node.condition);
node.visitChildren(this);
@@ -592,11 +614,10 @@
// typing rules may have inferred a more precise type for the variable
// based on the initializer.
} else {
- var dartType = getType(type);
for (VariableDeclaration variable in node.variables) {
var initializer = variable.initializer;
if (initializer != null) {
- checkAssignment(initializer, dartType);
+ checkAssignment(initializer, type.type);
}
}
}
@@ -818,6 +839,14 @@
[declElement.name]);
}
+ void _checkNonNullAssignment(Expression expression, DartType type) {
+ var exprType = expression.staticType;
+ if (rules.isNonNullableType(type) && !rules.isNonNullableType(exprType)) {
+ _recordMessage(expression, StaticTypeWarningCode.INVALID_ASSIGNMENT,
+ [exprType, type]);
+ }
+ }
+
void _checkReturnOrYield(Expression expression, AstNode node,
{bool yieldStar: false}) {
FunctionBody body = node.getAncestor((n) => n is FunctionBody);
@@ -853,90 +882,6 @@
}
}
- /// Records an implicit cast for the [expression] from [fromType] to [toType].
- ///
- /// This will emit the appropriate error/warning/hint message as well as mark
- /// the AST node.
- void _recordImplicitCast(
- Expression expression, DartType fromType, DartType toType) {
- // toT <:_R fromT => to <: fromT
- // NB: classes with call methods are subtypes of function
- // types, but the function type is not assignable to the class
- assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
-
- // Inference "casts":
- if (expression is Literal || expression is FunctionExpression) {
- // fromT should be an exact type - this will almost certainly fail at
- // runtime.
- _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
- [expression, fromType, toType]);
- return;
- }
-
- if (expression is InstanceCreationExpression) {
- ConstructorElement e = expression.staticElement;
- if (e == null || !e.isFactory) {
- // fromT should be an exact type - this will almost certainly fail at
- // runtime.
-
- _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
- [expression, fromType, toType]);
- return;
- }
- }
-
- if (isKnownFunction(expression)) {
- _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
- [expression, fromType, toType]);
- return;
- }
-
- // TODO(vsm): Change this to an assert when we have generic methods and
- // fix TypeRules._coerceTo to disallow implicit sideways casts.
- bool downCastComposite = false;
- if (!rules.isSubtypeOf(toType, fromType)) {
- assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
- downCastComposite = true;
- }
-
- // Composite cast: these are more likely to fail.
- if (!rules.isGroundType(toType)) {
- // This cast is (probably) due to our different treatment of dynamic.
- // It may be more likely to fail at runtime.
- if (fromType is InterfaceType) {
- // For class types, we'd like to allow non-generic down casts, e.g.,
- // Iterable<T> to List<T>. The intuition here is that raw (generic)
- // casts are problematic, and we should complain about those.
- var typeArgs = fromType.typeArguments;
- downCastComposite =
- typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic);
- } else {
- downCastComposite = true;
- }
- }
-
- var parent = expression.parent;
- ErrorCode errorCode;
- if (downCastComposite) {
- errorCode = StrongModeCode.DOWN_CAST_COMPOSITE;
- } else if (fromType.isDynamic) {
- errorCode = StrongModeCode.DYNAMIC_CAST;
- } else if (parent is VariableDeclaration &&
- parent.initializer == expression) {
- errorCode = StrongModeCode.ASSIGNMENT_CAST;
- } else {
- errorCode = StrongModeCode.DOWN_CAST_IMPLICIT;
- }
-
- _recordMessage(expression, errorCode, [fromType, toType]);
- setImplicitCast(expression, toType);
- _hasImplicitCasts = true;
- }
-
- // Produce a coercion which coerces something of type fromT
- // to something of type toT.
- // Returns the error coercion if the types cannot be coerced
- // according to our current criteria.
/// Gets the expected return type of the given function [body], either from
/// a normal return/yield, or from a yield*.
DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) {
@@ -991,6 +936,10 @@
}
}
+ // Produce a coercion which coerces something of type fromT
+ // to something of type toT.
+ // Returns the error coercion if the types cannot be coerced
+ // according to our current criteria.
DartType _getStaticType(Expression expr) {
DartType t = expr.staticType ?? DynamicTypeImpl.instance;
@@ -1085,6 +1034,86 @@
setIsDynamicInvoke(target, true);
}
+ /// Records an implicit cast for the [expression] from [fromType] to [toType].
+ ///
+ /// This will emit the appropriate error/warning/hint message as well as mark
+ /// the AST node.
+ void _recordImplicitCast(
+ Expression expression, DartType fromType, DartType toType) {
+ // toT <:_R fromT => to <: fromT
+ // NB: classes with call methods are subtypes of function
+ // types, but the function type is not assignable to the class
+ assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
+
+ // Inference "casts":
+ if (expression is Literal || expression is FunctionExpression) {
+ // fromT should be an exact type - this will almost certainly fail at
+ // runtime.
+ _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
+ [expression, fromType, toType]);
+ return;
+ }
+
+ if (expression is InstanceCreationExpression) {
+ ConstructorElement e = expression.staticElement;
+ if (e == null || !e.isFactory) {
+ // fromT should be an exact type - this will almost certainly fail at
+ // runtime.
+
+ _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
+ [expression, fromType, toType]);
+ return;
+ }
+ }
+
+ if (isKnownFunction(expression)) {
+ _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
+ [expression, fromType, toType]);
+ return;
+ }
+
+ // TODO(vsm): Change this to an assert when we have generic methods and
+ // fix TypeRules._coerceTo to disallow implicit sideways casts.
+ bool downCastComposite = false;
+ if (!rules.isSubtypeOf(toType, fromType)) {
+ assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
+ downCastComposite = true;
+ }
+
+ // Composite cast: these are more likely to fail.
+ if (!rules.isGroundType(toType)) {
+ // This cast is (probably) due to our different treatment of dynamic.
+ // It may be more likely to fail at runtime.
+ if (fromType is InterfaceType) {
+ // For class types, we'd like to allow non-generic down casts, e.g.,
+ // Iterable<T> to List<T>. The intuition here is that raw (generic)
+ // casts are problematic, and we should complain about those.
+ var typeArgs = fromType.typeArguments;
+ downCastComposite =
+ typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic);
+ } else {
+ downCastComposite = true;
+ }
+ }
+
+ var parent = expression.parent;
+ ErrorCode errorCode;
+ if (downCastComposite) {
+ errorCode = StrongModeCode.DOWN_CAST_COMPOSITE;
+ } else if (fromType.isDynamic) {
+ errorCode = StrongModeCode.DYNAMIC_CAST;
+ } else if (parent is VariableDeclaration &&
+ parent.initializer == expression) {
+ errorCode = StrongModeCode.ASSIGNMENT_CAST;
+ } else {
+ errorCode = StrongModeCode.DOWN_CAST_IMPLICIT;
+ }
+
+ _recordMessage(expression, errorCode, [fromType, toType]);
+ setImplicitCast(expression, toType);
+ _hasImplicitCasts = true;
+ }
+
void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) {
var severity = errorCode.errorSeverity;
if (severity == ErrorSeverity.ERROR) _failure = true;
@@ -1101,21 +1130,6 @@
}
}
-bool isKnownFunction(Expression expression) {
- Element element = null;
- if (expression is FunctionExpression) {
- return true;
- } else if (expression is PropertyAccess) {
- element = expression.propertyName.staticElement;
- } else if (expression is Identifier) {
- element = expression.staticElement;
- }
-// First class functions and static methods, where we know the original
-// declaration, will have an exact type, so we know a downcast will fail.
- return element is FunctionElement ||
- element is MethodElement && element.isStatic;
-}
-
/// Checks for overriding declarations of fields and methods. This is used to
/// check overrides between classes and superclasses, interfaces, and mixin
/// applications.
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 420fd61..ea4e0b3 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -279,6 +279,12 @@
List<FunctionType> overriddenTypes = new List<FunctionType>();
for (ExecutableElement overriddenMethod in overriddenMethods) {
FunctionType overriddenType = overriddenMethod.type;
+ if (overriddenType == null) {
+ // TODO(brianwilkerson) I think the overridden method should always have
+ // a type, but there appears to be a bug that causes it to sometimes be
+ // null, we guard against that case by not performing inference.
+ return;
+ }
if (overriddenType.typeFormals.isNotEmpty) {
if (overriddenType.typeFormals.length != typeFormals.length) {
return;
@@ -466,6 +472,7 @@
}
return element;
}
+
Element element = nonAccessor(node.staticElement);
if (element is VariableElement && (filter == null || filter(element))) {
results.add(element);
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 42691d9..4779ab9 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.27.4-alpha.19
+version: 0.27.4
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -7,10 +7,11 @@
sdk: '>=1.12.0 <2.0.0'
dependencies:
args: '>=0.12.1 <0.14.0'
+ charcode: ^1.1.0
crypto: '>=1.1.1 <3.0.0'
glob: ^1.0.3
isolate: ^0.2.2
- html: ^0.12.0
+ html: '>=0.12.0 <1.14.0'
package_config: '>=0.1.5 <2.0.0'
path: '>=0.9.0 <2.0.0'
plugin: ^0.2.0
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 70e1c73..63fdd85 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -1591,6 +1591,43 @@
expect(method.isSynthetic, isFalse);
}
+ void test_visitMethodDeclaration_duplicateField_synthetic() {
+ buildElementsForText(r'''
+class A {
+ int f;
+ int get f => 42;
+}
+''');
+ ClassDeclaration classNode = compilationUnit.declarations.single;
+ // ClassElement
+ ClassElement classElement = classNode.element;
+ expect(classElement.fields, hasLength(2));
+ expect(classElement.accessors, hasLength(3));
+ FieldElement notSyntheticFieldElement = classElement.fields
+ .singleWhere((f) => f.displayName == 'f' && !f.isSynthetic);
+ FieldElement syntheticFieldElement = classElement.fields
+ .singleWhere((f) => f.displayName == 'f' && f.isSynthetic);
+ PropertyAccessorElement syntheticGetterElement = classElement.accessors
+ .singleWhere(
+ (a) => a.displayName == 'f' && a.isGetter && a.isSynthetic);
+ PropertyAccessorElement syntheticSetterElement = classElement.accessors
+ .singleWhere(
+ (a) => a.displayName == 'f' && a.isSetter && a.isSynthetic);
+ PropertyAccessorElement notSyntheticGetterElement = classElement.accessors
+ .singleWhere(
+ (a) => a.displayName == 'f' && a.isGetter && !a.isSynthetic);
+ expect(notSyntheticFieldElement.getter, same(syntheticGetterElement));
+ expect(notSyntheticFieldElement.setter, same(syntheticSetterElement));
+ expect(syntheticFieldElement.getter, same(notSyntheticGetterElement));
+ expect(syntheticFieldElement.setter, isNull);
+ // class members nodes and their elements
+ FieldDeclaration fieldDeclNode = classNode.members[0];
+ VariableDeclaration fieldNode = fieldDeclNode.fields.variables.single;
+ MethodDeclaration getterNode = classNode.members[1];
+ expect(fieldNode.element, notSyntheticFieldElement);
+ expect(getterNode.element, notSyntheticGetterElement);
+ }
+
void test_visitMethodDeclaration_external() {
// external m();
ElementHolder holder = new ElementHolder();
@@ -2565,20 +2602,6 @@
@reflectiveTest
class ElementLocatorTest extends ResolverTestCase {
- void test_locate_ExportDirective() {
- AstNode id = _findNodeIn("export", "export 'dart:core';");
- Element element = ElementLocator.locate(id);
- EngineTestCase.assertInstanceOf(
- (obj) => obj is ExportElement, ExportElement, element);
- }
-
- void test_locate_Identifier_libraryDirective() {
- AstNode id = _findNodeIn("foo", "library foo.bar;");
- Element element = ElementLocator.locate(id);
- EngineTestCase.assertInstanceOf(
- (obj) => obj is LibraryElement, LibraryElement, element);
- }
-
void fail_locate_Identifier_partOfDirective() {
// Can't resolve the library element without the library declaration.
// AstNode id = findNodeIn("foo", "part of foo.bar;");
@@ -2643,6 +2666,13 @@
(obj) => obj is ConstructorElement, ConstructorElement, element);
}
+ void test_locate_ExportDirective() {
+ AstNode id = _findNodeIn("export", "export 'dart:core';");
+ Element element = ElementLocator.locate(id);
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is ExportElement, ExportElement, element);
+ }
+
void test_locate_FunctionDeclaration() {
AstNode id = _findNodeIn("f", "int f() => 3;");
FunctionDeclaration declaration =
@@ -2724,6 +2754,13 @@
(obj) => obj is FieldElement, FieldElement, element);
}
+ void test_locate_Identifier_libraryDirective() {
+ AstNode id = _findNodeIn("foo", "library foo.bar;");
+ Element element = ElementLocator.locate(id);
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is LibraryElement, LibraryElement, element);
+ }
+
void test_locate_Identifier_propertyAccess() {
AstNode id = _findNodeIn(
"length",
@@ -3287,6 +3324,11 @@
_assertFalse("v = 1;");
}
+ void test_assignmentExpression_compound_lazy() {
+ enableLazyAssignmentOperators = true;
+ _assertFalse("v ||= false;");
+ }
+
void test_assignmentExpression_lhs_throw() {
_assertTrue("a[throw ''] = 0;");
}
@@ -3467,14 +3509,6 @@
expect(new ExitDetector(), isNotNull);
}
- void test_doStatement_return() {
- _assertTrue("{ do { return null; } while (1 == 2); }");
- }
-
- void test_doStatement_throwCondition() {
- _assertTrue("{ do {} while (throw ''); }");
- }
-
void test_doStatement_break_and_throw() {
_assertFalse("{ do { if (1==1) break; throw 'T'; } while (0==1); }");
}
@@ -3483,19 +3517,6 @@
_assertFalse("{ do { if (1==1) continue; throw 'T'; } while (0==1); }");
}
- void test_doStatement_continueInSwitch_and_throw() {
- _assertFalse('''
-{
- do {
- switch (1) {
- L: case 0: continue;
- M: case 1: break;
- }
- throw 'T';
- } while (0 == 1);
-}''');
- }
-
void test_doStatement_continueDoInSwitch_and_throw() {
_assertFalse('''
{
@@ -3509,6 +3530,27 @@
}''');
}
+ void test_doStatement_continueInSwitch_and_throw() {
+ _assertFalse('''
+{
+ do {
+ switch (1) {
+ L: case 0: continue;
+ M: case 1: break;
+ }
+ throw 'T';
+ } while (0 == 1);
+}''');
+ }
+
+ void test_doStatement_return() {
+ _assertTrue("{ do { return null; } while (1 == 2); }");
+ }
+
+ void test_doStatement_throwCondition() {
+ _assertTrue("{ do {} while (throw ''); }");
+ }
+
void test_doStatement_true_break() {
_assertFalse("{ do { break; } while (true); }");
}
@@ -3521,7 +3563,6 @@
_assertTrue("{ x: do { continue x; } while (true); }");
}
-
void test_doStatement_true_if_return() {
_assertTrue("{ do { if (true) {return null;} } while (true); }");
}
@@ -3924,6 +3965,10 @@
_assertFalse("{ while (true) { break; } }");
}
+ void test_whileStatement_true_break_and_throw() {
+ _assertFalse("{ while (true) { if (1==1) break; throw 'T'; } }");
+ }
+
void test_whileStatement_true_continue() {
_assertTrue("{ while (true) { continue; } }");
}
@@ -3952,16 +3997,13 @@
_assertTrue("{ while (true) { throw ''; } }");
}
- void test_whileStatement_true_break_and_throw() {
- _assertFalse("{ while (true) { if (1==1) break; throw 'T'; } }");
- }
-
void _assertFalse(String source) {
_assertHasReturn(false, source);
}
void _assertHasReturn(bool expectedResult, String source) {
- Statement statement = ParserTestCase.parseStatement(source);
+ Statement statement = ParserTestCase.parseStatement(
+ source, [], enableLazyAssignmentOperators);
expect(ExitDetector.exits(statement), expectedResult);
}
@@ -4085,20 +4127,6 @@
_assertNthStatementDoesNotExit(source, 0);
}
- void test_whileStatement_switchWithBreakWithLabel() {
- Source source = addSource(r'''
-void f() {
- x: while (true) {
- switch (true) {
- case false: break;
- case true: break x;
- }
- }
-}
-''');
- _assertNthStatementDoesNotExit(source, 0);
- }
-
void test_whileStatement_breakWithLabel_afterExting() {
Source source = addSource(r'''
void f() {
@@ -4113,6 +4141,20 @@
_assertNthStatementExits(source, 0);
}
+ void test_whileStatement_switchWithBreakWithLabel() {
+ Source source = addSource(r'''
+void f() {
+ x: while (true) {
+ switch (true) {
+ case false: break;
+ case true: break x;
+ }
+ }
+}
+''');
+ _assertNthStatementDoesNotExit(source, 0);
+ }
+
void test_yieldStatement_plain() {
Source source = addSource(r'''
void f() sync* {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index ee61b20..1d3577e 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -2786,6 +2786,12 @@
bool enableGenericMethodComments = false;
/**
+ * A flag indicating whether lazy assignment operators should be enabled for
+ * the test.
+ */
+ bool enableLazyAssignmentOperators = false;
+
+ /**
* Return a CommentAndMetadata object with the given values that can be used for testing.
*
* @param comment the comment to be wrapped in the object
@@ -2829,6 +2835,7 @@
Scanner scanner =
new Scanner(null, new CharSequenceReader(source), listener);
scanner.scanGenericMethodComments = enableGenericMethodComments;
+ scanner.scanLazyAssignmentOperators = enableLazyAssignmentOperators;
Token tokenStream = scanner.tokenize();
listener.setLineInfo(new TestSource(), scanner.lineStarts);
//
@@ -3040,19 +3047,18 @@
}
/**
- * Parse the given source as a statement.
- *
- * @param source the source to be parsed
- * @param errorCodes the error codes of the errors that are expected to be found
- * @return the statement that was parsed
- * @throws Exception if the source could not be parsed, if the compilation errors in the source do
- * not match those that are expected, or if the result would have been `null`
+ * Parse the given [source] as a statement. The [errorCodes] are the error
+ * codes of the errors that are expected to be found. If
+ * [enableLazyAssignmentOperators] is `true`, then lazy assignment operators
+ * should be enabled.
*/
static Statement parseStatement(String source,
- [List<ErrorCode> errorCodes = ErrorCode.EMPTY_LIST]) {
+ [List<ErrorCode> errorCodes = ErrorCode.EMPTY_LIST,
+ bool enableLazyAssignmentOperators]) {
GatheringErrorListener listener = new GatheringErrorListener();
Scanner scanner =
new Scanner(null, new CharSequenceReader(source), listener);
+ scanner.scanLazyAssignmentOperators = enableLazyAssignmentOperators;
listener.setLineInfo(new TestSource(), scanner.lineStarts);
Token token = scanner.tokenize();
Parser parser = createParser(listener);
@@ -7452,6 +7458,15 @@
expect(expression.rightHandSide, isNotNull);
}
+ void test_parseExpression_assign_compound() {
+ enableLazyAssignmentOperators = true;
+ AssignmentExpression expression = parse4("parseExpression", "x ||= y");
+ expect(expression.leftHandSide, isNotNull);
+ expect(expression.operator, isNotNull);
+ expect(expression.operator.type, TokenType.BAR_BAR_EQ);
+ expect(expression.rightHandSide, isNotNull);
+ }
+
void test_parseExpression_comparison() {
BinaryExpression expression = parse4("parseExpression", "--a.b == c");
expect(expression.leftOperand, isNotNull);
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index 071231e..cb75945 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -192,6 +192,11 @@
_assertToken(TokenType.AMPERSAND_AMPERSAND, "&&");
}
+ void test_ampersand_ampersand_eq() {
+ _assertToken(TokenType.AMPERSAND_AMPERSAND_EQ, "&&=",
+ lazyAssignmentOperators: true);
+ }
+
void test_ampersand_eq() {
_assertToken(TokenType.AMPERSAND_EQ, "&=");
}
@@ -224,6 +229,10 @@
_assertToken(TokenType.BAR_BAR, "||");
}
+ void test_bar_bar_eq() {
+ _assertToken(TokenType.BAR_BAR_EQ, "||=", lazyAssignmentOperators: true);
+ }
+
void test_bar_eq() {
_assertToken(TokenType.BAR_EQ, "|=");
}
@@ -1177,8 +1186,10 @@
* Assert that the token scanned from the given [source] has the
* [expectedType].
*/
- Token _assertToken(TokenType expectedType, String source) {
- Token originalToken = _scan(source);
+ Token _assertToken(TokenType expectedType, String source,
+ {bool lazyAssignmentOperators: false}) {
+ Token originalToken =
+ _scan(source, lazyAssignmentOperators: lazyAssignmentOperators);
expect(originalToken, isNotNull);
expect(originalToken.type, expectedType);
expect(originalToken.offset, 0);
@@ -1190,7 +1201,8 @@
return originalToken;
} else if (expectedType == TokenType.SINGLE_LINE_COMMENT) {
// Adding space to an end-of-line comment changes the comment.
- Token tokenWithSpaces = _scan(" $source");
+ Token tokenWithSpaces =
+ _scan(" $source", lazyAssignmentOperators: lazyAssignmentOperators);
expect(tokenWithSpaces, isNotNull);
expect(tokenWithSpaces.type, expectedType);
expect(tokenWithSpaces.offset, 1);
@@ -1199,20 +1211,23 @@
return originalToken;
} else if (expectedType == TokenType.INT ||
expectedType == TokenType.DOUBLE) {
- Token tokenWithLowerD = _scan("${source}d");
+ Token tokenWithLowerD =
+ _scan("${source}d", lazyAssignmentOperators: lazyAssignmentOperators);
expect(tokenWithLowerD, isNotNull);
expect(tokenWithLowerD.type, expectedType);
expect(tokenWithLowerD.offset, 0);
expect(tokenWithLowerD.length, source.length);
expect(tokenWithLowerD.lexeme, source);
- Token tokenWithUpperD = _scan("${source}D");
+ Token tokenWithUpperD =
+ _scan("${source}D", lazyAssignmentOperators: lazyAssignmentOperators);
expect(tokenWithUpperD, isNotNull);
expect(tokenWithUpperD.type, expectedType);
expect(tokenWithUpperD.offset, 0);
expect(tokenWithUpperD.length, source.length);
expect(tokenWithUpperD.lexeme, source);
}
- Token tokenWithSpaces = _scan(" $source ");
+ Token tokenWithSpaces =
+ _scan(" $source ", lazyAssignmentOperators: lazyAssignmentOperators);
expect(tokenWithSpaces, isNotNull);
expect(tokenWithSpaces.type, expectedType);
expect(tokenWithSpaces.offset, 1);
@@ -1249,21 +1264,24 @@
expect(token.type, TokenType.EOF);
}
- Token _scan(String source, {bool genericMethodComments: false}) {
+ Token _scan(String source,
+ {bool genericMethodComments: false,
+ bool lazyAssignmentOperators: false}) {
GatheringErrorListener listener = new GatheringErrorListener();
Token token = _scanWithListener(source, listener,
- genericMethodComments: genericMethodComments);
+ genericMethodComments: genericMethodComments,
+ lazyAssignmentOperators: lazyAssignmentOperators);
listener.assertNoErrors();
return token;
}
Token _scanWithListener(String source, GatheringErrorListener listener,
- {bool genericMethodComments: false}) {
+ {bool genericMethodComments: false,
+ bool lazyAssignmentOperators: false}) {
Scanner scanner =
new Scanner(null, new CharSequenceReader(source), listener);
- if (genericMethodComments) {
- scanner.scanGenericMethodComments = true;
- }
+ scanner.scanGenericMethodComments = genericMethodComments;
+ scanner.scanLazyAssignmentOperators = lazyAssignmentOperators;
Token result = scanner.tokenize();
listener.setLineInfo(new TestSource(), scanner.lineStarts);
return result;
diff --git a/pkg/analyzer/test/generated/sdk_test.dart b/pkg/analyzer/test/generated/sdk_test.dart
index 7038f4d..ab634cb 100644
--- a/pkg/analyzer/test/generated/sdk_test.dart
+++ b/pkg/analyzer/test/generated/sdk_test.dart
@@ -66,7 +66,7 @@
return null;
}
- DartSdk _failIfCreated(_) {
+ DartSdk _failIfCreated(AnalysisOptions _) {
fail('Use of sdkCreator');
return null;
}
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 23fac6b..2795236 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -394,6 +394,19 @@
validate(TokenType.TILDE_SLASH_EQ);
}
+ void test_visitAssignmentExpression_compound_lazy() {
+ validate(TokenType operator) {
+ InterfaceType boolType = _typeProvider.boolType;
+ SimpleIdentifier identifier = _resolvedVariable(boolType, "b");
+ AssignmentExpression node = AstFactory.assignmentExpression(
+ identifier, operator, _resolvedBool(true));
+ expect(_analyze(node), same(boolType));
+ _listener.assertNoErrors();
+ }
+ validate(TokenType.AMPERSAND_AMPERSAND_EQ);
+ validate(TokenType.BAR_BAR_EQ);
+ }
+
void test_visitAssignmentExpression_compound_plusID() {
validate(TokenType operator) {
InterfaceType numType = _typeProvider.numType;
@@ -1565,6 +1578,16 @@
}
/**
+ * Return a boolean literal with the given [value] that has been resolved to
+ * the correct type.
+ */
+ BooleanLiteral _resolvedBool(bool value) {
+ BooleanLiteral literal = AstFactory.booleanLiteral(value);
+ literal.staticType = _typeProvider.intType;
+ return literal;
+ }
+
+ /**
* Return an integer literal that has been resolved to the correct type.
*
* @param value the value of the literal
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index be5ee6b..75f4ea9 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -222,7 +222,7 @@
check("g1", _isStreamOf([_isDynamic]));
check("g2", _isListOf(_isInt));
- check("g3", _isStreamOf([_isListOf(_isInt)]));
+ check("g3", _isStreamOf([(DartType type) => _isListOf(_isInt)(type)]));
}
void test_async_star_propagation() {
@@ -249,7 +249,7 @@
check("g1", _isStreamOf([_isDynamic]));
check("g2", _isListOf(_isInt));
- check("g3", _isStreamOf([_isListOf(_isInt)]));
+ check("g3", _isStreamOf([(DartType type) => _isListOf(_isInt)(type)]));
}
void test_cascadeExpression() {
@@ -698,7 +698,7 @@
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
Asserter<InterfaceType> assertMapOfIntToListOfInt =
- _isMapOf(_isInt, assertListOfInt);
+ _isMapOf(_isInt, (DartType type) => assertListOfInt(type));
VariableDeclaration mapB = AstFinder.getFieldInClass(unit, "B", "map");
MethodDeclaration mapC = AstFinder.getMethodInClass(unit, "C", "map");
@@ -955,7 +955,8 @@
}
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
- Asserter<InterfaceType> assertListOfListOfInt = _isListOf(assertListOfInt);
+ Asserter<InterfaceType> assertListOfListOfInt =
+ _isListOf((DartType type) => assertListOfInt(type));
assertListOfListOfInt(literal(0).staticType);
assertListOfListOfInt(literal(1).staticType);
@@ -1095,7 +1096,7 @@
Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
Asserter<InterfaceType> assertMapOfIntToListOfString =
- _isMapOf(_isInt, assertListOfString);
+ _isMapOf(_isInt, (DartType type) => assertListOfString(type));
assertMapOfIntToListOfString(literal(0).staticType);
assertMapOfIntToListOfString(literal(1).staticType);
@@ -1249,7 +1250,7 @@
check("f1", _isListOf(_isDynamic));
check("f2", _isListOf(_isInt));
- check("f3", _isListOf(_isListOf(_isInt)));
+ check("f3", _isListOf((DartType type) => _isListOf(_isInt)(type)));
}
void test_sync_star_propagation() {
@@ -1276,7 +1277,7 @@
check("f1", _isListOf(_isDynamic));
check("f2", _isListOf(_isInt));
- check("f3", _isListOf(_isListOf(_isInt)));
+ check("f3", _isListOf((DartType type) => _isListOf(_isInt)(type)));
}
}
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index 50489e4..1f94afa 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -679,7 +679,6 @@
expect(actual.enableGenericMethods, expected.enableGenericMethods);
expect(actual.enableSuperMixins, expected.enableSuperMixins);
expect(actual.enableTiming, expected.enableTiming);
- expect(actual.enableTrailingCommas, expected.enableTrailingCommas);
expect(actual.generateImplicitErrors, expected.generateImplicitErrors);
expect(actual.generateSdkErrors, expected.generateSdkErrors);
expect(actual.hint, expected.hint);
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index ab35ffb..dc09c80 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -701,6 +701,12 @@
unorderedEquals([new TargetedResult(target, result2)]));
expect(entry.getResultData(result2).dependedOnResults,
unorderedEquals([new TargetedResult(target, result1)]));
+ // record invalidated results
+ Set<TargetedResult> reportedInvalidatedResults = new Set<TargetedResult>();
+ cache.onResultInvalidated.listen((InvalidatedResult invalidatedResult) {
+ reportedInvalidatedResults.add(new TargetedResult(
+ invalidatedResult.entry.target, invalidatedResult.descriptor));
+ });
// invalidate result2 with Delta: keep result2, invalidate result3
entry.setState(result2, CacheState.INVALID,
delta: new _KeepContinueDelta(target, result2));
@@ -712,6 +718,10 @@
unorderedEquals([new TargetedResult(target, result2)]));
expect(entry.getResultData(result2).dependedOnResults,
unorderedEquals([new TargetedResult(target, result1)]));
+ // (target, result3) was reported as invalidated
+ // (target, result2) was NOT reported
+ expect(reportedInvalidatedResults,
+ unorderedEquals([new TargetedResult(target, result3)]));
}
test_setState_valid() {
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index 8c13cf5..f5b695f 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -338,7 +338,7 @@
// initially: A
{
LibraryElement libraryElement =
- context.getResult(exporterSource, LIBRARY_ELEMENT1) as LibraryElement;
+ context.getResult(exporterSource, LIBRARY_ELEMENT1);
expect(libraryElement.exportNamespace.definedNames.keys,
unorderedEquals(['A']));
}
@@ -350,7 +350,7 @@
_performPendingAnalysisTasks();
{
LibraryElement libraryElement =
- context.getResult(exporterSource, LIBRARY_ELEMENT1) as LibraryElement;
+ context.getResult(exporterSource, LIBRARY_ELEMENT1);
expect(libraryElement.exportNamespace.definedNames.keys,
unorderedEquals(['B']));
}
@@ -455,8 +455,42 @@
});
}
- void test_cacheConsistencyValidator_computed() {
+ void test_applyChanges_removeUsedLibrary_addAgain() {
+ String codeA = r'''
+import 'b.dart';
+B b = null;
+''';
+ String codeB = r'''
+class B {}
+''';
+ Source a = addSource('/a.dart', codeA);
+ Source b = addSource('/b.dart', codeB);
+ CacheState getErrorsState(Source source) =>
+ context.analysisCache.getState(source, LIBRARY_ERRORS_READY);
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(a).errors, hasLength(0));
+ // Remove b.dart - errors in a.dart are invalidated and recomputed.
+ // Now a.dart has an error.
+ _removeSource(b);
+ expect(getErrorsState(a), CacheState.INVALID);
+ _performPendingAnalysisTasks();
+ expect(getErrorsState(a), CacheState.VALID);
+ expect(context.getErrors(a).errors, hasLength(isPositive));
+ // Add b.dart - errors in a.dart are invalidated and recomputed.
+ // The reason is that a.dart adds dependencies on (not existing) b.dart
+ // results in cache.
+ // Now a.dart does not have errors.
+ addSource('/b.dart', codeB);
+ expect(getErrorsState(a), CacheState.INVALID);
+ _performPendingAnalysisTasks();
+ expect(getErrorsState(a), CacheState.VALID);
+ expect(context.getErrors(a).errors, hasLength(0));
+ }
+
+ void test_cacheConsistencyValidator_computed_deleted() {
CacheConsistencyValidator validator = context.cacheConsistencyValidator;
+ var stat = PerformanceStatistics.cacheConsistencyValidationStatistics;
+ stat.reset();
// Add sources.
MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
String path1 = '/test1.dart';
@@ -470,6 +504,45 @@
validator.sourceModificationTimesComputed([source1, source2],
[source1.modificationStamp, source2.modificationStamp]),
isFalse);
+ expect(stat.numOfChanged, 0);
+ expect(stat.numOfRemoved, 0);
+ // Add overlay
+ context.setContents(source1, '// 1-2');
+ expect(
+ validator.sourceModificationTimesComputed(
+ [source1, source2], [-1, source2.modificationStamp]),
+ isFalse);
+ context.setContents(source1, null);
+ expect(stat.numOfChanged, 0);
+ expect(stat.numOfRemoved, 0);
+ // Different modification times.
+ expect(
+ validator.sourceModificationTimesComputed(
+ [source1, source2], [-1, source2.modificationStamp]),
+ isTrue);
+ expect(stat.numOfChanged, 0);
+ expect(stat.numOfRemoved, 1);
+ }
+
+ void test_cacheConsistencyValidator_computed_modified() {
+ CacheConsistencyValidator validator = context.cacheConsistencyValidator;
+ var stat = PerformanceStatistics.cacheConsistencyValidationStatistics;
+ stat.reset();
+ // Add sources.
+ MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+ String path1 = '/test1.dart';
+ String path2 = '/test2.dart';
+ Source source1 = resourceProvider.newFile(path1, '// 1-1').createSource();
+ Source source2 = resourceProvider.newFile(path2, '// 2-1').createSource();
+ context.applyChanges(
+ new ChangeSet()..addedSource(source1)..addedSource(source2));
+ // Same modification times.
+ expect(
+ validator.sourceModificationTimesComputed([source1, source2],
+ [source1.modificationStamp, source2.modificationStamp]),
+ isFalse);
+ expect(stat.numOfChanged, 0);
+ expect(stat.numOfRemoved, 0);
// Add overlay
context.setContents(source1, '// 1-2');
expect(
@@ -477,11 +550,15 @@
[source1.modificationStamp + 1, source2.modificationStamp]),
isFalse);
context.setContents(source1, null);
+ expect(stat.numOfChanged, 0);
+ expect(stat.numOfRemoved, 0);
// Different modification times.
expect(
validator.sourceModificationTimesComputed([source1, source2],
[source1.modificationStamp + 1, source2.modificationStamp]),
isTrue);
+ expect(stat.numOfChanged, 1);
+ expect(stat.numOfRemoved, 0);
}
void test_cacheConsistencyValidator_getSources() {
@@ -2806,6 +2883,80 @@
_assertValid(b, LIBRARY_ERRORS_READY);
}
+ void test_class_annotation_add_deprecated() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+List<A> foo() => [];
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(0));
+ // Add @deprecated annotation.
+ // b.dart has valid resolution, because A is still A, so only errors are
+ // invalidated.
+ context.setContents(
+ a,
+ r'''
+@deprecated
+class A {}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertValidAllResolution(b);
+ // Analysis is done successfully.
+ _performPendingAnalysisTasks();
+ _assertValid(a, LIBRARY_ERRORS_READY);
+ _assertValid(a, READY_RESOLVED_UNIT);
+ _assertValid(b, LIBRARY_ERRORS_READY);
+ _assertValid(b, READY_RESOLVED_UNIT);
+ expect(context.getErrors(b).errors, hasLength(1));
+ }
+
+ void test_class_annotation_remove_deprecated() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+@deprecated
+class A {}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+List<A> foo() => [];
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(1));
+ // Add @deprecated annotation.
+ // b.dart has valid resolution, because A is still A, so only errors are
+ // invalidated.
+ context.setContents(
+ a,
+ r'''
+class A {}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertValidAllResolution(b);
+ // Analysis is done successfully.
+ _performPendingAnalysisTasks();
+ _assertValid(a, LIBRARY_ERRORS_READY);
+ _assertValid(a, READY_RESOLVED_UNIT);
+ _assertValid(b, LIBRARY_ERRORS_READY);
+ _assertValid(b, READY_RESOLVED_UNIT);
+ expect(context.getErrors(b).errors, hasLength(0));
+ }
+
void test_class_constructor_named_changeName() {
// Update a.dart: change A.named() to A.named2().
// b.dart is invalid, because it references A.named().
@@ -3407,30 +3558,6 @@
_assertInvalid(b, LIBRARY_ERRORS_READY);
}
- void test_sequence_add_annotation() {
- Source a = addSource(
- '/a.dart',
- r'''
-const myAnnotation = const Object();
-class A {}
-''');
- _performPendingAnalysisTasks();
- // Add a new annotation.
- context.setContents(
- a,
- r'''
-const myAnnotation = const Object();
-@myAnnotation
-class A {}
-''');
- _assertValidForChangedLibrary(a);
- _assertInvalid(a, LIBRARY_ERRORS_READY);
- // Analysis is done successfully.
- _performPendingAnalysisTasks();
- _assertValid(a, LIBRARY_ERRORS_READY);
- _assertValid(a, READY_RESOLVED_UNIT);
- }
-
void test_sequence_applyChanges_changedSource() {
Source a = addSource(
'/a.dart',
@@ -3927,6 +4054,40 @@
_assertInvalid(d, LIBRARY_ERRORS_READY);
}
+ void test_sequence_duplicateField_syntheticAndNot_renameNotSynthetic() {
+ context.analysisOptions =
+ new AnalysisOptionsImpl.from(context.analysisOptions)
+ ..strongMode = true;
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {
+ int foo;
+ int get foo => 1;
+}
+class B extends A {
+ int get foo => 2;
+}
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(a).errors, hasLength(2));
+ // Update a.dart: rename "int foo" to "int bar".
+ // The strong mode "getter cannot override field" error is gone.
+ context.setContents(
+ a,
+ r'''
+class A {
+ int bar;
+ int get foo => 1;
+}
+class B extends A {
+ int get foo => 2;
+}
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(a).errors, isEmpty);
+ }
+
void test_sequence_inBodyChange_addRef_deltaChange() {
Source a = addSource(
'/a.dart',
diff --git a/pkg/analyzer/test/src/dart/sdk/sdk_test.dart b/pkg/analyzer/test/src/dart/sdk/sdk_test.dart
new file mode 100644
index 0000000..e613f96
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/sdk/sdk_test.dart
@@ -0,0 +1,367 @@
+// 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.generated.sdk_test;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/embedder.dart' show EmbedderYamlLocator;
+import 'package:analyzer/src/dart/sdk/sdk.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_engine_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../generated/test_support.dart';
+import '../../../reflective_tests.dart';
+import '../../../resource_utils.dart';
+import '../../../source/embedder_test.dart';
+import '../../../utils.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(EmbedderSdkTest);
+ runReflectiveTests(FolderBasedDartSdkTest);
+ runReflectiveTests(SDKLibrariesReaderTest);
+}
+
+@reflectiveTest
+class EmbedderSdkTest extends EmbedderRelatedTest {
+ void test_creation() {
+ EmbedderYamlLocator locator = new EmbedderYamlLocator({
+ 'fox': [pathTranslator.getResource('/tmp')]
+ });
+ EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
+
+ expect(sdk.urlMappings, hasLength(5));
+ }
+
+ void test_fromFileUri() {
+ EmbedderYamlLocator locator = new EmbedderYamlLocator({
+ 'fox': [pathTranslator.getResource('/tmp')]
+ });
+ EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
+
+ expectSource(String posixPath, String dartUri) {
+ Uri uri = Uri.parse(posixToOSFileUri(posixPath));
+ Source source = sdk.fromFileUri(uri);
+ expect(source, isNotNull, reason: posixPath);
+ expect(source.uri.toString(), dartUri);
+ expect(source.fullName, posixToOSPath(posixPath));
+ }
+
+ expectSource('/tmp/slippy.dart', 'dart:fox');
+ expectSource('/tmp/deep/directory/file.dart', 'dart:deep');
+ expectSource('/tmp/deep/directory/part.dart', 'dart:deep/part.dart');
+ }
+
+ void test_getSdkLibrary() {
+ EmbedderYamlLocator locator = new EmbedderYamlLocator({
+ 'fox': [pathTranslator.getResource('/tmp')]
+ });
+ EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
+
+ SdkLibrary lib = sdk.getSdkLibrary('dart:fox');
+ expect(lib, isNotNull);
+ expect(lib.path, posixToOSPath('/tmp/slippy.dart'));
+ expect(lib.shortName, 'dart:fox');
+ }
+
+ void test_mapDartUri() {
+ EmbedderYamlLocator locator = new EmbedderYamlLocator({
+ 'fox': [pathTranslator.getResource('/tmp')]
+ });
+ EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
+
+ void expectSource(String dartUri, String posixPath) {
+ Source source = sdk.mapDartUri(dartUri);
+ expect(source, isNotNull, reason: posixPath);
+ expect(source.uri.toString(), dartUri);
+ expect(source.fullName, posixToOSPath(posixPath));
+ }
+
+ expectSource('dart:core', '/tmp/core.dart');
+ expectSource('dart:fox', '/tmp/slippy.dart');
+ expectSource('dart:deep', '/tmp/deep/directory/file.dart');
+ expectSource('dart:deep/part.dart', '/tmp/deep/directory/part.dart');
+ }
+}
+
+@reflectiveTest
+class FolderBasedDartSdkTest {
+ /**
+ * The resource provider used by these tests.
+ */
+ MemoryResourceProvider resourceProvider;
+
+ void test_analysisOptions_afterContextCreation() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ sdk.context;
+ expect(() {
+ sdk.analysisOptions = new AnalysisOptionsImpl();
+ }, throwsStateError);
+ }
+
+ void test_analysisOptions_beforeContextCreation() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ sdk.analysisOptions = new AnalysisOptionsImpl();
+ sdk.context;
+ // cannot change "analysisOptions" in the context
+ expect(() {
+ sdk.context.analysisOptions = new AnalysisOptionsImpl();
+ }, throwsStateError);
+ }
+
+ void test_creation() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ expect(sdk, isNotNull);
+ }
+
+ void test_fromFile_invalid() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ expect(
+ sdk.fromFileUri(
+ resourceProvider.getFile("/not/in/the/sdk.dart").toUri()),
+ isNull);
+ }
+
+ void test_fromFile_library() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ Source source = sdk.fromFileUri(sdk.libraryDirectory
+ .getChildAssumingFolder("core")
+ .getChildAssumingFile("core.dart")
+ .toUri());
+ expect(source, isNotNull);
+ expect(source.isInSystemLibrary, isTrue);
+ expect(source.uri.toString(), "dart:core");
+ }
+
+ void test_fromFile_library_firstExact() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ Folder dirHtml = sdk.libraryDirectory.getChildAssumingFolder("html");
+ Folder dirDartium = dirHtml.getChildAssumingFolder("dartium");
+ File file = dirDartium.getChildAssumingFile("html_dartium.dart");
+ Source source = sdk.fromFileUri(file.toUri());
+ expect(source, isNotNull);
+ expect(source.isInSystemLibrary, isTrue);
+ expect(source.uri.toString(), "dart:html");
+ }
+
+ void test_fromFile_library_html_common_dart2js() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ Folder dirHtml = sdk.libraryDirectory.getChildAssumingFolder("html");
+ Folder dirCommon = dirHtml.getChildAssumingFolder("html_common");
+ File file = dirCommon.getChildAssumingFile("html_common_dart2js.dart");
+ Source source = sdk.fromFileUri(file.toUri());
+ expect(source, isNotNull);
+ expect(source.isInSystemLibrary, isTrue);
+ expect(source.uri.toString(), "dart:html_common/html_common_dart2js.dart");
+ }
+
+ void test_fromFile_part() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ Source source = sdk.fromFileUri(sdk.libraryDirectory
+ .getChildAssumingFolder("core")
+ .getChildAssumingFile("num.dart")
+ .toUri());
+ expect(source, isNotNull);
+ expect(source.isInSystemLibrary, isTrue);
+ expect(source.uri.toString(), "dart:core/num.dart");
+ }
+
+ void test_getDirectory() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ Folder directory = sdk.directory;
+ expect(directory, isNotNull);
+ expect(directory.exists, isTrue);
+ }
+
+ void test_getDocDirectory() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ Folder directory = sdk.docDirectory;
+ expect(directory, isNotNull);
+ }
+
+ void test_getLibraryDirectory() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ Folder directory = sdk.libraryDirectory;
+ expect(directory, isNotNull);
+ expect(directory.exists, isTrue);
+ }
+
+ void test_getPubExecutable() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ File executable = sdk.pubExecutable;
+ expect(executable, isNotNull);
+ expect(executable.exists, isTrue);
+ }
+
+ void test_getSdkVersion() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ String version = sdk.sdkVersion;
+ expect(version, isNotNull);
+ expect(version.length > 0, isTrue);
+ }
+
+ void test_useSummary_afterContextCreation() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ sdk.context;
+ expect(() {
+ sdk.useSummary = true;
+ }, throwsStateError);
+ }
+
+ void test_useSummary_beforeContextCreation() {
+ FolderBasedDartSdk sdk = _createDartSdk();
+ sdk.useSummary = true;
+ sdk.context;
+ }
+
+ FolderBasedDartSdk _createDartSdk() {
+ resourceProvider = new MemoryResourceProvider();
+ Folder sdkDirectory = resourceProvider.getFolder('/sdk');
+ _createFile(sdkDirectory,
+ ['lib', '_internal', 'sdk_library_metadata', 'lib', 'libraries.dart'],
+ content: _librariesFileContent());
+ _createFile(sdkDirectory, ['bin', 'dart']);
+ _createFile(sdkDirectory, ['bin', 'dart2js']);
+ _createFile(sdkDirectory, ['bin', 'pub']);
+ _createFile(sdkDirectory, ['lib', 'async', 'async.dart']);
+ _createFile(sdkDirectory, ['lib', 'core', 'core.dart']);
+ _createFile(sdkDirectory, ['lib', 'core', 'num.dart']);
+ _createFile(sdkDirectory,
+ ['lib', 'html', 'html_common', 'html_common_dart2js.dart']);
+ _createFile(sdkDirectory, ['lib', 'html', 'dartium', 'html_dartium.dart']);
+ _createFile(
+ sdkDirectory, ['bin', (OSUtilities.isWindows() ? 'pub.bat' : 'pub')]);
+ return new FolderBasedDartSdk(resourceProvider, sdkDirectory);
+ }
+
+ void _createFile(Folder directory, List<String> segments,
+ {String content: ''}) {
+ Folder parent = directory;
+ int last = segments.length - 1;
+ for (int i = 0; i < last; i++) {
+ parent = parent.getChildAssumingFolder(segments[i]);
+ }
+ File file = parent.getChildAssumingFile(segments[last]);
+ resourceProvider.newFile(file.path, content);
+ }
+
+ String _librariesFileContent() => '''
+final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
+ "async": const LibraryInfo(
+ "async/async.dart",
+ categories: "Client,Server",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/async_patch.dart"),
+
+ "core": const LibraryInfo(
+ "core/core.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/core_patch.dart"),
+
+ "html": const LibraryInfo(
+ "html/dartium/html_dartium.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ dart2jsPath: "html/dart2js/html_dart2js.dart"),
+
+ "html_common": const LibraryInfo(
+ "html/html_common/html_common.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ dart2jsPath: "html/html_common/html_common_dart2js.dart",
+ documented: false,
+ implementation: true),
+};
+''';
+}
+
+@reflectiveTest
+class SDKLibrariesReaderTest extends EngineTestCase {
+ /**
+ * The resource provider used by these tests.
+ */
+ MemoryResourceProvider resourceProvider;
+
+ @override
+ void setUp() {
+ resourceProvider = new MemoryResourceProvider();
+ }
+
+ void test_readFrom_dart2js() {
+ LibraryMap libraryMap = new SdkLibrariesReader(true).readFromFile(
+ resourceProvider.getFile("/libs.dart"),
+ r'''
+final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
+ 'first' : const LibraryInfo(
+ 'first/first.dart',
+ categories: 'Client',
+ documented: true,
+ platforms: VM_PLATFORM,
+ dart2jsPath: 'first/first_dart2js.dart'),
+};''');
+ expect(libraryMap, isNotNull);
+ expect(libraryMap.size(), 1);
+ SdkLibrary first = libraryMap.getLibrary("dart:first");
+ expect(first, isNotNull);
+ expect(first.category, "Client");
+ expect(first.path, "first/first_dart2js.dart");
+ expect(first.shortName, "dart:first");
+ expect(first.isDart2JsLibrary, false);
+ expect(first.isDocumented, true);
+ expect(first.isImplementation, false);
+ expect(first.isVmLibrary, true);
+ }
+
+ void test_readFrom_empty() {
+ LibraryMap libraryMap = new SdkLibrariesReader(false)
+ .readFromFile(resourceProvider.getFile("/libs.dart"), "");
+ expect(libraryMap, isNotNull);
+ expect(libraryMap.size(), 0);
+ }
+
+ void test_readFrom_normal() {
+ LibraryMap libraryMap = new SdkLibrariesReader(false).readFromFile(
+ resourceProvider.getFile("/libs.dart"),
+ r'''
+final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
+ 'first' : const LibraryInfo(
+ 'first/first.dart',
+ categories: 'Client',
+ documented: true,
+ platforms: VM_PLATFORM),
+
+ 'second' : const LibraryInfo(
+ 'second/second.dart',
+ categories: 'Server',
+ documented: false,
+ implementation: true,
+ platforms: 0),
+};''');
+ expect(libraryMap, isNotNull);
+ expect(libraryMap.size(), 2);
+ SdkLibrary first = libraryMap.getLibrary("dart:first");
+ expect(first, isNotNull);
+ expect(first.category, "Client");
+ expect(first.path, "first/first.dart");
+ expect(first.shortName, "dart:first");
+ expect(first.isDart2JsLibrary, false);
+ expect(first.isDocumented, true);
+ expect(first.isImplementation, false);
+ expect(first.isVmLibrary, true);
+ SdkLibrary second = libraryMap.getLibrary("dart:second");
+ expect(second, isNotNull);
+ expect(second.category, "Server");
+ expect(second.path, "second/second.dart");
+ expect(second.shortName, "dart:second");
+ expect(second.isDart2JsLibrary, false);
+ expect(second.isDocumented, false);
+ expect(second.isImplementation, true);
+ expect(second.isVmLibrary, false);
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/sdk/test_all.dart b/pkg/analyzer/test/src/dart/sdk/test_all.dart
new file mode 100644
index 0000000..8052c9e
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/sdk/test_all.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.
+
+library analyzer.test.src.dart.sdk.test_all;
+
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'sdk_test.dart' as sdk;
+
+/// Utility for manually running all tests.
+main() {
+ initializeTestEnvironment();
+ group('sdk tests', () {
+ sdk.main();
+ });
+}
diff --git a/pkg/analyzer/test/src/dart/test_all.dart b/pkg/analyzer/test/src/dart/test_all.dart
index 15a0849..26e34d3 100644
--- a/pkg/analyzer/test/src/dart/test_all.dart
+++ b/pkg/analyzer/test/src/dart/test_all.dart
@@ -10,6 +10,7 @@
import 'ast/test_all.dart' as ast;
import 'constant/test_all.dart' as constant;
import 'element/test_all.dart' as element;
+import 'sdk/test_all.dart' as sdk;
/// Utility for manually running all tests.
main() {
@@ -18,5 +19,6 @@
ast.main();
constant.main();
element.main();
+ sdk.main();
});
}
diff --git a/pkg/analyzer/test/src/summary/index_unit_test.dart b/pkg/analyzer/test/src/summary/index_unit_test.dart
index 1bf2cf5..f6851c8 100644
--- a/pkg/analyzer/test/src/summary/index_unit_test.dart
+++ b/pkg/analyzer/test/src/summary/index_unit_test.dart
@@ -1134,12 +1134,34 @@
*/
int _findElementId(Element element) {
int unitId = _getUnitId(element);
- ElementInfo info = PackageIndexAssembler.newElementInfo(unitId, element);
+ // Prepare the element that was put into the index.
+ IndexElementInfo info = new IndexElementInfo(element);
+ element = info.element;
+ // Prepare element's name components.
+ int unitMemberId = _getStringId(PackageIndexAssembler.NULL_STRING);
+ int classMemberId = _getStringId(PackageIndexAssembler.NULL_STRING);
+ int parameterId = _getStringId(PackageIndexAssembler.NULL_STRING);
+ for (Element e = element; e != null; e = e.enclosingElement) {
+ if (e.enclosingElement is CompilationUnitElement) {
+ unitMemberId = _getStringId(e.name);
+ }
+ }
+ for (Element e = element; e != null; e = e.enclosingElement) {
+ if (e.enclosingElement is ClassElement) {
+ classMemberId = _getStringId(e.name);
+ }
+ }
+ if (element is ParameterElement) {
+ parameterId = _getStringId(element.name);
+ }
+ // Find the element's id.
for (int elementId = 0;
elementId < packageIndex.elementUnits.length;
elementId++) {
if (packageIndex.elementUnits[elementId] == unitId &&
- packageIndex.elementOffsets[elementId] == info.offset &&
+ packageIndex.elementNameUnitMemberIds[elementId] == unitMemberId &&
+ packageIndex.elementNameClassMemberIds[elementId] == classMemberId &&
+ packageIndex.elementNameParameterIds[elementId] == parameterId &&
packageIndex.elementKinds[elementId] == info.kind) {
return elementId;
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 4321f0d..420d515 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -157,6 +157,12 @@
@override
@failingTest
+ void test_constructors_inferenceFBounded() {
+ super.test_constructors_inferenceFBounded();
+ }
+
+ @override
+ @failingTest
void test_constructors_inferFromArguments() {
// TODO(jmesserly): does this need to be implemented in AST summaries?
// The test might need a change as well to not be based on local variable
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
index 60b30a8..0ac5099 100644
--- a/pkg/analyzer/test/src/summary/summarize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
@@ -375,7 +375,7 @@
linkerInputs.getUnit,
true);
linkedLibraries.forEach(assembler.addLinkedLibrary);
- linkerInputs._uriToUnit.forEach((String uri, UnlinkedUnitBuilder unit) {
+ linkerInputs._uriToUnit.forEach((String uri, UnlinkedUnit unit) {
// Note: it doesn't matter what we store for the hash because it isn't
// used in these tests.
assembler.addUnlinkedUnitWithHash(uri, unit, 'HASH');
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 27427dc..56f174e 100644
--- a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
+++ b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
@@ -42,6 +42,38 @@
return newCode.substring(node.offset, node.end);
}
+ test_classDelta_annotation_add() {
+ var helper = new _ClassDeltaHelper('A');
+ _buildOldUnit(r'''
+class A {}
+''');
+ helper.initOld(oldUnit);
+ expect(helper.element.metadata, isEmpty);
+ _buildNewUnit(r'''
+@deprecated
+class A {}
+''');
+ helper.initNew(newUnit, unitDelta);
+ expect(helper.delta.hasAnnotationChanges, isTrue);
+ expect(helper.element.metadata, hasLength(1));
+ }
+
+ test_classDelta_annotation_remove() {
+ var helper = new _ClassDeltaHelper('A');
+ _buildOldUnit(r'''
+@deprecated
+class A {}
+''');
+ helper.initOld(oldUnit);
+ expect(helper.element.metadata, hasLength(1));
+ _buildNewUnit(r'''
+class A {}
+''');
+ helper.initNew(newUnit, unitDelta);
+ expect(helper.delta.hasAnnotationChanges, isTrue);
+ expect(helper.element.metadata, isEmpty);
+ }
+
test_classDelta_constructor_0to1() {
var helper = new _ClassDeltaHelper('A');
_buildOldUnit(r'''
@@ -438,6 +470,7 @@
FieldElement newFieldElementB = newFieldsB[0].name.staticElement;
expect(newFieldElementB.name, 'bbb');
// verify delta
+ expect(helper.delta.hasAnnotationChanges, isFalse);
expect(helper.delta.addedConstructors, isEmpty);
expect(helper.delta.removedConstructors, isEmpty);
expect(helper.delta.addedAccessors,
@@ -480,6 +513,56 @@
expect(helper.delta.removedMethods, isEmpty);
}
+ test_classDelta_field_syntheticAndNot_renameNonSynthetic() {
+ var helper = new _ClassDeltaHelper('A');
+ _buildOldUnit(r'''
+class A {
+ int foo;
+ int get foo => 1;
+}
+''');
+ helper.initOld(oldUnit);
+ FieldDeclaration oldFieldDeclNode = helper.oldMembers[0];
+ VariableDeclaration oldFieldNode = oldFieldDeclNode.fields.variables.single;
+ FieldElement oldFieldElement = oldFieldNode.name.staticElement;
+ _buildNewUnit(r'''
+class A {
+ int _foo;
+ int get foo => 1;
+}
+''');
+ helper.initNew(newUnit, unitDelta);
+ // nodes
+ FieldDeclaration newFieldDeclNode = helper.newMembers[0];
+ VariableDeclaration newFieldNode = newFieldDeclNode.fields.variables.single;
+ MethodDeclaration getterNode = helper.newMembers[1];
+ expect(getterNode, same(helper.oldMembers[1]));
+ // elements
+ FieldElement newFieldElement = newFieldNode.name.staticElement;
+ PropertyAccessorElement getterElement = getterNode.element;
+ expect(newFieldElement.name, '_foo');
+ expect(
+ helper.element.fields,
+ unorderedMatches(
+ [same(newFieldElement), same(getterElement.variable)]));
+ expect(
+ helper.element.accessors,
+ unorderedMatches([
+ same(newFieldElement.getter),
+ same(newFieldElement.setter),
+ same(getterElement)
+ ]));
+ // verify delta
+ expect(helper.delta.addedConstructors, isEmpty);
+ expect(helper.delta.removedConstructors, isEmpty);
+ expect(helper.delta.addedAccessors,
+ unorderedEquals([newFieldElement.getter, newFieldElement.setter]));
+ expect(helper.delta.removedAccessors,
+ [oldFieldElement.getter, oldFieldElement.setter]);
+ expect(helper.delta.addedMethods, isEmpty);
+ expect(helper.delta.removedMethods, isEmpty);
+ }
+
test_classDelta_getter_add() {
var helper = new _ClassDeltaHelper('A');
_buildOldUnit(r'''
@@ -2051,6 +2134,7 @@
// Compare properties.
_verifyEqual('$desc name', expected.name, actual.name);
_verifyEqual('$desc nameOffset', expected.nameOffset, actual.nameOffset);
+ _verifyEqual('$desc isSynthetic', expected.isSynthetic, actual.isSynthetic);
if (expected is ElementImpl && actual is ElementImpl) {
_verifyEqual('$desc codeOffset', expected.codeOffset, actual.codeOffset);
_verifyEqual('$desc codeLength', expected.codeLength, actual.codeLength);
@@ -2077,6 +2161,12 @@
_verifyElement(expected.getter, actual.getter, '$desc getter');
_verifyElement(expected.setter, actual.setter, '$desc setter');
}
+ // Compare implicit properties.
+ if (expected is PropertyAccessorElement &&
+ actual is PropertyAccessorElement &&
+ !expected.isSynthetic) {
+ _verifyElement(expected.variable, actual.variable, '$desc variable');
+ }
// Compare parameters.
if (expected is ExecutableElement && actual is ExecutableElement) {
List<ParameterElement> actualParameters = actual.parameters;
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index feef92f..741659a 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -588,6 +588,24 @@
''');
}
+ void test_constructors_inferenceFBounded() {
+ // Regression for https://github.com/dart-lang/sdk/issues/26990
+ var unit = checkFile('''
+class Clonable<T> {}
+
+class Pair<T extends Clonable<T>, U extends Clonable<U>> {
+ T t;
+ U u;
+ Pair(this.t, this.u);
+ Pair._();
+ Pair<U, T> get reversed => /*info:INFERRED_TYPE_ALLOCATION*/new Pair(u, t);
+}
+final x = /*info:INFERRED_TYPE_ALLOCATION*/new Pair._();
+ ''');
+ var x = unit.topLevelVariables[0];
+ expect(x.type.toString(), 'Pair<Clonable<dynamic>, Clonable<dynamic>>');
+ }
+
void test_constructors_inferFromArguments() {
var unit = checkFile('''
class C<T> {
@@ -633,6 +651,23 @@
expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
}
+ void test_constructors_inferFromArguments_constWithUpperBound() {
+ // Regression for https://github.com/dart-lang/sdk/issues/26993
+ checkFile('''
+class C<T extends num> {
+ final T x;
+ const C(this.x);
+}
+class D<T extends num> {
+ const D();
+}
+void f() {
+ const c = /*info:INFERRED_TYPE_ALLOCATION*/const C(0);
+ const D<int> d = /*info:INFERRED_TYPE_ALLOCATION*/const D();
+}
+ ''');
+ }
+
void test_constructors_inferFromArguments_factory() {
var unit = checkFile('''
class C<T> {
@@ -734,6 +769,18 @@
expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
}
+ void test_constructors_reverseTypeParameters() {
+ // Regression for https://github.com/dart-lang/sdk/issues/26990
+ checkFile('''
+class Pair<T, U> {
+ T t;
+ U u;
+ Pair(this.t, this.u);
+ Pair<U, T> get reversed => /*info:INFERRED_TYPE_ALLOCATION*/new Pair(u, t);
+}
+ ''');
+ }
+
void test_doNotInferOverriddenFieldsThatExplicitlySayDynamic_infer() {
checkFile('''
class A {
diff --git a/pkg/analyzer/test/src/task/strong/non_null_checker_test.dart b/pkg/analyzer/test/src/task/strong/non_null_checker_test.dart
new file mode 100644
index 0000000..ac056c2
--- /dev/null
+++ b/pkg/analyzer/test/src/task/strong/non_null_checker_test.dart
@@ -0,0 +1,66 @@
+// 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.
+
+// These tests are for an experimental feature that treats Dart primitive types
+// (int, bool, double, etc.) as non-nullable. This file is not evidence for an
+// intention to officially support non-nullable primitives in Dart (or general
+// NNBD, for that matter) so don't get too crazy about it.
+
+library analyzer.test.src.task.non_null_primitives.checker_test;
+
+import '../../../reflective_tests.dart';
+import '../strong/strong_test_helper.dart';
+
+void main() {
+ initStrongModeTests();
+ runReflectiveTests(NonNullCheckerTest);
+}
+
+@reflectiveTest
+class NonNullCheckerTest {
+ // Tests simple usage of ints as iterators for a loop. Not directly related to
+ // non-nullability, but if it is implemented this should be more efficient,
+ // since languages.length will not be null-checked on every iteration.
+ void test_forLoop() {
+ checkFile('''
+class MyList {
+ int length;
+ MyList() {
+ length = 6;
+ }
+ String operator [](int i) {
+ return <String>["Dart", "Java", "JS", "C", "C++", "C#"][i];
+ }
+}
+
+main() {
+ var languages = new MyList();
+ for (int i = 0; i < languages.length; ++i) {
+ print(languages[i]);
+ }
+}
+''');
+ }
+
+ void test_nullableTypes() {
+ // By default x can be set to null.
+ checkFile('int x = null;');
+ }
+
+ void test_nonnullableTypes() {
+ // If `int`s are non-nullable, then this code should throw an error.
+ addFile('int x;');
+ addFile('int x = /*error:INVALID_ASSIGNMENT*/null;');
+ addFile('int x = 0;');
+ addFile('''
+int x = 0;
+
+main() {
+ x = 1;
+ x = /*error:INVALID_ASSIGNMENT*/null;
+}
+''');
+ check(nonnullableTypes: <String>['dart:core,int']);
+ }
+}
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 82829eb..9c36094 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -54,7 +54,10 @@
/// the file text.
///
/// Returns the main resolved library. This can be used for further checks.
-CompilationUnit check({bool implicitCasts: true, bool implicitDynamic: true}) {
+CompilationUnit check(
+ {bool implicitCasts: true,
+ bool implicitDynamic: true,
+ List<String> nonnullableTypes: AnalysisOptionsImpl.NONNULLABLE_TYPES}) {
_checkCalled = true;
expect(files.getFile('/main.dart').exists, true,
@@ -68,8 +71,9 @@
options.strongModeHints = true;
options.implicitCasts = implicitCasts;
options.implicitDynamic = implicitDynamic;
+ options.nonnullableTypes = nonnullableTypes;
var mockSdk = new MockSdk();
- mockSdk.context.analysisOptions.strongMode = true;
+ (mockSdk.context.analysisOptions as AnalysisOptionsImpl).strongMode = true;
context.sourceFactory =
new SourceFactory([new DartUriResolver(mockSdk), uriResolver]);
diff --git a/pkg/analyzer/test/stress/for_git_repository.dart b/pkg/analyzer/test/stress/for_git_repository.dart
new file mode 100644
index 0000000..ee8dab2
--- /dev/null
+++ b/pkg/analyzer/test/stress/for_git_repository.dart
@@ -0,0 +1,634 @@
+// 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.stress.limited_invalidation;
+
+import 'dart:async';
+import 'dart:io';
+
+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/file_system.dart' as fs;
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/context/builder.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/member.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/general.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+main() {
+ new StressTest().run();
+}
+
+void _failTypeMismatch(Object actual, Object expected, {String reason}) {
+ String message = 'Actual $actual is ${actual.runtimeType}, '
+ 'but expected $expected is ${expected.runtimeType}';
+ if (reason != null) {
+ message += ' $reason';
+ }
+ fail(message);
+}
+
+void _logPrint(String message) {
+ DateTime time = new DateTime.now();
+ print('$time: $message');
+}
+
+class FileInfo {
+ final String path;
+ final int modification;
+
+ FileInfo(this.path, this.modification);
+}
+
+class FolderDiff {
+ final List<String> added;
+ final List<String> changed;
+ final List<String> removed;
+
+ FolderDiff(this.added, this.changed, this.removed);
+
+ bool get isEmpty => added.isEmpty && changed.isEmpty && removed.isEmpty;
+ bool get isNotEmpty => !isEmpty;
+
+ @override
+ String toString() {
+ return '[added=$added, changed=$changed, removed=$removed]';
+ }
+}
+
+class FolderInfo {
+ final String path;
+ final List<FileInfo> files = <FileInfo>[];
+
+ FolderInfo(this.path) {
+ List<FileSystemEntity> entities =
+ new Directory(path).listSync(recursive: true);
+ for (FileSystemEntity entity in entities) {
+ if (entity is File) {
+ String path = entity.path;
+ if (path.contains('packages') || path.contains('.pub')) {
+ continue;
+ }
+ if (path.endsWith('.dart')) {
+ files.add(new FileInfo(
+ path, entity.lastModifiedSync().millisecondsSinceEpoch));
+ }
+ }
+ }
+ }
+
+ FolderDiff diff(FolderInfo oldFolder) {
+ Map<String, FileInfo> toMap(FolderInfo folder) {
+ Map<String, FileInfo> map = <String, FileInfo>{};
+ folder.files.forEach((file) {
+ map[file.path] = file;
+ });
+ return map;
+ }
+ Map<String, FileInfo> newFiles = toMap(this);
+ Map<String, FileInfo> oldFiles = toMap(oldFolder);
+ Set<String> addedPaths = newFiles.keys.toSet()..removeAll(oldFiles.keys);
+ Set<String> removedPaths = oldFiles.keys.toSet()..removeAll(newFiles.keys);
+ List<String> changedPaths = <String>[];
+ newFiles.forEach((path, newFile) {
+ FileInfo oldFile = oldFiles[path];
+ if (oldFile != null && oldFile.modification != newFile.modification) {
+ changedPaths.add(path);
+ }
+ });
+ return new FolderDiff(
+ addedPaths.toList(), changedPaths, removedPaths.toList());
+ }
+}
+
+class GitException {
+ final String message;
+ final String stdout;
+ final String stderr;
+
+ GitException(this.message)
+ : stdout = null,
+ stderr = null;
+
+ GitException.forProcessResult(this.message, ProcessResult processResult)
+ : stdout = processResult.stdout,
+ stderr = processResult.stderr;
+
+ @override
+ String toString() => '$message\n$stdout\n$stderr\n';
+}
+
+class GitRepository {
+ final String path;
+
+ GitRepository(this.path);
+
+ Future checkout(String hash) async {
+ // TODO(scheglov) use for updating only some files
+ if (hash.endsWith('hash')) {
+ List<String> filePaths = <String>[
+ '/Users/user/full/path/one.dart',
+ '/Users/user/full/path/two.dart',
+ ];
+ for (var filePath in filePaths) {
+ await Process.run('git', <String>['checkout', '-f', hash, filePath],
+ workingDirectory: path);
+ }
+ return;
+ }
+ ProcessResult processResult = await Process
+ .run('git', <String>['checkout', '-f', hash], workingDirectory: path);
+ _throwIfNotSuccess(processResult);
+ }
+
+ Future<List<GitRevision>> getRevisions({String after}) async {
+ List<String> args = <String>['log', '--format=%ct %H %s'];
+ if (after != null) {
+ args.add('--after=$after');
+ }
+ ProcessResult processResult =
+ await Process.run('git', args, workingDirectory: path);
+ _throwIfNotSuccess(processResult);
+ String output = processResult.stdout;
+ List<String> logLines = output.split('\n');
+ List<GitRevision> revisions = <GitRevision>[];
+ for (String logLine in logLines) {
+ int index1 = logLine.indexOf(' ');
+ if (index1 != -1) {
+ int index2 = logLine.indexOf(' ', index1 + 1);
+ if (index2 != -1) {
+ int timestamp = int.parse(logLine.substring(0, index1));
+ String hash = logLine.substring(index1 + 1, index2);
+ String message = logLine.substring(index2).trim();
+ revisions.add(new GitRevision(timestamp, hash, message));
+ }
+ }
+ }
+ return revisions;
+ }
+
+ void removeIndexLock() {
+ File file = new File('$path/.git/index.lock');
+ if (file.existsSync()) {
+ file.deleteSync();
+ }
+ }
+
+ Future resetHard() async {
+ ProcessResult processResult = await Process
+ .run('git', <String>['reset', '--hard'], workingDirectory: path);
+ _throwIfNotSuccess(processResult);
+ }
+
+ void _throwIfNotSuccess(ProcessResult processResult) {
+ if (processResult.exitCode != 0) {
+ throw new GitException.forProcessResult(
+ 'Unable to run "git log".', processResult);
+ }
+ }
+}
+
+class GitRevision {
+ final int timestamp;
+ final String hash;
+ final String message;
+
+ GitRevision(this.timestamp, this.hash, this.message);
+
+ @override
+ String toString() {
+ DateTime dateTime =
+ new DateTime.fromMillisecondsSinceEpoch(timestamp * 1000, isUtc: true)
+ .toLocal();
+ return '$dateTime|$hash|$message|';
+ }
+}
+
+class StressTest {
+ String repoPath = '/Users/scheglov/tmp/limited-invalidation/path';
+ String folderPath = '/Users/scheglov/tmp/limited-invalidation/path';
+// String repoPath = '/Users/scheglov/tmp/limited-invalidation/async';
+// String folderPath = '/Users/scheglov/tmp/limited-invalidation/async';
+// String repoPath = '/Users/scheglov/tmp/limited-invalidation/sdk';
+// String folderPath = '/Users/scheglov/tmp/limited-invalidation/sdk/pkg/analyzer';
+
+ fs.ResourceProvider resourceProvider;
+ path.Context pathContext;
+ DartSdkManager sdkManager;
+ ContentCache contentCache;
+
+ AnalysisContextImpl expectedContext;
+ AnalysisContextImpl actualContext;
+
+ Set<Element> currentRevisionValidatedElements = new Set<Element>();
+
+ void createContexts() {
+ assert(expectedContext == null);
+ assert(actualContext == null);
+ resourceProvider = PhysicalResourceProvider.INSTANCE;
+ pathContext = resourceProvider.pathContext;
+ sdkManager = new DartSdkManager(
+ DirectoryBasedDartSdk.defaultSdkDirectory.getAbsolutePath(),
+ false,
+ (_) => DirectoryBasedDartSdk.defaultSdk);
+ contentCache = new ContentCache();
+ ContextBuilder builder =
+ new ContextBuilder(resourceProvider, sdkManager, contentCache);
+ builder.defaultOptions = new AnalysisOptionsImpl();
+ expectedContext = builder.buildContext(folderPath);
+ actualContext = builder.buildContext(folderPath);
+ expectedContext.analysisOptions =
+ new AnalysisOptionsImpl.from(expectedContext.analysisOptions)
+ ..incremental = true;
+ actualContext.analysisOptions =
+ new AnalysisOptionsImpl.from(actualContext.analysisOptions)
+ ..incremental = true
+ ..finerGrainedInvalidation = true;
+ print('Created contexts');
+ }
+
+ run() async {
+ GitRepository repository = new GitRepository(repoPath);
+
+ // Recover.
+ repository.removeIndexLock();
+ await repository.resetHard();
+
+ await repository.checkout('master');
+ List<GitRevision> revisions =
+ await repository.getRevisions(after: '2016-01-01');
+ revisions = revisions.reversed.toList();
+ // TODO(scheglov) Use to compare two revisions.
+// List<GitRevision> revisions = [
+// new GitRevision(0, '99517a162cbabf3d3afbdb566df3fe2b18cd4877', 'aaa'),
+// new GitRevision(0, '2ef00b0c3d0182b5e4ea5ca55fd00b9d038ae40d', 'bbb'),
+// ];
+ FolderInfo oldFolder = null;
+ for (GitRevision revision in revisions) {
+ print(revision);
+ await repository.checkout(revision.hash);
+
+ // Run "pub get".
+ if (!new File('$folderPath/pubspec.yaml').existsSync()) {
+ continue;
+ }
+ {
+ ProcessResult processResult = await Process.run(
+ '/Users/scheglov/Applications/dart-sdk/bin/pub', <String>['get'],
+ workingDirectory: folderPath);
+ if (processResult.exitCode != 0) {
+ _logPrint('Pub get failed.');
+ _logPrint(processResult.stdout);
+ _logPrint(processResult.stderr);
+ continue;
+ }
+ _logPrint('\tpub get OK');
+ }
+ FolderInfo newFolder = new FolderInfo(folderPath);
+
+ if (expectedContext == null) {
+ createContexts();
+ _applyChanges(
+ newFolder.files.map((file) => file.path).toList(), [], []);
+ _analyzeContexts();
+ }
+
+ if (oldFolder != null) {
+ FolderDiff diff = newFolder.diff(oldFolder);
+ print(' $diff');
+ if (diff.isNotEmpty) {
+ _applyChanges(diff.added, diff.changed, diff.removed);
+ _analyzeContexts();
+ }
+ }
+ oldFolder = newFolder;
+ print('\n');
+ print('\n');
+ }
+ }
+
+ /**
+ * Perform analysis tasks up to 512 times and assert that it was enough.
+ */
+ void _analyzeAll_assertFinished(AnalysisContext context,
+ [int maxIterations = 1000000]) {
+ for (int i = 0; i < maxIterations; i++) {
+ List<ChangeNotice> notice = context.performAnalysisTask().changeNotices;
+ if (notice == null) {
+ return;
+ }
+ }
+ throw new StateError(
+ "performAnalysisTask failed to terminate after analyzing all sources");
+ }
+
+ void _analyzeContexts() {
+ {
+ Stopwatch sw = new Stopwatch()..start();
+ _analyzeAll_assertFinished(expectedContext);
+ print(' analyze(expected): ${sw.elapsedMilliseconds}');
+ }
+ {
+ Stopwatch sw = new Stopwatch()..start();
+ _analyzeAll_assertFinished(actualContext);
+ print(' analyze(actual): ${sw.elapsedMilliseconds}');
+ }
+ _validateContexts();
+ }
+
+ void _applyChanges(
+ List<String> added, List<String> changed, List<String> removed) {
+ ChangeSet changeSet = new ChangeSet();
+ added.map(_pathToSource).forEach(changeSet.addedSource);
+ removed.map(_pathToSource).forEach(changeSet.removedSource);
+ changed.map(_pathToSource).forEach(changeSet.changedSource);
+ changed.forEach((path) => new File(path).readAsStringSync());
+ {
+ Stopwatch sw = new Stopwatch()..start();
+ expectedContext.applyChanges(changeSet);
+ print(' apply(expected): ${sw.elapsedMilliseconds}');
+ }
+ {
+ Stopwatch sw = new Stopwatch()..start();
+ actualContext.applyChanges(changeSet);
+ print(' apply(actual): ${sw.elapsedMilliseconds}');
+ }
+ }
+
+ Source _pathToSource(String path) {
+ fs.File file = resourceProvider.getFile(path);
+ return _createSourceInContext(expectedContext, file);
+ }
+
+ void _validateContexts() {
+ currentRevisionValidatedElements.clear();
+ MapIterator<AnalysisTarget, CacheEntry> iterator =
+ expectedContext.privateAnalysisCachePartition.iterator();
+ while (iterator.moveNext()) {
+ AnalysisTarget target = iterator.key;
+ CacheEntry entry = iterator.value;
+ if (target is NonExistingSource) {
+ continue;
+ }
+ _validateEntry(target, entry);
+ }
+ }
+
+ void _validateElements(
+ Element actualValue, Element expectedValue, Set visited) {
+ if (actualValue == null && expectedValue == null) {
+ return;
+ }
+ if (!currentRevisionValidatedElements.add(expectedValue)) {
+ return;
+ }
+ if (!visited.add(expectedValue)) {
+ return;
+ }
+ List<Element> sortElements(List<Element> elements) {
+ elements = elements.toList();
+ elements.sort((a, b) {
+ if (a.nameOffset != b.nameOffset) {
+ return a.nameOffset - b.nameOffset;
+ }
+ return a.name.compareTo(b.name);
+ });
+ return elements;
+ }
+ void validateSortedElements(
+ List<Element> actualElements, List<Element> expectedElements) {
+ expect(actualElements, hasLength(expectedElements.length));
+ actualElements = sortElements(actualElements);
+ expectedElements = sortElements(expectedElements);
+ for (int i = 0; i < expectedElements.length; i++) {
+ _validateElements(actualElements[i], expectedElements[i], visited);
+ }
+ }
+ expect(actualValue?.runtimeType, expectedValue?.runtimeType);
+ expect(actualValue.nameOffset, expectedValue.nameOffset);
+ expect(actualValue.name, expectedValue.name);
+ if (expectedValue is ClassElement) {
+ var actualElement = actualValue as ClassElement;
+ validateSortedElements(actualElement.accessors, expectedValue.accessors);
+ validateSortedElements(
+ actualElement.constructors, expectedValue.constructors);
+ validateSortedElements(actualElement.fields, expectedValue.fields);
+ validateSortedElements(actualElement.methods, expectedValue.methods);
+ }
+ if (expectedValue is CompilationUnitElement) {
+ var actualElement = actualValue as CompilationUnitElement;
+ validateSortedElements(actualElement.accessors, expectedValue.accessors);
+ validateSortedElements(actualElement.functions, expectedValue.functions);
+ validateSortedElements(actualElement.types, expectedValue.types);
+ validateSortedElements(
+ actualElement.functionTypeAliases, expectedValue.functionTypeAliases);
+ validateSortedElements(
+ actualElement.topLevelVariables, expectedValue.topLevelVariables);
+ }
+ if (expectedValue is ExecutableElement) {
+ var actualElement = actualValue as ExecutableElement;
+ validateSortedElements(
+ actualElement.parameters, expectedValue.parameters);
+ _validateTypes(
+ actualElement.returnType, expectedValue.returnType, visited);
+ }
+ }
+
+ void _validateEntry(AnalysisTarget target, CacheEntry expectedEntry) {
+ CacheEntry actualEntry =
+ actualContext.privateAnalysisCachePartition.get(target);
+ if (actualEntry == null) {
+ return;
+ }
+ print(' (${target.runtimeType}) $target');
+ for (ResultDescriptor result in expectedEntry.nonInvalidResults) {
+ var expectedData = expectedEntry.getResultDataOrNull(result);
+ var actualData = actualEntry.getResultDataOrNull(result);
+ if (expectedData?.state == CacheState.INVALID) {
+ expectedData = null;
+ }
+ if (actualData?.state == CacheState.INVALID) {
+ actualData = null;
+ }
+ if (actualData == null) {
+ if (result != CONTENT &&
+ result != LIBRARY_ELEMENT4 &&
+ result != LIBRARY_ELEMENT5 &&
+ result != READY_LIBRARY_ELEMENT6 &&
+ result != READY_LIBRARY_ELEMENT7) {
+ Source targetSource = target.source;
+ if (targetSource != null &&
+ targetSource.fullName.startsWith(folderPath)) {
+ fail('No ResultData $result for $target');
+ }
+ }
+ continue;
+ }
+ Object expectedValue = expectedData.value;
+ Object actualValue = actualData.value;
+ print(' $result ${expectedValue?.runtimeType}');
+ _validateResult(target, result, actualValue, expectedValue);
+ }
+ }
+
+ void _validatePairs(AnalysisTarget target, ResultDescriptor result,
+ List actualList, List expectedList) {
+ if (expectedList == null) {
+ expect(actualList, isNull);
+ return;
+ }
+ expect(actualList, isNotNull);
+ expect(actualList, hasLength(expectedList.length));
+ for (int i = 0; i < expectedList.length; i++) {
+ Object expected = expectedList[i];
+ Object actual = actualList[i];
+ _validateResult(target, result, actual, expected);
+ }
+ }
+
+ void _validateResult(AnalysisTarget target, ResultDescriptor result,
+ Object actualValue, Object expectedValue) {
+ if (expectedValue is bool) {
+ expect(actualValue, expectedValue, reason: '$result of $target');
+ }
+ if (expectedValue is CompilationUnit) {
+ expect(actualValue, new isInstanceOf<CompilationUnit>());
+ new _AstValidator().isEqualNodes(expectedValue, actualValue);
+ }
+ if (expectedValue is Element) {
+ expect(actualValue, new isInstanceOf<Element>());
+ _validateElements(actualValue, expectedValue, new Set.identity());
+ }
+ if (expectedValue is List) {
+ if (actualValue is List) {
+ _validatePairs(target, result, actualValue, expectedValue);
+ } else {
+ _failTypeMismatch(actualValue, expectedValue);
+ }
+ }
+ if (expectedValue is AnalysisError) {
+ if (actualValue is AnalysisError) {
+ expect(actualValue.source, expectedValue.source);
+ expect(actualValue.offset, expectedValue.offset);
+ expect(actualValue.message, expectedValue.message);
+ } else {
+ _failTypeMismatch(actualValue, expectedValue);
+ }
+ }
+ }
+
+ void _validateTypes(DartType actualType, DartType expectedType, Set visited) {
+ if (!visited.add(expectedType)) {
+ return;
+ }
+ expect(actualType?.runtimeType, expectedType?.runtimeType);
+ _validateElements(actualType.element, expectedType.element, visited);
+ }
+
+ /**
+ * Create and return a source representing the given [file] within the given
+ * [context].
+ */
+ static Source _createSourceInContext(AnalysisContext context, fs.File file) {
+ Source source = file.createSource();
+ if (context == null) {
+ return source;
+ }
+ Uri uri = context.sourceFactory.restoreUri(source);
+ return file.createSource(uri);
+ }
+}
+
+/**
+ * Compares tokens and ASTs, and built elements of declared identifiers.
+ */
+class _AstValidator extends AstComparator {
+ @override
+ bool isEqualNodes(AstNode expected, AstNode actual) {
+ // TODO(scheglov) skip comments for now
+ // [ElementBuilder.visitFunctionExpression] in resolver_test.dart
+ // Going from c4493869ca19ef9ba6bd35d3d42e1209eb3b7e63
+ // to 3977c9f2274df35df6332a65af9973fd6517bc12
+ // With files:
+ // '/Users/scheglov/tmp/limited-invalidation/sdk/pkg/analyzer/lib/src/generated/resolver.dart',
+ // '/Users/scheglov/tmp/limited-invalidation/sdk/pkg/analyzer/lib/src/dart/element/builder.dart',
+ // '/Users/scheglov/tmp/limited-invalidation/sdk/pkg/analyzer/test/generated/resolver_test.dart',
+ if (expected is CommentReference) {
+ return true;
+ }
+ // Compare nodes.
+ bool result = super.isEqualNodes(expected, actual);
+ if (!result) {
+ fail('|$actual| != expected |$expected|');
+ }
+ // Verify that identifiers have equal elements and types.
+ if (expected is SimpleIdentifier && actual is SimpleIdentifier) {
+ _verifyElements(actual.staticElement, expected.staticElement,
+ '$expected staticElement');
+ _verifyElements(actual.propagatedElement, expected.propagatedElement,
+ '$expected staticElement');
+ _verifyTypes(
+ actual.staticType, expected.staticType, '$expected staticType');
+ _verifyTypes(actual.propagatedType, expected.propagatedType,
+ '$expected propagatedType');
+ _verifyElements(actual.staticParameterElement,
+ expected.staticParameterElement, '$expected staticParameterElement');
+ _verifyElements(
+ actual.propagatedParameterElement,
+ expected.propagatedParameterElement,
+ '$expected propagatedParameterElement');
+ }
+ return true;
+ }
+
+ void _verifyElements(Element actual, Element expected, String desc) {
+ if (expected == null && actual == null) {
+ return;
+ }
+ if (expected is MultiplyDefinedElement &&
+ actual is MultiplyDefinedElement) {
+ return;
+ }
+ while (expected is Member) {
+ if (actual is Member) {
+ actual = (actual as Member).baseElement;
+ expected = (expected as Member).baseElement;
+ } else {
+ _failTypeMismatch(actual, expected, reason: desc);
+ }
+ }
+ expect(actual, equals(expected), reason: desc);
+ }
+
+ void _verifyTypes(DartType actual, DartType expected, String desc) {
+ _verifyElements(actual?.element, expected?.element, '$desc element');
+ if (expected is InterfaceType) {
+ if (actual is InterfaceType) {
+ List<DartType> actualArguments = actual.typeArguments;
+ List<DartType> expectedArguments = expected.typeArguments;
+ expect(
+ actualArguments,
+ pairwiseCompare(expectedArguments, (a, b) {
+ _verifyTypes(a, b, '$desc typeArguments');
+ return true;
+ }, 'elements'));
+ } else {
+ _failTypeMismatch(actual, expected);
+ }
+ }
+ }
+}
diff --git a/pkg/analyzer_cli/.analysis_options b/pkg/analyzer_cli/.analysis_options
index 78831a9..dc60267 100644
--- a/pkg/analyzer_cli/.analysis_options
+++ b/pkg/analyzer_cli/.analysis_options
@@ -1,3 +1,4 @@
analyzer:
+ strong-mode: true
exclude:
- 'test/data'
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index f79e401..1883318 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -69,7 +69,7 @@
try {
// Add in the dart-sdk argument if `dartSdkPath` is not null, otherwise it
// will try to find the currently installed sdk.
- var arguments = new List.from(request.arguments);
+ var arguments = new List<String>.from(request.arguments);
if (dartSdkPath != null &&
!arguments.any((arg) => arg.startsWith('--dart-sdk'))) {
arguments.add('--dart-sdk=$dartSdkPath');
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 46316b7..da11426 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -772,15 +772,12 @@
exitCode = batchResult.ordinal;
}
// Prepare arguments.
- var args;
- {
- var lineArgs = line.split(new RegExp('\\s+'));
- args = new List<String>();
- args.addAll(sharedArgs);
- args.addAll(lineArgs);
- args.remove('-b');
- args.remove('--batch');
- }
+ var lineArgs = line.split(new RegExp('\\s+'));
+ var args = new List<String>();
+ args.addAll(sharedArgs);
+ args.addAll(lineArgs);
+ args.remove('-b');
+ args.remove('--batch');
// Analyze single set of arguments.
try {
totalTests++;
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index 030f1bf..2ad8bc4 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -166,7 +166,7 @@
buildMode = args['build-mode'],
buildModePersistentWorker = args['persistent_worker'],
buildSummaryFallback = args['build-summary-fallback'],
- buildSummaryInputs = args['build-summary-input'],
+ buildSummaryInputs = args['build-summary-input'] as List<String>,
buildSummaryOnly = args['build-summary-only'],
buildSummaryOnlyAst = args['build-summary-only-ast'],
buildSummaryOnlyDiet = args['build-summary-only-diet'],
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index e549603..58b5c1a 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -518,7 +518,7 @@
}
class TestProcessor extends OptionsProcessor {
- Map<String, YamlNode> options;
+ Map<String, Object> options;
Exception exception;
@override
@@ -527,8 +527,7 @@
}
@override
- void optionsProcessed(
- AnalysisContext context, Map<String, YamlNode> options) {
+ void optionsProcessed(AnalysisContext context, Map<String, Object> options) {
this.options = options;
}
}
diff --git a/pkg/compiler/lib/src/constant_system_dart.dart b/pkg/compiler/lib/src/constant_system_dart.dart
index a19e003..c42ca74 100644
--- a/pkg/compiler/lib/src/constant_system_dart.dart
+++ b/pkg/compiler/lib/src/constant_system_dart.dart
@@ -8,7 +8,7 @@
import 'constants/constant_system.dart';
import 'constants/values.dart';
import 'dart_types.dart';
-import 'tree/tree.dart' show DartString;
+import 'tree/dartstring.dart' show DartString;
const DART_CONSTANT_SYSTEM = const DartConstantSystem();
diff --git a/pkg/compiler/lib/src/constants/constant_system.dart b/pkg/compiler/lib/src/constants/constant_system.dart
index e278612..07787fd 100644
--- a/pkg/compiler/lib/src/constants/constant_system.dart
+++ b/pkg/compiler/lib/src/constants/constant_system.dart
@@ -7,7 +7,7 @@
import '../dart_types.dart';
import '../compiler.dart' show Compiler;
import '../resolution/operators.dart';
-import '../tree/tree.dart' show DartString;
+import '../tree/dartstring.dart' show DartString;
import 'values.dart';
abstract class Operation {
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index 9eb3fdc..2ea05a8 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -16,7 +16,7 @@
PrefixElement,
VariableElement;
import '../resolution/operators.dart';
-import '../tree/tree.dart' show DartString;
+import '../tree/dartstring.dart' show DartString;
import '../universe/call_structure.dart' show CallStructure;
import 'evaluation.dart';
import 'values.dart';
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 62749bf..fbda202 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -9,7 +9,7 @@
import '../dart_types.dart';
import '../elements/elements.dart'
show FieldElement, FunctionElement, PrefixElement;
-import '../tree/tree.dart' hide unparse;
+import '../tree/dartstring.dart';
import '../util/util.dart' show Hashing;
abstract class ConstantValueVisitor<R, A> {
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index b45d3012..b3668c1 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -36,7 +36,6 @@
import 'resolution/resolution.dart' show AnalyzableElementX;
import 'resolution/tree_elements.dart' show TreeElements;
import 'tree/tree.dart' as ast;
-import 'tree/tree.dart' show Import, Node;
import 'universe/use.dart' show StaticUse, TypeUse, TypeUseKind;
import 'universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
@@ -93,8 +92,7 @@
/// DeferredLibrary from dart:async
ClassElement get deferredLibraryClass => compiler.deferredLibraryClass;
- /// A synthetic [Import] representing the loading of the main
- /// program.
+ /// A synthetic import representing the loading of the main program.
final _DeferredImport _fakeMainImport = const _DeferredImport();
/// The OutputUnit that will be loaded when the program starts.
@@ -235,7 +233,7 @@
return imports.every((ImportElement import) => import.isDeferred);
}
- /// Returns a [Link] of every [Import] that imports [element] into [library].
+ /// Returns every [ImportElement] that imports [element] into [library].
Iterable<ImportElement> _getImports(Element element, LibraryElement library) {
if (element.isClassMember) {
element = element.enclosingClass;
@@ -347,8 +345,8 @@
// implicit constant expression are seen that we should be able to add
// (like primitive constant literals like `true`, `"foo"` and `0`).
// See dartbug.com/26406 for context.
- treeElements
- .forEachConstantNode((Node node, ConstantExpression expression) {
+ treeElements.forEachConstantNode(
+ (ast.Node node, ConstantExpression expression) {
if (compiler.serialization.isDeserialized(analyzableElement)) {
if (!expression.isImplicit && !expression.isPotential) {
// Enforce evaluation of [expression].
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index f8ae6ea..4f185c2 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -15,8 +15,8 @@
import '../elements/elements.dart';
import '../js_backend/js_backend.dart' show Annotations, JavaScriptBackend;
import '../resolution/tree_elements.dart' show TreeElementMapping;
-import '../tree/tree.dart' as ast
- show DartString, Node, LiteralBool, TryStatement;
+import '../tree/tree.dart' as ast show Node, LiteralBool, TryStatement;
+import '../tree/dartstring.dart' show DartString;
import '../types/constants.dart' show computeTypeMask;
import '../types/types.dart'
show ContainerTypeMask, MapTypeMask, TypeMask, TypesInferrer;
@@ -227,7 +227,7 @@
TypeInformation nonNullEmptyType;
- TypeInformation stringLiteralType(ast.DartString value) {
+ TypeInformation stringLiteralType(DartString value) {
return new StringLiteralTypeInformation(
value, compiler.typesTask.stringType);
}
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index dedb4e2..1a6842f 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -14,7 +14,8 @@
import '../dart_types.dart' show DartType, FunctionType, TypeKind;
import '../elements/elements.dart';
import '../native/native.dart' as native;
-import '../tree/tree.dart' as ast show DartString, Node, LiteralBool, Send;
+import '../tree/tree.dart' as ast show Node, LiteralBool, Send;
+import '../tree/dartstring.dart' show DartString;
import '../types/types.dart'
show
ContainerTypeMask,
@@ -1209,7 +1210,7 @@
}
class StringLiteralTypeInformation extends ConcreteTypeInformation {
- final ast.DartString value;
+ final DartString value;
StringLiteralTypeInformation(value, TypeMask mask)
: super(new ValueTypeMask(mask, new StringConstantValue(value))),
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 bfd156e..4bbf530 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -11,7 +11,7 @@
import '../core_types.dart' show CoreTypes;
import '../dart_types.dart';
import '../elements/elements.dart' show ClassElement, FieldElement;
-import '../tree/tree.dart' show DartString, LiteralDartString;
+import '../tree/dartstring.dart' show DartString, LiteralDartString;
import 'js_backend.dart';
const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem();
diff --git a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
index 27651c2..57ce762 100644
--- a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
+++ b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
@@ -8,7 +8,7 @@
import '../dart_types.dart';
import '../elements/elements.dart' show Element, Elements, FieldElement;
-import '../tree/tree.dart' show DartString;
+import '../tree/dartstring.dart' show DartString;
import '../js_backend/js_backend.dart' show SyntheticConstantKind;
/// A canonical but arbrary ordering of constants. The ordering is 'stable'
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index d89f9de..80f5e16 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -14,7 +14,7 @@
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart';
import '../native/native.dart' as native;
-import '../tree/tree.dart' as ast;
+import '../tree/dartstring.dart' as ast;
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart
index 1965695..866d0f0 100644
--- a/pkg/compiler/lib/src/string_validator.dart
+++ b/pkg/compiler/lib/src/string_validator.dart
@@ -10,7 +10,8 @@
import 'common.dart';
import 'tokens/token.dart' show Token;
-import 'tree/tree.dart';
+import 'tree/nodes.dart' show StringQuoting;
+import 'tree/dartstring.dart' show DartString;
import 'util/characters.dart';
class StringValidator {
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 499fc42..df10d3a 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -205,7 +205,6 @@
"--quiet",
"--output", rebase_path(output, root_build_dir),
"--input", rebase_path("vm/version_in.cc", root_build_dir),
- "--ignore_svn_revision",
]
}
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 2e92fe3..099686e 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -219,8 +219,6 @@
"scope",
[ "io_impl_sources.gypi" ])
-if (!defined(is_fuchsia) || (current_toolchain == host_toolchain)) {
-
executable("gen_snapshot") {
configs += ["..:dart_config",
"..:dart_product_config",
@@ -255,6 +253,13 @@
include_dirs = [
"..",
]
+
+ if (is_mac) {
+ libs = [
+ "CoreFoundation.framework",
+ "CoreServices.framework"
+ ]
+ }
}
# A source set for the implementation of 'dart:io' library
@@ -298,8 +303,6 @@
]
}
-} # current_toolchain == host_toolchain
-
source_set("libdart_embedder_noio") {
configs += ["..:dart_config",
"..:dart_product_config",
diff --git a/runtime/bin/builtin_impl_sources.gypi b/runtime/bin/builtin_impl_sources.gypi
index 2e6ae0c..ac6ee92 100644
--- a/runtime/bin/builtin_impl_sources.gypi
+++ b/runtime/bin/builtin_impl_sources.gypi
@@ -13,6 +13,7 @@
'crypto_fuchsia.cc',
'crypto_linux.cc',
'crypto_macos.cc',
+ 'crypto_test.cc',
'crypto_win.cc',
'builtin_common.cc',
'dartutils.cc',
diff --git a/runtime/bin/crypto_fuchsia.cc b/runtime/bin/crypto_fuchsia.cc
index 9423f7c..04c5f22 100644
--- a/runtime/bin/crypto_fuchsia.cc
+++ b/runtime/bin/crypto_fuchsia.cc
@@ -7,20 +7,23 @@
#include "bin/crypto.h"
+#include <magenta/syscalls.h>
+
namespace dart {
namespace bin {
bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) {
- uint32_t num;
intptr_t read = 0;
while (read < count) {
- if (rand_r(&num) != 0) {
+ const intptr_t remaining = count - read;
+ const intptr_t len =
+ (MX_CPRNG_DRAW_MAX_LEN < remaining) ? MX_CPRNG_DRAW_MAX_LEN
+ : remaining;
+ const mx_ssize_t res = mx_cprng_draw(buffer + read, len);
+ if (res == ERR_INVALID_ARGS) {
return false;
}
- for (int i = 0; i < 4 && read < count; i++) {
- buffer[read] = num >> (i * 8);
- read++;
- }
+ read += res;
}
return true;
}
diff --git a/runtime/bin/crypto_test.cc b/runtime/bin/crypto_test.cc
new file mode 100644
index 0000000..65a2ac3
--- /dev/null
+++ b/runtime/bin/crypto_test.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "bin/crypto.h"
+#include "platform/assert.h"
+#include "platform/globals.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+namespace bin {
+
+TEST_CASE(GetRandomBytes) {
+ const intptr_t kNumRandomBytes = 127;
+ uint8_t buf[kNumRandomBytes];
+ const bool res = Crypto::GetRandomBytes(kNumRandomBytes, buf);
+ EXPECT(res);
+}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index 43e1944..a3dcd7f 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -113,6 +113,7 @@
void FUNCTION_NAME(File_Close)(Dart_NativeArguments args) {
File* file = GetFile(args);
ASSERT(file != NULL);
+ file->Close();
file->DeleteWeakHandle(Dart_CurrentIsolate());
file->Release();
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index eab92d5..4f61db1 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -39,7 +39,8 @@
File::~File() {
- if (!IsClosed()) {
+ if (!IsClosed() &&
+ handle_->fd() != STDOUT_FILENO && handle_->fd() != STDERR_FILENO) {
Close();
}
delete handle_;
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index a43b14e..38699cd 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -41,7 +41,8 @@
File::~File() {
- if (!IsClosed()) {
+ if (!IsClosed() &&
+ handle_->fd() != STDOUT_FILENO && handle_->fd() != STDERR_FILENO) {
Close();
}
delete handle_;
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 8d45a17..f487a88 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -38,7 +38,8 @@
File::~File() {
- if (!IsClosed()) {
+ if (!IsClosed() &&
+ handle_->fd() != _fileno(stdout) && handle_->fd() != _fileno(stderr)) {
Close();
}
delete handle_;
diff --git a/runtime/bin/fuchsia_vm_tests.txt b/runtime/bin/fuchsia_vm_tests.txt
index 665cf38..0cbf30a9 100644
--- a/runtime/bin/fuchsia_vm_tests.txt
+++ b/runtime/bin/fuchsia_vm_tests.txt
@@ -1,3 +1,4 @@
+GetRandomBytes
CircularLinkedList
Read
FileLength
@@ -511,6 +512,8 @@
IsolateReload_PendingStaticCall_DefinedToNSM
IsolateReload_PendingStaticCall_NSMToDefined
IsolateReload_PendingSuperCall
+IsolateReload_TearOff_Equality
+IsolateReload_TearOff_List_Set
IsolateReload_EnumEquality
IsolateReload_EnumIdentical
IsolateReload_EnumReorderIdentical
@@ -524,6 +527,18 @@
IsolateReload_DirectSubclasses_Success
IsolateReload_DirectSubclasses_GhostSubclass
IsolateReload_DirectSubclasses_Failure
+IsolateReload_ChangeInstanceFormat0
+IsolateReload_ChangeInstanceFormat1
+IsolateReload_ChangeInstanceFormat2
+IsolateReload_ChangeInstanceFormat3
+IsolateReload_ChangeInstanceFormat4
+IsolateReload_ChangeInstanceFormat5
+IsolateReload_ChangeInstanceFormat6
+IsolateReload_ChangeInstanceFormat7
+IsolateReload_NoLibsModified
+IsolateReload_MainLibModified
+IsolateReload_ImportedLibModified
+IsolateReload_PrefixImportedLibModified
IsolateCurrent
IsolateSpawn
StackLimitInterrupts
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 0c6b8b7..a90c1a4 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -452,6 +452,26 @@
}
+static bool ProcessHotReloadRollbackTestModeOption(
+ const char* arg,
+ CommandLineOptions* vm_options) {
+ // Identity reload.
+ vm_options->AddArgument("--identity_reload");
+ // Start reloading quickly.
+ vm_options->AddArgument("--reload_every=4");
+ // Reload from optimized and unoptimized code.
+ vm_options->AddArgument("--reload_every_optimized=false");
+ // Reload less frequently as time goes on.
+ vm_options->AddArgument("--reload_every_back_off");
+ // Ensure that every isolate has reloaded once before exiting.
+ vm_options->AddArgument("--check_reloaded");
+ // Force all reloads to fail and execute the rollback code.
+ vm_options->AddArgument("--reload_force_rollback");
+
+ return true;
+}
+
+
static struct {
const char* option_name;
bool (*process)(const char* option, CommandLineOptions* vm_options);
@@ -477,6 +497,7 @@
{ "--use-blobs", ProcessUseBlobsOption },
{ "--trace-loading", ProcessTraceLoadingOption },
{ "--hot-reload-test-mode", ProcessHotReloadTestModeOption },
+ { "--hot-reload-rollback-test-mode", ProcessHotReloadRollbackTestModeOption },
{ NULL, NULL }
};
diff --git a/runtime/bin/platform_fuchsia.cc b/runtime/bin/platform_fuchsia.cc
index ace3c37..198521b 100644
--- a/runtime/bin/platform_fuchsia.cc
+++ b/runtime/bin/platform_fuchsia.cc
@@ -28,7 +28,7 @@
int Platform::NumberOfProcessors() {
- return mxr_get_nprocs();
+ return mxr_get_nprocs_conf();
}
diff --git a/runtime/bin/run_vm_tests_fuchsia.cc b/runtime/bin/run_vm_tests_fuchsia.cc
index 431b162..43185ac 100644
--- a/runtime/bin/run_vm_tests_fuchsia.cc
+++ b/runtime/bin/run_vm_tests_fuchsia.cc
@@ -21,8 +21,12 @@
// command line argument which is the path to a file containing a list of tests
// to run, one per line.
+// TODO(zra): Make this a command line argument
const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests";
+// The simulator only has 512MB;
+const intptr_t kOldGenHeapSizeMB = 256;
+
// Tests that are invalid, wedge, or cause panics.
const char* kSkip[] = {
// These expect a file to exist that we aren't putting in the image.
@@ -63,6 +67,8 @@
// No realpath.
"Dart2JSCompilerStats",
"Dart2JSCompileAll",
+ // Uses too much memory.
+ "PrintJSON",
};
// Expected to fail/crash.
@@ -103,11 +109,11 @@
"TimelinePauses_BeginEnd",
// Needs NativeSymbolResolver
"Service_PersistentHandles",
- // Need to investigate:
+ // Crashes in realloc:
"FindCodeObject",
- "ThreadIterator_AddFindRemove",
- "PrintJSON",
"SourceReport_Coverage_AllFunctions_ForceCompile",
+ // pthread TLS destructors are not run.
+ "ThreadIterator_AddFindRemove",
};
@@ -139,10 +145,16 @@
static int run_test(const char* test_name) {
- const intptr_t kArgc = 2;
- const char* argv[3];
+ const intptr_t kArgc = 3;
+ const char* argv[kArgc];
+
+ char old_gen_arg[64];
+ snprintf(old_gen_arg, sizeof(old_gen_arg), "--old_gen_heap_size=%ld",
+ kOldGenHeapSizeMB);
+
argv[0] = kRunVmTestsPath;
- argv[1] = test_name;
+ argv[1] = old_gen_arg;
+ argv[2] = test_name;
mx_handle_t p = launchpad_launch(argv[0], kArgc, argv);
if (p < 0) {
diff --git a/runtime/bin/secure_socket_boringssl.cc b/runtime/bin/secure_socket_boringssl.cc
index 0fd1c9e..def3aae 100644
--- a/runtime/bin/secure_socket_boringssl.cc
+++ b/runtime/bin/secure_socket_boringssl.cc
@@ -800,10 +800,14 @@
// PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case,
// backed by a memory buffer), and returns X509 objects, one by one.
// When the end of the bio is reached, it returns null.
- while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) {
+ while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL)) != NULL) {
X509_STORE_add_cert(store, root_cert);
}
BIO_free(roots_bio);
+ // If there is an error here, it must be the error indicating that we are done
+ // reading PEM certificates.
+ ASSERT((ERR_peek_error() == 0) || NoPEMStartLine());
+ ERR_clear_error();
#endif // defined(TARGET_OS_ANDROID)
}
diff --git a/runtime/bin/vmservice/loader.dart b/runtime/bin/vmservice/loader.dart
index bf5af11..8af63b5 100644
--- a/runtime/bin/vmservice/loader.dart
+++ b/runtime/bin/vmservice/loader.dart
@@ -891,7 +891,7 @@
isolateEmbedderData.values.toList().forEach((IsolateLoaderState ils) {
ils.cleanup();
assert(ils.sp != null);
- _sendResourceResponse(ils.sp, 1, null, null, message);
+ _sendResourceResponse(ils.sp, 1, null, null, null, message);
});
}
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
index 584ceb8..b4a8b14 100644
--- a/runtime/lib/vmservice.cc
+++ b/runtime/lib/vmservice.cc
@@ -416,8 +416,8 @@
intptr_t archive_size = archive.Length();
- const Array& result_list = Array::Handle(thread->zone(),
- Array::New(2 * archive_size));
+ Dart_Handle result_list = Dart_NewList(2 * archive_size);
+ ASSERT(!Dart_IsError(result_list));
intptr_t idx = 0;
while (archive.HasMore()) {
@@ -438,14 +438,11 @@
Dart_NewWeakPersistentHandle(
dart_contents, contents, contents_length, ContentsFinalizer);
- result_list.SetAt(idx, Api::UnwrapStringHandle(
- thread->zone(), dart_filename));
- result_list.SetAt(idx + 1, Api::UnwrapExternalTypedDataHandle(
- thread->zone(), dart_contents));
+ Dart_ListSetAt(result_list, idx, dart_filename);
+ Dart_ListSetAt(result_list, (idx + 1), dart_contents);
idx += 2;
}
-
- return result_list.raw();
+ return Api::UnwrapArrayHandle(thread->zone(), result_list).raw();
#else
return Object::null();
#endif
diff --git a/runtime/observatory/lib/cpu_profile.dart b/runtime/observatory/lib/cpu_profile.dart
index c8a2b53..5ebd9a5 100644
--- a/runtime/observatory/lib/cpu_profile.dart
+++ b/runtime/observatory/lib/cpu_profile.dart
@@ -5,6 +5,7 @@
library cpu_profiler;
import 'dart:typed_data';
+import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
import 'package:observatory/utils.dart';
diff --git a/runtime/observatory/lib/debugger.dart b/runtime/observatory/lib/debugger.dart
index 628b2a9..c62ce0b 100644
--- a/runtime/observatory/lib/debugger.dart
+++ b/runtime/observatory/lib/debugger.dart
@@ -5,6 +5,7 @@
library debugger;
import 'dart:async';
+import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
part 'src/debugger/debugger.dart';
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index 4d9786e..6e2f4f8 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -2,10 +2,9 @@
// Export elements.
export 'package:observatory/src/elements/action_link.dart';
-export 'package:observatory/src/elements/class_ref.dart';
+export 'package:observatory/src/elements/class_ref_as_value.dart';
export 'package:observatory/src/elements/class_tree.dart';
export 'package:observatory/src/elements/class_view.dart';
-export 'package:observatory/src/elements/code_ref.dart';
export 'package:observatory/src/elements/code_view.dart';
export 'package:observatory/src/elements/context_ref.dart';
export 'package:observatory/src/elements/context_view.dart';
@@ -16,10 +15,7 @@
export 'package:observatory/src/elements/eval_link.dart';
export 'package:observatory/src/elements/field_ref.dart';
export 'package:observatory/src/elements/field_view.dart';
-export 'package:observatory/src/elements/flag_list.dart';
-export 'package:observatory/src/elements/function_ref.dart';
export 'package:observatory/src/elements/function_view.dart';
-export 'package:observatory/src/elements/general_error.dart';
export 'package:observatory/src/elements/heap_map.dart';
export 'package:observatory/src/elements/heap_profile.dart';
export 'package:observatory/src/elements/heap_snapshot.dart';
@@ -32,7 +28,7 @@
export 'package:observatory/src/elements/isolate_summary.dart';
export 'package:observatory/src/elements/isolate_view.dart';
export 'package:observatory/src/elements/json_view.dart';
-export 'package:observatory/src/elements/library_ref.dart';
+export 'package:observatory/src/elements/library_ref_as_value.dart';
export 'package:observatory/src/elements/library_view.dart';
export 'package:observatory/src/elements/logging.dart';
export 'package:observatory/src/elements/megamorphiccache_view.dart';
@@ -46,7 +42,6 @@
export 'package:observatory/src/elements/persistent_handles.dart';
export 'package:observatory/src/elements/ports.dart';
export 'package:observatory/src/elements/script_inset.dart';
-export 'package:observatory/src/elements/script_ref.dart';
export 'package:observatory/src/elements/script_view.dart';
export 'package:observatory/src/elements/service_ref.dart';
export 'package:observatory/src/elements/service_view.dart';
@@ -56,10 +51,24 @@
import 'dart:async';
+import 'package:observatory/src/elements/class_ref.dart';
+import 'package:observatory/src/elements/class_ref_wrapper.dart';
+import 'package:observatory/src/elements/code_ref.dart';
+import 'package:observatory/src/elements/code_ref_wrapper.dart';
+import 'package:observatory/src/elements/containers/virtual_collection.dart';
+import 'package:observatory/src/elements/containers/virtual_tree.dart';
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/curly_block_wrapper.dart';
+import 'package:observatory/src/elements/error_ref.dart';
+import 'package:observatory/src/elements/error_ref_wrapper.dart';
+import 'package:observatory/src/elements/flag_list.dart';
+import 'package:observatory/src/elements/function_ref.dart';
+import 'package:observatory/src/elements/function_ref_wrapper.dart';
+import 'package:observatory/src/elements/general_error.dart';
import 'package:observatory/src/elements/isolate_ref.dart';
import 'package:observatory/src/elements/isolate_ref_wrapper.dart';
+import 'package:observatory/src/elements/library_ref.dart';
+import 'package:observatory/src/elements/library_ref_wrapper.dart';
import 'package:observatory/src/elements/nav/bar.dart';
import 'package:observatory/src/elements/nav/class_menu.dart';
import 'package:observatory/src/elements/nav/class_menu_wrapper.dart';
@@ -81,14 +90,27 @@
import 'package:observatory/src/elements/nav/top_menu_wrapper.dart';
import 'package:observatory/src/elements/nav/vm_menu.dart';
import 'package:observatory/src/elements/nav/vm_menu_wrapper.dart';
+import 'package:observatory/src/elements/script_ref.dart';
+import 'package:observatory/src/elements/script_ref_wrapper.dart';
+import 'package:observatory/src/elements/source_link.dart';
+import 'package:observatory/src/elements/source_link_wrapper.dart';
import 'package:observatory/src/elements/view_footer.dart';
import 'package:observatory/src/elements/vm_connect_target.dart';
import 'package:observatory/src/elements/vm_connect.dart';
export 'package:observatory/src/elements/helpers/rendering_queue.dart';
+export 'package:observatory/src/elements/class_ref.dart';
+export 'package:observatory/src/elements/code_ref.dart';
+export 'package:observatory/src/elements/containers/virtual_collection.dart';
+export 'package:observatory/src/elements/containers/virtual_tree.dart';
export 'package:observatory/src/elements/curly_block.dart';
+export 'package:observatory/src/elements/error_ref.dart';
+export 'package:observatory/src/elements/flag_list.dart';
+export 'package:observatory/src/elements/function_ref.dart';
+export 'package:observatory/src/elements/general_error.dart';
export 'package:observatory/src/elements/isolate_ref.dart';
+export 'package:observatory/src/elements/library_ref.dart';
export 'package:observatory/src/elements/nav/bar.dart';
export 'package:observatory/src/elements/nav/class_menu.dart';
export 'package:observatory/src/elements/nav/isolate_menu.dart';
@@ -101,6 +123,8 @@
export 'package:observatory/src/elements/nav/refresh.dart';
export 'package:observatory/src/elements/nav/top_menu.dart';
export 'package:observatory/src/elements/nav/vm_menu.dart';
+export 'package:observatory/src/elements/script_ref.dart';
+export 'package:observatory/src/elements/source_link.dart';
export 'package:observatory/src/elements/view_footer.dart';
export 'package:observatory/src/elements/vm_connect_target.dart';
export 'package:observatory/src/elements/vm_connect.dart';
@@ -108,10 +132,22 @@
// Even though this function does not invoke any asynchronous operation
// it is marked as async to allow future backward compatible changes.
Future initElements() async {
+ ClassRefElement.tag.ensureRegistration();
+ ClassRefElementWrapper.tag.ensureRegistration();
+ CodeRefElement.tag.ensureRegistration();
+ CodeRefElementWrapper.tag.ensureRegistration();
CurlyBlockElement.tag.ensureRegistration();
CurlyBlockElementWrapper.tag.ensureRegistration();
+ ErrorRefElement.tag.ensureRegistration();
+ ErrorRefElementWrapper.tag.ensureRegistration();
+ FlagListElement.tag.ensureRegistration();
+ FunctionRefElement.tag.ensureRegistration();
+ FunctionRefElementWrapper.tag.ensureRegistration();
+ GeneralErrorElement.tag.ensureRegistration();
IsolateRefElement.tag.ensureRegistration();
IsolateRefElementWrapper.tag.ensureRegistration();
+ LibraryRefElement.tag.ensureRegistration();
+ LibraryRefElementWrapper.tag.ensureRegistration();
NavBarElement.tag.ensureRegistration();
NavClassMenuElement.tag.ensureRegistration();
NavClassMenuElementWrapper.tag.ensureRegistration();
@@ -133,7 +169,13 @@
NavTopMenuElementWrapper.tag.ensureRegistration();
NavVMMenuElement.tag.ensureRegistration();
NavVMMenuElementWrapper.tag.ensureRegistration();
+ ScriptRefElement.tag.ensureRegistration();
+ ScriptRefElementWrapper.tag.ensureRegistration();
+ SourceLinkElement.tag.ensureRegistration();
+ SourceLinkElementWrapper.tag.ensureRegistration();
ViewFooterElement.tag.ensureRegistration();
+ VirtualCollectionElement.tag.ensureRegistration();
+ VirtualTreeElement.tag.ensureRegistration();
VMConnectElement.tag.ensureRegistration();
VMConnectTargetElement.tag.ensureRegistration();
}
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index 731c907..ed5c73c 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -1,8 +1,7 @@
<link rel="import" href="src/elements/action_link.html">
-<link rel="import" href="src/elements/class_ref.html">
+<link rel="import" href="src/elements/class_ref_as_value.html">
<link rel="import" href="src/elements/class_tree.html">
<link rel="import" href="src/elements/class_view.html">
-<link rel="import" href="src/elements/code_ref.html">
<link rel="import" href="src/elements/code_view.html">
<link rel="import" href="src/elements/cpu_profile.html">
<link rel="import" href="src/elements/debugger.html">
@@ -11,10 +10,7 @@
<link rel="import" href="src/elements/eval_link.html">
<link rel="import" href="src/elements/field_ref.html">
<link rel="import" href="src/elements/field_view.html">
-<link rel="import" href="src/elements/flag_list.html">
-<link rel="import" href="src/elements/function_ref.html">
<link rel="import" href="src/elements/function_view.html">
-<link rel="import" href="src/elements/general_error.html">
<link rel="import" href="src/elements/heap_map.html">
<link rel="import" href="src/elements/instance_ref.html">
<link rel="import" href="src/elements/instance_view.html">
@@ -25,7 +21,7 @@
<link rel="import" href="src/elements/isolate_summary.html">
<link rel="import" href="src/elements/isolate_view.html">
<link rel="import" href="src/elements/json_view.html">
-<link rel="import" href="src/elements/library_ref.html">
+<link rel="import" href="src/elements/library_ref_as_value.html">
<link rel="import" href="src/elements/library_view.html">
<link rel="import" href="src/elements/logging.html">
<link rel="import" href="src/elements/megamorphiccache_view.html">
@@ -38,7 +34,6 @@
<link rel="import" href="src/elements/persistent_handles.html">
<link rel="import" href="src/elements/ports.html">
<link rel="import" href="src/elements/script_inset.html">
-<link rel="import" href="src/elements/script_ref.html">
<link rel="import" href="src/elements/script_view.html">
<link rel="import" href="src/elements/service_ref.html">
<link rel="import" href="src/elements/timeline_page.html">
diff --git a/runtime/observatory/lib/mocks.dart b/runtime/observatory/lib/mocks.dart
index facf17f..2535fa0 100644
--- a/runtime/observatory/lib/mocks.dart
+++ b/runtime/observatory/lib/mocks.dart
@@ -11,8 +11,11 @@
part 'src/mocks/exceptions/connection_exception.dart';
part 'src/mocks/objects/error.dart';
+part 'src/mocks/objects/code.dart';
part 'src/mocks/objects/event.dart';
part 'src/mocks/objects/class.dart';
+part 'src/mocks/objects/flag.dart';
+part 'src/mocks/objects/function.dart';
part 'src/mocks/objects/isolate.dart';
part 'src/mocks/objects/library.dart';
part 'src/mocks/objects/notification.dart';
@@ -22,5 +25,7 @@
part 'src/mocks/objects/vm.dart';
part 'src/mocks/repositories/crash_dump.dart';
+part 'src/mocks/repositories/flag.dart';
part 'src/mocks/repositories/notification.dart';
+part 'src/mocks/repositories/script.dart';
part 'src/mocks/repositories/target.dart';
diff --git a/runtime/observatory/lib/models.dart b/runtime/observatory/lib/models.dart
index 878a72c..6fa8853 100644
--- a/runtime/observatory/lib/models.dart
+++ b/runtime/observatory/lib/models.dart
@@ -9,11 +9,14 @@
part 'src/models/exceptions.dart';
part 'src/models/objects/class.dart';
+part 'src/models/objects/code.dart';
part 'src/models/objects/breakpoint.dart';
part 'src/models/objects/error.dart';
part 'src/models/objects/event.dart';
part 'src/models/objects/extension_data.dart';
+part 'src/models/objects/flag.dart';
part 'src/models/objects/frame.dart';
+part 'src/models/objects/function.dart';
part 'src/models/objects/instance.dart';
part 'src/models/objects/isolate.dart';
part 'src/models/objects/library.dart';
@@ -25,6 +28,9 @@
part 'src/models/objects/timeline_event.dart';
part 'src/models/objects/vm.dart';
+part 'src/models/repository.dart';
part 'src/models/repositories/crash_dump.dart';
+part 'src/models/repositories/flag.dart';
part 'src/models/repositories/notification.dart';
+part 'src/models/repositories/script.dart';
part 'src/models/repositories/target.dart';
diff --git a/runtime/observatory/lib/repositories.dart b/runtime/observatory/lib/repositories.dart
index 4e7cd44..feeb8f2 100644
--- a/runtime/observatory/lib/repositories.dart
+++ b/runtime/observatory/lib/repositories.dart
@@ -8,9 +8,12 @@
import 'dart:convert';
import 'dart:html';
import 'package:observatory/models.dart' as M;
+import 'package:observatory/service.dart' as S;
import 'package:observatory/service_common.dart' as SC;
import 'package:observatory/utils.dart';
+part 'src/repositories/flag.dart';
part 'src/repositories/notification.dart';
+part 'src/repositories/script.dart';
part 'src/repositories/settings.dart';
part 'src/repositories/target.dart';
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index 0129c34..980fcfa 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -84,7 +84,7 @@
void onInstall() {
if (element == null) {
// Lazily create page.
- element = new Element.tag('general-error');
+ element = new GeneralErrorElement(app.notifications, queue: app.queue);
}
}
@@ -92,17 +92,7 @@
assert(element != null);
assert(canVisit(uri));
- /*
- if (uri.path == '') {
- // Nothing requested.
- return;
- }
- */
-
- if (element != null) {
- GeneralErrorElement serviceElement = element;
- serviceElement.message = "Path '${uri.path}' not found";
- }
+ (element as GeneralErrorElement).message = "Path '${uri.path}' not found";
}
/// Catch all.
@@ -111,14 +101,14 @@
/// Top-level vm info page.
class VMPage extends SimplePage {
- VMPage(app) : super('vm', 'service-view', app);
+ VMPage(app) : super('vm', 'vm-view', app);
void _visit(Uri uri) {
super._visit(uri);
app.vm.reload().then((vm) {
if (element != null) {
- ServiceObjectViewElement serviceElement = element;
- serviceElement.object = vm;
+ VMViewElement serviceElement = element;
+ serviceElement.vm = vm;
}
}).catchError((e, stack) {
Logger.root.severe('VMPage visit error: $e');
@@ -131,16 +121,16 @@
class FlagsPage extends SimplePage {
FlagsPage(app) : super('flags', 'flag-list', app);
+ @override
+ onInstall() {
+ element = new FlagListElement(app.vm,
+ app.vm.changes.map((_) => new VMUpdateEventMock(vm: app.vm)),
+ new FlagsRepository(),
+ app.notifications);
+ }
+
void _visit(Uri uri) {
super._visit(uri);
- app.vm.getFlagList().then((flags) {
- if (element != null) {
- FlagListElement serviceElement = element;
- serviceElement.flagList = flags;
- }
- }).catchError((e, stack) {
- Logger.root.severe('FlagsPage visit error: $e\n$stack');
- });
}
}
diff --git a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
index fb63fba..a572279 100644
--- a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
+++ b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
@@ -133,7 +133,7 @@
if (!profileCode.code.isDartCode) {
continue;
}
- if (profileCode.code.kind == CodeKind.Stub) {
+ if (profileCode.code.kind == M.CodeKind.stub) {
continue;
}
if (!profileCode.code.isOptimized) {
@@ -150,7 +150,7 @@
if (!profileCode.code.isDartCode) {
continue;
}
- if (profileCode.code.kind == CodeKind.Stub) {
+ if (profileCode.code.kind == M.CodeKind.stub) {
continue;
}
// If the code's function isn't this function.
@@ -418,9 +418,9 @@
code.profile = this;
- if (code.kind == CodeKind.Stub) {
+ if (code.kind == M.CodeKind.stub) {
attributes.add('stub');
- } else if (code.kind == CodeKind.Dart) {
+ } else if (code.kind == M.CodeKind.dart) {
if (code.isNative) {
attributes.add('ffi'); // Not to be confused with a C function.
} else {
@@ -434,9 +434,9 @@
} else {
attributes.add('unoptimized');
}
- } else if (code.kind == CodeKind.Tag) {
+ } else if (code.kind == M.CodeKind.tag) {
attributes.add('tag');
- } else if (code.kind == CodeKind.Native) {
+ } else if (code.kind == M.CodeKind.native) {
attributes.add('native');
}
inclusiveTicks = int.parse(data['inclusiveTicks']);
@@ -537,7 +537,7 @@
// Does this function have an unoptimized version of itself?
bool hasUnoptimizedCode() {
for (var profileCode in profileCodes) {
- if (profileCode.code.kind == CodeKind.Stub) {
+ if (profileCode.code.kind == M.CodeKind.stub) {
continue;
}
if (!profileCode.code.isDartCode) {
@@ -553,7 +553,7 @@
// Has this function been inlined in another function?
bool isInlined() {
for (var profileCode in profileCodes) {
- if (profileCode.code.kind == CodeKind.Stub) {
+ if (profileCode.code.kind == M.CodeKind.stub) {
continue;
}
if (!profileCode.code.isDartCode) {
@@ -568,13 +568,13 @@
}
void _addKindBasedAttributes(Set<String> attribs) {
- if (function.kind == FunctionKind.kTag) {
+ if (function.kind == M.FunctionKind.tag) {
attribs.add('tag');
- } else if (function.kind == FunctionKind.kStub) {
+ } else if (function.kind == M.FunctionKind.stub) {
attribs.add('stub');
- } else if (function.kind == FunctionKind.kNative) {
+ } else if (function.kind == M.FunctionKind.native) {
attribs.add('native');
- } else if (function.kind.isSynthetic()) {
+ } else if (M.isSyntheticFunction(function.kind)) {
attribs.add('synthetic');
} else if (function.isNative) {
attribs.add('ffi'); // Not to be confused with a C function.
diff --git a/runtime/observatory/lib/src/debugger/debugger_location.dart b/runtime/observatory/lib/src/debugger/debugger_location.dart
index ac3a9bf..d1b4054 100644
--- a/runtime/observatory/lib/src/debugger/debugger_location.dart
+++ b/runtime/observatory/lib/src/debugger/debugger_location.dart
@@ -233,7 +233,7 @@
for (var cls in classes) {
assert(cls.loaded);
for (var function in cls.functions) {
- if (function.kind == FunctionKind.kConstructor) {
+ if (function.kind == M.FunctionKind.constructor) {
// Constructor names are class-qualified.
if (match.group(0) == function.name) {
functions.add(function);
@@ -314,7 +314,7 @@
var completions = [];
for (var cls in classes) {
for (var function in cls.functions) {
- if (function.kind == FunctionKind.kConstructor) {
+ if (function.kind == M.FunctionKind.constructor) {
if (function.name.startsWith(match.group(0))) {
completions.add(function.name);
}
diff --git a/runtime/observatory/lib/src/elements/class_ref.dart b/runtime/observatory/lib/src/elements/class_ref.dart
index b8895c6..d9940fb 100644
--- a/runtime/observatory/lib/src/elements/class_ref.dart
+++ b/runtime/observatory/lib/src/elements/class_ref.dart
@@ -4,33 +4,57 @@
library class_ref_element;
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
+import 'dart:html';
import 'dart:async';
+import 'package:observatory/models.dart' as M
+ show IsolateRef, ClassRef;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
-@CustomTag('class-ref')
-class ClassRefElement extends ServiceRefElement {
- @observable bool asValue = false;
+class ClassRefElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<ClassRefElement>('class-ref-wrapped');
+
+ RenderingScheduler<ClassRefElement> _r;
+
+ Stream<RenderedEvent<ClassRefElement>> get onRendered => _r.onRendered;
+
+ M.IsolateRef _isolate;
+ M.ClassRef _class;
+
+ M.IsolateRef get isolate => _isolate;
+ M.ClassRef get cls => _class;
+
+ factory ClassRefElement(M.IsolateRef isolate, M.ClassRef cls,
+ {RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(cls != null);
+ ClassRefElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._class = cls;
+ return e;
+ }
ClassRefElement.created() : super.created();
- String makeExpandKey(String key) {
- return '${expandKey}/${key}';
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
}
- dynamic expander() {
- return expandEvent;
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ children = [];
}
- void expandEvent(bool expand, Function onDone) {
- if (expand) {
- Class cls = ref;
- cls.reload().then((result) {
- return Future.wait(cls.fields.map((field) => field.reload()));
- }).whenComplete(onDone);
- } else {
- onDone();
- }
+ void render() {
+ children = [
+ new AnchorElement(href: Uris.inspect(_isolate, object: _class))
+ ..text = _class.name
+ ];
}
-}
\ No newline at end of file
+}
diff --git a/runtime/observatory/lib/src/elements/class_ref_as_value.dart b/runtime/observatory/lib/src/elements/class_ref_as_value.dart
new file mode 100644
index 0000000..7e129f8
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/class_ref_as_value.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library class_ref_as_value_element;
+
+import 'package:observatory/service.dart';
+import 'package:polymer/polymer.dart';
+import 'service_ref.dart';
+import 'dart:async';
+
+@CustomTag('class-ref-as-value')
+class ClassRefAsValueElement extends ServiceRefElement {
+
+ ClassRefAsValueElement.created() : super.created();
+
+ String makeExpandKey(String key) {
+ return '${expandKey}/${key}';
+ }
+
+ dynamic expander() {
+ return expandEvent;
+ }
+
+ void expandEvent(bool expand, Function onDone) {
+ if (expand) {
+ Class cls = ref;
+ cls.reload().then((result) {
+ return Future.wait(cls.fields.map((field) => field.reload()));
+ }).whenComplete(onDone);
+ } else {
+ onDone();
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/class_ref.html b/runtime/observatory/lib/src/elements/class_ref_as_value.html
similarity index 70%
rename from runtime/observatory/lib/src/elements/class_ref.html
rename to runtime/observatory/lib/src/elements/class_ref_as_value.html
index 1ffe1d1..a148981 100644
--- a/runtime/observatory/lib/src/elements/class_ref.html
+++ b/runtime/observatory/lib/src/elements/class_ref_as_value.html
@@ -1,8 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-
<link rel="import" href="service_ref.html">
-<polymer-element name="class-ref">
+<polymer-element name="class-ref-as-value">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -12,9 +11,8 @@
line-height: 150%;
}
</style><!--
- --><a on-click="{{ goto }}" _href="{{ url }}">{{ ref.name }}</a><!--
- --><template if="{{ asValue }}">
- <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
+ --><class-ref ref="{{ ref }}"></class-ref><!--
+ --><curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
<div class="indented">
<template repeat="{{ field in ref.fields }}">
<template if="{{ field.isStatic }}">
@@ -25,9 +23,8 @@
</template>
</template>
</div>
- </curly-block>
- </template><!--
+ </curly-block><!--
--></template>
</polymer-element>
-<script type="application/dart" src="class_ref.dart"></script>
+<script type="application/dart" src="class_ref_as_value.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/class_ref_wrapper.dart b/runtime/observatory/lib/src/elements/class_ref_wrapper.dart
new file mode 100644
index 0000000..daa15b7
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/class_ref_wrapper.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service_html.dart' show Class;
+import 'package:observatory/src/elements/class_ref.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+@bindable
+class ClassRefElementWrapper extends HtmlElement {
+
+ static const binder = const Binder<ClassRefElementWrapper>(const {
+ 'ref': #ref
+ });
+
+ static const tag = const Tag<ClassRefElementWrapper>('class-ref');
+
+ Class _class;
+ Class get ref => _class;
+ void set ref(Class ref) { _class = ref; render(); }
+
+ ClassRefElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (ref == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ class-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+ }
+ class-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+ }''',
+ new ClassRefElement(_class.isolate, _class,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/class_tree.html b/runtime/observatory/lib/src/elements/class_tree.html
index 94e43f7..e2fbb32 100644
--- a/runtime/observatory/lib/src/elements/class_tree.html
+++ b/runtime/observatory/lib/src/elements/class_tree.html
@@ -1,5 +1,4 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<polymer-element name="class-tree">
<template>
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index df003cd..94efab1 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -4,11 +4,8 @@
<link rel="import" href="eval_box.html">
<link rel="import" href="eval_link.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="library_ref.html">
<link rel="import" href="script_inset.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="class-view">
<template>
diff --git a/runtime/observatory/lib/src/elements/code_ref.dart b/runtime/observatory/lib/src/elements/code_ref.dart
index 88464de..bead036 100644
--- a/runtime/observatory/lib/src/elements/code_ref.dart
+++ b/runtime/observatory/lib/src/elements/code_ref.dart
@@ -4,31 +4,59 @@
library code_ref_element;
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
-import 'package:observatory/service.dart';
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M
+ show IsolateRef, CodeRef, isSyntheticCode;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
-@CustomTag('code-ref')
-class CodeRefElement extends ServiceRefElement {
- CodeRefElement.created() : super.created();
+class CodeRefElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<CodeRefElement>('code-ref-wrapped');
- Code get code => ref;
+ RenderingScheduler<CodeRefElement> _r;
- refChanged(oldValue) {
- super.refChanged(oldValue);
- _updateShadowDom();
+ Stream<RenderedEvent<CodeRefElement>> get onRendered => _r.onRendered;
+
+ M.IsolateRef _isolate;
+ M.CodeRef _code;
+
+ M.IsolateRef get isolate => _isolate;
+ M.CodeRef get code => _code;
+
+ factory CodeRefElement(M.IsolateRef isolate, M.CodeRef code,
+ {RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(code != null);
+ CodeRefElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._code = code;
+ return e;
}
- void _updateShadowDom() {
- clearShadowRoot();
- if (code == null) {
- return;
- }
- var name = (code.isOptimized ? '*' : '') + code.name;
- if (code.isDartCode) {
- insertLinkIntoShadowRoot(name, url, hoverText);
- } else {
- insertTextSpanIntoShadowRoot(name);
- }
+ CodeRefElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ children = [];
+ }
+
+ void render() {
+ final name = (_code.isOptimized ? '*' : '') + _code.name;
+ children = [
+ new AnchorElement(href: M.isSyntheticCode(_code.kind) ? null
+ : Uris.inspect(_isolate, object: _code))
+ ..text = name
+ ];
}
}
diff --git a/runtime/observatory/lib/src/elements/code_ref.html b/runtime/observatory/lib/src/elements/code_ref.html
deleted file mode 100644
index 4a8c7f5..0000000
--- a/runtime/observatory/lib/src/elements/code_ref.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="code-ref">
- <template><link rel="stylesheet" href="css/shared.css"></template>
-</polymer-element>
-
-<script type="application/dart" src="code_ref.dart"></script>
\ No newline at end of file
diff --git a/runtime/observatory/lib/src/elements/code_ref_wrapper.dart b/runtime/observatory/lib/src/elements/code_ref_wrapper.dart
new file mode 100644
index 0000000..503a784
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/code_ref_wrapper.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service_html.dart' show Code;
+import 'package:observatory/src/elements/code_ref.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+@bindable
+class CodeRefElementWrapper extends HtmlElement {
+
+ static const binder = const Binder<CodeRefElementWrapper>(const {
+ 'ref': #ref
+ });
+
+ static const tag = const Tag<CodeRefElementWrapper>('code-ref');
+
+ Code _code;
+ Code get ref => _code;
+ void set ref(Code ref) { _code = ref; render(); }
+
+ CodeRefElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (ref == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ code-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+ }
+ code-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+ }''',
+ new CodeRefElement(_code.isolate, _code,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/code_view.html b/runtime/observatory/lib/src/elements/code_view.html
index 10e280c..048024e 100644
--- a/runtime/observatory/lib/src/elements/code_view.html
+++ b/runtime/observatory/lib/src/elements/code_view.html
@@ -1,7 +1,5 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="code-view">
<template>
diff --git a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
new file mode 100644
index 0000000..36e682c
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
@@ -0,0 +1,158 @@
+// 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:async';
+import 'dart:html';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+
+typedef HtmlElement VirtualCollectionCreateCallback();
+typedef void VirtualCollectionUpdateCallback(HtmlElement el, dynamic item,
+ int index);
+
+class VirtualCollectionElement extends HtmlElement implements Renderable {
+ static const tag =
+ const Tag<VirtualCollectionElement>('virtual-collection');
+
+ RenderingScheduler<VirtualCollectionElement> _r;
+
+ Stream<RenderedEvent<VirtualCollectionElement>> get onRendered =>
+ _r.onRendered;
+
+ VirtualCollectionCreateCallback _create;
+ VirtualCollectionUpdateCallback _update;
+ double _itemHeight;
+ int _top;
+ int _height;
+ List _items;
+ StreamSubscription _onScrollSubscription;
+ StreamSubscription _onResizeSubscription;
+
+ List get items => _items;
+
+ set items(Iterable value) {
+ _items = new List.unmodifiable(value);
+ _r.dirty();
+ }
+
+
+ factory VirtualCollectionElement(VirtualCollectionCreateCallback create,
+ VirtualCollectionUpdateCallback update, {Iterable items: const [],
+ RenderingQueue queue}) {
+ assert(create != null);
+ assert(update != null);
+ assert(items != null);
+ VirtualCollectionElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._create = create;
+ e._update = update;
+ e._items = new List.unmodifiable(items);
+ return e;
+ }
+
+ VirtualCollectionElement.created() : super.created();
+
+ @override
+ attached() {
+ super.attached();
+ _r.enable();
+ _top = 0;
+ _height = getBoundingClientRect().height;
+ _itemHeight = _computeItemHeight();
+ _onScrollSubscription = onScroll.listen(_onScroll);
+ _onResizeSubscription = window.onResize.listen(_onResize);
+ }
+
+ @override
+ detached() {
+ super.detached();
+ _r.disable(notify: true);
+ children = const [];
+ _onScrollSubscription.cancel();
+ _onResizeSubscription.cancel();
+ }
+
+ final DivElement _scroller = new DivElement()..classes = const ['scroller'];
+ final DivElement _shifter = new DivElement()..classes = const ['shifter'];
+
+ dynamic getItemFromElement(HtmlElement element) {
+ final el_index = _shifter.children.indexOf(element);
+ if (el_index < 0) {
+ return null;
+ }
+ final item_index =
+ _top + el_index - (_shifter.children.length * _inverse_preload).floor();
+ if (0 <= item_index && item_index < items.length) {
+ return _items[item_index];
+ }
+ return null;
+ }
+
+ /// The preloaded element before and after the visible area are:
+ /// 1/preload_size of the number of items in the visble area.
+ /// See shared.css for the "top:-25%;".
+ static const int _preload = 2;
+ /// L = length of all the elements loaded
+ /// l = length of the visible area
+ ///
+ /// L = l + 2 * l / _preload
+ /// l = L * _preload / (_preload + 2)
+ ///
+ /// tail = l / _preload = L * 1 / (_preload + 2) = L * _inverse_preload
+ static const double _inverse_preload = 1 / (_preload + 2);
+
+ void render() {
+ _top = (scrollTop / _itemHeight).floor();
+
+ _scroller.style.height = '${_itemHeight*(_items.length)}px';
+ _shifter.style.top = '${_itemHeight*_top}px';
+ final tail_length = (_height / _itemHeight / _preload).ceil();
+ final length = tail_length * 2 + tail_length * _preload;
+
+ if (_shifter.children.length < length) {
+ while (_shifter.children.length != length) {
+ var e = _create();
+ e..style.display = 'hidden';
+ _shifter.children.add(e);
+ }
+ _shifter.style.height = '${_itemHeight*length}px';
+ children = [
+ _scroller
+ ..children = [_shifter]
+ ];
+ }
+
+ int i = _top - tail_length;
+ for (final HtmlElement e in _shifter.children) {
+ if (0 <= i && i < _items.length) {
+ e..style.display = null;
+ _update(e, _items[i], i);
+ } else {
+ e.style.display = 'hidden';
+ }
+ i++;
+ }
+ }
+
+ double _computeItemHeight() {
+ final c = children;
+ children = [_create()];
+ final height = children[0].getBoundingClientRect().height;
+ children = c;
+ return height;
+ }
+
+ void _onScroll(_) {
+ if(_r.isDirty) return;
+ if ((scrollTop - _top * _itemHeight).abs() >=
+ _shifter.children.length * _inverse_preload * _itemHeight) {
+ _r.dirty();
+ }
+ }
+
+ void _onResize(_) {
+ _height = getBoundingClientRect().height;
+ _r.dirty();
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/containers/virtual_tree.dart b/runtime/observatory/lib/src/elements/containers/virtual_tree.dart
new file mode 100644
index 0000000..78ea96b
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/containers/virtual_tree.dart
@@ -0,0 +1,149 @@
+// 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:async';
+import 'dart:html';
+import 'package:observatory/src/elements/containers/virtual_collection.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+
+typedef HtmlElement VirtualTreeCreateCallback(
+ toggle({bool autoToggleSingleChildNodes, bool autoToggleWholeTree}));
+typedef void VirtualTreeUpdateCallback(HtmlElement el, dynamic item, int depth);
+typedef Iterable<dynamic> VritualTreeGetChildrenCallback(dynamic value);
+
+class VirtualTreeElement extends HtmlElement implements Renderable {
+ static const tag =
+ const Tag<VirtualTreeElement>('virtual-tree', dependencies: const [
+ VirtualCollectionElement.tag
+ ]);
+
+ RenderingScheduler<VirtualTreeElement> _r;
+
+ Stream<RenderedEvent<VirtualTreeElement>> get onRendered => _r.onRendered;
+
+ VritualTreeGetChildrenCallback _children;
+ List _items;
+ List _depths;
+ final Set _expanded = new Set();
+
+ List get items => _items;
+
+ set items(Iterable value) {
+ _items = new List.unmodifiable(value);
+ _expanded.clear();
+ _r.dirty();
+ }
+
+ factory VirtualTreeElement(VirtualTreeCreateCallback create,
+ VirtualTreeUpdateCallback update, VritualTreeGetChildrenCallback children,
+ {Iterable items: const [], RenderingQueue queue}) {
+ assert(create != null);
+ assert(update != null);
+ assert(children != null);
+ assert(items != null);
+ VirtualTreeElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._children = children;
+ e._collection = new VirtualCollectionElement(() {
+ var element;
+ return element = create(({bool autoToggleSingleChildNodes: false,
+ bool autoToggleWholeTree: false}) {
+ var item = e._collection.getItemFromElement(element);
+ if (e.isExpanded(item)) {
+ e.collapse(item, autoCollapseWholeTree: autoToggleWholeTree,
+ autoCollapseSingleChildNodes: autoToggleSingleChildNodes);
+ } else {
+ e.expand(item, autoExpandWholeTree: autoToggleWholeTree,
+ autoExpandSingleChildNodes: autoToggleSingleChildNodes);
+ }
+ });
+ }, (HtmlElement el, dynamic item, int index) {
+ update(el, item, e._depths[index]);
+ }, queue: queue);
+ e._items = new List.unmodifiable(items);
+ return e;
+ }
+
+ VirtualTreeElement.created() : super.created();
+
+ bool isExpanded(item) {
+ return _expanded.contains(item);
+ }
+
+ void expand(item, {bool autoExpandSingleChildNodes : false,
+ bool autoExpandWholeTree: false}) {
+ if (_expanded.add(item)) _r.dirty();
+ if (autoExpandWholeTree) {
+ for (final child in _children(item)) {
+ expand(child, autoExpandWholeTree: true);
+ }
+ } else if (autoExpandSingleChildNodes) {
+ var children = _children(item);
+ while (children.length == 1) {
+ _expanded.add(children.first);
+ children = _children(children.first);
+ }
+ }
+ }
+
+ void collapse(item, {bool autoCollapseSingleChildNodes : false,
+ bool autoCollapseWholeTree: false}) {
+ if (_expanded.remove(item)) _r.dirty();
+ if (autoCollapseWholeTree) {
+ for (final child in _children(item)) {
+ collapse(child, autoCollapseWholeTree: true);
+ }
+ } else if (autoCollapseSingleChildNodes) {
+ var children = _children(item);
+ while (children.length == 1) {
+ _expanded.remove(children.first);
+ children = _children(children.first);
+ }
+ }
+ }
+
+ @override
+ attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ detached() {
+ super.detached(); _r.disable(notify: true);
+ children = const [];
+ }
+
+ VirtualCollectionElement _collection;
+
+ void render() {
+ if (children.length == 0) {
+ children = [_collection];
+ }
+ Iterable _toList(item) {
+ if (isExpanded(item)) {
+ Iterable children = _children(item);
+ if (children.isNotEmpty) {
+ return [item]..addAll(children.expand(_toList));
+ }
+ }
+ return [item];
+ }
+ _collection.items = _items.expand(_toList);
+ var depth = 0;
+ Iterable _toDepth(item) {
+ if (isExpanded(item)) {
+ Iterable children = _children(item);
+ if (children.isNotEmpty) {
+ depth++;
+ return children.expand(_toDepth).toList()
+ ..insert(0, --depth);
+ }
+ }
+ return [depth];
+ }
+ _depths = _items.expand(_toDepth).toList();
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/context_view.html b/runtime/observatory/lib/src/elements/context_view.html
index f9a2fbf..f75b548 100644
--- a/runtime/observatory/lib/src/elements/context_view.html
+++ b/runtime/observatory/lib/src/elements/context_view.html
@@ -1,7 +1,5 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="object_common.html">
<link rel="import" href="context_ref.html">
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 305706a..82f479d 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:html';
import 'observatory_element.dart';
+import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
import 'package:observatory/app.dart';
import 'package:observatory/cpu_profile.dart';
@@ -347,7 +348,7 @@
makeInfoBox();
functionRow.children.add(infoBox);
- if (node.profileFunction.function.kind.hasDartCode()) {
+ if (M.hasDartCode(node.profileFunction.function.kind)) {
infoBox.children.add(div('Code for current node'));
infoBox.children.add(br());
var totalTicks = node.totalCodesTicks;
@@ -393,7 +394,7 @@
'Call stack time' : node.profileFunction.formattedOnStackTime,
});
- if (node.profileFunction.function.kind.hasDartCode()) {
+ if (M.hasDartCode(node.profileFunction.function.kind)) {
infoBox.children.add(div('Code containing function'));
infoBox.children.add(br());
var totalTicks = profile.sampleCount;
@@ -647,7 +648,7 @@
FunctionCallTreeNode node)
: node = node,
super(tree, depth) {
- if ((node.profileFunction.function.kind == FunctionKind.kTag) &&
+ if ((node.profileFunction.function.kind == M.FunctionKind.tag) &&
(node.profileFunction.normalizedExclusiveTicks == 0) &&
(node.profileFunction.normalizedInclusiveTicks == 0)) {
selfPercent = '';
@@ -735,7 +736,7 @@
CodeCallTreeNode node)
: node = node,
super(tree, depth) {
- if ((node.profileCode.code.kind == CodeKind.Tag) &&
+ if ((node.profileCode.code.kind == M.CodeKind.tag) &&
(node.profileCode.normalizedExclusiveTicks == 0) &&
(node.profileCode.normalizedInclusiveTicks == 0)) {
selfPercent = '';
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index 05fc581..32363c7 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -1,6 +1,4 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="code_ref.html">
-<link rel="import" href="function_ref.html">
<polymer-element name="sample-buffer-control">
<template>
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index 1f32ad4..bd15c93 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -364,8 +364,101 @@
-webkit-animation: shake 0.5s;
}
+/* class-ref */
+/* TODO(cbernaschina) fix class-ref-wrapped to class-ref when wrapper
+removed */
+
+class-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+}
+class-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+}
+
+/* code-ref */
+/* TODO(cbernaschina) fix code-ref-wrapped to code-ref when wrapper
+removed */
+
+code-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+}
+code-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+}
+
+/* error-ref */
+/* TODO(cbernaschina) fix error-ref-wrapped to error-ref when wrapper
+removed */
+
+error-ref-wrapped > pre {
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ padding: 10px;
+ font-family: consolas, courier, monospace;
+ font-size: 1em;
+ line-height: 1.2em;
+ white-space: pre;
+}
+
+/* flag-list */
+
+flag-list .comment {
+ color: #aaa;
+}
+
+flag-list .flag {
+ padding: 3px 0;
+}
+
+flag-list .name {
+ font-weight: bold;
+ margin-right: 0.7em;
+}
+
+flag-list .value {
+ margin-left: 0.7em;
+}
+
+/* function-ref */
+/* TODO(cbernaschina) fix function-ref-wrapped to function-ref when wrapper
+removed */
+
+function-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+}
+function-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+}
+
+/* isolate-ref */
+/* TODO(cbernaschina) fix isolate-ref-wrapped to isolate-ref when wrapper
+removed */
+
+isolate-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+}
+isolate-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+}
+
+/* library-ref */
+/* TODO(cbernaschina) fix library-ref-wrapped to library-ref when wrapper
+removed */
+
+library-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+}
+library-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+}
+
/* nav-notify */
-/* TODO(cbernaschina) fix nav-notify-ref-wrapped to nav-notify-ref when wrapper
+/* TODO(cbernaschina) fix nav-notify-wrapped to nav-notify when wrapper
removed */
nav-notify-wrapped > div {
float: right;
@@ -460,6 +553,34 @@
margin: 0;
}
+/* script-ref */
+/* TODO(cbernaschina) fix script-ref-wrapped to script-ref when wrapper
+removed */
+
+script-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+}
+
+script-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+}
+
+/* source-link */
+/* TODO(cbernaschina) fix source-link-wrapped to source-link when wrapper
+removed */
+
+source-link-wrapped > a[href]:hover {
+ text-decoration: underline;
+}
+
+source-link-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+}
+
+
+
/* view-footer */
view-footer {
@@ -477,6 +598,34 @@
display: block;
}
+/* virtual-collection */
+
+virtual-collection {
+ display: block;
+ overflow-y: scroll;
+ width: 100%;
+ height: 100%;
+}
+
+virtual-collection .scroller {
+ position: relative;
+ overflow: hidden;
+ background: transparent;
+}
+
+virtual-collection .shifter {
+ background: transparent;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+
+virtual-collection .shifter > * {
+ position: relative;
+ top: -25%;
+}
+
/* vm-connect-target */
vm-connect-target > button.delete-button {
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 54fee31..42fb892 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="eval_link.html">
<link rel="import" href="script_inset.html">
-<link rel="import" href="script_ref.html">
<!-- TODO(turnidge): Use core-icon once core_elements work properly in
devtools -->
diff --git a/runtime/observatory/lib/src/elements/error_ref.dart b/runtime/observatory/lib/src/elements/error_ref.dart
index d69726b..b30dd90 100644
--- a/runtime/observatory/lib/src/elements/error_ref.dart
+++ b/runtime/observatory/lib/src/elements/error_ref.dart
@@ -1,13 +1,52 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// 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 error_ref_element;
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart'
+ show ErrorRef;
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
-@CustomTag('error-ref')
-class ErrorRefElement extends ServiceRefElement {
+class ErrorRefElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<ErrorRefElement>('error-ref-wrapped');
+
+ RenderingScheduler<ErrorRefElement> _r;
+
+ Stream<RenderedEvent<ErrorRefElement>> get onRendered => _r.onRendered;
+
+ ErrorRef _error;
+ ErrorRef get error => _error;
+
+ factory ErrorRefElement(ErrorRef error, {RenderingQueue queue}) {
+ assert(error != null);
+ ErrorRefElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler<ErrorRefElement>(e, queue: queue);
+ e._error = error;
+ return e;
+ }
+
ErrorRefElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ }
+
+ void render() {
+ children = [
+ new PreElement()..text = error.message
+ ];
+ }
}
diff --git a/runtime/observatory/lib/src/elements/error_ref.html b/runtime/observatory/lib/src/elements/error_ref.html
deleted file mode 100644
index a132039..0000000
--- a/runtime/observatory/lib/src/elements/error_ref.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="error-ref">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <style>
- .errorBox {
- background-color: #f5f5f5;
- border: 1px solid #ccc;
- padding: 10px;
- font-family: consolas, courier, monospace;
- font-size: 1em;
- line-height: 1.2em;
- white-space: pre;
- }
- </style>
- <span>
- <pre class="errorBox">{{ ref.message }}</pre>
- </span>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="error_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/error_ref_wrapper.dart b/runtime/observatory/lib/src/elements/error_ref_wrapper.dart
new file mode 100644
index 0000000..4efe939
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/error_ref_wrapper.dart
@@ -0,0 +1,78 @@
+// 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:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/mocks.dart' show ErrorRefMock;
+import 'package:observatory/service_html.dart' show ServiceMap, DartError;
+import 'package:observatory/src/elements/error_ref.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+class ErrorRefElementWrapper extends HtmlElement {
+
+ static const binder = const Binder<ErrorRefElementWrapper>(const {
+ 'ref': #ref
+ });
+
+ static const tag = const Tag<ErrorRefElementWrapper>('error-ref');
+
+ ServiceMap _error;
+ ServiceMap get ref => _error;
+ void set ref(ServiceMap ref) { _error = ref; render(); }
+
+ ErrorRefElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_error == null) return;
+
+ if (ref is Map) {
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ error-ref-wrapped > pre {
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ padding: 10px;
+ font-family: consolas, courier, monospace;
+ font-size: 1em;
+ line-height: 1.2em;
+ white-space: pre;
+ }
+ ''',
+ new ErrorRefElement(new ErrorRefMock(message: ref['message']))
+ ];
+ } else {
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ error-ref-wrapped > pre {
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ padding: 10px;
+ font-family: consolas, courier, monospace;
+ font-size: 1em;
+ line-height: 1.2em;
+ white-space: pre;
+ }
+ ''',
+ new ErrorRefElement(
+ new ErrorRefMock(message: (ref as DartError).message),
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/eval_box.html b/runtime/observatory/lib/src/elements/eval_box.html
index eb1e639..96a3f53 100644
--- a/runtime/observatory/lib/src/elements/eval_box.html
+++ b/runtime/observatory/lib/src/elements/eval_box.html
@@ -1,6 +1,5 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="error_ref.html">
<polymer-element name="eval-box">
diff --git a/runtime/observatory/lib/src/elements/eval_link.html b/runtime/observatory/lib/src/elements/eval_link.html
index 38d2981..a55b50b 100644
--- a/runtime/observatory/lib/src/elements/eval_link.html
+++ b/runtime/observatory/lib/src/elements/eval_link.html
@@ -1,6 +1,5 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="error_ref.html">
<polymer-element name="eval-link">
diff --git a/runtime/observatory/lib/src/elements/field_view.html b/runtime/observatory/lib/src/elements/field_view.html
index 4df7b24..8b78538 100644
--- a/runtime/observatory/lib/src/elements/field_view.html
+++ b/runtime/observatory/lib/src/elements/field_view.html
@@ -1,8 +1,5 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="library_ref.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="field-view">
<template>
diff --git a/runtime/observatory/lib/src/elements/flag_list.dart b/runtime/observatory/lib/src/elements/flag_list.dart
index f2d1cfc..19d7816 100644
--- a/runtime/observatory/lib/src/elements/flag_list.dart
+++ b/runtime/observatory/lib/src/elements/flag_list.dart
@@ -4,35 +4,148 @@
library flag_list_element;
+import 'dart:html';
import 'dart:async';
-import 'package:polymer/polymer.dart';
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/view_footer.dart';
-@CustomTag('flag-list')
-class FlagListElement extends ObservatoryElement {
- @published ServiceMap flagList;
+class FlagListElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<FlagListElement>('flag-list',
+ dependencies: const [NavBarElement.tag,
+ NavMenuElement.tag,
+ NavNotifyElement.tag,
+ NavRefreshElement.tag,
+ NavTopMenuElement.tag,
+ NavVMMenuElement.tag,
+ ViewFooterElement.tag,]);
- void flagListChanged(oldValue) {
- modifiedFlags =
- flagList['flags'].where((flag) => flag['modified']).toList();
- unmodifiedFlags =
- flagList['flags'].where((flag) => !flag['modified']).toList();
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<FlagListElement>> get onRendered => _r.onRendered;
+
+ M.VMRef _vm;
+ Stream<M.VMUpdateEvent> _vmUpdates;
+ M.FlagsRepository _repository;
+ M.NotificationRepository _notifications;
+ Iterable<M.Flag> _flags;
+
+ M.VMRef get vm => _vm;
+
+ factory FlagListElement(M.VMRef vm,
+ Stream<M.VMUpdateEvent> vmUpdates,
+ M.FlagsRepository repository,
+ M.NotificationRepository notifications,
+ {RenderingQueue queue}) {
+ assert(vm != null);
+ assert(vmUpdates != null);
+ assert(repository != null);
+ assert(notifications != null);
+ FlagListElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._vm = vm;
+ e._vmUpdates = vmUpdates;
+ e._repository = repository;
+ e._notifications = notifications;
+ return e;
}
- @observable List<ServiceMap> modifiedFlags = new List<ServiceMap>();
- @observable List<ServiceMap> unmodifiedFlags = new List<ServiceMap>();
-
FlagListElement.created() : super.created();
- Future refresh() {
- return flagList.reload();
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ _refresh();
}
-}
-@CustomTag('flag-item')
-class FlagItemElement extends ObservatoryElement {
- @published ObservableMap flag;
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ }
- FlagItemElement.created() : super.created();
+ void render() {
+ final content = <Element>[];
+ if (_flags == null) {
+ content.add(new HeadingElement.h1()..text = 'Loading Flags...');
+ } else {
+ final modified = _flags.where(_isModified);
+ final unmodified = _flags.where(_isUnmodified);
+
+ if (modified.isNotEmpty) {
+ content.add(new HeadingElement.h1()..text = 'Modified Flags');
+ content.add(new BRElement());
+ content.addAll(modified.expand(_renderFlag));
+ content.add(new HRElement());
+ }
+
+ content.add(new HeadingElement.h1()..text = 'Unmodified Flags');
+ content.add(new BRElement());
+
+ if (unmodified.isEmpty) {
+ content.add(new HeadingElement.h2()..text = 'None');
+ } else {
+ content.addAll(unmodified.expand(_renderFlag));
+ }
+ }
+
+ children = [
+ new NavBarElement(queue: _r.queue)
+ ..children = [
+ new NavTopMenuElement(queue: _r.queue),
+ new NavVMMenuElement(_vm, _vmUpdates, queue: _r.queue),
+ new NavMenuElement('flags', link: Uris.flags(), last: true,
+ queue: _r.queue),
+ new NavRefreshElement(queue: _r.queue)
+ ..onRefresh.listen((e) async {
+ e.element.disabled = true;
+ try {
+ await _refresh();
+ } finally {
+ e.element.disabled = false;
+ }
+ }),
+ new NavNotifyElement(_notifications, queue: _r.queue)
+ ],
+ new DivElement()
+ ..classes = ['content-centered']
+ ..children = content,
+ new ViewFooterElement(queue: _r.queue)
+ ];
+ }
+
+ Future _refresh() async {
+ _flags = await _repository.list(_vm);
+ _r.dirty();
+ }
+
+ static bool _isModified(M.Flag flag) => flag.modified;
+ static bool _isUnmodified(M.Flag flag) => !flag.modified;
+
+ static List<Element> _renderFlag(M.Flag flag) {
+ return [
+ new SpanElement()..classes = const ['comment']
+ ..text = '// ${flag.comment}',
+ new DivElement()..classes = flag.modified ? const ['flag', 'modified']
+ : const ['flag', 'unmodified']
+ ..children = [
+ new SpanElement()..classes = const ['name']
+ ..text = flag.name,
+ new SpanElement()..text = '=',
+ new SpanElement()..classes = const ['value']
+ ..text = flag.valueAsString ?? 'NULL'
+ ],
+ new BRElement(),
+ ];
+ }
}
diff --git a/runtime/observatory/lib/src/elements/flag_list.html b/runtime/observatory/lib/src/elements/flag_list.html
deleted file mode 100644
index 2c21db0..0000000
--- a/runtime/observatory/lib/src/elements/flag_list.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="flag-list">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <nav-bar>
- <top-nav-menu></top-nav-menu>
- <vm-nav-menu vm="{{ app.vm }}"></vm-nav-menu>
- <nav-menu link="{{ makeLink('/flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
- <nav-refresh callback="{{ refresh }}"></nav-refresh>
- <nav-notify notifications="{{ app.notifications }}"></nav-notify>
- </nav-bar>
-
- <div class="content-centered">
- <template if="{{ modifiedFlags.isNotEmpty }}">
- <h1>Modified Flags</h1>
- <br>
- <template repeat="{{ flag in modifiedFlags }}">
- <flag-item flag="{{ flag }}"></flag-item>
- <br>
- </template>
- <hr>
- </template>
-
- <h1>Unmodified Flags</h1>
- <br>
- <template if="{{ unmodifiedFlags.isEmpty }}">
- <em>None</em>
- </template>
- <template if="{{ unmodifiedFlags.isNotEmpty }}">
- <template repeat="{{ flag in unmodifiedFlags }}">
- <flag-item flag="{{ flag }}"></flag-item>
- <br>
- </template>
- </template>
- </div>
- <view-footer></view-footer>
- </template>
-</polymer-element>
-
-<polymer-element name="flag-item">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <span style="color:#aaa">// {{ flag['comment'] }}</span>
- <div style="padding: 3px 0">
- <b>{{ flag['name'] }}</b>
- =
- {{ flag['valueAsString'] }}
- </div>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="flag_list.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/function_ref.dart b/runtime/observatory/lib/src/elements/function_ref.dart
index d91a512..f6b2ec3 100644
--- a/runtime/observatory/lib/src/elements/function_ref.dart
+++ b/runtime/observatory/lib/src/elements/function_ref.dart
@@ -5,45 +5,82 @@
library function_ref_element;
import 'dart:html';
-import 'package:polymer/polymer.dart';
-import 'package:observatory/service.dart';
-import 'service_ref.dart';
+import 'dart:async';
+import 'package:observatory/models.dart' as M
+ show IsolateRef, FunctionRef, isSyntheticFunction, ClassRef, ObjectRef;
+import 'package:observatory/src/elements/class_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
-@CustomTag('function-ref')
-class FunctionRefElement extends ServiceRefElement {
- @published bool qualified = true;
+class FunctionRefElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<FunctionRefElement>('function-ref-wrapped');
+
+ RenderingScheduler<FunctionRefElement> _r;
+
+ Stream<RenderedEvent<FunctionRefElement>> get onRendered => _r.onRendered;
+
+ M.IsolateRef _isolate;
+ M.FunctionRef _function;
+ bool _qualified;
+
+ M.IsolateRef get isolate => _isolate;
+ M.FunctionRef get function => _function;
+ bool get qualified => _qualified;
+
+ factory FunctionRefElement(M.IsolateRef isolate, M.FunctionRef function,
+ {bool qualified: true, RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(function != null);
+ assert(qualified != null);
+ FunctionRefElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._function = function;
+ e._qualified = qualified;
+ return e;
+ }
FunctionRefElement.created() : super.created();
- refChanged(oldValue) {
- super.refChanged(oldValue);
- _updateShadowDom();
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
}
- ServiceFunction get function => ref;
- void _updateShadowDom() {
- clearShadowRoot();
- if (ref == null) {
- return;
- }
- if (!function.kind.isDart()) {
- insertTextSpanIntoShadowRoot(name);
- return;
- }
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ children = [];
+ }
+
+ void render() {
+ var content = <Element>[
+ new AnchorElement(href: M.isSyntheticFunction(function.kind) ? null
+ : Uris.inspect(_isolate, object: _function))
+ ..text = _function.name
+ ];
if (qualified) {
- if (function.dartOwner is ServiceFunction) {
- var functionRef = new Element.tag('function-ref');
- functionRef.ref = function.dartOwner;
- functionRef.qualified = true;
- shadowRoot.children.add(functionRef);
- insertTextSpanIntoShadowRoot('.');
- } else if (function.dartOwner is Class) {
- var classRef = new Element.tag('class-ref');
- classRef.ref = function.dartOwner;
- shadowRoot.children.add(classRef);
- insertTextSpanIntoShadowRoot('.');
+ M.ObjectRef owner = _function.dartOwner;
+ while (owner is M.FunctionRef) {
+ M.FunctionRef function = (owner as M.FunctionRef);
+ content.addAll([
+ new SpanElement()..text = '.',
+ new AnchorElement(href: M.isSyntheticFunction(function.kind) ? null
+ : Uris.inspect(_isolate, object: function))
+ ..text = function.name
+ ]);
+ owner = function.dartOwner;
+ }
+ if (owner is M.ClassRef) {
+ content.addAll([
+ new SpanElement()..text = '.',
+ new ClassRefElement(_isolate, owner, queue: _r.queue)
+ ]);
}
}
- insertLinkIntoShadowRoot(name, url, hoverText);
+ children = content.reversed.toList(growable: false);
}
}
diff --git a/runtime/observatory/lib/src/elements/function_ref.html b/runtime/observatory/lib/src/elements/function_ref.html
deleted file mode 100644
index 4669386..0000000
--- a/runtime/observatory/lib/src/elements/function_ref.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="function-ref">
- <template><link rel="stylesheet" href="css/shared.css"></template>
-</polymer-element>
-
-<script type="application/dart" src="function_ref.dart"></script>
\ No newline at end of file
diff --git a/runtime/observatory/lib/src/elements/function_ref_wrapper.dart b/runtime/observatory/lib/src/elements/function_ref_wrapper.dart
new file mode 100644
index 0000000..e41e43a
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/function_ref_wrapper.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service.dart' show ServiceFunction;
+import 'package:observatory/src/elements/function_ref.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+@bindable
+class FunctionRefElementWrapper extends HtmlElement {
+
+ static const binder = const Binder<FunctionRefElementWrapper>(const {
+ 'ref': #ref, 'qualified': #qualified
+ });
+
+ static const tag = const Tag<FunctionRefElementWrapper>('function-ref');
+
+ bool _qualified = true;
+ ServiceFunction _function;
+ bool get qualified => _qualified;
+ ServiceFunction get ref => _function;
+ void set qualified(bool qualified) { _qualified = qualified; render(); }
+ void set ref(ServiceFunction ref) { _function = ref; render(); }
+
+ FunctionRefElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (ref == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ class-ref-wrapped > a[href]:hover,
+ function-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+ }
+ class-ref-wrapped > a[href],
+ function-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+ }''',
+ new FunctionRefElement(_function.isolate, _function, qualified: qualified,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/function_view.html b/runtime/observatory/lib/src/elements/function_view.html
index 70accd2..a196455 100644
--- a/runtime/observatory/lib/src/elements/function_view.html
+++ b/runtime/observatory/lib/src/elements/function_view.html
@@ -1,10 +1,5 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
-<link rel="import" href="code_ref.html">
-<link rel="import" href="function_ref.html">
-<link rel="import" href="library_ref.html">
<link rel="import" href="script_inset.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="function-view">
<template>
diff --git a/runtime/observatory/lib/src/elements/general_error.dart b/runtime/observatory/lib/src/elements/general_error.dart
index d47ec04..943ba3c 100644
--- a/runtime/observatory/lib/src/elements/general_error.dart
+++ b/runtime/observatory/lib/src/elements/general_error.dart
@@ -1,16 +1,76 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// 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 general_error_element;
-import 'observatory_element.dart';
-import 'package:polymer/polymer.dart';
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
-/// Displays an error message
-@CustomTag('general-error')
-class GeneralErrorElement extends ObservatoryElement {
- @published String message;
+class GeneralErrorElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<GeneralErrorElement>('general-error',
+ dependencies: const [NavBarElement.tag,
+ NavTopMenuElement.tag,
+ NavNotifyElement.tag]);
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<GeneralErrorElement>> get onRendered => _r.onRendered;
+
+ M.NotificationRepository _notifications;
+ String _message;
+
+ String get message => _message;
+
+ set message(String value) => _message = _r.checkAndReact(_message, value);
+
+
+ factory GeneralErrorElement(M.NotificationRepository notifications,
+ {String message: '', RenderingQueue queue}) {
+ assert(notifications != null);
+ assert(message != null);
+ GeneralErrorElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._message = message;
+ e._notifications = notifications;
+ return e;
+ }
GeneralErrorElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ }
+
+ void render() {
+ children = [
+ new NavBarElement(queue: _r.queue)
+ ..children = [
+ new NavTopMenuElement(last: true, queue: _r.queue),
+ new NavNotifyElement(_notifications, queue: _r.queue)
+ ],
+ new DivElement()..classes = ['content-centered']
+ ..children = [
+ new HeadingElement.h1()..text = 'Error',
+ new BRElement(),
+ new DivElement()..classes = ['well']
+ ..text = message
+ ]
+ ];
+ }
}
diff --git a/runtime/observatory/lib/src/elements/general_error.html b/runtime/observatory/lib/src/elements/general_error.html
deleted file mode 100644
index ef809d1..0000000
--- a/runtime/observatory/lib/src/elements/general_error.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="general-error">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <nav-bar>
- <top-nav-menu last="{{ true }}"></top-nav-menu>
- <nav-notify notifications="{{ app.notifications }}"></nav-notify>
- </nav-bar>
- <div class="content-centered">
- <h1>Error</h1>
- <br>
- <div class="well">{{ message }}</div>
- </div>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="general_error.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/heap_map.html b/runtime/observatory/lib/src/elements/heap_map.html
index 82aad68..d68aed2 100644
--- a/runtime/observatory/lib/src/elements/heap_map.html
+++ b/runtime/observatory/lib/src/elements/heap_map.html
@@ -1,5 +1,4 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<polymer-element name="heap-map">
<template>
diff --git a/runtime/observatory/lib/src/elements/heap_profile.dart b/runtime/observatory/lib/src/elements/heap_profile.dart
index 9e5b142..3e0116e 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.dart
+++ b/runtime/observatory/lib/src/elements/heap_profile.dart
@@ -6,6 +6,7 @@
import 'dart:async';
import 'dart:html';
+import 'class_ref_wrapper.dart';
import 'observatory_element.dart';
import 'package:charted/charted.dart';
import 'package:observatory/app.dart';
@@ -252,7 +253,7 @@
var row = classTable.rows[rowIndex];
// Add class ref.
- ClassRefElement classRef = tr.children[0].children[0];
+ ClassRefElementWrapper classRef = tr.children[0].children[0];
classRef.ref = row.values[0];
for (var i = 1; i < row.values.length; i++) {
diff --git a/runtime/observatory/lib/src/elements/heap_profile.html b/runtime/observatory/lib/src/elements/heap_profile.html
index 47ac16b..ece5446 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.html
+++ b/runtime/observatory/lib/src/elements/heap_profile.html
@@ -1,5 +1,4 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<polymer-element name="heap-profile">
<template>
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.dart b/runtime/observatory/lib/src/elements/heap_snapshot.dart
index 4894e9f..fbfb9eb 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
@@ -6,6 +6,7 @@
import 'dart:async';
import 'dart:html';
+import 'class_ref_wrapper.dart';
import 'observatory_element.dart';
import 'package:observatory/app.dart';
import 'package:observatory/service.dart';
@@ -162,7 +163,7 @@
gap.style.display = 'inline-block';
firstColumn.children.add(gap);
- ClassRefElement classRef = new Element.tag("class-ref");
+ ClassRefElementWrapper classRef = new Element.tag("class-ref");
classRef.ref = isolate.getClassByCid(vertex.cid);
classRef.style.alignSelf = 'center';
firstColumn.children.add(classRef);
@@ -296,7 +297,7 @@
rootName.text = '<root>';
firstColumn.children.add(rootName);
} else {
- ClassRefElement classRef = new Element.tag("class-ref");
+ ClassRefElementWrapper classRef = new Element.tag("class-ref");
classRef.ref = isolate.getClassByCid(v.cid);
classRef.style.alignSelf = 'center';
firstColumn.children.add(classRef);
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.html b/runtime/observatory/lib/src/elements/heap_snapshot.html
index f7a8bf5..46e73d5 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.html
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.html
@@ -1,5 +1,4 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<polymer-element name="heap-snapshot">
<template>
diff --git a/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart b/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
index 562d04b..a2ab155 100644
--- a/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
+++ b/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
@@ -35,9 +35,13 @@
final T element;
/// Queue used for rendering operations.
final RenderingQueue queue;
+ /// Does the element need a new rendering cycle.
+ bool get isDirty => _dirty;
+ /// Is the scheduler enabled.
+ bool get isEnabled => _enabled;
final StreamController<RenderedEvent<T>> _onRendered =
- new StreamController<RenderedEvent<T>>.broadcast();
+ new StreamController<RenderedEvent<T>>.broadcast();
Stream<RenderedEvent<T>> get onRendered => _onRendered.stream;
/// Creates a new scheduler for an element.
diff --git a/runtime/observatory/lib/src/elements/helpers/uris.dart b/runtime/observatory/lib/src/elements/helpers/uris.dart
index 1c9660c..a099bbf 100644
--- a/runtime/observatory/lib/src/elements/helpers/uris.dart
+++ b/runtime/observatory/lib/src/elements/helpers/uris.dart
@@ -13,8 +13,12 @@
return '#' + new Uri(path: path, queryParameters: parameters).toString();
}
- static String inspect(M.IsolateRef isolate, {M.ObjectRef object})
- => _isolatePage('/inspect', isolate, object: object);
+ static String inspect(M.IsolateRef isolate, {M.ObjectRef object, int pos}) {
+ if (pos == null) {
+ return _isolatePage('/inspect', isolate, object: object);
+ }
+ return _isolatePage('/inspect', isolate, object: object) + '---pos=${pos}';
+ }
static String debugger(M.IsolateRef isolate)
=> _isolatePage('/debugger', isolate);
static String classTree(M.IsolateRef isolate)
@@ -39,4 +43,5 @@
=> _isolatePage('/logging', isolate);
static String vm() => '#/vm';
static String vmConnect() => '#/vm-connect';
+ static String flags() => '#/flags';
}
diff --git a/runtime/observatory/lib/src/elements/icdata_view.html b/runtime/observatory/lib/src/elements/icdata_view.html
index 9a5cf7b..f087b7e 100644
--- a/runtime/observatory/lib/src/elements/icdata_view.html
+++ b/runtime/observatory/lib/src/elements/icdata_view.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="error_view.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="object_common.html">
diff --git a/runtime/observatory/lib/src/elements/instance_view.html b/runtime/observatory/lib/src/elements/instance_view.html
index dd522e5..a28d0d6 100644
--- a/runtime/observatory/lib/src/elements/instance_view.html
+++ b/runtime/observatory/lib/src/elements/instance_view.html
@@ -1,10 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="error_view.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="eval_link.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="object_common.html">
diff --git a/runtime/observatory/lib/src/elements/instructions_view.html b/runtime/observatory/lib/src/elements/instructions_view.html
index 07c5343..4751c55 100644
--- a/runtime/observatory/lib/src/elements/instructions_view.html
+++ b/runtime/observatory/lib/src/elements/instructions_view.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="error_view.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="object_common.html">
diff --git a/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart b/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart
index 93978c5..369e68a 100644
--- a/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart
+++ b/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart
@@ -72,7 +72,14 @@
shadowRoot.children = [
new StyleElement()
- ..text = '@import "packages/observatory/src/elements/css/shared.css";',
+ ..text = '''
+ isolate-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+ }
+ isolate-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+ }''',
new IsolateRefElement(_isolate, _updates,
queue: ObservatoryApplication.app.queue)
];
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index 7b62b4d..1a0c0a1 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -1,8 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="action_link.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="script_inset.html">
-<link rel="import" href="script_ref.html">
+
<polymer-element name="isolate-summary">
<template>
<link rel="stylesheet" href="css/shared.css">
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index a414e3f..16d3150 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -1,11 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="action_link.html">
<link rel="import" href="eval_box.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="isolate_summary.html">
-<link rel="import" href="library_ref.html">
<link rel="import" href="script_inset.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="isolate-view">
<template>
diff --git a/runtime/observatory/lib/src/elements/library_ref.dart b/runtime/observatory/lib/src/elements/library_ref.dart
index 4f65a39..be8918b 100644
--- a/runtime/observatory/lib/src/elements/library_ref.dart
+++ b/runtime/observatory/lib/src/elements/library_ref.dart
@@ -4,33 +4,58 @@
library library_ref_element;
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
+import 'dart:html';
import 'dart:async';
+import 'package:observatory/models.dart' as M
+ show IsolateRef, LibraryRef;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
-@CustomTag('library-ref')
-class LibraryRefElement extends ServiceRefElement {
- @observable bool asValue = false;
+class LibraryRefElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<LibraryRefElement>('library-ref-wrapped');
+
+ RenderingScheduler<LibraryRefElement> _r;
+
+ Stream<RenderedEvent<LibraryRefElement>> get onRendered => _r.onRendered;
+
+ M.IsolateRef _isolate;
+ M.LibraryRef _library;
+
+ M.IsolateRef get isolate => _isolate;
+ M.LibraryRef get library => _library;
+
+ factory LibraryRefElement(M.IsolateRef isolate, M.LibraryRef library,
+ {RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(library != null);
+ LibraryRefElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._library = library;
+ return e;
+ }
LibraryRefElement.created() : super.created();
- String makeExpandKey(String key) {
- return '${expandKey}/${key}';
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
}
- dynamic expander() {
- return expandEvent;
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ children = [];
}
- void expandEvent(bool expand, Function onDone) {
- if (expand) {
- Library lib = ref;
- lib.reload().then((result) {
- return Future.wait(lib.variables.map((field) => field.reload()));
- }).whenComplete(onDone);
- } else {
- onDone();
- }
+ void render() {
+ final name = _library.name;
+ children = [
+ new AnchorElement(href: Uris.inspect(_isolate, object: _library))
+ ..text = (name == null || name.isEmpty) ? 'unnamed' : name
+ ];
}
}
diff --git a/runtime/observatory/lib/src/elements/library_ref.html b/runtime/observatory/lib/src/elements/library_ref.html
deleted file mode 100644
index 6e8c7a0..0000000
--- a/runtime/observatory/lib/src/elements/library_ref.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="library-ref">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <style>
- .indented {
- margin-left: 1.5em;
- font: 400 14px 'Montserrat', sans-serif;
- line-height: 150%;
- }
- </style>
- <template if="{{ nameIsEmpty }}">
- <a on-click="{{ goto }}" _href="{{ url }}">unnamed</a>
- </template>
- <template if="{{ !nameIsEmpty }}">
- <a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a>
- </template>
- <template if="{{ asValue }}">
- <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
- <div class="indented">
- <template repeat="{{ field in ref.variables }}">
- <template if="{{ field.isStatic }}">
- {{ field.name }} :
- <any-service-ref ref="{{ field.staticValue }}"
- expandKey="{{ makeExpandKey(field.name) }}">
- </any-service-ref><br>
- </template>
- </template>
- </div>
- </curly-block>
- </template>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="library_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/library_ref_as_value.dart b/runtime/observatory/lib/src/elements/library_ref_as_value.dart
new file mode 100644
index 0000000..6de3313
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/library_ref_as_value.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library library_ref_as_value_element;
+
+import 'package:observatory/service.dart';
+import 'package:polymer/polymer.dart';
+import 'service_ref.dart';
+import 'dart:async';
+
+@CustomTag('library-ref-as-value')
+class LibraryRefAsValueElement extends ServiceRefElement {
+ LibraryRefAsValueElement.created() : super.created();
+
+ String makeExpandKey(String key) {
+ return '${expandKey}/${key}';
+ }
+
+ dynamic expander() {
+ return expandEvent;
+ }
+
+ void expandEvent(bool expand, Function onDone) {
+ if (expand) {
+ Library lib = ref;
+ lib.reload().then((result) {
+ return Future.wait(lib.variables.map((field) => field.reload()));
+ }).whenComplete(onDone);
+ } else {
+ onDone();
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/library_ref_as_value.html b/runtime/observatory/lib/src/elements/library_ref_as_value.html
new file mode 100644
index 0000000..49dc900
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/library_ref_as_value.html
@@ -0,0 +1,30 @@
+<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="service_ref.html">
+
+<polymer-element name="library-ref-as-value">
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ .indented {
+ margin-left: 1.5em;
+ font: 400 14px 'Montserrat', sans-serif;
+ line-height: 150%;
+ }
+ </style>
+ <library-ref ref="{{ ref }}"></library-ref>
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
+ <div class="indented">
+ <template repeat="{{ field in ref.variables }}">
+ <template if="{{ field.isStatic }}">
+ {{ field.name }} :
+ <any-service-ref ref="{{ field.staticValue }}"
+ expandKey="{{ makeExpandKey(field.name) }}">
+ </any-service-ref><br>
+ </template>
+ </template>
+ </div>
+ </curly-block>
+ </template>
+</polymer-element>
+
+<script type="application/dart" src="library_ref_as_value.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/library_ref_wrapper.dart b/runtime/observatory/lib/src/elements/library_ref_wrapper.dart
new file mode 100644
index 0000000..0a2caf4
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/library_ref_wrapper.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service_html.dart' show Library;
+import 'package:observatory/src/elements/library_ref.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+@bindable
+class LibraryRefElementWrapper extends HtmlElement {
+
+ static const binder = const Binder<LibraryRefElementWrapper>(const {
+ 'ref': #ref
+ });
+
+ static const tag = const Tag<LibraryRefElementWrapper>('library-ref');
+
+ Library _library;
+ Library get ref => _library;
+ void set ref(Library ref) { _library = ref; render(); }
+
+ LibraryRefElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (ref == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ library-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+ }
+ library-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+ }''',
+ new LibraryRefElement(_library.isolate, _library,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/library_view.html b/runtime/observatory/lib/src/elements/library_view.html
index 97417fa..5368cbf 100644
--- a/runtime/observatory/lib/src/elements/library_view.html
+++ b/runtime/observatory/lib/src/elements/library_view.html
@@ -1,11 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="library_ref.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="library-view">
<template>
diff --git a/runtime/observatory/lib/src/elements/logging.html b/runtime/observatory/lib/src/elements/logging.html
index 0360c82bf..fc74304 100644
--- a/runtime/observatory/lib/src/elements/logging.html
+++ b/runtime/observatory/lib/src/elements/logging.html
@@ -1,6 +1,4 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="code_ref.html">
-<link rel="import" href="function_ref.html">
<polymer-element name="logging-page">
<template>
diff --git a/runtime/observatory/lib/src/elements/megamorphiccache_view.html b/runtime/observatory/lib/src/elements/megamorphiccache_view.html
index 720dc29..93f06af 100644
--- a/runtime/observatory/lib/src/elements/megamorphiccache_view.html
+++ b/runtime/observatory/lib/src/elements/megamorphiccache_view.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="error_view.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="object_common.html">
diff --git a/runtime/observatory/lib/src/elements/object_common.html b/runtime/observatory/lib/src/elements/object_common.html
index c0167ea..0235248 100644
--- a/runtime/observatory/lib/src/elements/object_common.html
+++ b/runtime/observatory/lib/src/elements/object_common.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="error_view.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="eval_link.html">
diff --git a/runtime/observatory/lib/src/elements/object_view.html b/runtime/observatory/lib/src/elements/object_view.html
index 99917f2..406f68e 100644
--- a/runtime/observatory/lib/src/elements/object_view.html
+++ b/runtime/observatory/lib/src/elements/object_view.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="error_view.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="object_common.html">
diff --git a/runtime/observatory/lib/src/elements/objectpool_view.html b/runtime/observatory/lib/src/elements/objectpool_view.html
index 1aff2dd..0899734 100644
--- a/runtime/observatory/lib/src/elements/objectpool_view.html
+++ b/runtime/observatory/lib/src/elements/objectpool_view.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="error_view.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="object_common.html">
diff --git a/runtime/observatory/lib/src/elements/objectstore_view.html b/runtime/observatory/lib/src/elements/objectstore_view.html
index 01f467b..bbf5efb 100644
--- a/runtime/observatory/lib/src/elements/objectstore_view.html
+++ b/runtime/observatory/lib/src/elements/objectstore_view.html
@@ -1,11 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="class_ref.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="library_ref.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="objectstore-view">
<template>
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index d4f2899..fbbef3a 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -9,6 +9,7 @@
import 'dart:math';
import 'observatory_element.dart';
import 'service_ref.dart';
+import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
import 'package:observatory/utils.dart';
import 'package:polymer/polymer.dart';
@@ -929,8 +930,8 @@
for (var func in script.library.functions) {
if ((func.location != null) &&
(func.location.script == script) &&
- (func.kind != FunctionKind.kImplicitGetterFunction) &&
- (func.kind != FunctionKind.kImplicitSetterFunction)) {
+ (func.kind != M.FunctionKind.implicitGetter) &&
+ (func.kind != M.FunctionKind.implicitSetter)) {
// We annotate a field declaration with the field instead of the
// implicit getter or setter.
var a = new FunctionDeclarationAnnotation(func, inspectLink(func));
@@ -941,8 +942,8 @@
for (var func in cls.functions) {
if ((func.location != null) &&
(func.location.script == script) &&
- (func.kind != FunctionKind.kImplicitGetterFunction) &&
- (func.kind != FunctionKind.kImplicitSetterFunction)) {
+ (func.kind != M.FunctionKind.implicitGetter) &&
+ (func.kind != M.FunctionKind.implicitSetter)) {
// We annotate a field declaration with the field instead of the
// implicit getter or setter.
var a = new FunctionDeclarationAnnotation(func, inspectLink(func));
diff --git a/runtime/observatory/lib/src/elements/script_ref.dart b/runtime/observatory/lib/src/elements/script_ref.dart
index c11f26d..8cc2f68 100644
--- a/runtime/observatory/lib/src/elements/script_ref.dart
+++ b/runtime/observatory/lib/src/elements/script_ref.dart
@@ -4,69 +4,59 @@
library script_ref_element;
-import 'package:polymer/polymer.dart';
-import 'package:observatory/service.dart';
-import 'service_ref.dart';
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M show IsolateRef, ScriptRef;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
-@CustomTag('script-ref')
-class ScriptRefElement extends ServiceRefElement {
- @published int pos;
+class ScriptRefElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<ScriptRefElement>('script-ref-wrapped');
- String get hoverText {
- if (ref == null) {
- return super.hoverText;
- }
- return ref.vmName;
- }
+ RenderingScheduler _r;
- void posChanged(oldValue) {
- _updateProperties(null);
- }
+ Stream<RenderedEvent<ScriptRefElement>> get onRendered => _r.onRendered;
- void _updateProperties(_) {
- if (ref != null && ref.loaded) {
- notifyPropertyChange(#name, 0, 1);
- notifyPropertyChange(#url, 0, 1);
- }
- }
- String get name {
- if (ref == null) {
- return super.name;
- }
- if ((pos != null) && (pos >= 0)) {
- if (ref.loaded) {
- // Script is loaded, get the line number.
- Script script = ref;
- return '${super.name}:${script.tokenToLine(pos)}:'
- '${script.tokenToCol(pos)}';
- } else {
- ref.load().then(_updateProperties);
- }
- }
- return super.name;
- }
+ M.IsolateRef _isolate;
+ M.ScriptRef _script;
- String get url {
- if (ref == null) {
- return super.url;
- }
- if ((pos != null) && (pos >= 0)) {
- if (ref.loaded) {
- return '${super.url}---pos=${pos}';
- } else {
- ref.load().then(_updateProperties);
- }
- }
- return super.url;
+ M.IsolateRef get isolate => _isolate;
+ M.ScriptRef get script => _script;
+
+ factory ScriptRefElement(M.IsolateRef isolate, M.ScriptRef script,
+ {RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(script != null);
+ ScriptRefElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._script = script;
+ return e;
}
ScriptRefElement.created() : super.created();
-}
-@CustomTag('source-link')
-class SourceLinkElement extends PolymerElement {
- SourceLinkElement.created() : super.created();
+ @override
+ void attached() {
+ super.attached();
+ assert(script != null);
+ _r.enable();
+ }
- @published SourceLocation location;
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ }
+
+ void render() {
+ children = [
+ new AnchorElement(href: Uris.inspect(isolate, object: script))
+ ..title = script.uri
+ ..text = script.uri.split('/').last
+ ];
+ }
}
diff --git a/runtime/observatory/lib/src/elements/script_ref.html b/runtime/observatory/lib/src/elements/script_ref.html
deleted file mode 100644
index 7a9f0f1..0000000
--- a/runtime/observatory/lib/src/elements/script_ref.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="script-ref">
-<template>
- <link rel="stylesheet" href="css/shared.css">
- <a on-click="{{ goto }}" title="{{ hoverText }}" _href="{{ url }}">{{ name }}</a>
-</template>
-</polymer-element>
-
-<polymer-element name="source-link">
-<template>
- <template if="{{ location != null }}">
- <script-ref ref="{{ location.script }}"
- pos="{{ location.tokenPos }}"></script-ref>
- </template>
-</template>
-</polymer-element>
-
-
-<script type="application/dart" src="script_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/script_ref_wrapper.dart b/runtime/observatory/lib/src/elements/script_ref_wrapper.dart
new file mode 100644
index 0000000..01f6940
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/script_ref_wrapper.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service_html.dart' show Script;
+import 'package:observatory/src/elements/script_ref.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+@bindable
+class ScriptRefElementWrapper extends HtmlElement {
+ static const binder = const Binder<ScriptRefElementWrapper>(const {
+ 'ref': #ref
+ });
+
+ static const tag = const Tag<ScriptRefElementWrapper>('script-ref');
+
+ Script _script;
+ Script get ref => _script;
+ set ref(Script script) { _script = script; render(); }
+
+ ScriptRefElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ Future render() async {
+ shadowRoot.children = [];
+ if (_script == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ script-ref-wrapped > a[href]:hover {
+ text-decoration: underline;
+ }
+ script-ref-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+ }''',
+ new ScriptRefElement(_script.isolate, _script,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index d368713..e0a28fe 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -7,11 +7,18 @@
import 'dart:html';
import 'package:logging/logging.dart';
+import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
import 'package:polymer/polymer.dart';
import 'class_ref.dart';
+import 'class_ref_as_value.dart';
+import 'code_ref.dart';
+import 'error_ref.dart';
+import 'function_ref.dart';
import 'library_ref.dart';
+import 'library_ref_as_value.dart';
+import 'script_ref.dart';
import 'observatory_element.dart';
class ServiceRefElement extends ObservatoryElement {
@@ -91,43 +98,49 @@
var type = ref.type;
switch (type) {
case 'Class':
- ClassRefElement element = new Element.tag('class-ref');
- element.ref = ref;
- element.asValue = asValue;
- return element;
+ if (asValue) {
+ ClassRefAsValueElement element =
+ new Element.tag('class-ref-as-element');
+ element.ref = ref;
+ return element;
+ }
+ return new ClassRefElement(ref.isolate,
+ ref as M.ClassRef,
+ queue: app.queue);
case 'Code':
- ServiceRefElement element = new Element.tag('code-ref');
- element.ref = ref;
- return element;
+ return new CodeRefElement(ref.isolate, ref as M.Code, queue: app.queue);
case 'Context':
ServiceRefElement element = new Element.tag('context-ref');
element.ref = ref;
return element;
case 'Error':
- ServiceRefElement element = new Element.tag('error-ref');
- element.ref = ref;
- return element;
+ return new ErrorRefElement(ref as M.ErrorRef, queue: app.queue);
case 'Field':
ServiceRefElement element = new Element.tag('field-ref');
element.ref = ref;
return element;
case 'Function':
- ServiceRefElement element = new Element.tag('function-ref');
- element.ref = ref;
- return element;
+ return new FunctionRefElement(ref.isolate,
+ ref as M.FunctionRef,
+ queue: app.queue);
case 'Library':
- LibraryRefElement element = new Element.tag('library-ref');
- element.ref = ref;
- element.asValue = asValue;
- return element;
+ if (asValue) {
+ LibraryRefAsValueElement element =
+ new Element.tag('library-ref-as-value');
+ element.ref = ref;
+ return element;
+ }
+ return new LibraryRefElement(ref.isolate,
+ ref as M.LibraryRef,
+ queue: app.queue);
case 'Object':
ServiceRefElement element = new Element.tag('object-ref');
element.ref = ref;
return element;
case 'Script':
- ServiceRefElement element = new Element.tag('script-ref');
- element.ref = ref;
- return element;
+ return new ScriptRefElement(ref.isolate,
+ ref as M.ScriptRef,
+ queue: app.queue);
case 'Instance':
case 'Sentinel':
ServiceRefElement element = new Element.tag('instance-ref');
diff --git a/runtime/observatory/lib/src/elements/service_view.dart b/runtime/observatory/lib/src/elements/service_view.dart
index c9924a6..0e3ed2d 100644
--- a/runtime/observatory/lib/src/elements/service_view.dart
+++ b/runtime/observatory/lib/src/elements/service_view.dart
@@ -46,10 +46,6 @@
FieldViewElement element = new Element.tag('field-view');
element.field = object;
return element;
- case 'FlagList':
- FlagListElement element = new Element.tag('flag-list');
- element.flagList = object;
- return element;
case 'Function':
FunctionViewElement element = new Element.tag('function-view');
element.function = object;
diff --git a/runtime/observatory/lib/src/elements/source_link.dart b/runtime/observatory/lib/src/elements/source_link.dart
new file mode 100644
index 0000000..02eec26
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/source_link.dart
@@ -0,0 +1,74 @@
+// 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 source_link_element;
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart'
+ show IsolateRef, SourceLocation, Script, ScriptRepository;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+
+class SourceLinkElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<SourceLinkElement>('source-link-wrapped');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<SourceLinkElement>> get onRendered => _r.onRendered;
+
+ IsolateRef _isolate;
+ SourceLocation _location;
+ Script _script;
+ ScriptRepository _repository;
+
+ IsolateRef get isolate => _isolate;
+ SourceLocation get location => _location;
+
+ factory SourceLinkElement(IsolateRef isolate, SourceLocation location,
+ ScriptRepository repository, {RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(location != null);
+ SourceLinkElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._location = location;
+ e._repository = repository;
+ return e;
+ }
+
+ SourceLinkElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ assert(location != null);
+ _r.enable();
+ _repository.get(_location.script.id).then((script) {
+ _script = script;
+ _r.dirty();
+ });
+ }
+
+ @override
+ void detached() { super.detached(); children = []; _r.disable(notify: true); }
+
+ Future render() async {
+ if (_script == null) {
+ children = [new SpanElement()..text = '<LOADING>'];
+ } else {
+ String label = _script.uri.split('/').last;
+ int token = _location.tokenPos;
+ int line = _script.tokenToLine(token);
+ int column = _script.tokenToCol(token);
+ children = [
+ new AnchorElement(
+ href: Uris.inspect(isolate, object: _script, pos: token))
+ ..title = _script.uri
+ ..text = '${label}:${line}:${column}'
+ ];
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/source_link_wrapper.dart b/runtime/observatory/lib/src/elements/source_link_wrapper.dart
new file mode 100644
index 0000000..d38d70f
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/source_link_wrapper.dart
@@ -0,0 +1,59 @@
+// 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:html';
+import 'dart:async';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/repositories.dart' show ScriptRepository;
+import 'package:observatory/service_html.dart' show SourceLocation;
+import 'package:observatory/src/elements/source_link.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+@bindable
+class SourceLinkElementWrapper extends HtmlElement {
+ static const binder = const Binder<SourceLinkElementWrapper>(const {
+ 'location' : #location
+ });
+
+ static const tag = const Tag<SourceLinkElementWrapper>('source-link');
+
+ SourceLocation _location;
+ SourceLocation get location => location;
+ set location(SourceLocation location) { _location = location; render(); }
+
+ SourceLinkElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ Future render() async {
+ shadowRoot.children = [];
+ if (_location == null) return;
+
+ ScriptRepository repository = new ScriptRepository(_location.isolate);
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ source-link-wrapped > a[href]:hover {
+ text-decoration: underline;
+ }
+ source-link-wrapped > a[href] {
+ color: #0489c3;
+ text-decoration: none;
+ }''',
+ new SourceLinkElement(_location.isolate, _location, repository,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/vm_connect.dart b/runtime/observatory/lib/src/elements/vm_connect.dart
index 8539921..65487cf 100644
--- a/runtime/observatory/lib/src/elements/vm_connect.dart
+++ b/runtime/observatory/lib/src/elements/vm_connect.dart
@@ -16,7 +16,7 @@
import 'package:observatory/src/elements/view_footer.dart';
import 'package:observatory/src/elements/vm_connect_target.dart';
-class VMConnectElement extends HtmlElement implements Renderable{
+class VMConnectElement extends HtmlElement implements Renderable {
static const tag = const Tag<VMConnectElement>('vm-connect',
dependencies: const [NavBarElement.tag,
NavTopMenuElement.tag,
@@ -67,6 +67,8 @@
}
void render() {
+ final host = window.location.hostname;
+ final port = window.location.port;
children = [
new NavBarElement(queue: _r.queue)
..children = [
@@ -125,7 +127,7 @@
new PreElement()
..classes = ['well']
..text = 'Request a crash dump with:\n'
- '\'curl localhost:8181/_getCrashDump > dump.json\'',
+ '\'curl $host:$port/_getCrashDump > dump.json\'',
new HRElement()
]
],
diff --git a/runtime/observatory/lib/src/elements/vm_connect_target.dart b/runtime/observatory/lib/src/elements/vm_connect_target.dart
index 3fa7d12..43a0cec 100644
--- a/runtime/observatory/lib/src/elements/vm_connect_target.dart
+++ b/runtime/observatory/lib/src/elements/vm_connect_target.dart
@@ -15,7 +15,7 @@
TargetEvent(this.target);
}
-class VMConnectTargetElement extends HtmlElement implements Renderable{
+class VMConnectTargetElement extends HtmlElement implements Renderable {
static const tag =
const Tag<VMConnectTargetElement>('vm-connect-target');
diff --git a/runtime/observatory/lib/src/elements/vm_view.html b/runtime/observatory/lib/src/elements/vm_view.html
index a078f04..a73d50b 100644
--- a/runtime/observatory/lib/src/elements/vm_view.html
+++ b/runtime/observatory/lib/src/elements/vm_view.html
@@ -1,9 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="eval_box.html">
-<link rel="import" href="function_ref.html">
<link rel="import" href="isolate_summary.html">
-<link rel="import" href="library_ref.html">
-<link rel="import" href="script_ref.html">
<polymer-element name="vm-view">
<template>
diff --git a/runtime/observatory/lib/src/mocks/objects/code.dart b/runtime/observatory/lib/src/mocks/objects/code.dart
new file mode 100644
index 0000000..d0529ae
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/code.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
+
+part of mocks;
+
+class CodeRefMock implements M.CodeRef {
+ final String id;
+ final String name;
+ final M.CodeKind kind;
+ final bool isOptimized;
+
+ const CodeRefMock({this.id, this.name, this.kind, this.isOptimized: false });
+}
+
+class CodeMock implements M.Code {
+ final String id;
+ final String name;
+ final M.CodeKind kind;
+ final bool isOptimized;
+
+ const CodeMock({this.id, this.name, this.kind, this.isOptimized: false });
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/flag.dart b/runtime/observatory/lib/src/mocks/objects/flag.dart
new file mode 100644
index 0000000..1b250ff
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/flag.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
+
+part of mocks;
+
+class FlagMock implements M.Flag {
+ final String name;
+ final String comment;
+ final bool modified;
+ final String valueAsString;
+
+ const FlagMock({this.name, this.comment, this.modified, this.valueAsString});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/function.dart b/runtime/observatory/lib/src/mocks/objects/function.dart
new file mode 100644
index 0000000..8a60adf
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/function.dart
@@ -0,0 +1,31 @@
+// 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
+
+part of mocks;
+
+class FunctionRefMock implements M.FunctionRef {
+ final String id;
+ final String name;
+ final M.ObjectRef dartOwner;
+ final bool isStatic;
+ final bool isConst;
+ final M.FunctionKind kind;
+
+ const FunctionRefMock({this.id, this.name, this.dartOwner,
+ this.isStatic : false, this.isConst : false, this.kind});
+}
+
+class FunctionMock implements M.Function {
+ final String id;
+ final String name;
+ final M.ObjectRef dartOwner;
+ final bool isStatic;
+ final bool isConst;
+ final M.FunctionKind kind;
+ final M.SourceLocation location;
+ final M.CodeRef code;
+ const FunctionMock({this.id, this.name, this.dartOwner,
+ this.isStatic : false, this.isConst : false, this.kind, this.location,
+ this.code});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/script.dart b/runtime/observatory/lib/src/mocks/objects/script.dart
index bb264dc..7ce801a 100644
--- a/runtime/observatory/lib/src/mocks/objects/script.dart
+++ b/runtime/observatory/lib/src/mocks/objects/script.dart
@@ -7,6 +7,7 @@
class ScriptRefMock implements M.ScriptRef {
final String id;
final String uri;
+
const ScriptRefMock({this.id, this.uri});
}
diff --git a/runtime/observatory/lib/src/mocks/objects/source_location.dart b/runtime/observatory/lib/src/mocks/objects/source_location.dart
index 481b44b..1c9c0f2 100644
--- a/runtime/observatory/lib/src/mocks/objects/source_location.dart
+++ b/runtime/observatory/lib/src/mocks/objects/source_location.dart
@@ -8,5 +8,6 @@
final M.ScriptRef script;
final int tokenPos;
final int endTokenPos;
+
const SourceLocationMock({this.script, this.tokenPos, this.endTokenPos});
}
diff --git a/runtime/observatory/lib/src/mocks/repositories/flag.dart b/runtime/observatory/lib/src/mocks/repositories/flag.dart
new file mode 100644
index 0000000..1c9c11d
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/repositories/flag.dart
@@ -0,0 +1,21 @@
+// 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
+
+part of mocks;
+
+typedef Future<Iterable<M.Flag>> FlagsRepositoryMockCallback(M.VMRef vm);
+
+class FlagsRepositoryMock implements M.FlagsRepository {
+ final FlagsRepositoryMockCallback _list;
+
+ Future<Iterable<M.Flag>> list(M.VMRef vm) {
+ if (_list != null) {
+ return _list(vm);
+ }
+ return new Future.value(const []);
+ }
+
+ FlagsRepositoryMock({FlagsRepositoryMockCallback list})
+ : _list = list;
+}
diff --git a/runtime/observatory/lib/src/mocks/repositories/script.dart b/runtime/observatory/lib/src/mocks/repositories/script.dart
new file mode 100644
index 0000000..7ab9114
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/repositories/script.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.
+
+part of mocks;
+
+class ScriptRepositoryMock implements M.ScriptRepository {
+ final Map<String, M.Script> scripts;
+
+ bool _invoked = false;
+ bool get invoked => _invoked;
+
+ ScriptRepositoryMock(this.scripts);
+
+ Future<M.Script> get(String id) async {
+ _invoked = true;
+ return scripts[id];
+ }
+}
diff --git a/runtime/observatory/lib/src/models/objects/class.dart b/runtime/observatory/lib/src/models/objects/class.dart
index a2a9007..b9e5f50 100644
--- a/runtime/observatory/lib/src/models/objects/class.dart
+++ b/runtime/observatory/lib/src/models/objects/class.dart
@@ -9,7 +9,7 @@
String get name;
}
-abstract class Class extends ObjectRef implements ClassRef {
+abstract class Class extends Object implements ClassRef {
/// The error which occurred during class finalization, if it exists.
/// [optional]
ErrorRef get error;
@@ -42,7 +42,7 @@
/// The mixin type for this class, if any.
///
/// The value will be of the kind: Type. [optional]
- Iterable<InstanceRef> get mixin;
+ InstanceRef get mixin;
/// A list of fields in this class. Does not include fields from
/// superclasses.
diff --git a/runtime/observatory/lib/src/models/objects/code.dart b/runtime/observatory/lib/src/models/objects/code.dart
new file mode 100644
index 0000000..1a8758e
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/code.dart
@@ -0,0 +1,39 @@
+// 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
+
+part of models;
+
+enum CodeKind {
+ dart,
+ native,
+ stub,
+ tag,
+ collected
+}
+
+bool isSyntheticCode(CodeKind kind) {
+ switch (kind) {
+ case CodeKind.collected:
+ case CodeKind.native:
+ case CodeKind.tag:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool isDartCode(CodeKind kind) => !isSyntheticCode(kind);
+
+abstract class CodeRef extends ObjectRef {
+ /// The name of this class.
+ String get name;
+
+ // What kind of code object is this?
+ CodeKind get kind;
+
+ bool get isOptimized;
+}
+
+abstract class Code extends Object implements CodeRef {
+}
diff --git a/runtime/observatory/lib/src/models/objects/flag.dart b/runtime/observatory/lib/src/models/objects/flag.dart
new file mode 100644
index 0000000..3813f88
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/flag.dart
@@ -0,0 +1,21 @@
+// 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
+
+part of models;
+
+abstract class Flag {
+ /// The name of the flag.
+ String get name;
+
+ /// A description of the flag.
+ String get comment;
+
+ /// Has this flag been modified from its default setting?
+ bool get modified;
+
+ /// The value of this flag as a string. [optional]
+ ///
+ /// If this property is absent, then the value of the flag was NULL.
+ String get valueAsString;
+}
diff --git a/runtime/observatory/lib/src/models/objects/function.dart b/runtime/observatory/lib/src/models/objects/function.dart
new file mode 100644
index 0000000..bb763af
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/function.dart
@@ -0,0 +1,69 @@
+// 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
+
+part of models;
+
+enum FunctionKind {
+ regular,
+ closure,
+ getter,
+ setter,
+ constructor,
+ implicitGetter,
+ implicitSetter,
+ implicitStaticFinalGetter,
+ irregexpFunction,
+ staticInitializer,
+ methodExtractor,
+ noSuchMethodDispatcher,
+ invokeFieldDispatcher,
+ collected,
+ native,
+ stub,
+ tag,
+ signatureFunction
+}
+
+bool isSyntheticFunction(FunctionKind kind) {
+ switch (kind) {
+ case FunctionKind.collected:
+ case FunctionKind.native:
+ case FunctionKind.stub:
+ case FunctionKind.tag:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool isDartFunction(FunctionKind kind) => !isSyntheticFunction(kind);
+bool isStubFunction(FunctionKind kind) => kind == FunctionKind.stub;
+bool hasDartCode(FunctionKind kind) =>
+ isDartFunction(kind) || isStubFunction(kind);
+
+abstract class FunctionRef extends ObjectRef {
+ /// The name of this class.
+ String get name;
+
+ /// The owner of this function, which can be a LibraryRef, ClassRef,
+ /// or a FunctionRef.
+ ObjectRef get dartOwner; // owner
+
+ /// Is this function static?
+ bool get isStatic;
+
+ /// Is this function const?
+ bool get isConst;
+
+ /// The kind of the function.
+ FunctionKind get kind;
+}
+
+abstract class Function extends Object implements FunctionRef {
+ /// The location of this function in the source code. [optional]
+ SourceLocation get location;
+
+ /// The compiled code associated with this function. [optional]
+ CodeRef get code;
+}
diff --git a/runtime/observatory/lib/src/models/repositories/flag.dart b/runtime/observatory/lib/src/models/repositories/flag.dart
new file mode 100644
index 0000000..2bdc018
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/flag.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
+
+part of models;
+
+abstract class FlagsRepository {
+ Future<Iterable<Flag>> list(VMRef vm);
+}
diff --git a/runtime/observatory/lib/src/models/repositories/script.dart b/runtime/observatory/lib/src/models/repositories/script.dart
new file mode 100644
index 0000000..e3b54ad
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/script.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.
+
+part of models;
+
+abstract class ScriptRepository extends Repository<Script, String> {}
diff --git a/runtime/observatory/lib/src/models/repository.dart b/runtime/observatory/lib/src/models/repository.dart
new file mode 100644
index 0000000..9aec1fd
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repository.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.
+
+part of models;
+
+abstract class Repository<ObjectT, DescriptorT> {
+ Future<ObjectT> get(DescriptorT id);
+}
diff --git a/runtime/observatory/lib/src/repositories/flag.dart b/runtime/observatory/lib/src/repositories/flag.dart
new file mode 100644
index 0000000..9a644e6
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/flag.dart
@@ -0,0 +1,34 @@
+// 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
+
+part of repositories;
+
+class Flag implements M.Flag {
+ final String name;
+ final String comment;
+ final bool modified;
+ final String valueAsString;
+ Flag(this.name, this.comment, this.modified, this.valueAsString) {
+ assert(name != null);
+ assert(comment != null);
+ assert(modified != null);
+ }
+}
+
+class FlagsRepository implements M.FlagsRepository {
+ Future<Iterable<Flag>> list(M.VM vm) async{
+ if (vm is S.VM) {
+ List<Map> flags = ((await vm.getFlagList()) as S.ServiceMap)['flags'];
+ return flags.map(_toFlag);
+ }
+ return const [];
+ }
+
+ static _toFlag(Map map){
+ return new Flag(map['name'],
+ map['comment'],
+ map['modified'],
+ map['valueAsString']);
+ }
+}
diff --git a/runtime/observatory/lib/src/repositories/script.dart b/runtime/observatory/lib/src/repositories/script.dart
new file mode 100644
index 0000000..918de35
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/script.dart
@@ -0,0 +1,15 @@
+// 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.
+
+part of repositories;
+
+class ScriptRepository implements M.ScriptRepository {
+ final S.Isolate isolate;
+
+ ScriptRepository(this.isolate);
+
+ Future<M.Script> get(String id) async {
+ return (await isolate.getObject(id)) as M.Script;
+ }
+}
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 85574fe..d2f44d9 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -426,7 +426,7 @@
/// A [SourceLocation] represents a location or range in the source code.
class SourceLocation extends ServiceObject implements Location,
- M.SourceLocation {
+ M.SourceLocation {
Script script;
int tokenPos;
int endTokenPos;
@@ -1799,12 +1799,6 @@
final ObservableMap _map = new ObservableMap();
static String objectIdRingPrefix = 'objects/';
- bool get canCache {
- return (_type == 'Class' ||
- _type == 'Function' ||
- _type == 'Field') &&
- !_id.startsWith(objectIdRingPrefix);
- }
bool get immutable => false;
ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner);
@@ -2047,7 +2041,6 @@
// TODO(turnidge): Add state to track if a breakpoint has been
// removed from the program. Remove from the cache when deleted.
- bool get canCache => true;
bool get immutable => false;
// A unique integer identifier for this breakpoint.
@@ -2146,7 +2139,6 @@
@reflectable final variables = new ObservableList<Field>();
@reflectable final functions = new ObservableList<ServiceFunction>();
- bool get canCache => true;
bool get immutable => false;
bool isDart(String libraryName) {
@@ -2270,7 +2262,6 @@
@observable Instance superType;
@observable Instance mixin;
- bool get canCache => true;
bool get immutable => false;
Class._empty(ServiceObjectOwner owner) : super._empty(owner);
@@ -2405,10 +2396,10 @@
@observable Instance key; // If a WeakProperty.
@observable Instance value; // If a WeakProperty.
@observable Breakpoint activationBreakpoint; // If a Closure.
- @observable Function oneByteFunction; // If a RegExp.
- @observable Function twoByteFunction; // If a RegExp.
- @observable Function externalOneByteFunction; // If a RegExp.
- @observable Function externalTwoByteFunction; // If a RegExp.
+ @observable ServiceFunction oneByteFunction; // If a RegExp.
+ @observable ServiceFunction twoByteFunction; // If a RegExp.
+ @observable ServiceFunction externalOneByteFunction; // If a RegExp.
+ @observable ServiceFunction externalTwoByteFunction; // If a RegExp.
@observable Instance oneByteBytecode; // If a RegExp.
@observable Instance twoByteBytecode; // If a RegExp.
@observable bool isCaseSensitive; // If a RegExp.
@@ -2498,10 +2489,11 @@
isCaseSensitive = map['isCaseSensitive'];
isMultiLine = map['isMultiLine'];
- oneByteFunction = map['_oneByteFunction'];
- twoByteFunction = map['_twoByteFunction'];
- externalOneByteFunction = map['_externalOneByteFunction'];
- externalTwoByteFunction = map['_externalTwoByteFunction'];
+ bool isCompiled = map['_oneByteFunction'] is ServiceFunction;
+ oneByteFunction = isCompiled ? map['_oneByteFunction'] : null;
+ twoByteFunction = isCompiled ? map['_twoByteFunction'] : null;
+ externalOneByteFunction = isCompiled ? map['_externalOneByteFunction'] : null;
+ externalTwoByteFunction = isCompiled ? map['_externalTwoByteFunction'] : null;
oneByteBytecode = map['_oneByteBytecode'];
twoByteBytecode = map['_twoByteBytecode'];
@@ -2604,65 +2596,35 @@
String toString() => 'Context($length)';
}
-
-// TODO(koda): Sync this with VM.
-class FunctionKind {
- final String _strValue;
- FunctionKind._internal(this._strValue);
- toString() => _strValue;
- bool isSynthetic() => [kCollected, kNative, kStub, kTag].contains(this);
- bool isDart() => !isSynthetic();
- bool isStub() => (this == kStub);
- bool hasDartCode() => isDart() || isStub();
- static FunctionKind fromJSON(String value) {
- switch(value) {
- case 'RegularFunction': return kRegularFunction;
- case 'ClosureFunction': return kClosureFunction;
- case 'GetterFunction': return kGetterFunction;
- case 'SetterFunction': return kSetterFunction;
- case 'Constructor': return kConstructor;
- case 'ImplicitGetter': return kImplicitGetterFunction;
- case 'ImplicitSetter': return kImplicitSetterFunction;
- case 'ImplicitStaticFinalGetter': return kImplicitStaticFinalGetter;
- case 'IrregexpFunction': return kIrregexpFunction;
- case 'StaticInitializer': return kStaticInitializer;
- case 'MethodExtractor': return kMethodExtractor;
- case 'NoSuchMethodDispatcher': return kNoSuchMethodDispatcher;
- case 'InvokeFieldDispatcher': return kInvokeFieldDispatcher;
- case 'Collected': return kCollected;
- case 'Native': return kNative;
- case 'Stub': return kStub;
- case 'Tag': return kTag;
- case 'SignatureFunction': return kSignatureFunction;
- }
- Logger.root.severe('Unrecognized function kind: $value');
- throw new FallThroughError();
+M.FunctionKind stringToFunctionKind(String value) {
+ switch(value) {
+ case 'RegularFunction': return M.FunctionKind.regular;
+ case 'ClosureFunction': return M.FunctionKind.closure;
+ case 'GetterFunction': return M.FunctionKind.getter;
+ case 'SetterFunction': return M.FunctionKind.setter;
+ case 'Constructor': return M.FunctionKind.constructor;
+ case 'ImplicitGetter': return M.FunctionKind.implicitGetter;
+ case 'ImplicitSetter': return M.FunctionKind.implicitSetter;
+ case 'ImplicitStaticFinalGetter':
+ return M.FunctionKind.implicitStaticFinalGetter;
+ case 'IrregexpFunction': return M.FunctionKind.irregexpFunction;
+ case 'StaticInitializer': return M.FunctionKind.staticInitializer;
+ case 'MethodExtractor': return M.FunctionKind.methodExtractor;
+ case 'NoSuchMethodDispatcher': return M.FunctionKind.noSuchMethodDispatcher;
+ case 'InvokeFieldDispatcher': return M.FunctionKind.invokeFieldDispatcher;
+ case 'Collected': return M.FunctionKind.collected;
+ case 'Native': return M.FunctionKind.native;
+ case 'Stub': return M.FunctionKind.stub;
+ case 'Tag': return M.FunctionKind.tag;
+ case 'SignatureFunction': return M.FunctionKind.signatureFunction;
}
-
- static FunctionKind kRegularFunction = new FunctionKind._internal('function');
- static FunctionKind kClosureFunction = new FunctionKind._internal('closure function');
- static FunctionKind kGetterFunction = new FunctionKind._internal('getter function');
- static FunctionKind kSetterFunction = new FunctionKind._internal('setter function');
- static FunctionKind kConstructor = new FunctionKind._internal('constructor');
- static FunctionKind kImplicitGetterFunction = new FunctionKind._internal('implicit getter function');
- static FunctionKind kImplicitSetterFunction = new FunctionKind._internal('implicit setter function');
- static FunctionKind kImplicitStaticFinalGetter = new FunctionKind._internal('implicit static final getter');
- static FunctionKind kIrregexpFunction = new FunctionKind._internal('ir regexp function');
- static FunctionKind kStaticInitializer = new FunctionKind._internal('static initializer');
- static FunctionKind kMethodExtractor = new FunctionKind._internal('method extractor');
- static FunctionKind kNoSuchMethodDispatcher = new FunctionKind._internal('noSuchMethod dispatcher');
- static FunctionKind kInvokeFieldDispatcher = new FunctionKind._internal('invoke field dispatcher');
- static FunctionKind kCollected = new FunctionKind._internal('Collected');
- static FunctionKind kNative = new FunctionKind._internal('Native');
- static FunctionKind kTag = new FunctionKind._internal('Tag');
- static FunctionKind kStub = new FunctionKind._internal('Stub');
- static FunctionKind kSignatureFunction = new FunctionKind._internal('SignatureFunction');
- static FunctionKind kUNKNOWN = new FunctionKind._internal('UNKNOWN');
+ Logger.root.severe('Unrecognized function kind: $value');
+ throw new FallThroughError();
}
-class ServiceFunction extends HeapObject {
+class ServiceFunction extends HeapObject implements M.Function {
// owner is a Library, Class, or ServiceFunction.
- @observable ServiceObject dartOwner;
+ @observable M.ObjectRef dartOwner;
@observable Library library;
@observable bool isStatic;
@observable bool isConst;
@@ -2674,7 +2636,7 @@
@observable bool hasIntrinsic;
@observable bool isRecognized;
@observable bool isNative;
- @observable FunctionKind kind;
+ @observable M.FunctionKind kind;
@observable int deoptimizations;
@observable String qualifiedName;
@observable int usageCounter;
@@ -2683,7 +2645,6 @@
@observable Instance icDataArray;
@observable Field field;
- bool get canCache => true;
bool get immutable => false;
ServiceFunction._empty(ServiceObject owner) : super._empty(owner);
@@ -2696,8 +2657,8 @@
vmName = (map.containsKey('_vmName') ? map['_vmName'] : name);
dartOwner = map['owner'];
- kind = FunctionKind.fromJSON(map['_kind']);
- isDart = kind.isDart();
+ kind = stringToFunctionKind(map['_kind']);
+ isDart = M.isDartFunction(kind);
if (dartOwner is ServiceFunction) {
ServiceFunction ownerFunction = dartOwner;
@@ -3304,7 +3265,6 @@
class PcDescriptors extends ServiceObject {
@observable Class clazz;
@observable int size;
- bool get canCache => false;
bool get immutable => true;
@reflectable final List<PcDescriptor> descriptors =
new ObservableList<PcDescriptor>();
@@ -3347,7 +3307,6 @@
class LocalVarDescriptors extends ServiceObject {
@observable Class clazz;
@observable int size;
- bool get canCache => false;
bool get immutable => true;
@reflectable final List<LocalVarDescriptor> descriptors =
new ObservableList<LocalVarDescriptor>();
@@ -3375,7 +3334,6 @@
}
class ObjectPool extends HeapObject {
- bool get canCache => false;
bool get immutable => false;
@observable int length;
@@ -3401,7 +3359,6 @@
@observable Instance argumentsDescriptor;
@observable Instance entries;
- bool get canCache => false;
bool get immutable => false;
ICData._empty(ServiceObjectOwner owner) : super._empty(owner);
@@ -3426,7 +3383,6 @@
@observable String selector;
@observable Instance argumentsDescriptor;
- bool get canCache => false;
bool get immutable => false;
MegamorphicCache._empty(ServiceObjectOwner owner) : super._empty(owner);
@@ -3447,7 +3403,6 @@
}
class Instructions extends HeapObject {
- bool get canCache => false;
bool get immutable => true;
@observable Code code;
@@ -3468,7 +3423,6 @@
}
class TokenStream extends HeapObject {
- bool get canCache => false;
bool get immutable => true;
@observable String privateKey;
@@ -3550,32 +3504,20 @@
}
}
-class CodeKind {
- final _value;
- const CodeKind._internal(this._value);
- String toString() => '$_value';
- bool isSynthetic() => [Collected, Native, Tag].contains(this);
- bool isDart() => !isSynthetic();
- static CodeKind fromString(String s) {
- if (s == 'Native') {
- return Native;
- } else if (s == 'Dart') {
- return Dart;
- } else if (s == 'Collected') {
- return Collected;
- } else if (s == 'Tag') {
- return Tag;
- } else if (s == 'Stub') {
- return Stub;
- }
- Logger.root.severe("Unrecognized code kind: '$s'");
- throw new FallThroughError();
+M.CodeKind stringToCodeKind(String s) {
+ if (s == 'Native') {
+ return M.CodeKind.native;
+ } else if (s == 'Dart') {
+ return M.CodeKind.dart;
+ } else if (s == 'Collected') {
+ return M.CodeKind.collected;
+ } else if (s == 'Tag') {
+ return M.CodeKind.tag;
+ } else if (s == 'Stub') {
+ return M.CodeKind.stub;
}
- static const Collected = const CodeKind._internal('Collected');
- static const Dart = const CodeKind._internal('Dart');
- static const Native = const CodeKind._internal('Native');
- static const Stub = const CodeKind._internal('Stub');
- static const Tag = const CodeKind._internal('Tag');
+ Logger.root.severe("Unrecognized code kind: '$s'");
+ throw new FallThroughError();
}
class CodeInlineInterval {
@@ -3586,8 +3528,8 @@
CodeInlineInterval(this.start, this.end);
}
-class Code extends HeapObject {
- @observable CodeKind kind;
+class Code extends HeapObject implements M.Code {
+ @observable M.CodeKind kind;
@observable ServiceObject objectPool;
@observable ServiceFunction function;
@observable Script script;
@@ -3624,7 +3566,7 @@
// Already done.
return;
}
- if (kind != CodeKind.Dart){
+ if (kind != M.CodeKind.dart){
return;
}
if (function == null) {
@@ -3663,7 +3605,7 @@
name = m['name'];
vmName = (m.containsKey('_vmName') ? m['_vmName'] : name);
isOptimized = m['_optimized'];
- kind = CodeKind.fromString(m['kind']);
+ kind = stringToCodeKind(m['kind']);
hasIntrinsic = m['_intrinsic'];
isNative = m['_native'];
if (mapIsRef) {
@@ -3683,7 +3625,7 @@
descriptors = descriptors['members'];
_processDescriptors(descriptors);
}
- hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart);
+ hasDisassembly = (instructions.length != 0) && (kind == M.CodeKind.dart);
inlinedFunctions.clear();
var inlinedFunctionsTable = m['_inlinedFunctions'];
var inlinedIntervals = m['_inlinedIntervals'];
@@ -3801,8 +3743,8 @@
return (address >= startAddress) && (address < endAddress);
}
- @reflectable bool get isDartCode => (kind == CodeKind.Dart) ||
- (kind == CodeKind.Stub);
+ @reflectable bool get isDartCode => (kind == M.CodeKind.dart) ||
+ (kind == M.CodeKind.stub);
String toString() => 'Code($kind, $name)';
}
@@ -3851,8 +3793,6 @@
class Socket extends ServiceObject {
Socket._empty(ServiceObjectOwner owner) : super._empty(owner);
- bool get canCache => true;
-
ServiceObject socketOwner;
@reflectable bool get isPipe => (kind == SocketKind.Pipe);
@@ -3920,7 +3860,6 @@
ServiceMetric._empty(ServiceObjectOwner owner) : super._empty(owner) {
}
- bool get canCache => true;
bool get immutable => false;
@observable bool recording = false;
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
index 43099f1..adf1c26 100644
--- a/runtime/observatory/observatory_sources.gypi
+++ b/runtime/observatory/observatory_sources.gypi
@@ -33,19 +33,23 @@
'lib/src/elements/action_link.dart',
'lib/src/elements/action_link.html',
'lib/src/elements/class_ref.dart',
- 'lib/src/elements/class_ref.html',
+ 'lib/src/elements/class_ref_wrapper.dart',
+ 'lib/src/elements/class_ref_as_value.dart',
+ 'lib/src/elements/class_ref_as_value.html',
'lib/src/elements/class_tree.dart',
'lib/src/elements/class_tree.html',
'lib/src/elements/class_view.dart',
'lib/src/elements/class_view.html',
'lib/src/elements/code_ref.dart',
- 'lib/src/elements/code_ref.html',
+ 'lib/src/elements/code_ref_wrapper.dart',
'lib/src/elements/code_view.dart',
'lib/src/elements/code_view.html',
'lib/src/elements/context_ref.dart',
'lib/src/elements/context_ref.html',
'lib/src/elements/context_view.dart',
'lib/src/elements/context_view.html',
+ 'lib/src/elements/containers/virtual_collection.dart',
+ 'lib/src/elements/containers/virtual_tree.dart',
'lib/src/elements/cpu_profile.dart',
'lib/src/elements/cpu_profile.html',
'lib/src/elements/css/shared.css',
@@ -54,7 +58,7 @@
'lib/src/elements/debugger.dart',
'lib/src/elements/debugger.html',
'lib/src/elements/error_ref.dart',
- 'lib/src/elements/error_ref.html',
+ 'lib/src/elements/error_ref_wrapper.dart',
'lib/src/elements/error_view.dart',
'lib/src/elements/error_view.html',
'lib/src/elements/eval_box.dart',
@@ -66,13 +70,11 @@
'lib/src/elements/field_view.dart',
'lib/src/elements/field_view.html',
'lib/src/elements/flag_list.dart',
- 'lib/src/elements/flag_list.html',
'lib/src/elements/function_ref.dart',
- 'lib/src/elements/function_ref.html',
+ 'lib/src/elements/function_ref_wrapper.dart',
'lib/src/elements/function_view.dart',
'lib/src/elements/function_view.html',
'lib/src/elements/general_error.dart',
- 'lib/src/elements/general_error.html',
'lib/src/elements/heap_map.dart',
'lib/src/elements/heap_map.html',
'lib/src/elements/heap_profile.dart',
@@ -109,7 +111,9 @@
'lib/src/elements/json_view.dart',
'lib/src/elements/json_view.html',
'lib/src/elements/library_ref.dart',
- 'lib/src/elements/library_ref.html',
+ 'lib/src/elements/library_ref_wrapper.dart',
+ 'lib/src/elements/library_ref_as_value.dart',
+ 'lib/src/elements/library_ref_as_value.html',
'lib/src/elements/library_view.dart',
'lib/src/elements/library_view.html',
'lib/src/elements/objectstore_view.dart',
@@ -156,14 +160,16 @@
'lib/src/elements/ports.html',
'lib/src/elements/script_inset.dart',
'lib/src/elements/script_inset.html',
+ 'lib/src/elements/script_ref_wrapper.dart',
'lib/src/elements/script_ref.dart',
- 'lib/src/elements/script_ref.html',
'lib/src/elements/script_view.dart',
'lib/src/elements/script_view.html',
'lib/src/elements/service_ref.dart',
'lib/src/elements/service_ref.html',
'lib/src/elements/service_view.dart',
'lib/src/elements/service_view.html',
+ 'lib/src/elements/source_link_wrapper.dart',
+ 'lib/src/elements/source_link.dart',
'lib/src/elements/shims/binding.dart',
'lib/src/elements/timeline_page.dart',
'lib/src/elements/timeline_page.html',
@@ -173,9 +179,12 @@
'lib/src/elements/vm_view.dart',
'lib/src/elements/vm_view.html',
'lib/src/mocks/exceptions/connection_exception.dart',
+ 'lib/src/mocks/objects/class.dart',
+ 'lib/src/mocks/objects/code.dart',
'lib/src/mocks/objects/error.dart',
'lib/src/mocks/objects/event.dart',
- 'lib/src/mocks/objects/class.dart',
+ 'lib/src/mocks/objects/flag.dart',
+ 'lib/src/mocks/objects/function.dart',
'lib/src/mocks/objects/isolate.dart',
'lib/src/mocks/objects/library.dart',
'lib/src/mocks/objects/notification.dart',
@@ -184,15 +193,20 @@
'lib/src/mocks/objects/target.dart',
'lib/src/mocks/objects/vm.dart',
'lib/src/mocks/repositories/crash_dump.dart',
+ 'lib/src/mocks/repositories/flag.dart',
+ 'lib/src/mocks/repositories/script.dart',
'lib/src/mocks/repositories/notification.dart',
'lib/src/mocks/repositories/target.dart',
'lib/src/models/exceptions.dart',
'lib/src/models/objects/breakpoint.dart',
'lib/src/models/objects/class.dart',
+ 'lib/src/models/objects/code.dart',
'lib/src/models/objects/error.dart',
'lib/src/models/objects/event.dart',
'lib/src/models/objects/extension_data.dart',
+ 'lib/src/models/objects/flag.dart',
'lib/src/models/objects/frame.dart',
+ 'lib/src/models/objects/function.dart',
'lib/src/models/objects/instance.dart',
'lib/src/models/objects/isolate.dart',
'lib/src/models/objects/library.dart',
@@ -204,9 +218,14 @@
'lib/src/models/objects/timeline_event.dart',
'lib/src/models/objects/vm.dart',
'lib/src/models/repositories/crash_dump.dart',
+ 'lib/src/models/repositories/flag.dart',
'lib/src/models/repositories/notification.dart',
+ 'lib/src/models/repositories/script.dart',
'lib/src/models/repositories/target.dart',
+ 'lib/src/models/repository.dart',
+ 'lib/src/repositories/flag.dart',
'lib/src/repositories/notification.dart',
+ 'lib/src/repositories/script.dart',
'lib/src/repositories/settings.dart',
'lib/src/repositories/target.dart',
'lib/src/service/object.dart',
diff --git a/runtime/observatory/tests/observatory_ui/class_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/class_ref/element_test.dart
new file mode 100644
index 0000000..ef812fd
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/class_ref/element_test.dart
@@ -0,0 +1,29 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/class_ref.dart';
+
+main(){
+ ClassRefElement.tag.ensureRegistration();
+
+ final IsolateRefMock isolate = new IsolateRefMock(id: 'i-id', name: 'i-name');
+ final ClassRefMock cls = new ClassRefMock(id: 'c-id', name: 'c-name');
+ test('instantiation', () {
+ final ClassRefElement e = new ClassRefElement(isolate, cls);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(isolate));
+ expect(e.cls, equals(cls));
+ });
+ test('elements created after attachment', () async {
+ final ClassRefElement e = new ClassRefElement(isolate, cls);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/class_ref/element_test.html b/runtime/observatory/tests/observatory_ui/class_ref/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/class_ref/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/code_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/code_ref/element_test.dart
new file mode 100644
index 0000000..0e2c9ee
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/code_ref/element_test.dart
@@ -0,0 +1,29 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/code_ref.dart';
+
+main(){
+ CodeRefElement.tag.ensureRegistration();
+
+ final IsolateRefMock isolate = new IsolateRefMock(id: 'i-id', name: 'i-name');
+ final CodeRefMock code = new CodeRefMock(id: 'c-id', name: 'c-name');
+ test('instantiation', () {
+ final CodeRefElement e = new CodeRefElement(isolate, code);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(isolate));
+ expect(e.code, equals(code));
+ });
+ test('elements created after attachment', () async {
+ final CodeRefElement e = new CodeRefElement(isolate, code);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/code_ref/element_test.html b/runtime/observatory/tests/observatory_ui/code_ref/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/code_ref/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/error_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/error_ref/element_test.dart
new file mode 100644
index 0000000..0495656
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/error_ref/element_test.dart
@@ -0,0 +1,31 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/models.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/error_ref.dart';
+
+main() {
+ ErrorRefElement.tag.ensureRegistration();
+
+ final ErrorRef ref = new ErrorRefMock(id: 'id', message: 'fixed-error-m');
+ test('instantiation', () {
+ final ErrorRefElement e = new ErrorRefElement(ref);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.error, equals(ref));
+ });
+ test('elements created after attachment', () async {
+ final ErrorRefElement e = new ErrorRefElement(ref);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.innerHtml.contains(ref.message), isTrue,
+ reason: 'no message in the component');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero,
+ reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/error_ref/element_test.html b/runtime/observatory/tests/observatory_ui/error_ref/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/error_ref/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/flag_list/element_test.dart b/runtime/observatory/tests/observatory_ui/flag_list/element_test.dart
new file mode 100644
index 0000000..e88dea6
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/flag_list/element_test.dart
@@ -0,0 +1,60 @@
+// 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:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/flag_list.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+
+main() {
+ FlagListElement.tag.ensureRegistration();
+
+ final nTag = NavNotifyElement.tag.name;
+ const vm = const VMMock(name: 'vm');
+ final stream = new StreamController().stream;
+
+ group('instantiation', () {
+ test('default', () {
+ final FlagListElement e = new FlagListElement(vm, stream,
+ new FlagsRepositoryMock(),
+ new NotificationRepositoryMock());
+ expect(e, isNotNull, reason: 'element correctly created');
+ });
+ });
+ group('elements', () {
+ test('created after attachment', () async {
+ const modified = const [
+ const FlagMock(name: 'f1', comment: 'c1', modified: true),
+ ];
+ const unmodifed = const [
+ const FlagMock(name: 'f2', comment: 'c2', modified: false),
+ const FlagMock(name: 'f3', comment: 'c3', modified: false),
+ ];
+ final flags = new List.unmodifiable([]..addAll(modified)
+ ..addAll(unmodifed));
+ final FlagListElement e = new FlagListElement(vm, stream,
+ new FlagsRepositoryMock(list: expectAsync((input) async {
+ expect(input, equals(vm));
+ return flags;
+ }, count: 1)), new NotificationRepositoryMock());
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.querySelectorAll(nTag).length, equals(1));
+ expect(e.querySelectorAll('.flag').length, equals(flags.length));
+ expect(e.querySelectorAll('.flag.modified').length,
+ equals(modified.length));
+ expect(e.querySelectorAll('.flag.unmodified').length,
+ equals(unmodifed.length));
+ expect(e.querySelectorAll('.flag').length, equals(flags.length));
+ expect(e.querySelectorAll('.comment').length, equals(flags.length));
+ expect(e.querySelectorAll('.name').length, equals(flags.length));
+ expect(e.querySelectorAll('.value').length, equals(flags.length));
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/flag_list/element_test.html b/runtime/observatory/tests/observatory_ui/flag_list/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/flag_list/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/function_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/function_ref/element_test.dart
new file mode 100644
index 0000000..a647d3d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/function_ref/element_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.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/function_ref.dart';
+
+main(){
+ FunctionRefElement.tag.ensureRegistration();
+
+ final IsolateRefMock isolate = new IsolateRefMock(id: 'i-id', name: 'i-name');
+ final FunctionRefMock function = new FunctionRefMock(id: 'f-id',
+ name: 'f-name');
+ test('instantiation', () {
+ final FunctionRefElement e = new FunctionRefElement(isolate, function);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(isolate));
+ expect(e.function, equals(function));
+ });
+ test('elements created after attachment', () async {
+ final FunctionRefElement e = new FunctionRefElement(isolate, function);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/function_ref/element_test.html b/runtime/observatory/tests/observatory_ui/function_ref/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/function_ref/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/general_error/element_test.dart b/runtime/observatory/tests/observatory_ui/general_error/element_test.dart
new file mode 100644
index 0000000..31a9031
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/general_error/element_test.dart
@@ -0,0 +1,61 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/general_error.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+
+main() {
+ GeneralErrorElement.tag.ensureRegistration();
+
+ final nTag = NavNotifyElement.tag.name;
+ final notifications = new NotificationRepositoryMock();
+ final String message = 'content-of-the-message';
+
+ group('instantiation', () {
+ test('default', () {
+ final GeneralErrorElement e = new GeneralErrorElement(notifications);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.message, isNotNull, reason: 'message should not be null');
+ expect(e.message, equals(''), reason: 'message should be empty');
+ });
+ test('message', () {
+ final GeneralErrorElement e = new GeneralErrorElement(notifications,
+ message: message);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.message, isNotNull, reason: 'message should not be null');
+ expect(e.message, equals(message), reason: 'message should be the same');
+ });
+ });
+ group('elements', () {
+ test('created after attachment', () async {
+ final GeneralErrorElement e = new GeneralErrorElement(notifications);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.querySelectorAll(nTag).length, equals(1));
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ test('react to message change', () async {
+ final GeneralErrorElement e = new GeneralErrorElement(notifications);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(message), isFalse,
+ reason: 'should not contain');
+ e.message = message;
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(message), isTrue,
+ reason: 'should contain');
+ e.message = '';
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(message), isFalse,
+ reason: 'should not contain');
+ e.remove();
+ await e.onRendered.first;
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/general_error/element_test.html b/runtime/observatory/tests/observatory_ui/general_error/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/general_error/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.dart
new file mode 100644
index 0000000..c7d64a4
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.dart
@@ -0,0 +1,69 @@
+// 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:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/models.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/isolate_ref.dart';
+
+main(){
+ IsolateRefElement.tag.ensureRegistration();
+
+ StreamController<IsolateUpdateEvent> updatesController;
+ final IsolateRefMock ref = new IsolateRefMock(id: 'id', name: 'old-name');
+ final IsolateMock obj = new IsolateMock(id: 'id', name: 'new-name');
+ setUp(() {
+ updatesController = new StreamController<IsolateUpdateEvent>();
+ });
+ group('instantiation', () {
+ test('IsolateRef', () {
+ final IsolateRefElement e = new IsolateRefElement(ref,
+ updatesController.stream);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(ref));
+ });
+ test('Isolate', () {
+ final IsolateRefElement e = new IsolateRefElement(obj,
+ updatesController.stream);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(obj));
+ });
+ });
+ test('elements created after attachment', () async {
+ final IsolateRefElement e = new IsolateRefElement(ref,
+ updatesController.stream);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ group('updates', () {
+ test('are correctly listen', () async {
+ final IsolateRefElement e = new IsolateRefElement(ref,
+ updatesController.stream);
+ expect(updatesController.hasListener, isFalse);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(updatesController.hasListener, isTrue);
+ e.remove();
+ await e.onRendered.first;
+ expect(updatesController.hasListener, isFalse);
+ });
+ test('have effects', () async {
+ final IsolateRefElement e = new IsolateRefElement(ref,
+ updatesController.stream);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(ref.id), isTrue);
+ updatesController.add(new IsolateUpdateEventMock(isolate: obj));
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(ref.name), isFalse);
+ expect(e.innerHtml.contains(obj.name), isTrue);
+ e.remove();
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.html b/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/library_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/library_ref/element_test.dart
new file mode 100644
index 0000000..cb33f6b
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/library_ref/element_test.dart
@@ -0,0 +1,29 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/library_ref.dart';
+
+main(){
+ LibraryRefElement.tag.ensureRegistration();
+
+ final IsolateRefMock isolate = new IsolateRefMock(id: 'i-id', name: 'i-name');
+ final LibraryRefMock library = new LibraryRefMock(id: 'c-id', name: 'c-name');
+ test('instantiation', () {
+ final LibraryRefElement e = new LibraryRefElement(isolate, library);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(isolate));
+ expect(e.library, equals(library));
+ });
+ test('elements created after attachment', () async {
+ final LibraryRefElement e = new LibraryRefElement(isolate, library);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/library_ref/element_test.html b/runtime/observatory/tests/observatory_ui/library_ref/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/library_ref/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/script_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/script_ref/element_test.dart
new file mode 100644
index 0000000..eda7d49
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/script_ref/element_test.dart
@@ -0,0 +1,38 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/script_ref.dart';
+
+main() {
+ ScriptRefElement.tag.ensureRegistration();
+
+ final M.IsolateRef isolate = const IsolateRefMock(id: 'isolate-id');
+ final M.ScriptRef ref = const ScriptRefMock(id: 'script-id',
+ uri: 'package/filename.dart');
+ group('instantiation', () {
+ test('no position', () {
+ final ScriptRefElement e = new ScriptRefElement(isolate, ref);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(isolate));
+ expect(e.script, equals(ref));
+ });
+ });
+ test('elements created after attachment', () async {
+ final ScriptRefElement e = new ScriptRefElement(isolate, ref);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.innerHtml.contains(isolate.id), isTrue,
+ reason: 'no message in the component');
+ expect(e.innerHtml.contains('filename.dart'), isTrue,
+ reason: 'no message in the component');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero,
+ reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/script_ref/element_test.html b/runtime/observatory/tests/observatory_ui/script_ref/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/script_ref/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/source_link/element_test.dart b/runtime/observatory/tests/observatory_ui/source_link/element_test.dart
new file mode 100644
index 0000000..2d4cfba
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/source_link/element_test.dart
@@ -0,0 +1,46 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/source_link.dart';
+
+main() {
+ SourceLinkElement.tag.ensureRegistration();
+
+ final M.IsolateRef isolate = const IsolateRefMock(id: 'isolate-id');
+ final M.Script script = new ScriptMock(id: 'script-id',
+ uri: 'package/filename.dart',
+ tokenToLine: (int token) => 1,
+ tokenToCol: (int token) => 2);
+ final M.SourceLocation location = new SourceLocationMock(script: script,
+ tokenPos: 0, endTokenPos: 1);
+ M.ScriptRepository repository;
+ setUp(() {
+ repository = new ScriptRepositoryMock({ 'script-id': script });
+ });
+ test('instantiation', () {
+ final SourceLinkElement e = new SourceLinkElement(isolate, location,
+ repository);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(isolate));
+ expect(e.location, equals(location));
+ });
+ test('elements created after attachment', () async {
+ final SourceLinkElement e = new SourceLinkElement(isolate, location,
+ repository);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.innerHtml.contains(isolate.id), isTrue,
+ reason: 'no message in the component');
+ expect(e.innerHtml.contains('filename.dart'), isTrue,
+ reason: 'no message in the component');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero,
+ reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/source_link/element_test.html b/runtime/observatory/tests/observatory_ui/source_link/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/source_link/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/service/dev_fs_weird_char_test.dart b/runtime/observatory/tests/service/dev_fs_weird_char_test.dart
new file mode 100644
index 0000000..9ee2412
--- /dev/null
+++ b/runtime/observatory/tests/service/dev_fs_weird_char_test.dart
@@ -0,0 +1,57 @@
+// 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.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'dart:convert';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+var tests = [
+ // Write a file with the ? character in the filename.
+ (VM vm) async {
+ var fsId = 'test';
+ var filePath = '/foo/bar?dat';
+ var fileContents = BASE64.encode(UTF8.encode('fileContents'));
+
+ var result;
+ // Create DevFS.
+ result = await vm.invokeRpcNoUpgrade('_createDevFS', { 'fsName': fsId });
+ expect(result['type'], equals('FileSystem'));
+ expect(result['name'], equals(fsId));
+ expect(result['uri'], new isInstanceOf<String>());
+
+ // Write the file.
+ result = await vm.invokeRpcNoUpgrade('_writeDevFSFile', {
+ 'fsName': fsId,
+ 'path': filePath,
+ 'fileContents': fileContents
+ });
+ expect(result['type'], equals('Success'));
+
+ // Read the file back.
+ result = await vm.invokeRpcNoUpgrade('_readDevFSFile', {
+ 'fsName': fsId,
+ 'path': filePath,
+ });
+ expect(result['type'], equals('FSFile'));
+ expect(result['fileContents'], equals(fileContents));
+
+ // List all the files in the file system.
+ result = await vm.invokeRpcNoUpgrade('_listDevFSFiles', {
+ 'fsName': fsId,
+ });
+ expect(result['type'], equals('FSFileList'));
+ expect(result['files'].length, equals(1));
+ expect(result['files'][0]['name'], equals('/foo/bar?dat'));
+
+ // Delete DevFS.
+ result = await vm.invokeRpcNoUpgrade('_deleteDevFS', {
+ 'fsName': fsId,
+ });
+ expect(result['type'], equals('Success'));
+ },
+];
+
+main(args) async => runVMTests(args, tests);
diff --git a/runtime/observatory/tests/service/regexp_function_test.dart b/runtime/observatory/tests/service/regexp_function_test.dart
new file mode 100644
index 0000000..4736266
--- /dev/null
+++ b/runtime/observatory/tests/service/regexp_function_test.dart
@@ -0,0 +1,60 @@
+// 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.
+// VMOptions=
+// VMOptions=--interpret_irregexp
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+var regex0;
+var regex;
+
+void script() {
+ // Check the internal NUL doesn't trip up the name scrubbing in the vm.
+ regex0 = new RegExp("with internal \u{0} NUL");
+ regex = new RegExp(r"(\w+)");
+ String str = "Parse my string";
+ Iterable<Match> matches = regex.allMatches(str); // Run to generate bytecode.
+ expect(matches.length, equals(3));
+}
+
+var tests = [
+
+(Isolate isolate) async {
+ Library lib = isolate.rootLibrary;
+ await lib.load();
+
+ Field field0 = lib.variables.singleWhere((v) => v.name == 'regex0');
+ await field0.load(); // No crash due to embedded NUL.
+
+ Field field = lib.variables.singleWhere((v) => v.name == 'regex');
+ await field.load();
+ Instance regex = field.staticValue;
+ expect(regex.isInstance, isTrue);
+ expect(regex.isRegExp, isTrue);
+ await regex.load();
+
+ if (regex.oneByteFunction == null) {
+ // Running with interpreted regexp.
+ var b1 = await regex.oneByteBytecode.load();
+ expect(b1.isTypedData, isTrue);
+ var b2 = await regex.twoByteBytecode.load();
+ expect(b2.isTypedData, isFalse); // No two-byte string subject was used.
+ } else {
+ // Running with compiled regexp.
+ var f1 = await regex.oneByteFunction.load();
+ expect(f1 is ServiceFunction, isTrue);
+ var f2 = await regex.twoByteFunction.load();
+ expect(f2 is ServiceFunction, isTrue);
+ var f3 = await regex.externalOneByteFunction.load();
+ expect(f3 is ServiceFunction, isTrue);
+ var f4 = await regex.externalTwoByteFunction.load();
+ expect(f4 is ServiceFunction, isTrue);
+ }
+}
+
+];
+
+main(args) => runIsolateTests(args, tests, testeeBefore: script);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 0e627a0..8e9cc6c 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -55,6 +55,9 @@
get_cpu_profile_timeline_rpc_test: RuntimeError # Profiling unimplemented.
implicit_getter_setter_test: RuntimeError # Field guards unimplemented.
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
# Skip all service tests because random reloads interfere.
*: SkipByDesign # The service tests should run without being reloaded.
+
+[ $system == windows ]
+dev_fs_weird_char_test: Skip # Windows disallows question mark in paths
\ No newline at end of file
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 15b1de4..4828557 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -333,6 +333,7 @@
var pid = process.process.pid;
var wait = new Duration(seconds: 10);
print("Testee has pid $pid, waiting $wait before continuing");
+ sleep(wait);
}
serviceWebsocketAddress = 'ws://localhost:$port/ws';
serviceHttpAddress = 'http://localhost:$port';
diff --git a/runtime/platform/text_buffer.cc b/runtime/platform/text_buffer.cc
index 9cbb577..5b4cc05 100644
--- a/runtime/platform/text_buffer.cc
+++ b/runtime/platform/text_buffer.cc
@@ -57,6 +57,7 @@
buf_[msg_len_] = '\0';
}
+
intptr_t TextBuffer::Printf(const char* format, ...) {
va_list args;
va_start(args, format);
@@ -79,6 +80,7 @@
return len;
}
+
// Write a UTF-32 code unit so it can be read by a JSON parser in a string
// literal. Use official encoding from JSON specification. http://json.org/
void TextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) {
@@ -119,6 +121,7 @@
}
}
+
// Write an incomplete UTF-16 code unit so it can be read by a JSON parser in a
// string literal.
void TextBuffer::EscapeAndAddUTF16CodeUnit(uint16_t codeunit) {
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 364613f..ebb0df9 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -157,6 +157,6 @@
# This test is meaningless for DBC as allocation stubs are not used.
cc/RegenerateAllocStubs: Skip
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
diff --git a/runtime/vm/become.cc b/runtime/vm/become.cc
index a4d9fd1..accca31 100644
--- a/runtime/vm/become.cc
+++ b/runtime/vm/become.cc
@@ -148,17 +148,50 @@
};
+// On IA32, object pointers are embedded directly in the instruction stream,
+// which is normally write-protected, so we need to make it temporarily writable
+// to forward the pointers. On all other architectures, object pointers are
+// accessed through ObjectPools.
+#if defined(TARGET_ARCH_IA32)
+class WritableCodeLiteralsScope : public ValueObject {
+ public:
+ explicit WritableCodeLiteralsScope(Heap* heap) : heap_(heap) {
+ if (FLAG_write_protect_code) {
+ heap_->WriteProtectCode(false);
+ }
+ }
+
+ ~WritableCodeLiteralsScope() {
+ if (FLAG_write_protect_code) {
+ heap_->WriteProtectCode(true);
+ }
+ }
+
+ private:
+ Heap* heap_;
+};
+#else
+class WritableCodeLiteralsScope : public ValueObject {
+ public:
+ explicit WritableCodeLiteralsScope(Heap* heap) { }
+ ~WritableCodeLiteralsScope() { }
+};
+#endif
+
+
void Become::MakeDummyObject(const Instance& instance) {
// Make the forward pointer point to itself.
// This is needed to distinguish it from a real forward object.
ForwardObjectTo(instance.raw(), instance.raw());
}
+
static bool IsDummyObject(RawObject* object) {
if (!object->IsForwardingCorpse()) return false;
return GetForwardedObject(object) == object;
}
+
void Become::ElementsForwardIdentity(const Array& before, const Array& after) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
@@ -210,9 +243,12 @@
isolate->VisitWeakPersistentHandles(&handle_visitor);
// Heap pointers (may require updating the remembered set)
- ForwardHeapPointersVisitor object_visitor(&pointer_visitor);
- heap->VisitObjects(&object_visitor);
- pointer_visitor.VisitingObject(NULL);
+ {
+ WritableCodeLiteralsScope writable_code(heap);
+ ForwardHeapPointersVisitor object_visitor(&pointer_visitor);
+ heap->VisitObjects(&object_visitor);
+ pointer_visitor.VisitingObject(NULL);
+ }
#if !defined(PRODUCT)
tds.SetNumArguments(2);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index b0b3a9c1..bc9689c 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1357,13 +1357,13 @@
}
if (do_reload) {
#ifndef PRODUCT
+ JSONStream js;
// Maybe adjust the rate of future reloads.
isolate->MaybeIncreaseReloadEveryNStackOverflowChecks();
// Issue a reload.
- isolate->ReloadSources(true /* force_reload */);
- const Error& error = Error::Handle(isolate->sticky_reload_error());
- if (!error.IsNull()) {
- FATAL1("*** Isolate reload failed: %s\n", error.ToErrorCString());
+ bool success = isolate->ReloadSources(&js, true /* force_reload */);
+ if (!success) {
+ FATAL1("*** Isolate reload failed:\n%s\n", js.ToCString());
}
#endif
}
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index b7e437b..2f53147 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -13,19 +13,20 @@
namespace dart {
-VM_TEST_CASE(FindCodeObject) {
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
- const int kLoopCount = 50000;
- const int kScriptSize = 512 * KB;
+static const int kScriptSize = 512 * KB;
+static const int kLoopCount = 50000;
#elif defined(TARGET_ARCH_DBC)
- const int kLoopCount = 60000;
- const int kScriptSize = 1 * MB;
+static const int kScriptSize = 1 * MB;
+static const int kLoopCount = 60000;
#else
- const int kLoopCount = 25000;
- const int kScriptSize = 512 * KB;
+static const int kScriptSize = 512 * KB;
+static const int kLoopCount = 25000;
#endif
+static char scriptChars[kScriptSize];
+
+VM_TEST_CASE(FindCodeObject) {
const int kNumFunctions = 1024;
- char scriptChars[kScriptSize];
// Get access to the code index table.
Isolate* isolate = Isolate::Current();
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 27a3529..32dc967 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -660,12 +660,6 @@
MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
const Error& result) {
- NOT_IN_PRODUCT(
- if (I->IsReloading()) {
- I->ReportReloadError(result);
- return kOK;
- }
- )
// Generate the error and stacktrace strings for the error message.
String& exc_str = String::Handle(T->zone());
String& stacktrace_str = String::Handle(T->zone());
@@ -827,7 +821,6 @@
tag_table_(GrowableObjectArray::null()),
deoptimized_code_array_(GrowableObjectArray::null()),
sticky_error_(Error::null()),
- sticky_reload_error_(Error::null()),
background_compiler_(NULL),
background_compiler_disabled_depth_(0),
pending_service_extension_calls_(GrowableObjectArray::null()),
@@ -1090,26 +1083,28 @@
#ifndef PRODUCT
-void Isolate::ReportReloadError(const Error& error) {
- ASSERT(IsReloading());
- reload_context_->AbortReload(error);
-}
-
-
-void Isolate::ReloadSources(bool force_reload,
+bool Isolate::ReloadSources(JSONStream* js,
+ bool force_reload,
bool dont_delete_reload_context) {
- // TODO(asiva): Add verification of canonical objects.
ASSERT(!IsReloading());
has_attempted_reload_ = true;
- reload_context_ = new IsolateReloadContext(this);
- reload_context_->StartReload(force_reload);
- // TODO(asiva): Add verification of canonical objects.
- if (dont_delete_reload_context) {
- // Unit tests use the reload context later. Caller is responsible
- // for deleting the context.
- return;
+ reload_context_ = new IsolateReloadContext(this, js);
+ reload_context_->Reload(force_reload);
+ bool success = !reload_context_->reload_aborted();
+ if (!dont_delete_reload_context) {
+ DeleteReloadContext();
}
- DeleteReloadContext();
+#if defined(DEBUG)
+ if (success) {
+ return success;
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ isolate->heap()->CollectAllGarbage();
+ VerifyCanonicalVisitor check_canonical(thread);
+ isolate->heap()->IterateObjects(&check_canonical);
+ }
+#endif // DEBUG
+ return success;
}
@@ -1123,13 +1118,7 @@
void Isolate::DoneFinalizing() {
NOT_IN_PRODUCT(
if (IsReloading()) {
- reload_context_->FinishReload();
- if (reload_context_->has_error()) {
- // Remember the reload error.
- sticky_reload_error_ = reload_context_->error();
- } else {
- reload_context_->ReportSuccess();
- }
+ reload_context_->FinalizeLoading();
}
)
}
@@ -1505,7 +1494,8 @@
ASSERT(thread->isolate() == isolate);
StackZone zone(thread);
HandleScope handle_scope(thread);
-#if defined(DEBUG)
+ // TODO(27003): Enable for precompiled.
+#if defined(DEBUG) && !defined(DART_PRECOMPILED_RUNTIME)
if (!isolate->HasAttemptedReload()) {
isolate->heap()->CollectAllGarbage();
VerifyCanonicalVisitor check_canonical(thread);
@@ -1831,9 +1821,6 @@
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&sticky_error_));
- visitor->VisitPointer(
- reinterpret_cast<RawObject**>(&sticky_reload_error_));
-
// Visit the pending service extension calls.
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&pending_service_extension_calls_));
@@ -2094,11 +2081,6 @@
}
-void Isolate::clear_sticky_reload_error() {
- sticky_reload_error_ = Error::null();
-}
-
-
void Isolate::set_pending_service_extension_calls(
const GrowableObjectArray& value) {
pending_service_extension_calls_ = value.raw();
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 9c55cf3..2e603f1 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -249,7 +249,8 @@
// By default the reload context is deleted. This parameter allows
// the caller to delete is separately if it is still needed.
- void ReloadSources(bool force_reload,
+ bool ReloadSources(JSONStream* js,
+ bool force_reload,
bool dont_delete_reload_context = false);
bool MakeRunnable();
@@ -482,8 +483,6 @@
bool CanReload() const;
- void ReportReloadError(const Error& error);
-
void set_last_reload_timestamp(int64_t value) {
last_reload_timestamp_ = value;
}
@@ -539,9 +538,6 @@
RawError* sticky_error() const { return sticky_error_; }
void clear_sticky_error();
- RawError* sticky_reload_error() const { return sticky_reload_error_; }
- void clear_sticky_reload_error();
-
bool compilation_allowed() const { return compilation_allowed_; }
void set_compilation_allowed(bool allowed) {
compilation_allowed_ = allowed;
@@ -771,8 +767,6 @@
RawError* sticky_error_;
- RawError* sticky_reload_error_;
-
// Background compilation.
BackgroundCompiler* background_compiler_;
intptr_t background_compiler_disabled_depth_;
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index f174406..e635a7b 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -32,6 +32,8 @@
DEFINE_FLAG(bool, reload_every_optimized, true, "Only from optimized code.");
DEFINE_FLAG(bool, reload_every_back_off, false,
"Double the --reload-every value after each reload.");
+DEFINE_FLAG(bool, reload_force_rollback, false,
+ "Force all reloads to fail and rollback.");
DEFINE_FLAG(bool, check_reloaded, false,
"Assert that an isolate has reloaded at least once.")
#ifndef PRODUCT
@@ -45,11 +47,11 @@
#name)
-InstanceMorpher::InstanceMorpher(const Class& from, const Class& to)
- : from_(from), to_(to), mapping_() {
+InstanceMorpher::InstanceMorpher(Zone* zone, const Class& from, const Class& to)
+ : from_(from), to_(to), mapping_(zone, 0) {
ComputeMapping();
- before_ = new ZoneGrowableArray<const Instance*>();
- after_ = new ZoneGrowableArray<const Instance*>();
+ before_ = new(zone) ZoneGrowableArray<const Instance*>(zone, 0);
+ after_ = new(zone) ZoneGrowableArray<const Instance*>(zone, 0);
ASSERT(from_.id() == to_.id());
cid_ = from_.id();
}
@@ -165,10 +167,10 @@
void InstanceMorpher::AppendTo(JSONArray* array) {
JSONObject jsobj(array);
- jsobj.AddProperty("type", "Morpher");
+ jsobj.AddProperty("type", "ShapeChangeMapping");
jsobj.AddProperty("class", to_);
- jsobj.AddProperty("instances", before()->length());
- JSONArray map(&jsobj, "mapping");
+ jsobj.AddProperty("instanceCount", before()->length());
+ JSONArray map(&jsobj, "fieldOffsetMappings");
for (int i = 0; i < mapping_.length(); i += 2) {
JSONArray pair(&map);
pair.AddValue(mapping_.At(i));
@@ -200,7 +202,7 @@
JSONObject jsobj(array);
jsobj.AddProperty("type", "ReasonForCancelling");
const String& message = String::Handle(ToString());
- jsobj.AddProperty("message", message);
+ jsobj.AddProperty("message", message.ToCString());
}
@@ -209,15 +211,15 @@
jsobj.AddProperty("type", "ReasonForCancelling");
jsobj.AddProperty("class", from_);
const String& message = String::Handle(ToString());
- jsobj.AddProperty("message", message);
+ jsobj.AddProperty("message", message.ToCString());
}
+
RawError* IsolateReloadContext::error() const {
- ASSERT(has_error());
+ ASSERT(reload_aborted());
// Report the first error to the surroundings.
const Error& error =
Error::Handle(reasons_to_cancel_reload_.At(0)->ToError());
- OS::Print("[[%s]]\n", error.ToCString());
return error.raw();
}
@@ -355,16 +357,21 @@
}
-IsolateReloadContext::IsolateReloadContext(Isolate* isolate)
- : start_time_micros_(OS::GetCurrentMonotonicMicros()),
+IsolateReloadContext::IsolateReloadContext(Isolate* isolate,
+ JSONStream* js)
+ : zone_(Thread::Current()->zone()),
+ start_time_micros_(OS::GetCurrentMonotonicMicros()),
reload_timestamp_(OS::GetCurrentTimeMillis()),
isolate_(isolate),
reload_skipped_(false),
+ reload_aborted_(false),
+ reload_finalized_(false),
+ js_(js),
saved_num_cids_(-1),
saved_class_table_(NULL),
num_saved_libs_(-1),
- instance_morphers_(),
- reasons_to_cancel_reload_(),
+ instance_morphers_(zone_, 0),
+ reasons_to_cancel_reload_(zone_, 0),
cid_mapper_(),
modified_libs_(NULL),
script_uri_(String::null()),
@@ -380,6 +387,7 @@
// NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not
// associated with the isolate yet and if a GC is triggered here the raw
// objects will not be properly accounted for.
+ ASSERT(zone_ != NULL);
}
@@ -405,8 +413,8 @@
class Aborted : public ReasonForCancelling {
public:
- explicit Aborted(const Error& error)
- : ReasonForCancelling(), error_(error) { }
+ explicit Aborted(Zone* zone, const Error& error)
+ : ReasonForCancelling(zone), error_(error) { }
private:
const Error& error_;
@@ -418,7 +426,8 @@
};
-void IsolateReloadContext::StartReload(bool force_reload) {
+// NOTE: This function returns *after* FinalizeLoading is called.
+void IsolateReloadContext::Reload(bool force_reload) {
TIMELINE_SCOPE(Reload);
Thread* thread = Thread::Current();
ASSERT(isolate() == thread->isolate());
@@ -433,10 +442,12 @@
if (!modified_libs_->Contains(root_lib.index())) {
ASSERT(modified_libs_->IsEmpty());
reload_skipped_ = true;
- TIR_Print("Skipping reload. No libraries were modified\n");
+ TIR_Print("---- SKIPPING RELOAD (No libraries were modified)\n");
return;
}
+ TIR_Print("---- STARTING RELOAD\n");
+
// Preallocate storage for maps.
old_classes_set_storage_ =
HashTables::New<UnorderedHashSet<ClassMapTraits> >(4);
@@ -455,11 +466,6 @@
// Disable the background compiler while we are performing the reload.
BackgroundCompiler::Disable();
- if (FLAG_write_protect_code) {
- // Disable code page write protection while we are reloading.
- I->heap()->WriteProtectCode(false);
- }
-
// Ensure all functions on the stack have unoptimized code.
EnsuredUnoptimizedCodeForStack();
// Deoptimize all code that had optimizing decisions that are dependent on
@@ -469,6 +475,25 @@
DeoptimizeDependentCode();
Checkpoint();
+ // WEIRD CONTROL FLOW BEGINS.
+ //
+ // The flow of execution until we return from the tag handler can be complex.
+ //
+ // On a successful load, the following will occur:
+ // 1) Tag Handler is invoked and the embedder is in control.
+ // 2) All sources and libraries are loaded.
+ // 3) Dart_FinalizeLoading is called by the embedder.
+ // 4) Dart_FinalizeLoading invokes IsolateReloadContext::FinalizeLoading
+ // and we are temporarily back in control.
+ // This is where we validate the reload and commit or reject.
+ // 5) Dart_FinalizeLoading invokes Dart code related to deferred libraries.
+ // 6) The tag handler returns and we move on.
+ //
+ // Even after a successful reload the Dart code invoked in (5) can result
+ // in an Unwind error or an UnhandledException error. This error will be
+ // returned by the tag handler. The tag handler can return other errors,
+ // for example, top level parse errors. We want to capture these errors while
+ // propagating the UnwindError or an UnhandledException error.
Object& result = Object::Handle(thread->zone());
{
TransitionVMToNative transition(thread);
@@ -480,9 +505,22 @@
Api::NewHandle(thread, root_lib_url.raw()));
result = Api::UnwrapHandle(retval);
}
+ //
+ // WEIRD CONTROL FLOW ENDS.
+
+ BackgroundCompiler::Enable();
+
+ if (result.IsUnwindError() ||
+ result.IsUnhandledException()) {
+ // If the tag handler returns with an UnwindError or an UnhandledException
+ // error, propagate it and give up.
+ Exceptions::PropagateError(Error::Cast(result));
+ UNREACHABLE();
+ }
+
+ // Other errors (e.g. a parse error) are captured by the reload system.
if (result.IsError()) {
- const Error& error = Error::Cast(result);
- AddReasonForCancelling(new Aborted(error));
+ FinalizeFailedLoad(Error::Cast(result));
}
}
@@ -513,12 +551,15 @@
}
-void IsolateReloadContext::FinishReload() {
+// FinalizeLoading will be called *before* Reload() returns but will not be
+// called if the embedder fails to load sources.
+void IsolateReloadContext::FinalizeLoading() {
if (reload_skipped_) {
return;
}
+ ASSERT(!reload_finalized_);
BuildLibraryMapping();
- TIR_Print("---- DONE FINALIZING\n");
+ TIR_Print("---- LOAD SUCCEEDED\n");
if (ValidateReload()) {
Commit();
PostCommit();
@@ -531,48 +572,63 @@
// not remove dead subclasses. Rebuild the direct subclass
// information from scratch.
RebuildDirectSubclasses();
+ CommonFinalizeTail();
+}
- if (FLAG_write_protect_code) {
- // Re-enable code page write protection.
- I->heap()->WriteProtectCode(true);
+
+// FinalizeFailedLoad will be called *before* Reload() returns and will only
+// be called if the embedder fails to load sources.
+void IsolateReloadContext::FinalizeFailedLoad(const Error& error) {
+ TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
+ AddReasonForCancelling(new Aborted(zone_, error));
+ ReportReasonsForCancelling();
+ if (!reload_finalized_) {
+ Rollback();
}
+ CommonFinalizeTail();
+}
- BackgroundCompiler::Enable();
- if (FLAG_trace_reload) {
- JSONStream stream;
- ReportOnJSON(&stream);
- OS::Print("\nJSON report:\n %s\n", stream.ToCString());
- }
+void IsolateReloadContext::CommonFinalizeTail() {
+ ReportOnJSON(js_);
+ reload_finalized_ = true;
}
void IsolateReloadContext::ReportOnJSON(JSONStream* stream) {
+ // Clear the buffer.
+ stream->buffer()->Clear();
JSONObject jsobj(stream);
- jsobj.AddProperty("type", "Reload");
- jsobj.AddProperty("succeeded", !HasReasonsForCancelling());
- if (HasReasonsForCancelling()) {
- JSONArray array(&jsobj, "reasons");
- for (intptr_t i = 0; i < reasons_to_cancel_reload_.length(); i++) {
- ReasonForCancelling* reason = reasons_to_cancel_reload_.At(i);
- reason->AppendTo(&array);
- }
- } else {
- JSONArray array(&jsobj, "changes");
- for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
- instance_morphers_.At(i)->AppendTo(&array);
+ jsobj.AddProperty("type", "ReloadReport");
+ jsobj.AddProperty("success", !HasReasonsForCancelling());
+ {
+ JSONObject details(&jsobj, "details");
+ if (HasReasonsForCancelling()) {
+ // Reload was rejected.
+ JSONArray array(&jsobj, "notices");
+ for (intptr_t i = 0; i < reasons_to_cancel_reload_.length(); i++) {
+ ReasonForCancelling* reason = reasons_to_cancel_reload_.At(i);
+ reason->AppendTo(&array);
+ }
+ } else {
+ // Reload was successful.
+ const GrowableObjectArray& libs =
+ GrowableObjectArray::Handle(object_store()->libraries());
+ const intptr_t final_library_count = libs.Length();
+ const intptr_t loaded_library_count =
+ final_library_count - num_saved_libs_;
+ details.AddProperty("savedLibraryCount", num_saved_libs_);
+ details.AddProperty("loadedLibraryCount", loaded_library_count);
+ details.AddProperty("finalLibraryCount", final_library_count);
+ JSONArray array(&jsobj, "shapeChangeMappings");
+ for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
+ instance_morphers_.At(i)->AppendTo(&array);
+ }
}
}
}
-void IsolateReloadContext::AbortReload(const Error& error) {
- AddReasonForCancelling(new Aborted(error));
- ReportReasonsForCancelling();
- Rollback();
-}
-
-
void IsolateReloadContext::EnsuredUnoptimizedCodeForStack() {
TIMELINE_SCOPE(EnsuredUnoptimizedCodeForStack);
StackFrameIterator it(StackFrameIterator::kDontValidateFrames);
@@ -709,12 +765,13 @@
// Construct the imported-by graph.
ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >* imported_by =
- new ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >(num_libs);
+ new(zone_) ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >(
+ zone_, num_libs);
imported_by->SetLength(num_libs);
for (intptr_t i = 0; i < num_libs; i++) {
- (*imported_by)[i] = new ZoneGrowableArray<intptr_t>();
+ (*imported_by)[i] = new(zone_) ZoneGrowableArray<intptr_t>(zone_, 0);
}
- Array& imports = Array::Handle();
+ Array& ports = Array::Handle();
Namespace& ns = Namespace::Handle();
Library& target = Library::Handle();
@@ -727,9 +784,19 @@
}
// Add imports to the import-by graph.
- imports = lib.imports();
- for (intptr_t import_idx = 0; import_idx < imports.Length(); import_idx++) {
- ns ^= imports.At(import_idx);
+ ports = lib.imports();
+ for (intptr_t import_idx = 0; import_idx < ports.Length(); import_idx++) {
+ ns ^= ports.At(import_idx);
+ if (!ns.IsNull()) {
+ target = ns.library();
+ (*imported_by)[target.index()]->Add(lib.index());
+ }
+ }
+
+ // Add exports to the import-by graph.
+ ports = lib.exports();
+ for (intptr_t export_idx = 0; export_idx < ports.Length(); export_idx++) {
+ ns ^= ports.At(export_idx);
if (!ns.IsNull()) {
target = ns.library();
(*imported_by)[target.index()]->Add(lib.index());
@@ -744,10 +811,10 @@
entry = entries.GetNext();
if (entry.IsLibraryPrefix()) {
prefix ^= entry.raw();
- imports = prefix.imports();
- for (intptr_t import_idx = 0; import_idx < imports.Length();
+ ports = prefix.imports();
+ for (intptr_t import_idx = 0; import_idx < ports.Length();
import_idx++) {
- ns ^= imports.At(import_idx);
+ ns ^= ports.At(import_idx);
if (!ns.IsNull()) {
target = ns.library();
(*imported_by)[target.index()]->Add(lib.index());
@@ -784,7 +851,7 @@
void IsolateReloadContext::CheckpointLibraries() {
TIMELINE_SCOPE(CheckpointLibraries);
-
+ TIR_Print("---- CHECKPOINTING LIBRARIES\n");
// Save the root library in case we abort the reload.
const Library& root_lib =
Library::Handle(object_store()->root_library());
@@ -884,6 +951,7 @@
void IsolateReloadContext::Rollback() {
+ TIR_Print("---- ROLLING BACK");
RollbackClasses();
RollbackLibraries();
}
@@ -927,7 +995,7 @@
void IsolateReloadContext::Commit() {
TIMELINE_SCOPE(Commit);
- TIR_Print("---- COMMITTING REVERSE MAP\n");
+ TIR_Print("---- COMMITTING RELOAD\n");
// Note that the object heap contains before and after instances
// used for morphing. It is therefore important that morphing takes
@@ -947,9 +1015,8 @@
// Copy static field values from the old classes to the new classes.
// Patch fields and functions in the old classes so that they retain
// the old script.
- Class& cls = Class::Handle();
+ Class& old_cls = Class::Handle();
Class& new_cls = Class::Handle();
-
UnorderedHashMap<ClassMapTraits> class_map(class_map_storage_);
{
@@ -957,15 +1024,16 @@
while (it.MoveNext()) {
const intptr_t entry = it.Current();
new_cls = Class::RawCast(class_map.GetKey(entry));
- cls = Class::RawCast(class_map.GetPayload(entry, 0));
- if (new_cls.raw() != cls.raw()) {
- ASSERT(new_cls.is_enum_class() == cls.is_enum_class());
+ old_cls = Class::RawCast(class_map.GetPayload(entry, 0));
+ if (new_cls.raw() != old_cls.raw()) {
+ ASSERT(new_cls.is_enum_class() == old_cls.is_enum_class());
if (new_cls.is_enum_class() && new_cls.is_finalized()) {
- new_cls.ReplaceEnum(cls);
+ new_cls.ReplaceEnum(old_cls);
} else {
- new_cls.CopyStaticFieldValues(cls);
+ new_cls.CopyStaticFieldValues(old_cls);
}
- cls.PatchFieldsAndFunctions();
+ old_cls.PatchFieldsAndFunctions();
+ old_cls.MigrateImplicitStaticClosures(this, new_cls);
}
}
}
@@ -1094,6 +1162,7 @@
void IsolateReloadContext::AddReasonForCancelling(ReasonForCancelling* reason) {
+ reload_aborted_ = true;
reasons_to_cancel_reload_.Add(reason);
}
@@ -1105,7 +1174,7 @@
void IsolateReloadContext::ReportReasonsForCancelling() {
- ASSERT(HasReasonsForCancelling());
+ ASSERT(FLAG_reload_force_rollback || HasReasonsForCancelling());
for (int i = 0; i < reasons_to_cancel_reload_.length(); i++) {
reasons_to_cancel_reload_.At(i)->Report(this);
}
@@ -1194,7 +1263,9 @@
bool IsolateReloadContext::ValidateReload() {
TIMELINE_SCOPE(ValidateReload);
- if (has_error()) return false;
+ if (reload_aborted()) return false;
+
+ TIR_Print("---- VALIDATING RELOAD\n");
// Validate libraries.
{
@@ -1232,7 +1303,7 @@
map.Release();
}
- return !HasReasonsForCancelling();
+ return !FLAG_reload_force_rollback && !HasReasonsForCancelling();
}
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index a479aae..213a988 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -52,7 +52,7 @@
class InstanceMorpher : public ZoneAllocated {
public:
- InstanceMorpher(const Class& from, const Class& to);
+ InstanceMorpher(Zone* zone, const Class& from, const Class& to);
virtual ~InstanceMorpher() {}
// Called on each instance that needs to be morphed.
@@ -93,7 +93,7 @@
class ReasonForCancelling : public ZoneAllocated {
public:
- ReasonForCancelling() {}
+ explicit ReasonForCancelling(Zone* zone) {}
virtual ~ReasonForCancelling() {}
// Reports a reason for cancelling reload.
@@ -117,8 +117,8 @@
// Abstract class for also capturing the from_ and to_ class.
class ClassReasonForCancelling : public ReasonForCancelling {
public:
- ClassReasonForCancelling(const Class& from, const Class& to)
- : from_(from), to_(to) { }
+ ClassReasonForCancelling(Zone* zone, const Class& from, const Class& to)
+ : ReasonForCancelling(zone), from_(from), to_(to) { }
void AppendTo(JSONArray* array);
@@ -130,32 +130,36 @@
class IsolateReloadContext {
public:
- explicit IsolateReloadContext(Isolate* isolate);
+ explicit IsolateReloadContext(Isolate* isolate,
+ JSONStream* js);
~IsolateReloadContext();
- void StartReload(bool force_reload);
- void FinishReload();
- void AbortReload(const Error& error);
+ void Reload(bool force_reload);
- RawLibrary* saved_root_library() const;
-
- RawGrowableObjectArray* saved_libraries() const;
-
- // Report back through the observatory channels.
- void ReportError(const Error& error);
- void ReportSuccess();
+ // All zone allocated objects must be allocated from this zone.
+ Zone* zone() const { return zone_; }
bool reload_skipped() const { return reload_skipped_; }
-
- bool has_error() const { return HasReasonsForCancelling(); }
+ bool reload_aborted() const { return reload_aborted_; }
RawError* error() const;
-
int64_t reload_timestamp() const { return reload_timestamp_; }
+ static Dart_FileModifiedCallback file_modified_callback() {
+ return file_modified_callback_;
+ }
+ static void SetFileModifiedCallback(Dart_FileModifiedCallback callback) {
+ file_modified_callback_ = callback;
+ }
+
static bool IsSameField(const Field& a, const Field& b);
static bool IsSameLibrary(const Library& a_lib, const Library& b_lib);
static bool IsSameClass(const Class& a, const Class& b);
+ private:
+ RawLibrary* saved_root_library() const;
+
+ RawGrowableObjectArray* saved_libraries() const;
+
RawClass* FindOriginalClass(const Class& cls);
bool IsDirty(const Library& lib);
@@ -193,14 +197,22 @@
return !instance_morphers_.is_empty();
}
- static Dart_FileModifiedCallback file_modified_callback() {
- return file_modified_callback_;
- }
- static void SetFileModifiedCallback(Dart_FileModifiedCallback callback) {
- file_modified_callback_ = callback;
- }
+ // NOTE: FinalizeLoading will be called *before* Reload() returns. This
+ // function will not be called if the embedder does not call
+ // Dart_FinalizeLoading.
+ void FinalizeLoading();
- private:
+ // NOTE: FinalizeFailedLoad will be called *before* Reload returns. This
+ // function will not be called if the embedder calls Dart_FinalizeLoading.
+ void FinalizeFailedLoad(const Error& error);
+
+ // Called by both FinalizeLoading and FinalizeFailedLoad.
+ void CommonFinalizeTail();
+
+ // Report back through the observatory channels.
+ void ReportError(const Error& error);
+ void ReportSuccess();
+
void set_saved_root_library(const Library& value);
void set_saved_libraries(const GrowableObjectArray& value);
@@ -248,10 +260,16 @@
void ResetMegamorphicCaches();
void InvalidateWorld();
+ // The zone used for all reload related allocations.
+ Zone* zone_;
+
int64_t start_time_micros_;
int64_t reload_timestamp_;
Isolate* isolate_;
bool reload_skipped_;
+ bool reload_aborted_;
+ bool reload_finalized_;
+ JSONStream* js_;
intptr_t saved_num_cids_;
RawClass** saved_class_table_;
@@ -322,7 +340,10 @@
friend class Isolate;
friend class Class; // AddStaticFieldMapping, AddEnumBecomeMapping.
+ friend class Library;
friend class ObjectLocator;
+ friend class MarkFunctionsForRecompilation; // IsDirty.
+ friend class ReasonForCancelling;
static Dart_FileModifiedCallback file_modified_callback_;
};
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 46774c7..070897e 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -784,51 +784,57 @@
TEST_CASE(IsolateReload_LibraryLookup) {
+ const char* kImportScript =
+ "importedFunc() => 'a';\n";
+ TestCase::AddTestLib("test:lib1", kImportScript);
+
const char* kScript =
"main() {\n"
" return importedFunc();\n"
"}\n";
-
Dart_Handle result;
-
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
- // Fail to find 'test:importable_lib' in the isolate.
- result = Dart_LookupLibrary(NewString("test:importable_lib"));
+ // Fail to find 'test:lib1' in the isolate.
+ result = Dart_LookupLibrary(NewString("test:lib1"));
EXPECT(Dart_IsError(result));
const char* kReloadScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc();\n"
"}\n";
- // Reload and add 'test:importable_lib' to isolate.
+ // Reload and add 'test:lib1' to isolate.
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
- // Find 'test:importable_lib' in the isolate.
- result = Dart_LookupLibrary(NewString("test:importable_lib"));
+ // Find 'test:lib1' in the isolate.
+ result = Dart_LookupLibrary(NewString("test:lib1"));
EXPECT(Dart_IsLibrary(result));
// Reload and remove 'dart:math' from isolate.
lib = TestCase::ReloadTestScript(kScript);
EXPECT_VALID(lib);
- // Fail to find 'test:importable_lib' in the isolate.
- result = Dart_LookupLibrary(NewString("test:importable_lib"));
+ // Fail to find 'test:lib1' in the isolate.
+ result = Dart_LookupLibrary(NewString("test:lib1"));
EXPECT(Dart_IsError(result));
}
TEST_CASE(IsolateReload_LibraryHide) {
- // Import 'test:importable_lib' with importedFunc hidden. Will result in an
+ const char* kImportScript =
+ "importedFunc() => 'a';\n";
+ TestCase::AddTestLib("test:lib1", kImportScript);
+
+ // Import 'test:lib1' with importedFunc hidden. Will result in an
// error.
const char* kScript =
- "import 'test:importable_lib' hide importedFunc;\n"
+ "import 'test:lib1' hide importedFunc;\n"
"main() {\n"
" return importedFunc();\n"
"}\n";
@@ -839,9 +845,9 @@
EXPECT_VALID(lib);
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
- // Import 'test:importable_lib'.
+ // Import 'test:lib1'.
const char* kReloadScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc();\n"
"}\n";
@@ -853,10 +859,15 @@
TEST_CASE(IsolateReload_LibraryShow) {
- // Import 'test:importable_lib' with importedIntFunc visible. Will result in
+ const char* kImportScript =
+ "importedFunc() => 'a';\n"
+ "importedIntFunc() => 4;\n";
+ TestCase::AddTestLib("test:lib1", kImportScript);
+
+ // Import 'test:lib1' with importedIntFunc visible. Will result in
// an error when 'main' is invoked.
const char* kScript =
- "import 'test:importable_lib' show importedIntFunc;\n"
+ "import 'test:lib1' show importedIntFunc;\n"
"main() {\n"
" return importedFunc();\n"
"}\n"
@@ -873,10 +884,10 @@
// Results in an error.
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
- // Import 'test:importable_lib' with importedFunc visible. Will result in
+ // Import 'test:lib1' with importedFunc visible. Will result in
// an error when 'mainInt' is invoked.
const char* kReloadScript =
- "import 'test:importable_lib' show importedFunc;\n"
+ "import 'test:lib1' show importedFunc;\n"
"main() {\n"
" return importedFunc();\n"
"}\n"
@@ -897,9 +908,13 @@
// Verifies that we clear the ICs for the functions live on the stack in a way
// that is compatible with the fast path smi stubs.
TEST_CASE(IsolateReload_SmiFastPathStubs) {
+ const char* kImportScript =
+ "importedIntFunc() => 4;\n";
+ TestCase::AddTestLib("test:lib1", kImportScript);
+
const char* kScript =
"import 'test:isolate_reload_helper';\n"
- "import 'test:importable_lib' show importedIntFunc;\n"
+ "import 'test:lib1' show importedIntFunc;\n"
"main() {\n"
" var x = importedIntFunc();\n"
" var y = importedIntFunc();\n"
@@ -921,8 +936,14 @@
// Verifies that we assign the correct patch classes for imported
// mixins when we reload.
TEST_CASE(IsolateReload_ImportedMixinFunction) {
+ const char* kImportScript =
+ "class ImportedMixin {\n"
+ " mixinFunc() => 'mixin';\n"
+ "}\n";
+ TestCase::AddTestLib("test:lib1", kImportScript);
+
const char* kScript =
- "import 'test:importable_lib' show ImportedMixin;\n"
+ "import 'test:lib1' show ImportedMixin;\n"
"class A extends Object with ImportedMixin {\n"
"}"
"var func = new A().mixinFunc;\n"
@@ -936,7 +957,7 @@
EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
- "import 'test:importable_lib' show ImportedMixin;\n"
+ "import 'test:lib1' show ImportedMixin;\n"
"class A extends Object with ImportedMixin {\n"
"}"
"var func;\n"
@@ -1289,7 +1310,7 @@
}
-TEST_CASE(IsolateReload_TearOff_Equality) {
+TEST_CASE(IsolateReload_TearOff_Instance_Equality) {
const char* kScript =
"import 'test:isolate_reload_helper';\n"
"class C {\n"
@@ -1328,6 +1349,80 @@
}
+TEST_CASE(IsolateReload_TearOff_Class_Identity) {
+ const char* kScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class C {\n"
+ " static foo() => 'old';\n"
+ "}\n"
+ "getFoo() => C.foo;\n"
+ "main() {\n"
+ " var f1 = getFoo();\n"
+ " reloadTest();\n"
+ " var f2 = getFoo();\n"
+ " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class C {\n"
+ " static foo() => 'new';\n"
+ "}\n"
+ "getFoo() => C.foo;\n"
+ "main() {\n"
+ " var f1 = getFoo();\n"
+ " reloadTest();\n"
+ " var f2 = getFoo();\n"
+ " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+}
+
+
+TEST_CASE(IsolateReload_TearOff_Library_Identity) {
+ const char* kScript =
+ "import 'test:isolate_reload_helper';\n"
+ "foo() => 'old';\n"
+ "getFoo() => foo;\n"
+ "main() {\n"
+ " var f1 = getFoo();\n"
+ " reloadTest();\n"
+ " var f2 = getFoo();\n"
+ " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'test:isolate_reload_helper';\n"
+ "foo() => 'new';\n"
+ "getFoo() => foo;\n"
+ "main() {\n"
+ " var f1 = getFoo();\n"
+ " reloadTest();\n"
+ " var f2 = getFoo();\n"
+ " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+}
+
+
TEST_CASE(IsolateReload_TearOff_List_Set) {
const char* kScript =
"import 'test:isolate_reload_helper';\n"
@@ -2231,10 +2326,10 @@
TEST_CASE(IsolateReload_NoLibsModified) {
const char* kImportScript =
"importedFunc() => 'fancy';";
- TestCase::SetImportableTestLibScript(kImportScript);
+ TestCase::AddTestLib("test:lib1", kImportScript);
const char* kScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc() + ' feast';\n"
"}\n";
@@ -2245,10 +2340,10 @@
const char* kReloadImportScript =
"importedFunc() => 'bossy';";
- TestCase::SetImportableTestLibScript(kReloadImportScript);
+ TestCase::AddTestLib("test:lib1", kReloadImportScript);
const char* kReloadScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc() + ' pants';\n"
"}\n";
@@ -2274,10 +2369,10 @@
TEST_CASE(IsolateReload_MainLibModified) {
const char* kImportScript =
"importedFunc() => 'fancy';";
- TestCase::SetImportableTestLibScript(kImportScript);
+ TestCase::AddTestLib("test:lib1", kImportScript);
const char* kScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc() + ' feast';\n"
"}\n";
@@ -2288,10 +2383,10 @@
const char* kReloadImportScript =
"importedFunc() => 'bossy';";
- TestCase::SetImportableTestLibScript(kReloadImportScript);
+ TestCase::AddTestLib("test:lib1", kReloadImportScript);
const char* kReloadScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc() + ' pants';\n"
"}\n";
@@ -2307,7 +2402,7 @@
static bool ImportModifiedCallback(const char* url, int64_t since) {
- if (strcmp(url, "test:importable_lib") == 0) {
+ if (strcmp(url, "test:lib1") == 0) {
return true;
}
return false;
@@ -2317,10 +2412,10 @@
TEST_CASE(IsolateReload_ImportedLibModified) {
const char* kImportScript =
"importedFunc() => 'fancy';";
- TestCase::SetImportableTestLibScript(kImportScript);
+ TestCase::AddTestLib("test:lib1", kImportScript);
const char* kScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc() + ' feast';\n"
"}\n";
@@ -2331,10 +2426,10 @@
const char* kReloadImportScript =
"importedFunc() => 'bossy';";
- TestCase::SetImportableTestLibScript(kReloadImportScript);
+ TestCase::AddTestLib("test:lib1", kReloadImportScript);
const char* kReloadScript =
- "import 'test:importable_lib';\n"
+ "import 'test:lib1';\n"
"main() {\n"
" return importedFunc() + ' pants';\n"
"}\n";
@@ -2352,10 +2447,10 @@
TEST_CASE(IsolateReload_PrefixImportedLibModified) {
const char* kImportScript =
"importedFunc() => 'fancy';";
- TestCase::SetImportableTestLibScript(kImportScript);
+ TestCase::AddTestLib("test:lib1", kImportScript);
const char* kScript =
- "import 'test:importable_lib' as cobra;\n"
+ "import 'test:lib1' as cobra;\n"
"main() {\n"
" return cobra.importedFunc() + ' feast';\n"
"}\n";
@@ -2366,10 +2461,10 @@
const char* kReloadImportScript =
"importedFunc() => 'bossy';";
- TestCase::SetImportableTestLibScript(kReloadImportScript);
+ TestCase::AddTestLib("test:lib1", kReloadImportScript);
const char* kReloadScript =
- "import 'test:importable_lib' as cobra;\n"
+ "import 'test:lib1' as cobra;\n"
"main() {\n"
" return cobra.importedFunc() + ' pants';\n"
"}\n";
@@ -2385,6 +2480,52 @@
}
+static bool ExportModifiedCallback(const char* url, int64_t since) {
+ if (strcmp(url, "test:exportlib") == 0) {
+ return true;
+ }
+ return false;
+}
+
+
+TEST_CASE(IsolateReload_ExportedLibModified) {
+ const char* kImportScript =
+ "export 'test:exportlib';";
+ TestCase::AddTestLib("test:importlib", kImportScript);
+
+ const char* kExportScript =
+ "exportedFunc() => 'fancy';";
+ TestCase::AddTestLib("test:exportlib", kExportScript);
+
+ const char* kScript =
+ "import 'test:importlib';\n"
+ "main() {\n"
+ " return exportedFunc() + ' feast';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadExportScript =
+ "exportedFunc() => 'bossy';";
+ TestCase::AddTestLib("test:exportlib", kReloadExportScript);
+
+ const char* kReloadScript =
+ "import 'test:importlib';\n"
+ "main() {\n"
+ " return exportedFunc() + ' pants';\n"
+ "}\n";
+
+ Dart_SetFileModifiedCallback(&ExportModifiedCallback);
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ Dart_SetFileModifiedCallback(NULL);
+
+ // Modification of an exported library propagates.
+ EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
+}
+
#endif // !PRODUCT
} // namespace dart
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2f062f1..0506fa7 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -15325,6 +15325,12 @@
const Class& cls = Class::Handle(zone, this->clazz());
SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
result ^= cls.LookupCanonicalInstance(zone, *this);
+ // TODO(johnmccutchan) : Temporary workaround for issue (26988).
+ if ((result.raw() != raw()) &&
+ isolate->HasAttemptedReload() &&
+ (GetClassId() == kImmutableArrayCid)) {
+ return true;
+ }
return (result.raw() == this->raw());
}
#endif // DEBUG
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 802bf513..e9c9280 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1401,6 +1401,8 @@
void ReplaceEnum(const Class& old_enum) const;
void CopyStaticFieldValues(const Class& old_cls) const;
void PatchFieldsAndFunctions() const;
+ void MigrateImplicitStaticClosures(IsolateReloadContext* context,
+ const Class& new_cls) const;
void CopyCanonicalConstants(const Class& old_cls) const;
void CopyCanonicalType(const Class& old_cls) const;
void CheckReload(const Class& replacement,
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index c646dd6..ec79c6b 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -232,7 +232,10 @@
String& enum_ident = String::Handle();
Instance& old_enum_value = Instance::Handle(zone);
Instance& enum_value = Instance::Handle(zone);
-
+ // The E.values array.
+ Instance& old_enum_values = Instance::Handle(zone);
+ // The E.values array.
+ Instance& enum_values = Instance::Handle(zone);
Array& enum_map_storage = Array::Handle(zone,
HashTables::New<UnorderedHashMap<EnumMapTraits> >(4));
ASSERT(!enum_map_storage.IsNull());
@@ -251,6 +254,7 @@
continue;
}
if (enum_ident.Equals(Symbols::Values())) {
+ old_enum_values = field.StaticValue();
// Non-enum instance.
continue;
}
@@ -279,6 +283,7 @@
continue;
}
if (enum_ident.Equals(Symbols::Values())) {
+ enum_values = field.StaticValue();
// Non-enum instance.
continue;
}
@@ -302,6 +307,11 @@
enum_map_storage = enum_map.Release().raw();
}
+ // Map the old E.values array to the new E.values array.
+ ASSERT(!old_enum_values.IsNull());
+ ASSERT(!enum_values.IsNull());
+ reload_context->AddEnumBecomeMapping(old_enum_values, enum_values);
+
if (enums_deleted && FLAG_trace_reload_verbose) {
// TODO(johnmccutchan): Add this to the reload 'notices' list.
VTIR_Print("The following enum values were deleted and are forever lost in "
@@ -363,10 +373,36 @@
}
+void Class::MigrateImplicitStaticClosures(IsolateReloadContext* irc,
+ const Class& new_cls) const {
+ const Array& funcs = Array::Handle(functions());
+ Function& old_func = Function::Handle();
+ String& selector = String::Handle();
+ Function& new_func = Function::Handle();
+ Instance& old_closure = Instance::Handle();
+ Instance& new_closure = Instance::Handle();
+ for (intptr_t i = 0; i < funcs.Length(); i++) {
+ old_func ^= funcs.At(i);
+ if (old_func.is_static() &&
+ old_func.HasImplicitClosureFunction()) {
+ selector = old_func.name();
+ new_func = new_cls.LookupFunction(selector);
+ if (!new_func.IsNull() && new_func.is_static()) {
+ old_func = old_func.ImplicitClosureFunction();
+ old_closure = old_func.ImplicitStaticClosure();
+ new_func = new_func.ImplicitClosureFunction();
+ new_closure = new_func.ImplicitStaticClosure();
+ irc->AddBecomeMapping(old_closure, new_closure);
+ }
+ }
+ }
+}
+
+
class EnumClassConflict : public ClassReasonForCancelling {
public:
- EnumClassConflict(const Class& from, const Class& to)
- : ClassReasonForCancelling(from, to) { }
+ EnumClassConflict(Zone* zone, const Class& from, const Class& to)
+ : ClassReasonForCancelling(zone, from, to) { }
RawString* ToString() {
return String::NewFormatted(
@@ -380,20 +416,27 @@
class EnsureFinalizedError : public ClassReasonForCancelling {
public:
- EnsureFinalizedError(const Class& from, const Class& to, const Error& error)
- : ClassReasonForCancelling(from, to), error_(error) { }
+ EnsureFinalizedError(Zone* zone,
+ const Class& from,
+ const Class& to,
+ const Error& error)
+ : ClassReasonForCancelling(zone, from, to), error_(error) { }
private:
const Error& error_;
RawError* ToError() { return error_.raw(); }
+
+ RawString* ToString() {
+ return String::New(error_.ToErrorCString());
+ }
};
class NativeFieldsConflict : public ClassReasonForCancelling {
public:
- NativeFieldsConflict(const Class& from, const Class& to)
- : ClassReasonForCancelling(from, to) { }
+ NativeFieldsConflict(Zone* zone, const Class& from, const Class& to)
+ : ClassReasonForCancelling(zone, from, to) { }
private:
RawString* ToString() {
@@ -405,8 +448,8 @@
class TypeParametersChanged : public ClassReasonForCancelling {
public:
- TypeParametersChanged(const Class& from, const Class& to)
- : ClassReasonForCancelling(from, to) {}
+ TypeParametersChanged(Zone* zone, const Class& from, const Class& to)
+ : ClassReasonForCancelling(zone, from, to) {}
RawString* ToString() {
return String::NewFormatted(
@@ -427,8 +470,8 @@
class PreFinalizedConflict : public ClassReasonForCancelling {
public:
- PreFinalizedConflict(const Class& from, const Class& to)
- : ClassReasonForCancelling(from, to) {}
+ PreFinalizedConflict(Zone* zone, const Class& from, const Class& to)
+ : ClassReasonForCancelling(zone, from, to) {}
private:
RawString* ToString() {
@@ -442,8 +485,8 @@
class InstanceSizeConflict : public ClassReasonForCancelling {
public:
- InstanceSizeConflict(const Class& from, const Class& to)
- : ClassReasonForCancelling(from, to) {}
+ InstanceSizeConflict(Zone* zone, const Class& from, const Class& to)
+ : ClassReasonForCancelling(zone, from, to) {}
private:
RawString* ToString() {
@@ -460,10 +503,11 @@
class UnimplementedDeferredLibrary : public ReasonForCancelling {
public:
- UnimplementedDeferredLibrary(const Library& from,
+ UnimplementedDeferredLibrary(Zone* zone,
+ const Library& from,
const Library& to,
const String& name)
- : ReasonForCancelling(), from_(from), to_(to), name_(name) {}
+ : ReasonForCancelling(zone), from_(from), to_(to), name_(name) {}
private:
const Library& from_;
@@ -489,7 +533,8 @@
// Class cannot change enum property.
if (is_enum_class() != replacement.is_enum_class()) {
context->AddReasonForCancelling(
- new EnumClassConflict(*this, replacement));
+ new(context->zone())
+ EnumClassConflict(context->zone(), *this, replacement));
return;
}
@@ -499,16 +544,19 @@
Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
if (!error.IsNull()) {
context->AddReasonForCancelling(
- new EnsureFinalizedError(*this, replacement, error));
+ new(context->zone())
+ EnsureFinalizedError(context->zone(), *this, replacement, error));
return; // No reason to check other properties.
}
+ ASSERT(replacement.is_finalized());
TIR_Print("Finalized replacement class for %s\n", ToCString());
}
// Native field count cannot change.
if (num_native_fields() != replacement.num_native_fields()) {
context->AddReasonForCancelling(
- new NativeFieldsConflict(*this, replacement));
+ new(context->zone())
+ NativeFieldsConflict(context->zone(), *this, replacement));
return;
}
@@ -575,11 +623,14 @@
AbstractType::Handle(replacement.DeclarationType());
if (!dt.Equals(replacement_dt)) {
context->AddReasonForCancelling(
- new TypeParametersChanged(*this, replacement));
+ new(context->zone())
+ TypeParametersChanged(context->zone(), *this, replacement));
return false;
}
if (RequiresInstanceMorphing(replacement)) {
- context->AddInstanceMorpher(new InstanceMorpher(*this, replacement));
+ context->AddInstanceMorpher(
+ new(context->zone())
+ InstanceMorpher(context->zone(), *this, replacement));
}
return true;
}
@@ -590,13 +641,15 @@
// The replacement class must also prefinalized.
if (!replacement.is_prefinalized()) {
context->AddReasonForCancelling(
- new PreFinalizedConflict(*this, replacement));
+ new(context->zone())
+ PreFinalizedConflict(context->zone(), *this, replacement));
return false;
}
// Check the instance sizes are equal.
if (instance_size() != replacement.instance_size()) {
context->AddReasonForCancelling(
- new InstanceSizeConflict(*this, replacement));
+ new(context->zone())
+ InstanceSizeConflict(context->zone(), *this, replacement));
return false;
}
return true;
@@ -614,7 +667,9 @@
if (prefix.is_deferred_load()) {
const String& prefix_name = String::Handle(prefix.name());
context->AddReasonForCancelling(
- new UnimplementedDeferredLibrary(*this, replacement, prefix_name));
+ new(context->zone())
+ UnimplementedDeferredLibrary(context->zone(),
+ *this, replacement, prefix_name));
return;
}
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index d11536b..fc3e0f9 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -8724,16 +8724,20 @@
// Parse stream expression.
ExpectToken(Token::kIN);
+
+ // Open a block for the iterator variable and the try-finally statement
+ // that contains the loop. Ensure that the block starts at a different
+ // token position than the following loop block. Both blocks can allocate
+ // contexts and if they have a matching token position range,
+ // it can be an issue (cf. bug 26941).
+ OpenBlock();
+ const Block* await_for_block = current_block_;
+
const TokenPosition stream_expr_pos = TokenPos();
AstNode* stream_expr =
ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
ExpectToken(Token::kRPAREN);
- // Open a block for the iterator variable and the try-finally
- // statement that contains the loop.
- OpenBlock();
- const Block* loop_block = current_block_;
-
// Build creation of implicit StreamIterator.
// var :for-in-iter = new StreamIterator(stream_expr).
const Class& stream_iterator_cls =
@@ -8983,8 +8987,8 @@
try_index,
finally_clause);
- ASSERT(current_block_ == loop_block);
- loop_block->statements->Add(try_catch_node);
+ ASSERT(current_block_ == await_for_block);
+ await_for_block->statements->Add(try_catch_node);
return CloseBlock(); // Implicit block around while loop.
}
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index dc0edb5..657af55 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -516,6 +516,70 @@
if (!changed_) {
TraceConstFunctions();
}
+ CollectCallbackFields();
+ }
+}
+
+
+void Precompiler::CollectCallbackFields() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Class& subcls = Class::Handle(Z);
+ Array& fields = Array::Handle(Z);
+ Field& field = Field::Handle(Z);
+ Function& function = Function::Handle(Z);
+ Function& dispatcher = Function::Handle(Z);
+ Array& args_desc = Array::Handle(Z);
+ AbstractType& field_type = AbstractType::Handle(Z);
+ String& field_name = String::Handle(Z);
+ GrowableArray<intptr_t> cids;
+
+ 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.is_allocated()) continue;
+
+ fields = cls.fields();
+ for (intptr_t k = 0; k < fields.Length(); k++) {
+ field ^= fields.At(k);
+ if (field.is_static()) continue;
+ field_type = field.type();
+ if (!field_type.IsFunctionType()) continue;
+ field_name = field.name();
+ if (!IsSent(field_name)) continue;
+ // Create arguments descriptor with fixed parameters from
+ // signature of field_type.
+ function = Type::Cast(field_type).signature();
+ if (function.HasOptionalParameters()) continue;
+ if (FLAG_trace_precompiler) {
+ THR_Print("Found callback field %s\n", field_name.ToCString());
+ }
+ args_desc =
+ ArgumentsDescriptor::New(function.num_fixed_parameters());
+ cids.Clear();
+ if (T->cha()->ConcreteSubclasses(cls, &cids)) {
+ for (intptr_t j = 0; j < cids.length(); ++j) {
+ subcls ^= I->class_table()->At(cids[j]);
+ if (subcls.is_allocated()) {
+ // Add dispatcher to cls.
+ dispatcher = subcls.GetInvocationDispatcher(
+ field_name,
+ args_desc,
+ RawFunction::kInvokeFieldDispatcher,
+ /* create_if_absent = */ true);
+ if (FLAG_trace_precompiler) {
+ THR_Print("Added invoke-field-dispatcher for %s to %s\n",
+ field_name.ToCString(), subcls.ToCString());
+ }
+ AddFunction(dispatcher);
+ }
+ }
+ }
+ }
+ }
}
}
@@ -1319,7 +1383,7 @@
functions = cls.functions();
for (intptr_t j = 0; j < functions.Length(); j++) {
function ^= functions.At(j);
- bool retain = function.HasCode();
+ bool retain = enqueued_functions_.Lookup(&function) != NULL;
if (!retain && function.HasImplicitClosureFunction()) {
// It can happen that all uses of an implicit closure inline their
// target function, leaving the target function uncompiled. Keep
@@ -1339,7 +1403,7 @@
closures = isolate()->object_store()->closure_functions();
for (intptr_t j = 0; j < closures.Length(); j++) {
function ^= closures.At(j);
- bool retain = function.HasCode();
+ bool retain = enqueued_functions_.Lookup(&function) != NULL;
if (retain) {
AddTypesOf(function);
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 5cae27e..ad7f0ca 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -299,6 +299,7 @@
void ProcessFunction(const Function& function);
void CheckForNewDynamicFunctions();
void TraceConstFunctions();
+ void CollectCallbackFields();
void TraceForRetainedFunctions();
void DropFunctions();
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 165822e..21b8bf8 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -335,11 +335,11 @@
char* native_symbol_name =
NativeSymbolResolver::LookupSymbolName(pc, &start);
if (native_symbol_name == NULL) {
- OS::Print("Frame[%" Pd "] = `unknown symbol` [0x%" Px "]\n",
- frame_index, pc);
+ OS::PrintErr("Frame[%" Pd "] = `unknown symbol` [0x%" Px "]\n",
+ frame_index, pc);
} else {
- OS::Print("Frame[%" Pd "] = `%s` [0x%" Px "]\n",
- frame_index, native_symbol_name, pc);
+ OS::PrintErr("Frame[%" Pd "] = `%s` [0x%" Px "]\n",
+ frame_index, native_symbol_name, pc);
NativeSymbolResolver::FreeSymbolName(native_symbol_name);
}
}
@@ -351,8 +351,8 @@
if (code.IsNull()) {
DumpStackFrame(frame_index, pc);
} else {
- OS::Print("Frame[%" Pd "] = Dart:`%s` [0x%" Px "]\n",
- frame_index, code.ToCString(), pc);
+ OS::PrintErr("Frame[%" Pd "] = Dart:`%s` [0x%" Px "]\n",
+ frame_index, code.ToCString(), pc);
}
}
@@ -959,9 +959,9 @@
const bool exited_dart_code = thread->HasExitedDartCode();
- OS::Print("Dumping %s stack trace for thread %" Px "\n",
- native_stack_trace ? "native" : "dart-only",
- OSThread::ThreadIdToIntPtr(os_thread->trace_id()));
+ OS::PrintErr("Dumping %s stack trace for thread %" Px "\n",
+ native_stack_trace ? "native" : "dart-only",
+ OSThread::ThreadIdToIntPtr(os_thread->trace_id()));
uintptr_t sp = Thread::GetCurrentStackPointer();
uintptr_t fp = 0;
@@ -973,7 +973,7 @@
uword stack_upper = 0;
if (!InitialRegisterCheck(pc, fp, sp)) {
- OS::Print(
+ OS::PrintErr(
"Stack dump aborted because InitialRegisterCheck.\n");
return;
}
@@ -983,7 +983,7 @@
sp,
&stack_lower,
&stack_upper)) {
- OS::Print(
+ OS::PrintErr(
"Stack dump aborted because GetAndValidateIsolateStackBounds.\n");
return;
}
@@ -1014,7 +1014,7 @@
fp,
sp);
}
- OS::Print("-- End of DumpStackTrace");
+ OS::PrintErr("-- End of DumpStackTrace");
}
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index f119a25..9edfbf6 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -5251,13 +5251,7 @@
const intptr_t kParamCount = RegExpMacroAssembler::kParamCount;
Function& fn = Function::Handle(zone, Function::New(
- // Append the regexp pattern to the function name.
- String::Handle(zone, Symbols::New(thread,
- String::Handle(zone, String::Concat(
- String::Handle(zone, String::Concat(
- Symbols::ColonMatcher(),
- Symbols::ColonSpace(), Heap::kOld)),
- String::Handle(regexp.pattern()), Heap::kOld)))),
+ Symbols::ColonMatcher(),
RawFunction::kIrregexpFunction,
true, // Static.
false, // Not const.
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 8ef6e89..c57890a 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2493,18 +2493,8 @@
const bool force_reload =
BoolParameter::Parse(js->LookupParam("force"), false);
- isolate->ReloadSources(force_reload);
+ isolate->ReloadSources(js, force_reload);
- const Error& error = Error::Handle(isolate->sticky_reload_error());
-
- if (error.IsNull()) {
- PrintSuccess(js);
- } else {
- // Clear the sticky error.
- isolate->clear_sticky_reload_error();
- js->PrintError(kIsolateReloadFailed,
- "Isolate reload failed: %s", error.ToErrorCString());
- }
return true;
}
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index 19ccf68..c5e2e75 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -331,7 +331,9 @@
NULL,
&error));
if (isolate == NULL) {
- OS::PrintErr("vm-service: Isolate creation error: %s\n", error);
+ if (FLAG_trace_service) {
+ OS::PrintErr("vm-service: Isolate creation error: %s\n", error);
+ }
ServiceIsolate::SetServiceIsolate(NULL);
ServiceIsolate::FinishedInitializing();
ServiceIsolate::FinishedExiting();
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 753594c..97d74af 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -298,7 +298,6 @@
V(BooleanExpression, "boolean expression") \
V(MegamorphicMiss, "megamorphic_miss") \
V(CommaSpace, ", ") \
- V(ColonSpace, ": ") \
V(RParenArrow, ") => ") \
V(SpaceExtendsSpace, " extends ") \
V(SpaceWhereNewLine, " where\n") \
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 9c89d9c..a877a1a 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -74,37 +74,45 @@
}
-static bool IsImportableTestLib(const char* url_name) {
- const char* kImportTestLibUri = "test:importable_lib";
- static const intptr_t kImportTestLibUriLen = strlen(kImportTestLibUri);
- return (strncmp(url_name, kImportTestLibUri, kImportTestLibUriLen) == 0);
+struct TestLibEntry {
+ const char* url;
+ const char* source;
+};
+
+
+static MallocGrowableArray<TestLibEntry>* test_libs_ = NULL;
+
+
+void TestCase::AddTestLib(const char* url, const char* source) {
+ if (test_libs_ == NULL) {
+ test_libs_ = new MallocGrowableArray<TestLibEntry>();
+ }
+ // If the test lib is already added, replace the source.
+ for (intptr_t i = 0; i < test_libs_->length(); i++) {
+ if (strcmp(url, (*test_libs_)[i].url) == 0) {
+ (*test_libs_)[i].source = source;
+ return;
+ }
+ }
+ TestLibEntry entry;
+ entry.url = url;
+ entry.source = source;
+ test_libs_->Add(entry);
}
-const char* kDefaultImportableTestLibScript =
- "importedFunc() => 'a';\n"
- "importedIntFunc() => 4;\n"
- "class ImportedMixin {\n"
- " mixinFunc() => 'mixin';\n"
- "}\n";
-const char* importable_test_lib_script = kDefaultImportableTestLibScript;
-
-
-void TestCase::SetImportableTestLibScript(const char* source) {
- importable_test_lib_script = source;
+const char* TestCase::GetTestLib(const char* url) {
+ if (test_libs_ == NULL) {
+ return NULL;
+ }
+ for (intptr_t i = 0; i < test_libs_->length(); i++) {
+ if (strcmp(url, (*test_libs_)[i].url) == 0) {
+ return (*test_libs_)[i].source;
+ }
+ }
+ return NULL;
}
-
-void TestCase::RestoreImportableTestLibScript() {
- importable_test_lib_script = kDefaultImportableTestLibScript;
-}
-
-
-static Dart_Handle ImportableTestLibSource() {
- return DartUtils::NewString(importable_test_lib_script);
-}
-
-
#ifndef PRODUCT
static bool IsIsolateReloadTestLib(const char* url_name) {
const char* kIsolateReloadTestLibUri = "test:isolate_reload_helper";
@@ -204,8 +212,10 @@
return DartUtils::NewError("Do not know how to load '%s'", url_chars);
}
}
- if (IsImportableTestLib(url_chars)) {
- return Dart_LoadLibrary(url, Dart_Null(), ImportableTestLibSource(), 0, 0);
+ const char* lib_source = TestCase::GetTestLib(url_chars);
+ if (lib_source != NULL) {
+ Dart_Handle source = Dart_NewStringFromCString(lib_source);
+ return Dart_LoadLibrary(url, Dart_Null(), source, 0, 0);
}
NOT_IN_PRODUCT(
if (IsIsolateReloadTestLib(url_chars)) {
@@ -280,14 +290,21 @@
Dart_Handle TestCase::TriggerReload() {
Isolate* isolate = Isolate::Current();
-
+ JSONStream js;
+ bool success = false;
{
TransitionNativeToVM transition(Thread::Current());
- isolate->ReloadSources(false, // force_reload
- true); // dont_delete_reload_context
+ success = isolate->ReloadSources(&js,
+ false, // force_reload
+ true); // dont_delete_reload_context
+ fprintf(stderr, "RELOAD REPORT:\n%s\n", js.ToCString());
}
- return Dart_FinalizeLoading(false);
+ if (success) {
+ return Dart_FinalizeLoading(false);
+ } else {
+ return Dart_Null();
+ }
}
@@ -295,7 +312,7 @@
Isolate* isolate = Isolate::Current();
if (isolate->reload_context() != NULL &&
- isolate->reload_context()->has_error()) {
+ isolate->reload_context()->reload_aborted()) {
// Return a handle to the error.
return Api::NewHandle(Thread::Current(),
isolate->reload_context()->error());
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 5a72dbb..8622a4f 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -314,9 +314,8 @@
// Helper function which reloads the current isolate using |script|.
static Dart_Handle ReloadTestScript(const char* script);
- // Changes the default importable test lib script.
- static void SetImportableTestLibScript(const char* source);
- static void RestoreImportableTestLibScript();
+ static void AddTestLib(const char* url, const char* source);
+ static const char* GetTestLib(const char* url);
private:
static Dart_Isolate CreateIsolate(const uint8_t* buffer, const char* name);
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index b4f835b..3b0de9d 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -11507,11 +11507,11 @@
another.y <= top + height;
}
- Point get topLeft => new Point(this.left, this.top);
- Point get topRight => new Point(this.left + this.width, this.top);
- Point get bottomRight => new Point(this.left + this.width,
+ Point get topLeft => new Point/*<num>*/(this.left, this.top);
+ Point get topRight => new Point/*<num>*/(this.left + this.width, this.top);
+ Point get bottomRight => new Point/*<num>*/(this.left + this.width,
this.top + this.height);
- Point get bottomLeft => new Point(this.left,
+ Point get bottomLeft => new Point/*<num>*/(this.left,
this.top + this.height);
// To suppress missing implicit constructor warnings.
@@ -13865,13 +13865,13 @@
bool sameAsParent = identical(current, parent);
bool foundAsParent = sameAsParent || parent.tagName == 'HTML';
if (current == null || sameAsParent) {
- if (foundAsParent) return new Point(0, 0);
+ if (foundAsParent) return new Point/*<num>*/(0, 0);
throw new ArgumentError("Specified element is not a transitive offset "
"parent of this element.");
}
Element parentOffset = current.offsetParent;
Point p = Element._offsetToHelper(parentOffset, parent);
- return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
+ return new Point/*<num>*/(p.x + current.offsetLeft, p.y + current.offsetTop);
}
static HtmlDocument _parseDocument;
@@ -24071,14 +24071,14 @@
@DomName('MouseEvent.clientX')
@DomName('MouseEvent.clientY')
- Point get client => new Point(_clientX, _clientY);
+ Point get client => new Point/*<num>*/(_clientX, _clientY);
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_movementX, _movementY);
+ Point get movement => new Point/*<num>*/(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
@@ -24091,7 +24091,7 @@
if (JS('bool', '!!#.offsetX', this)) {
var x = JS('int', '#.offsetX', this);
var y = JS('int', '#.offsetY', this);
- return new Point(x, y);
+ return new Point/*<num>*/(x, y);
} else {
// Firefox does not support offsetX.
if (!(this.target is Element)) {
@@ -24100,21 +24100,21 @@
}
Element target = this.target;
var point = (this.client - target.getBoundingClientRect().topLeft);
- return new Point(point.x.toInt(), point.y.toInt());
+ return new Point/*<num>*/(point.x.toInt(), point.y.toInt());
}
}
@DomName('MouseEvent.screenX')
@DomName('MouseEvent.screenY')
- Point get screen => new Point(_screenX, _screenY);
+ Point get screen => new Point/*<num>*/(_screenX, _screenY);
@DomName('MouseEvent.layerX')
@DomName('MouseEvent.layerY')
- Point get layer => new Point(_layerX, _layerY);
+ Point get layer => new Point/*<num>*/(_layerX, _layerY);
@DomName('MouseEvent.pageX')
@DomName('MouseEvent.pageY')
- Point get page => new Point(_pageX, _pageY);
+ Point get page => new Point/*<num>*/(_pageX, _pageY);
}
// 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
@@ -32743,15 +32743,15 @@
@DomName('Touch.clientX')
@DomName('Touch.clientY')
- Point get client => new Point(__clientX, __clientY);
+ Point get client => new Point/*<num>*/(__clientX, __clientY);
@DomName('Touch.pageX')
@DomName('Touch.pageY')
- Point get page => new Point(__pageX, __pageY);
+ Point get page => new Point/*<num>*/(__pageX, __pageY);
@DomName('Touch.screenX')
@DomName('Touch.screenY')
- Point get screen => new Point(__screenX, __screenY);
+ Point get screen => new Point/*<num>*/(__screenX, __screenY);
@DomName('Touch.radiusX')
@DocsEditable()
@@ -37486,11 +37486,11 @@
another.y <= top + height;
}
- Point get topLeft => new Point(this.left, this.top);
- Point get topRight => new Point(this.left + this.width, this.top);
- Point get bottomRight => new Point(this.left + this.width,
+ Point get topLeft => new Point/*<num>*/(this.left, this.top);
+ Point get topRight => new Point/*<num>*/(this.left + this.width, this.top);
+ Point get bottomRight => new Point/*<num>*/(this.left + this.width,
this.top + this.height);
- Point get bottomLeft => new Point(this.left,
+ Point get bottomLeft => new Point/*<num>*/(this.left,
this.top + this.height);
// To suppress missing implicit constructor warnings.
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 68ec664..080bfe3 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -12112,11 +12112,11 @@
another.y <= top + height;
}
- Point get topLeft => new Point(this.left, this.top);
- Point get topRight => new Point(this.left + this.width, this.top);
- Point get bottomRight => new Point(this.left + this.width,
+ Point get topLeft => new Point/*<num>*/(this.left, this.top);
+ Point get topRight => new Point/*<num>*/(this.left + this.width, this.top);
+ Point get bottomRight => new Point/*<num>*/(this.left + this.width,
this.top + this.height);
- Point get bottomLeft => new Point(this.left,
+ Point get bottomLeft => new Point/*<num>*/(this.left,
this.top + this.height);
// To suppress missing implicit constructor warnings.
@@ -14449,13 +14449,13 @@
bool sameAsParent = current == parent;
bool foundAsParent = sameAsParent || parent.tagName == 'HTML';
if (current == null || sameAsParent) {
- if (foundAsParent) return new Point(0, 0);
+ if (foundAsParent) return new Point/*<num>*/(0, 0);
throw new ArgumentError("Specified element is not a transitive offset "
"parent of this element.");
}
Element parentOffset = current.offsetParent;
Point p = Element._offsetToHelper(parentOffset, parent);
- return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
+ return new Point/*<num>*/(p.x + current.offsetLeft, p.y + current.offsetTop);
}
static HtmlDocument _parseDocument;
@@ -26837,14 +26837,14 @@
@DomName('MouseEvent.clientX')
@DomName('MouseEvent.clientY')
- Point get client => new Point(_clientX, _clientY);
+ Point get client => new Point/*<num>*/(_clientX, _clientY);
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_movementX, _movementY);
+ Point get movement => new Point/*<num>*/(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
@@ -26853,19 +26853,19 @@
* after the event has fired or if the element has CSS transforms affecting
* it.
*/
- Point get offset => new Point(_offsetX, _offsetY);
+ Point get offset => new Point/*<num>*/(_offsetX, _offsetY);
@DomName('MouseEvent.screenX')
@DomName('MouseEvent.screenY')
- Point get screen => new Point(_screenX, _screenY);
+ Point get screen => new Point/*<num>*/(_screenX, _screenY);
@DomName('MouseEvent.layerX')
@DomName('MouseEvent.layerY')
- Point get layer => new Point(_layerX, _layerY);
+ Point get layer => new Point/*<num>*/(_layerX, _layerY);
@DomName('MouseEvent.pageX')
@DomName('MouseEvent.pageY')
- Point get page => new Point(_pageX, _pageY);
+ Point get page => new Point/*<num>*/(_pageX, _pageY);
}
// 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
@@ -36962,15 +36962,15 @@
@DomName('Touch.clientX')
@DomName('Touch.clientY')
- Point get client => new Point(__clientX, __clientY);
+ Point get client => new Point/*<num>*/(__clientX, __clientY);
@DomName('Touch.pageX')
@DomName('Touch.pageY')
- Point get page => new Point(__pageX, __pageY);
+ Point get page => new Point/*<num>*/(__pageX, __pageY);
@DomName('Touch.screenX')
@DomName('Touch.screenY')
- Point get screen => new Point(__screenX, __screenY);
+ Point get screen => new Point/*<num>*/(__screenX, __screenY);
@DomName('Touch.radiusX')
@DocsEditable()
@@ -37662,10 +37662,10 @@
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaSource)) {
+ if ((blob_OR_source_OR_stream is MediaStream)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaStream)) {
+ if ((blob_OR_source_OR_stream is MediaSource)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
@@ -41794,11 +41794,11 @@
another.y <= top + height;
}
- Point get topLeft => new Point(this.left, this.top);
- Point get topRight => new Point(this.left + this.width, this.top);
- Point get bottomRight => new Point(this.left + this.width,
+ Point get topLeft => new Point/*<num>*/(this.left, this.top);
+ Point get topRight => new Point/*<num>*/(this.left + this.width, this.top);
+ Point get bottomRight => new Point/*<num>*/(this.left + this.width,
this.top + this.height);
- Point get bottomLeft => new Point(this.left,
+ Point get bottomLeft => new Point/*<num>*/(this.left,
this.top + this.height);
// To suppress missing implicit constructor warnings.
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index 4ac1197..a8f0661 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -642,7 +642,8 @@
if (isDom || isJsInterop) {
// TODO(jacobr): verify class implements JavaScriptObject.
var className = mirrors.MirrorSystem.getName(clazz.simpleName);
- bool isPrivate = className.startsWith('_');
+ bool isPrivateUserDefinedClass =
+ className.startsWith('_') && !dartLibrary;
var classNameImpl = '${className}Impl';
var sbPatch = new StringBuffer();
if (isJsInterop) {
@@ -715,7 +716,7 @@
sbPatch.write(
" static Type get instanceRuntimeType => ${classNameImpl};\n");
}
- if (isPrivate) {
+ if (isPrivateUserDefinedClass) {
sb.write("""
class ${escapePrivateClassPrefix}${className} implements $className {}
""");
@@ -810,6 +811,9 @@
for (var typeMirror in jsInterfaceTypes) {
mirrors.LibraryMirror libraryMirror = typeMirror.owner;
+ var location = libraryMirror.location;
+ var dartLibrary = location != null && location.sourceUri.scheme == 'dart';
+
var prefixName;
if (libraryPrefixes.containsKey(libraryMirror)) {
prefixName = libraryPrefixes[libraryMirror];
@@ -831,8 +835,9 @@
var isFunction = typeMirror.isSubtypeOf(functionMirror);
var isJSObject = typeMirror.isSubtypeOf(jsObjectMirror);
var className = mirrors.MirrorSystem.getName(typeMirror.simpleName);
- var isPrivate = className.startsWith('_');
- if (isPrivate) className = '${escapePrivateClassPrefix}${className}';
+ var isPrivateUserDefinedClass = className.startsWith('_') && !dartLibrary;
+ if (isPrivateUserDefinedClass)
+ className = '${escapePrivateClassPrefix}${className}';
var fullName = '${prefixName}.${className}';
(isArray ? implementsArray : implements).add(fullName);
if (!isArray && !isFunction && !isJSObject) {
diff --git a/sdk/lib/vmservice/devfs.dart b/sdk/lib/vmservice/devfs.dart
index 35af748..4735512 100644
--- a/sdk/lib/vmservice/devfs.dart
+++ b/sdk/lib/vmservice/devfs.dart
@@ -37,10 +37,18 @@
}
Uri pathUri;
try {
- pathUri = Uri.parse(path);
+ pathUri = new Uri.file(path);
} on FormatException catch(e) {
return null;
}
+
+ try {
+ // Make sure that this pathUri can be converted to a file path.
+ pathUri.toFilePath();
+ } on UnsupportedError catch (e) {
+ return null;
+ }
+
Uri resolvedUri = uri.resolveUri(pathUri);
if (!resolvedUri.toString().startsWith(uri.toString())) {
// Resolved uri must be within the filesystem's base uri.
@@ -313,6 +321,10 @@
return _encodeFileSystemDoesNotExistError(message, fsName);
}
var fileList = await listFiles(fs.uri);
+ // Remove any url-encoding in the filenames.
+ for (int i = 0; i < fileList.length; i++) {
+ fileList[i]['name'] = Uri.decodeFull(fileList[i]['name']);
+ }
var result = { 'type': 'FSFileList', 'files': fileList };
return encodeResult(message, result);
}
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index efbfd7a..bc8772c 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -193,7 +193,7 @@
[ $compiler == precompiler && $runtime == dart_precompiled && $arch == simarm ]
LibTest/typed_data/Float32x4/operator_division_A01_t02: RuntimeError # Issue #26675
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
Language/Expressions/Assignment/prefix_object_t02: Crash # Requires deferred libraries
Language/Expressions/Constants/constant_constructor_t03: Crash # Requires deferred libraries
Language/Expressions/Constants/identifier_denotes_a_constant_t06: Crash # Requires deferred libraries
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 1902a62..ab8dec3 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -208,7 +208,7 @@
[ $compiler == precompiler && $runtime == dart_precompiled && $system == android ]
*: Skip # Issue #26373
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
function_send_test: Pass, Fail # Closure identity
message3_test/fun: Pass, Fail # Closure identity
deferred_in_isolate_test: Crash # Requires deferred libraries
diff --git a/tests/language/language.status b/tests/language/language.status
index 34798b6..64c1c4a 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -246,7 +246,7 @@
vm/optimized_guarded_field_isolates_test: Skip # Issue #26373
issue23244_test: Skip # Issue #26373
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
static_closure_identical_test: Pass, Fail # Closure identity
cha_deopt1_test: Crash # Requires deferred libraries
cha_deopt2_test: Crash # Requires deferred libraries
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 37f4f1e..469b3b3 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -374,19 +374,13 @@
# version.
mirrors/accessor_cache_overflow_test: Skip
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
+async/multiple_timer_test: Pass, Fail # Timing related
+math/double_pow_test: RuntimeError, Pass, Fail # Issue 26887
async/stream_transformer_test: Pass, Fail # Closure identity
mirrors/closurization_equivalence_test: SkipByDesign # Method equality
mirrors/fake_function_with_call_test: SkipByDesign # Method equality
-async/multiple_timer_test: Pass, Fail # Timing related
-
-mirrors/generic_bounded_by_type_parameter_test/02: Fail # Type equality - Issue 26869
-mirrors/typedef_reflected_type_test/01: Fail # Type equality - Issue 26869
-mirrors/generic_bounded_test/02: Fail # Type equality - Issue 26869
-mirrors/generic_bounded_by_type_parameter_test/02: Fail # Type equality - Issue 26869
-mirrors/typedef_reflected_type_test/01: Fail # Type equality - Issue 26869
-
mirrors/library_enumeration_deferred_loading_test: Crash # Deferred loading
mirrors/library_imports_deferred_test: Crash # Deferred loading
mirrors/library_import_deferred_loading_test: Crash # Deferred loading
@@ -396,7 +390,8 @@
mirrors/deferred_mirrors_metatarget_test: Crash # Deferred loading
mirrors/load_library_test: Crash # Deferred loading
+[ $hot_reload ]
mirrors/metadata_scope_test/none: Fail # Constant equality - Issue 26868
-
-typed_data/float32x4_unbox_regress_test: Pass, Crash # Issue 26888
-math/double_pow_test: Pass, Fail # Issue 26887
+mirrors/generic_bounded_test/02: Fail # Type equality - Issue 26869
+mirrors/typedef_reflected_type_test/01: Fail # Type equality - Issue 26869
+mirrors/generic_bounded_by_type_parameter_test/02: Fail # Type equality - Issue 26869
diff --git a/tests/standalone/io/issue_26954_test.dart b/tests/standalone/io/issue_26954_test.dart
new file mode 100644
index 0000000..5e8738b
--- /dev/null
+++ b/tests/standalone/io/issue_26954_test.dart
@@ -0,0 +1,35 @@
+// 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:convert';
+import 'dart:io';
+
+final List<int> _UTF8_PLS_CERTIFICATE = UTF8.encode('''
+-----BEGIN CERTIFICATE-----
+MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
+cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDI3MTAyNjM1WhcNMjUxMDI0MTAyNjM1
+WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCkg/Qr8RQeLTOSgCkyiEX2ztgkgscX8hKGHEHdvlkmVK3JVEIIwkvu
+/Y9LtHZUia3nPAgqEEbexzTENZjSCcC0V6I2XW/e5tIE3rO0KLZyhtZhN/2SfJ6p
+KbOh0HLr1VtkKJGp1tzUmHW/aZI32pK60ZJ/N917NLPCJpCaL8+wHo3+w3oNqln6
+oJsfgxy9SUM8Bsc9WMYKMUdqLO1QKs1A5YwqZuO7Mwj+4LY2QDixC7Ua7V9YAPo2
+1SBeLvMCHbYxSPCuxcZ/kDkgax/DF9u7aZnGhMImkwBka0OQFvpfjKtTIuoobTpe
+PAG7MQYXk4RjnjdyEX/9XAQzvNo1CDObAgMBAAGjgbQwgbEwPAYDVR0RBDUwM4IJ
+bG9jYWxob3N0ggkxMjcuMC4wLjGCAzo6MYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAA
+ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSvhJo6taTggJQBukEvMo/PDk8tKTAf
+BgNVHSMEGDAWgBS98L4T5RaIToE3DkBRsoeWPil0eDAOBgNVHQ8BAf8EBAMCA6gw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAHLOt0mL2S4A
+B7vN7KsfQeGlVgZUVlEjem6kqBh4fIzl4CsQuOO8oJ0FlO1z5JAIo98hZinymJx1
+phBVpyGIKakT/etMH0op5evLe9dD36VA3IM/FEv5ibk35iGnPokiJXIAcdHd1zam
+YaTHRAnZET5S03+7BgRTKoRuszhbvuFz/vKXaIAnVNOF4Gf2NUJ/Ax7ssJtRkN+5
+UVxe8TZVxzgiRv1uF6NTr+J8PDepkHCbJ6zEQNudcFKAuC56DN1vUe06gRDrNbVq
+2JHEh4pRfMpdsPCrS5YHBjVq/XHtFHgwDR6g0WTwSUJvDeM4OPQY5f61FB0JbFza
+PkLkXmoIod8=
+-----END CERTIFICATE-----''');
+
+main() {
+ // create context for establishing socket later
+ final _context = SecurityContext.defaultContext;
+ _context.useCertificateChainBytes(_UTF8_PLS_CERTIFICATE);
+}
diff --git a/tests/standalone/io/stdio_implicit_close_script.dart b/tests/standalone/io/stdio_implicit_close_script.dart
new file mode 100644
index 0000000..4be58a88
--- /dev/null
+++ b/tests/standalone/io/stdio_implicit_close_script.dart
@@ -0,0 +1,20 @@
+// 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:io";
+
+void main(List<String> arguments) {
+ // Access stdout and stderr so that the system grabs a handle to it. This
+ // initializes some internal structures.
+ if (stdout.hashCode == -1234 && stderr.hashCode == (stderr.hashCode + 1)) {
+ throw "we have other problems.";
+ }
+
+ if (arguments.contains("stdout")) {
+ stdout.close();
+ }
+ if (arguments.contains("stderr")) {
+ stderr.close();
+ }
+}
diff --git a/tests/standalone/io/stdio_implicit_close_test.dart b/tests/standalone/io/stdio_implicit_close_test.dart
new file mode 100644
index 0000000..dc67f0e
--- /dev/null
+++ b/tests/standalone/io/stdio_implicit_close_test.dart
@@ -0,0 +1,56 @@
+// 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 "dart:convert";
+import "dart:io";
+
+void test({bool closeStdout, bool closeStderr}) {
+ var scriptFile = "stdio_implicit_close_script.dart";
+ var script = Platform.script.resolve(scriptFile).toFilePath();
+
+ // Relying on these flags to print something specific on stdout and stderr
+ // is brittle, but otherwise we would need to add our own flag.
+ var arguments = [
+ "--print-metrics", // Prints on stderr.
+ "--timing", // Prints on stdout.
+ script,
+ ];
+ if (closeStdout) arguments.add("stdout");
+ if (closeStderr) arguments.add("stderr");
+
+ asyncStart();
+ Process.run(Platform.executable,
+ arguments,
+ stdoutEncoding: ASCII,
+ stderrEncoding: ASCII).then((result) {
+ print(result.stdout);
+ print(result.stderr);
+ Expect.equals(0, result.exitCode);
+
+ if (closeStdout) {
+ Expect.equals("", result.stdout);
+ } else {
+ Expect.isTrue(result.stdout.contains("Timing for"));
+ }
+
+ if (closeStderr) {
+ Expect.equals("", result.stderr);
+ } else {
+ Expect.isTrue(result.stderr.contains("Printing metrics"));
+ }
+
+ asyncEnd();
+ });
+}
+
+void main() {
+ asyncStart();
+ test(closeStdout: false, closeStderr: false);
+ test(closeStdout: false, closeStderr: true);
+ test(closeStdout: true, closeStderr: false);
+ test(closeStdout: true, closeStderr: true);
+ asyncEnd();
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index ff14249..3476560 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -252,6 +252,7 @@
io/http_client_stays_alive_test: Skip # Platform.executable
io/print_sync_test: Skip # Platform.executable
io/signals_test: Skip # Platform.executable
+io/stdio_implicit_close_test: Skip # Platform.executable
io/stdio_nonblocking_test: Skip # Platform.executable
io/regress_7191_test: Skip # Platform.executable
io/secure_unauthorized_test: Skip # Platform.executable
@@ -287,6 +288,7 @@
no_support_il_printer_test: SkipByDesign
no_support_service_test: SkipByDesign
no_support_timeline_test: SkipByDesign
+io/stdio_implicit_close_test: Skip # SkipByDesign
# Following tests are skipped on dart_app as package mapping is not supported.
[ $runtime == dart_precompiled || $runtime == dart_app ]
@@ -322,7 +324,7 @@
[ $runtime == vm || $runtime == dart_app || $runtime == dart_precompiled ]
deferred_transitive_import_error_test: Skip # Contains intentional errors.
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
deferred_transitive_import_error_test: Crash # Uses deferred imports.
package/*: SkipByDesign # Launches VMs in interesting ways.
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index 66ec0d2..e2df361 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -21,6 +21,6 @@
dummy_compiler_test: Crash # Issue 24485
recursive_import_test: Crash # Issue 24485
-[ $hot_reload ]
+[ $hot_reload || $hot_reload_rollback ]
recursive_import_test: Skip # Running dart2js under frequent reloads is slow.
dummy_compiler_test: Skip # Running dart2js under frequent reloads is slow.
diff --git a/tools/VERSION b/tools/VERSION
index 064bcd1..3eb18d8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 19
PATCH 0
-PRERELEASE 2
-PRERELEASE_PATCH 3
+PRERELEASE 3
+PRERELEASE_PATCH 0
diff --git a/tools/build.py b/tools/build.py
index 055b19a..a27dd41 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -60,7 +60,7 @@
default=utils.GuessArchitecture())
result.add_option("--os",
help='Target OSs (comma-separated).',
- metavar='[all,host,android,fuchsia]',
+ metavar='[all,host,android]',
default='host')
result.add_option("-t", "--toolchain",
help='Cross-compiler toolchain path',
@@ -109,11 +109,11 @@
return False
options.os = [ProcessOsOption(os_name) for os_name in options.os]
for os_name in options.os:
- if not os_name in ['android', 'freebsd', 'fuchsia', 'linux', 'macos', 'win32']:
+ if not os_name in ['android', 'freebsd', 'linux', 'macos', 'win32']:
print "Unknown os %s" % os_name
return False
if os_name != HOST_OS:
- if os_name != 'android' and os_name != 'fuchsia':
+ if os_name != 'android':
print "Unsupported target os %s" % os_name
return False
if not HOST_OS in ['linux']:
@@ -148,13 +148,6 @@
if arch == 'x64':
return os.path.join(android_toolchain, 'x86_64-linux-android')
- if target_os == 'fuchsia':
- fuchsia_toolchain = GetFuchsiaToolchainDir(HOST_OS, arch)
- if arch == 'arm64':
- return os.path.join(fuchsia_toolchain, 'aarch64-elf')
- if arch == 'x64':
- return os.path.join(fuchsia_toolchain, 'x86_64-elf')
-
# If no cross compiler is specified, only try to figure one out on Linux.
if not HOST_OS in ['linux']:
raise Exception('Unless --toolchain is used cross-building is only '
@@ -182,8 +175,6 @@
linker = ""
if target_os == 'android':
linker = os.path.join(DART_ROOT, 'tools', 'android_link.py')
- elif target_os == 'fuchsia':
- linker = os.path.join(DART_ROOT, 'tools', 'fuchsia_link.py')
elif toolchainprefix:
linker = toolchainprefix + "-g++"
@@ -235,28 +226,6 @@
return android_toolchain
-def GetFuchsiaToolchainDir(host_os, target_arch):
- global THIRD_PARTY_ROOT
- if host_os not in ['linux']:
- raise Exception('Unsupported host os %s' % host_os)
- if target_arch not in ['x64', 'arm64',]:
- raise Exception('Unsupported target architecture %s' % target_arch)
-
- # Set up path to the Android NDK.
- CheckDirExists(THIRD_PARTY_ROOT, 'third party tools')
- fuchsia_tools = os.path.join(THIRD_PARTY_ROOT, 'fuchsia_tools')
- CheckDirExists(fuchsia_tools, 'Fuchsia tools')
-
- toolchain_arch = 'x86_64-elf-5.3.0-Linux-x86_64'
- if target_arch == 'arm64':
- toolchain_arch = 'aarch64-elf-5.3.0-Linux-x86_64'
- fuchsia_toolchain = os.path.join(
- fuchsia_tools, 'toolchains', toolchain_arch, 'bin')
- CheckDirExists(fuchsia_toolchain, 'Fuchsia toolchain')
-
- return fuchsia_toolchain
-
-
def Execute(args):
process = subprocess.Popen(args)
process.wait()
diff --git a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
index 8077fb0..f5b7e1b 100644
--- a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
@@ -24,14 +24,14 @@
@DomName('MouseEvent.clientX')
@DomName('MouseEvent.clientY')
- Point get client => new Point(_clientX, _clientY);
+ Point get client => new Point/*<num>*/(_clientX, _clientY);
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_movementX, _movementY);
+ Point get movement => new Point/*<num>*/(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
@@ -44,7 +44,7 @@
if (JS('bool', '!!#.offsetX', this)) {
var x = JS('int', '#.offsetX', this);
var y = JS('int', '#.offsetY', this);
- return new Point(x, y);
+ return new Point/*<num>*/(x, y);
} else {
// Firefox does not support offsetX.
if (!(this.target is Element)) {
@@ -53,19 +53,19 @@
}
Element target = this.target;
var point = (this.client - target.getBoundingClientRect().topLeft);
- return new Point(point.x.toInt(), point.y.toInt());
+ return new Point/*<num>*/(point.x.toInt(), point.y.toInt());
}
}
@DomName('MouseEvent.screenX')
@DomName('MouseEvent.screenY')
- Point get screen => new Point(_screenX, _screenY);
+ Point get screen => new Point/*<num>*/(_screenX, _screenY);
@DomName('MouseEvent.layerX')
@DomName('MouseEvent.layerY')
- Point get layer => new Point(_layerX, _layerY);
+ Point get layer => new Point/*<num>*/(_layerX, _layerY);
@DomName('MouseEvent.pageX')
@DomName('MouseEvent.pageY')
- Point get page => new Point(_pageX, _pageY);
+ Point get page => new Point/*<num>*/(_pageX, _pageY);
}
diff --git a/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate b/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate
index 1b2bbc8..229afe6 100644
--- a/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate
+++ b/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate
@@ -43,14 +43,14 @@
@DomName('MouseEvent.clientX')
@DomName('MouseEvent.clientY')
- Point get client => new Point(_clientX, _clientY);
+ Point get client => new Point/*<num>*/(_clientX, _clientY);
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_movementX, _movementY);
+ Point get movement => new Point/*<num>*/(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
@@ -59,17 +59,17 @@
* after the event has fired or if the element has CSS transforms affecting
* it.
*/
- Point get offset => new Point(_offsetX, _offsetY);
+ Point get offset => new Point/*<num>*/(_offsetX, _offsetY);
@DomName('MouseEvent.screenX')
@DomName('MouseEvent.screenY')
- Point get screen => new Point(_screenX, _screenY);
+ Point get screen => new Point/*<num>*/(_screenX, _screenY);
@DomName('MouseEvent.layerX')
@DomName('MouseEvent.layerY')
- Point get layer => new Point(_layerX, _layerY);
+ Point get layer => new Point/*<num>*/(_layerX, _layerY);
@DomName('MouseEvent.pageX')
@DomName('MouseEvent.pageY')
- Point get page => new Point(_pageX, _pageY);
+ Point get page => new Point/*<num>*/(_pageX, _pageY);
}
diff --git a/tools/dom/templates/html/impl/impl_ClientRect.darttemplate b/tools/dom/templates/html/impl/impl_ClientRect.darttemplate
index 22f115e..f52240a 100644
--- a/tools/dom/templates/html/impl/impl_ClientRect.darttemplate
+++ b/tools/dom/templates/html/impl/impl_ClientRect.darttemplate
@@ -89,11 +89,11 @@
another.y <= top + height;
}
- Point get topLeft => new Point(this.left, this.top);
- Point get topRight => new Point(this.left + this.width, this.top);
- Point get bottomRight => new Point(this.left + this.width,
+ Point get topLeft => new Point/*<num>*/(this.left, this.top);
+ Point get topRight => new Point/*<num>*/(this.left + this.width, this.top);
+ Point get bottomRight => new Point/*<num>*/(this.left + this.width,
this.top + this.height);
- Point get bottomLeft => new Point(this.left,
+ Point get bottomLeft => new Point/*<num>*/(this.left,
this.top + this.height);
$!MEMBERS}
diff --git a/tools/dom/templates/html/impl/impl_DOMRectReadOnly.darttemplate b/tools/dom/templates/html/impl/impl_DOMRectReadOnly.darttemplate
index b17b5bc..e9bf8a6 100644
--- a/tools/dom/templates/html/impl/impl_DOMRectReadOnly.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DOMRectReadOnly.darttemplate
@@ -89,11 +89,11 @@
another.y <= top + height;
}
- Point get topLeft => new Point(this.left, this.top);
- Point get topRight => new Point(this.left + this.width, this.top);
- Point get bottomRight => new Point(this.left + this.width,
+ Point get topLeft => new Point/*<num>*/(this.left, this.top);
+ Point get topRight => new Point/*<num>*/(this.left + this.width, this.top);
+ Point get bottomRight => new Point/*<num>*/(this.left + this.width,
this.top + this.height);
- Point get bottomLeft => new Point(this.left,
+ Point get bottomLeft => new Point/*<num>*/(this.left,
this.top + this.height);
$!MEMBERS}
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index c9ef54a..e89c912 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -1272,13 +1272,13 @@
$endif
bool foundAsParent = sameAsParent || parent.tagName == 'HTML';
if (current == null || sameAsParent) {
- if (foundAsParent) return new Point(0, 0);
+ if (foundAsParent) return new Point/*<num>*/(0, 0);
throw new ArgumentError("Specified element is not a transitive offset "
"parent of this element.");
}
Element parentOffset = current.offsetParent;
Point p = Element._offsetToHelper(parentOffset, parent);
- return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
+ return new Point/*<num>*/(p.x + current.offsetLeft, p.y + current.offsetTop);
}
static HtmlDocument _parseDocument;
diff --git a/tools/dom/templates/html/impl/impl_Touch.darttemplate b/tools/dom/templates/html/impl/impl_Touch.darttemplate
index 889485d..a23e2f5 100644
--- a/tools/dom/templates/html/impl/impl_Touch.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Touch.darttemplate
@@ -32,15 +32,15 @@
@DomName('Touch.clientX')
@DomName('Touch.clientY')
- Point get client => new Point(__clientX, __clientY);
+ Point get client => new Point/*<num>*/(__clientX, __clientY);
@DomName('Touch.pageX')
@DomName('Touch.pageY')
- Point get page => new Point(__pageX, __pageY);
+ Point get page => new Point/*<num>*/(__pageX, __pageY);
@DomName('Touch.screenX')
@DomName('Touch.screenY')
- Point get screen => new Point(__screenX, __screenY);
+ Point get screen => new Point/*<num>*/(__screenX, __screenY);
@DomName('Touch.radiusX')
@DocsEditable()
diff --git a/tools/fuchsia_link.py b/tools/fuchsia_link.py
deleted file mode 100755
index 74936b0..0000000
--- a/tools/fuchsia_link.py
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2016 The Dart Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-This script performs the final link step for Fuchsia NDK executables.
-Usage:
-./fuchsia_link {arm,arm64,ia32} {executable,library,shared_library}
- {host,target} [linker args]
-"""
-
-import os
-import subprocess
-import sys
-
-# Figure out where we are.
-SCRIPT_DIR = os.path.dirname(sys.argv[0])
-DART_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..'))
-THIRD_PARTY_ROOT = os.path.join(DART_ROOT, 'third_party')
-
-
-def CheckDirExists(path, docstring):
- if not os.path.isdir(path):
- raise Exception('Could not find %s directory %s'
- % (docstring, path))
-
-
-def execute(args):
- process = subprocess.Popen(args)
- process.wait()
- return process.returncode
-
-
-def main():
- if len(sys.argv) < 5:
- raise Exception(sys.argv[0] + " failed: not enough arguments")
-
- # gyp puts -shared first in a shared_library link. Remove it.
- if sys.argv[1] == '-shared':
- sys.argv.remove('-shared')
-
- # Grab the command line arguments.
- target_arch = sys.argv[1]
- link_type = sys.argv[2]
- link_target = sys.argv[3]
- link_args = sys.argv[4:]
-
- # Check arguments.
- if target_arch not in ['arm64', 'x64',]:
- raise Exception(sys.argv[0] +
- " first argument must be 'arm64', or 'x64'")
- if link_type not in ['executable', 'library', 'shared_library']:
- raise Exception(sys.argv[0] +
- " second argument must be 'executable' or 'library' or 'shared_library'")
- if link_target not in ['host', 'target']:
- raise Exception(sys.argv[0] + " third argument must be 'host' or 'target'")
-
- # TODO(zra): Figure out how to link a shared library with the
- # cross-compilers. For now, we disable it by generating empty files
- # for the results. We disable it here to avoid inspecting the OS type in
- # the gyp files.
- if link_type == 'shared_library':
- print "NOT linking shared library for Fuchsia."
- o_index = link_args.index('-o')
- output = os.path.join(DART_ROOT, link_args[o_index + 1])
- open(output, 'a').close()
- sys.exit(0)
-
- # Set up path to the Fuchsia NDK.
- CheckDirExists(THIRD_PARTY_ROOT, 'third party tools')
- fuchsia_tools = os.path.join(THIRD_PARTY_ROOT, 'fuchsia_tools')
- CheckDirExists(fuchsia_tools, 'Fuchsia tools')
-
- # Set up the directory of the Fuchsia NDK cross-compiler toolchain.
- toolchain_arch = 'x86_64-elf-5.3.0-Linux-x86_64'
- if target_arch == 'arm64':
- toolchain_arch = 'aarch64-elf-5.3.0-Linux-x86_64'
- fuchsia_toolchain = os.path.join(
- fuchsia_tools, 'toolchains', toolchain_arch, 'bin')
- CheckDirExists(fuchsia_toolchain, 'Fuchsia toolchain')
-
- # Set up the path to the linker executable.
- fuchsia_linker = os.path.join(fuchsia_toolchain, 'x86_64-elf-g++')
- if target_arch == 'arm64':
- fuchsia_linker = os.path.join(fuchsia_toolchain, 'aarch64-elf-c++')
-
- # Grab the path to libgcc.a, which we must explicitly add to the link,
- # by invoking the cross-compiler with the -print-libgcc-file-name flag.
- fuchsia_gcc = os.path.join(fuchsia_toolchain, 'x86_64-elf-gcc')
- if target_arch == 'arm64':
- fuchsia_gcc = os.path.join(fuchsia_toolchain, 'aarch64-elf-gcc')
- fuchsia_libgcc = subprocess.check_output(
- [fuchsia_gcc, '-print-libgcc-file-name']).strip()
-
- # Set up the path to the system root directory, which is where we'll find the
- # Fuchsia specific system includes and libraries.
- fuchsia_sysroot = os.path.join(fuchsia_tools, 'sysroot', 'x86_64')
- if target_arch == 'arm64':
- fuchsia_sysroot = os.path.join(fuchsia_tools, 'sysroot', 'arm64')
- CheckDirExists(fuchsia_sysroot, 'Fuchsia sysroot')
- fuchsia_lib = os.path.join(fuchsia_sysroot, 'usr', 'lib')
- crtn_fuchsia = os.path.join(fuchsia_lib, 'crtn.o')
-
- if link_target == 'target':
- # Add and remove libraries as listed in configurations_fuchsia.gypi
- libs_to_rm = ['-lrt', '-lpthread']
- libs_to_add = [fuchsia_libgcc, '-lc', '-ldl', '-lm']
-
- # Add crtn_fuchsia to end if we are linking an executable.
- if link_type == 'executable':
- libs_to_add.extend([crtn_fuchsia])
-
- link_args = [i for i in link_args if i not in libs_to_rm]
- link_args.extend(libs_to_add)
-
- link_args.insert(0, fuchsia_linker)
- else:
- link_args.extend(['-ldl', '-lrt'])
- link_args.insert(0, 'g++')
-
- print ' '.join(link_args)
- sys.exit(execute(link_args))
-
-if __name__ == '__main__':
- main()
diff --git a/tools/gyp/configurations.gypi b/tools/gyp/configurations.gypi
index 267be04..29f457e 100644
--- a/tools/gyp/configurations.gypi
+++ b/tools/gyp/configurations.gypi
@@ -41,7 +41,6 @@
},
'includes': [
'configurations_android.gypi',
- 'configurations_fuchsia.gypi',
'configurations_make.gypi',
'configurations_xcode.gypi',
'configurations_msvs.gypi',
@@ -730,21 +729,6 @@
],
},
- # Fuchsia configurations. The configuration names explicitly include
- # 'Fuchsia' because we are cross-building from Linux, and, when building
- # the standalone VM, we cannot inspect the gyp built-in 'OS' variable to
- # figure out that we are building for Fuchsia. Since we have not re-run
- # gyp, it will still be 'linux'.
- 'ProductFuchsiaX64': {
- 'inherit_from': [
- 'Dart_Base', 'Dart_x64_Base', 'Dart_Product',
- 'Dart_Fuchsia_Base',
- 'Dart_Fuchsia_x64_Base',
- 'Dart_Fuchsia_Product',
- ],
- },
-
-
# Android configurations. The configuration names explicitly include
# 'Android' because we are cross-building from Linux, and, when building
# the standalone VM, we cannot inspect the gyp built-in 'OS' variable to
diff --git a/tools/gyp/configurations_fuchsia.gypi b/tools/gyp/configurations_fuchsia.gypi
deleted file mode 100644
index 5b291d3..0000000
--- a/tools/gyp/configurations_fuchsia.gypi
+++ /dev/null
@@ -1,152 +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.
-
-# Definitions for building standalone Dart binaries to run on Fuchsia.
-
-{
- 'variables': {
- 'fuchsia_tools': '<(PRODUCT_DIR)/../../third_party/fuchsia_tools/',
- }, # variables
- 'target_defaults': {
- 'configurations': {
- 'Dart_Fuchsia_Base': {
- 'abstract': 1,
- 'cflags': [
- '-Werror',
- '<@(common_gcc_warning_flags)',
- '-Wnon-virtual-dtor',
- '-Wvla',
- '-Woverloaded-virtual',
- '-g3',
- '-ggdb3',
- '-fno-rtti',
- '-fno-exceptions',
- '-fstack-protector',
- '-Wa,--noexecstack',
- ],
- 'target_conditions': [
- ['_toolset=="target"', {
- 'cflags!': [
- '-pthread', # Not supported by Android toolchain.
- ],
- }],
- ],
- },
- 'Dart_Fuchsia_Debug': {
- 'abstract': 1,
- 'defines': [
- 'DEBUG',
- ],
- 'cflags': [
- '-fno-omit-frame-pointer',
- ],
- },
- 'Dart_Fuchsia_Release': {
- 'abstract': 1,
- 'defines': [
- 'NDEBUG',
- ],
- 'cflags!': [
- '-O2',
- '-Os',
- ],
- 'cflags': [
- '-fno-omit-frame-pointer',
- '-fdata-sections',
- '-ffunction-sections',
- '-O3',
- ],
- },
- 'Dart_Fuchsia_Product': {
- 'abstract': 1,
- 'defines': [
- 'NDEBUG',
- 'PRODUCT',
- ],
- 'cflags!': [
- '-O2',
- '-Os',
- ],
- 'cflags': [
- '-fdata-sections',
- '-ffunction-sections',
- '-O3',
- ],
- },
- 'Dart_Fuchsia_x64_Base': {
- 'abstract': 1,
- 'variables': {
- 'fuchsia_sysroot': '<(fuchsia_tools)/sysroot/x86_64',
- 'fuchsia_include': '<(fuchsia_sysroot)/usr/include',
- 'fuchsia_lib': '<(fuchsia_sysroot)/usr/lib',
- },
- 'target_conditions': [
- ['_toolset=="target"', {
- 'defines': [
- 'TARGET_OS_FUCHSIA',
- ],
- 'cflags': [
- '--sysroot=<(fuchsia_sysroot)',
- '-I<(fuchsia_include)',
- '-fno-threadsafe-statics',
- ],
- 'ldflags': [
- 'x64', '>(_type)', 'target',
- '-nostdlib',
- '-T<(fuchsia_sysroot)/usr/user.ld',
- '-L<(fuchsia_lib)',
- '-Wl,-z,noexecstack',
- '-Wl,-z,now',
- '-Wl,-z,relro',
- '<(fuchsia_lib)/crt1.o',
- '<(fuchsia_lib)/crti.o',
- ],
- 'ldflags!': [
- '-pthread',
- ],
- }],
- ['_toolset=="host"', {
- 'cflags': [ '-pthread' ],
- 'ldflags': [ '-pthread' ],
- }],
- ],
- },
- 'Dart_Fuchsia_arm64_Base': {
- 'abstract': 1,
- 'variables': {
- 'fuchsia_sysroot': '<(fuchsia_tools)/sysroot/arm64',
- 'fuchsia_include': '<(fuchsia_sysroot)/usr/include',
- 'fuchsia_lib': '<(fuchsia_sysroot)/usr/lib',
- },
- 'target_conditions': [
- ['_toolset=="target"', {
- 'defines': [
- 'TARGET_OS_FUCHSIA',
- ],
- 'cflags': [
- '--sysroot=<(fuchsia_sysroot)',
- '-I<(fuchsia_include)',
- '-fno-threadsafe-statics',
- ],
- 'ldflags': [
- 'arm64', '>(_type)', 'target',
- '-nostdlib',
- '-L<(fuchsia_lib)',
- '-Wl,-z,noexecstack',
- '-Wl,-z,now',
- '-Wl,-z,relro',
- ],
- 'ldflags!': [
- '-pthread',
- ],
- }],
- ['_toolset=="host"', {
- 'cflags': [ '-pthread' ],
- 'ldflags': [ '-pthread' ],
- }],
- ],
- }, # Dart_Fuchsia_arm64_Base
- }, # configurations
- }, # target_defaults
-}
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 1747731..bf6db43 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -54,6 +54,7 @@
bool useCps = configuration['cps_ir'];
bool useBlobs = configuration['use_blobs'];
bool hotReload = configuration['hot_reload'];
+ bool hotReloadRollback = configuration['hot_reload_rollback'];
switch (compiler) {
case 'dart2analyzer':
@@ -91,7 +92,8 @@
isChecked: isChecked,
isHostChecked: isHostChecked,
useSdk: useSdk,
- hotReload: hotReload);
+ hotReload: hotReload,
+ hotReloadRollback: hotReloadRollback);
default:
throw "Unknown compiler '$compiler'";
}
@@ -152,16 +154,19 @@
/// The "none" compiler.
class NoneCompilerConfiguration extends CompilerConfiguration {
final bool hotReload;
+ final bool hotReloadRollback;
NoneCompilerConfiguration(
{bool isDebug, bool isChecked, bool isHostChecked, bool useSdk,
- bool hotReload})
+ bool hotReload,
+ bool hotReloadRollback})
: super._subclass(
isDebug: isDebug,
isChecked: isChecked,
isHostChecked: isHostChecked,
useSdk: useSdk),
- this.hotReload = hotReload;
+ this.hotReload = hotReload,
+ this.hotReloadRollback = hotReloadRollback;
bool get hasCompiler => false;
@@ -180,6 +185,8 @@
}
if (hotReload) {
args.add('--hot-reload-test-mode');
+ } else if (hotReloadRollback) {
+ args.add('--hot-reload-rollback-test-mode');
}
return args
..addAll(vmOptions)
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 8c10e10..8983cc5 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -70,7 +70,7 @@
RuntimeConfiguration._subclass();
int computeTimeoutMultiplier(
- {String mode, bool isChecked: false, String arch}) {
+ {String mode, bool isChecked: false, bool isReload: false, String arch}) {
return 1;
}
@@ -164,7 +164,7 @@
DartVmRuntimeConfiguration() : super._subclass();
int computeTimeoutMultiplier(
- {String mode, bool isChecked: false, String arch}) {
+ {String mode, bool isChecked: false, bool isReload: false, String arch}) {
int multiplier = 1;
switch (arch) {
case 'simarm':
@@ -183,6 +183,9 @@
}
if (mode == 'debug') {
multiplier *= 2;
+ if (isReload) {
+ multiplier *= 2;
+ }
}
return multiplier;
}
@@ -192,13 +195,14 @@
/// program named Dump Render Tree, hence the name.
class DrtRuntimeConfiguration extends DartVmRuntimeConfiguration {
int computeTimeoutMultiplier(
- {String mode, bool isChecked: false, String arch}) {
+ {String mode, bool isChecked: false, bool isReload: false, String arch}) {
return 4 // Allow additional time for browser testing to run.
// TODO(ahe): We might need to distinquish between DRT for running
// JavaScript and Dart code. I'm not convinced the inherited timeout
// multiplier is relevant for JavaScript.
*
- super.computeTimeoutMultiplier(mode: mode, isChecked: isChecked);
+ super.computeTimeoutMultiplier(
+ mode: mode, isChecked: isChecked, isReload: isReload);
}
}
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index ee9c107..6f76125 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -190,6 +190,11 @@
'hot_reload', 'Run hot reload stress tests', ['--hot-reload'], [],
false, type: 'bool'),
new _TestOptionSpecification(
+ 'hot_reload_rollback',
+ 'Run hot reload rollback stress tests', ['--hot-reload-rollback'],
+ [],
+ false, type: 'bool'),
+ new _TestOptionSpecification(
'use_blobs',
'Use mmap instead of shared libraries for precompilation',
['--use-blobs'], [], false, type: 'bool'),
@@ -819,12 +824,15 @@
// Adjust default timeout based on mode, compiler, and sometimes runtime.
if (configuration['timeout'] == -1) {
+ var isReload = configuration['hot_reload'] ||
+ configuration['hot_reload_rollback'];
int compilerMulitiplier =
new CompilerConfiguration(configuration).computeTimeoutMultiplier();
int runtimeMultiplier = new RuntimeConfiguration(configuration)
.computeTimeoutMultiplier(
mode: configuration['mode'],
isChecked: configuration['checked'],
+ isReload: isReload,
arch: configuration['arch']);
configuration['timeout'] = 60 * compilerMulitiplier * runtimeMultiplier;
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 5dfbd39..2c4b541 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -300,7 +300,7 @@
return;
}
- if (configuration['hot_reload']) {
+ if (configuration['hot_reload'] || configuration['hot_reload_rollback']) {
// Handle reload special cases.
if (expectations.contains(Expectation.COMPILETIME_ERROR)) {
// Running a test that expects a compilation error with hot reloading
@@ -850,7 +850,8 @@
buildDir,
suiteDir,
createTestCase,
- configuration['hot_reload']));
+ (configuration['hot_reload'] ||
+ configuration['hot_reload_rollback'])));
} else {
createTestCase(filePath, filePath, optionsFromFile['hasCompileError'],
optionsFromFile['hasRuntimeError'],
diff --git a/tools/update_ddc_dep.py b/tools/update_ddc_dep.py
new file mode 100755
index 0000000..d3a3979
--- /dev/null
+++ b/tools/update_ddc_dep.py
@@ -0,0 +1,135 @@
+#!/usr/bin/python
+
+# Update ddc dep automatically.
+
+import optparse
+import os
+import re
+from subprocess import Popen, PIPE
+import sys
+
+# Instructions:
+#
+# To run locally:
+# (a) Create and change to a directory to run the updater in:
+# mkdir /usr/local/google/home/$USER/ddc_deps_updater
+#
+# (b) Test by running (Ctrl-C to quit):
+# > ./update_ddc_deps.py
+#
+# (c) Run periodical update:
+# > while true; do ./update_ddc_deps.py --force ; sleep 300 ; done
+
+########################################################################
+# Actions
+########################################################################
+
+def write_file(filename, content):
+ f = open(filename, "w")
+ f.write(content)
+ f.close()
+
+def run_cmd(cmd):
+ print "\n[%s]\n$ %s" % (os.getcwd(), " ".join(cmd))
+ pipe = Popen(cmd, stdout=PIPE, stderr=PIPE)
+ output = pipe.communicate()
+ if pipe.returncode == 0:
+ return output[0]
+ else:
+ print output[1]
+ print "FAILED. RET_CODE=%d" % pipe.returncode
+ sys.exit(pipe.returncode)
+
+def main():
+ option_parser = optparse.OptionParser()
+ option_parser.add_option(
+ '',
+ '--force',
+ help="Push DEPS update to server without prompting",
+ action="store_true",
+ dest="force")
+ options, args = option_parser.parse_args()
+
+ target = 'ddc'
+ repo = 'dev_compiler'
+ repo_name = 'git@github.com:dart-lang/sdk.git'
+ ddc_repo_name = 'git@github.com:dart-lang/%s.git' % (repo)
+ repo_branch = 'origin/master'
+ repo_branch_parts = repo_branch.split('/')
+
+ root_dir = "/usr/local/google/home/%s/ddc_deps_updater" % (os.environ["USER"])
+ src_dir = "%s/sdk" % (root_dir)
+ ddc_dir = "%s/%s" % (root_dir, repo)
+ deps_file = src_dir + '/DEPS'
+
+ os.putenv("GIT_PAGER", "")
+
+ if not os.path.exists(src_dir):
+ print run_cmd(['git', 'clone', repo_name])
+
+ if not os.path.exists(ddc_dir):
+ print run_cmd(['git', 'clone', ddc_repo_name])
+
+ os.chdir(ddc_dir)
+ run_cmd(['git', 'fetch'])
+
+ os.chdir(src_dir)
+ run_cmd(['git', 'fetch'])
+ run_cmd(['git', 'stash'])
+ run_cmd(['git', 'checkout', '-B', repo_branch_parts[1], repo_branch])
+
+ # parse DEPS
+ deps = run_cmd(['cat', deps_file])
+ rev_num = {}
+ revision = '%s_rev":\s*"@(.+)"' % (repo)
+ rev_num = re.search(revision, deps).group(1)
+
+ # update repos
+ all_revs = []
+ os.chdir(ddc_dir)
+
+ output = run_cmd(["git", "log", "--pretty=%H", "%s..HEAD" % (rev_num),
+ "origin/master"])
+ commits = output.split('\n')
+ if not commits or len(commits[0]) < 10:
+ print "DEPS is up-to-date."
+ sys.exit(0)
+
+ revision = commits[0]
+
+ history = run_cmd(["git", "log", "--format=short", "%s..HEAD" % (rev_num),
+ "origin/master"])
+
+ print "Pending DEPS update: %s" % (revision)
+
+ # make the next DEPS update
+ os.chdir(src_dir)
+ run_cmd(['rm', deps_file])
+
+ pattern = re.compile('%s_rev":\s*"@(.+)"' % (repo))
+ new_deps = pattern.sub('%s_rev": "@%s"' % (repo, revision), deps)
+ write_file(deps_file, new_deps)
+
+ commit_log = 'DEPS AutoUpdate: %s\n\n' % (repo)
+ commit_log += history
+
+ write_file('commit_log.txt', commit_log)
+ run_cmd(['git', 'add', deps_file])
+
+ print run_cmd(['git', 'diff', 'HEAD'])
+ print
+ print "Commit log:"
+ print "---------------------------------------------"
+ print commit_log
+ print "---------------------------------------------"
+
+ if not options.force:
+ print "Ready to push; press Enter to continue or Control-C to abort..."
+ sys.stdin.readline()
+ print run_cmd(['git', 'commit', '-F', 'commit_log.txt'])
+ print run_cmd(['git', 'push', repo_branch_parts[0], repo_branch_parts[1]])
+ print "Done."
+
+
+if '__main__' == __name__:
+ main()
diff --git a/tools/utils.py b/tools/utils.py
index 496b499..0611bdd 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -268,7 +268,7 @@
(target_os != GuessOS()))
def GetBuildConf(mode, arch, conf_os=None):
- if conf_os == 'android' or conf_os == 'fuchsia':
+ if conf_os == 'android':
return '%s%s%s' % (GetBuildMode(mode), conf_os.title(), arch.upper())
else:
# Ask for a cross build if the host and target architectures don't match.