Version 1.21.0-dev.9.0
Merge commit 'f6fbc40423a146ee378e52dacbc6e3a75f06ec89' into dev
diff --git a/DEPS b/DEPS
index 9aef0a8..97e943b 100644
--- a/DEPS
+++ b/DEPS
@@ -73,8 +73,8 @@
"isolate_tag": "@0.2.3",
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "@2.0.2",
- "kernel_rev": "@11edd6208940d227dc0b2cf87a6518d2508c0858",
- "linter_tag": "@0.1.28",
+ "kernel_rev": "@8e2b2c03c2a22d9fdf581a8e3ce798f189531081",
+ "linter_tag": "@0.1.29",
"logging_tag": "@0.11.3+1",
"markdown_tag": "@0.11.0",
"matcher_tag": "@0.12.0+2",
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index c0df56e..6bad443 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -107,14 +107,11 @@
if (server.searchEngine == null) {
return new Response.noIndexGenerated(request);
}
- runZoned(() {
- try {
- String requestName = request.method;
- if (requestName == COMPLETION_GET_SUGGESTIONS) {
- processRequest(request);
- }
- } on RequestFailure catch (exception) {
- return exception.response;
+ return runZoned(() {
+ String requestName = request.method;
+ if (requestName == COMPLETION_GET_SUGGESTIONS) {
+ processRequest(request);
+ return Response.DELAYED_RESPONSE;
}
return null;
}, onError: (exception, stackTrace) {
@@ -123,7 +120,6 @@
exception,
stackTrace);
});
- return Response.DELAYED_RESPONSE;
}
/**
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index e6607ca..3b61ade 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -52,23 +52,22 @@
}
/**
- * Adds [edit] to the [FileEdit] for the given [element].
+ * Adds [edit] to the file containing the given [element].
*/
void doSourceChange_addElementEdit(
SourceChange change, engine.Element element, SourceEdit edit) {
- engine.AnalysisContext context = element.context;
engine.Source source = element.source;
- doSourceChange_addSourceEdit(change, context, source, edit);
+ doSourceChange_addSourceEdit(change, source, edit);
}
/**
- * Adds [edit] to the [FileEdit] for the given [source].
+ * Adds [edit] for the given [source] to the [change].
*/
-void doSourceChange_addSourceEdit(SourceChange change,
- engine.AnalysisContext context, engine.Source source, SourceEdit edit) {
+void doSourceChange_addSourceEdit(
+ SourceChange change, engine.Source source, SourceEdit edit,
+ {bool isNewFile: false}) {
String file = source.fullName;
- int fileStamp = context.getModificationStamp(source);
- change.addEdit(file, fileStamp, edit);
+ change.addEdit(file, isNewFile ? -1 : 0, edit);
}
String getReturnTypeString(engine.Element element) {
diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart
index 399ea8b..63d5280 100644
--- a/pkg/analysis_server/lib/src/search/element_references.dart
+++ b/pkg/analysis_server/lib/src/search/element_references.dart
@@ -10,6 +10,7 @@
show SearchResult, newSearchResult_fromMatch;
import 'package:analysis_server/src/services/search/hierarchy.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -92,7 +93,7 @@
SearchResult _newDeclarationResult(Element refElement) {
int nameOffset = refElement.nameOffset;
int nameLength = refElement.nameLength;
- SearchMatch searchMatch = new SearchMatch(
+ SearchMatch searchMatch = new SearchMatchImpl(
refElement.context,
refElement.library.source.uri.toString(),
refElement.source.uri.toString(),
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 051ae23..f813e78 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -393,7 +393,7 @@
analysisServerOptions.enablePubSummaryManager =
results[ENABLE_PUB_SUMMARY_MANAGER];
analysisServerOptions.finerGrainedInvalidation =
- true /*results[FINER_GRAINED_INVALIDATION]*/;
+ results[FINER_GRAINED_INVALIDATION];
analysisServerOptions.noErrorNotification = results[NO_ERROR_NOTIFICATION];
analysisServerOptions.noIndex = results[NO_INDEX];
analysisServerOptions.useAnalysisHighlight2 =
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 1a99f8f..1a886be 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1216,7 +1216,7 @@
if (isAbsolute(file) && AnalysisEngine.isDartFileName(file)) {
String libName = _computeLibraryName(file);
SourceEdit edit = new SourceEdit(0, 0, 'library $libName;$eol$eol');
- doSourceChange_addSourceEdit(change, context, source, edit);
+ doSourceChange_addSourceEdit(change, source, edit, isNewFile: true);
_addFix(DartFixKind.CREATE_FILE, [source.shortName]);
}
}
@@ -1435,7 +1435,7 @@
if (source != null) {
String libName = unitLibraryElement.name;
SourceEdit edit = new SourceEdit(0, 0, 'part of $libName;$eol$eol');
- doSourceChange_addSourceEdit(change, context, source, edit);
+ doSourceChange_addSourceEdit(change, source, edit, isNewFile: true);
_addFix(DartFixKind.CREATE_FILE, [source.shortName]);
}
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
index 17fdb68..7e18c6b 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
@@ -12,7 +12,6 @@
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/source.dart';
/**
@@ -68,8 +67,6 @@
SourceReference(this._match);
- AnalysisContext get context => _match.context;
-
Element get element => _match.element;
/**
@@ -106,7 +103,7 @@
*/
void addEdit(SourceChange change, String newText, {String id}) {
SourceEdit edit = createEdit(newText, id: id);
- doSourceChange_addSourceEdit(change, context, unitSource, edit);
+ doSourceChange_addSourceEdit(change, unitSource, edit);
}
/**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
index 80fd4b1..cb9d88d 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -16,6 +16,7 @@
import 'package:analysis_server/src/services/refactoring/rename.dart';
import 'package:analysis_server/src/services/search/hierarchy.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -96,7 +97,7 @@
} else {
sourceRange = rangeStartLength(element.nameEnd, 0);
}
- return new SourceReference(new SearchMatch(
+ return new SourceReference(new SearchMatchImpl(
element.context,
element.library.source.uri.toString(),
element.source.uri.toString(),
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine.dart b/pkg/analysis_server/lib/src/services/search/search_engine.dart
index 9f283fc..6ea3395 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine.dart
@@ -7,11 +7,7 @@
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/visitor.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
/**
* Instances of the enum [MatchKind] represent the kind of reference that was
@@ -110,138 +106,53 @@
* Instances of the class [SearchMatch] represent a match found by
* [SearchEngine].
*/
-class SearchMatch {
- /**
- * The [AnalysisContext] containing the match.
- */
- final AnalysisContext context;
-
- /**
- * The URI of the source of the library containing the match.
- */
- final String libraryUri;
-
- /**
- * The URI of the source of the unit containing the match.
- */
- final String unitUri;
-
- /**
- * The kind of the match.
- */
- final MatchKind kind;
-
- /**
- * The source range that was matched.
- */
- final SourceRange sourceRange;
-
- /**
- * Is `true` if the match is a resolved reference to some [Element].
- */
- final bool isResolved;
-
- /**
- * Is `true` if field or method access is done using qualifier.
- */
- final bool isQualified;
-
- Source _librarySource;
- Source _unitSource;
- LibraryElement _libraryElement;
- Element _element;
-
- SearchMatch(this.context, this.libraryUri, this.unitUri, this.kind,
- this.sourceRange, this.isResolved, this.isQualified);
-
+abstract class SearchMatch {
/**
* Return the [Element] containing the match. Can return `null` if the unit
* does not exist, or its element was invalidated, or the element cannot be
* found, etc.
*/
- Element get element {
- if (_element == null) {
- CompilationUnitElement unitElement =
- context.getCompilationUnitElement(unitSource, librarySource);
- if (unitElement != null) {
- _ContainingElementFinder finder =
- new _ContainingElementFinder(sourceRange.offset);
- unitElement.accept(finder);
- _element = finder.containingElement;
- }
- }
- return _element;
- }
+ Element get element;
/**
* The absolute path of the file containing the match.
*/
- String get file => unitSource.fullName;
+ String get file;
- @override
- int get hashCode {
- return JenkinsSmiHash.hash4(libraryUri.hashCode, unitUri.hashCode,
- kind.hashCode, sourceRange.hashCode);
- }
+ /**
+ * Is `true` if field or method access is done using qualifier.
+ */
+ bool get isQualified;
+
+ /**
+ * Is `true` if the match is a resolved reference to some [Element].
+ */
+ bool get isResolved;
+
+ /**
+ * The kind of the match.
+ */
+ MatchKind get kind;
/**
* Return the [LibraryElement] for the [libraryUri] in the [context].
*/
- LibraryElement get libraryElement {
- _libraryElement ??= context.getLibraryElement(librarySource);
- return _libraryElement;
- }
+ LibraryElement get libraryElement;
/**
* The library [Source] of the reference.
*/
- Source get librarySource {
- _librarySource ??= context.sourceFactory.forUri(libraryUri);
- return _librarySource;
- }
+ Source get librarySource;
+
+ /**
+ * The source range that was matched.
+ */
+ SourceRange get sourceRange;
/**
* The unit [Source] of the reference.
*/
- Source get unitSource {
- _unitSource ??= context.sourceFactory.forUri(unitUri);
- return _unitSource;
- }
-
- @override
- bool operator ==(Object object) {
- if (identical(object, this)) {
- return true;
- }
- if (object is SearchMatch) {
- return kind == object.kind &&
- libraryUri == object.libraryUri &&
- unitUri == object.unitUri &&
- isResolved == object.isResolved &&
- isQualified == object.isQualified &&
- sourceRange == object.sourceRange;
- }
- return false;
- }
-
- @override
- String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.write("SearchMatch(kind=");
- buffer.write(kind);
- buffer.write(", libraryUri=");
- buffer.write(libraryUri);
- buffer.write(", unitUri=");
- buffer.write(unitUri);
- buffer.write(", range=");
- buffer.write(sourceRange);
- buffer.write(", isResolved=");
- buffer.write(isResolved);
- buffer.write(", isQualified=");
- buffer.write(isQualified);
- buffer.write(")");
- return buffer.toString();
- }
+ Source get unitSource;
/**
* Return elements of [matches] which has not-null elements.
@@ -253,24 +164,3 @@
return matches.where((match) => match.element != null).toList();
}
}
-
-/**
- * A visitor that finds the deep-most [Element] that contains the [offset].
- */
-class _ContainingElementFinder extends GeneralizingElementVisitor {
- final int offset;
- Element containingElement;
-
- _ContainingElementFinder(this.offset);
-
- visitElement(Element element) {
- if (element is ElementImpl) {
- if (element.codeOffset != null &&
- element.codeOffset <= offset &&
- offset <= element.codeOffset + element.codeLength) {
- containingElement = element;
- super.visitElement(element);
- }
- }
- }
-}
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 5b2b6e3..cdd6a91 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
@@ -12,10 +12,13 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/resolver.dart' show NamespaceBuilder;
import 'package:analyzer/src/generated/source.dart' show Source, SourceRange;
+import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/summary/idl.dart';
/**
@@ -127,7 +130,7 @@
throw new ArgumentError('Unsupported relation kind $relationKind');
}
}
- return new SearchMatch(
+ return new SearchMatchImpl(
location.context,
location.libraryUri,
location.unitUri,
@@ -234,7 +237,7 @@
for (Directive directive in unit.directives) {
if (directive is PartOfDirective &&
directive.element == libraryElement) {
- matches.add(new SearchMatch(
+ matches.add(new SearchMatchImpl(
context,
librarySource.uri.toString(),
unitSource.uri.toString(),
@@ -288,6 +291,174 @@
}
/**
+ * Implementation of [SearchMatch].
+ */
+class SearchMatchImpl implements SearchMatch {
+ /**
+ * The [AnalysisContext] containing the match.
+ */
+ final AnalysisContext _context;
+
+ /**
+ * The URI of the source of the library containing the match.
+ */
+ final String libraryUri;
+
+ /**
+ * The URI of the source of the unit containing the match.
+ */
+ final String unitUri;
+
+ /**
+ * The kind of the match.
+ */
+ final MatchKind kind;
+
+ /**
+ * The source range that was matched.
+ */
+ final SourceRange sourceRange;
+
+ /**
+ * Is `true` if the match is a resolved reference to some [Element].
+ */
+ final bool isResolved;
+
+ /**
+ * Is `true` if field or method access is done using qualifier.
+ */
+ final bool isQualified;
+
+ Source _librarySource;
+ Source _unitSource;
+ LibraryElement _libraryElement;
+ Element _element;
+
+ SearchMatchImpl(this._context, this.libraryUri, this.unitUri, this.kind,
+ this.sourceRange, this.isResolved, this.isQualified);
+
+ /**
+ * Return the [Element] containing the match. Can return `null` if the unit
+ * does not exist, or its element was invalidated, or the element cannot be
+ * found, etc.
+ */
+ Element get element {
+ if (_element == null) {
+ CompilationUnitElement unitElement =
+ _context.getCompilationUnitElement(unitSource, librarySource);
+ if (unitElement != null) {
+ _ContainingElementFinder finder =
+ new _ContainingElementFinder(sourceRange.offset);
+ unitElement.accept(finder);
+ _element = finder.containingElement;
+ }
+ }
+ return _element;
+ }
+
+ /**
+ * The absolute path of the file containing the match.
+ */
+ String get file => unitSource.fullName;
+
+ @override
+ int get hashCode {
+ return JenkinsSmiHash.hash4(libraryUri.hashCode, unitUri.hashCode,
+ kind.hashCode, sourceRange.hashCode);
+ }
+
+ /**
+ * Return the [LibraryElement] for the [libraryUri] in the [context].
+ */
+ LibraryElement get libraryElement {
+ _libraryElement ??= _context.getLibraryElement(librarySource);
+ return _libraryElement;
+ }
+
+ /**
+ * The library [Source] of the reference.
+ */
+ Source get librarySource {
+ _librarySource ??= _context.sourceFactory.forUri(libraryUri);
+ return _librarySource;
+ }
+
+ /**
+ * The unit [Source] of the reference.
+ */
+ Source get unitSource {
+ _unitSource ??= _context.sourceFactory.forUri(unitUri);
+ return _unitSource;
+ }
+
+ @override
+ bool operator ==(Object object) {
+ if (identical(object, this)) {
+ return true;
+ }
+ if (object is SearchMatchImpl) {
+ return kind == object.kind &&
+ libraryUri == object.libraryUri &&
+ unitUri == object.unitUri &&
+ isResolved == object.isResolved &&
+ isQualified == object.isQualified &&
+ sourceRange == object.sourceRange;
+ }
+ return false;
+ }
+
+ @override
+ String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.write("SearchMatch(kind=");
+ buffer.write(kind);
+ buffer.write(", libraryUri=");
+ buffer.write(libraryUri);
+ buffer.write(", unitUri=");
+ buffer.write(unitUri);
+ buffer.write(", range=");
+ buffer.write(sourceRange);
+ buffer.write(", isResolved=");
+ buffer.write(isResolved);
+ buffer.write(", isQualified=");
+ buffer.write(isQualified);
+ buffer.write(")");
+ return buffer.toString();
+ }
+
+ /**
+ * Return elements of [matches] which has not-null elements.
+ *
+ * When [SearchMatch.element] is not `null` we cache its value, so it cannot
+ * become `null` later.
+ */
+ static List<SearchMatch> withNotNullElement(List<SearchMatch> matches) {
+ return matches.where((match) => match.element != null).toList();
+ }
+}
+
+/**
+ * A visitor that finds the deep-most [Element] that contains the [offset].
+ */
+class _ContainingElementFinder extends GeneralizingElementVisitor {
+ final int offset;
+ Element containingElement;
+
+ _ContainingElementFinder(this.offset);
+
+ visitElement(Element element) {
+ if (element is ElementImpl) {
+ if (element.codeOffset != null &&
+ element.codeOffset <= offset &&
+ offset <= element.codeOffset + element.codeLength) {
+ containingElement = element;
+ super.visitElement(element);
+ }
+ }
+ }
+}
+
+/**
* Visitor that adds [SearchMatch]es for [importElement], both with an explicit
* prefix or an implicit one.
*/
@@ -350,7 +521,7 @@
}
void _addMatchForRange(SourceRange range) {
- matches.add(new SearchMatch(
+ matches.add(new SearchMatchImpl(
context, libraryUri, unitUri, MatchKind.REFERENCE, range, true, false));
}
}
@@ -407,7 +578,7 @@
void _addMatch(AstNode node, MatchKind kind) {
bool isQualified = node.parent is Label;
- matches.add(new SearchMatch(context, libraryUri, unitUri, kind,
+ matches.add(new SearchMatchImpl(context, libraryUri, unitUri, kind,
rangeNode(node), true, isQualified));
}
}
diff --git a/pkg/analysis_server/test/services/correction/status_test.dart b/pkg/analysis_server/test/services/correction/status_test.dart
index 9e60de9..9c9169e 100644
--- a/pkg/analysis_server/test/services/correction/status_test.dart
+++ b/pkg/analysis_server/test/services/correction/status_test.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/services/correction/source_range.dart';
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -41,7 +42,7 @@
resolveTestUnit('class MyClass {}');
Element element = findElement('MyClass');
SourceRange range = rangeElementName(element);
- SearchMatch match = new SearchMatch(
+ SearchMatch match = new SearchMatchImpl(
context,
element.library.source.uri.toString(),
element.source.uri.toString(),
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 7486496b..0a43fa5 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -13,6 +13,8 @@
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/index.dart';
+import 'package:analyzer/src/dart/analysis/search.dart';
import 'package:analyzer/src/dart/analysis/status.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisEngine, AnalysisOptions, ChangeSet;
@@ -67,7 +69,7 @@
/**
* The version of data format, should be incremented on every format change.
*/
- static const int DATA_VERSION = 5;
+ static const int DATA_VERSION = 7;
/**
* The name of the driver, e.g. the name of the folder.
@@ -176,16 +178,16 @@
final _resultController = new StreamController<AnalysisResult>();
/**
- * Mapping from library URIs to the dependency signature of the library.
- */
- final _dependencySignatureMap = <Uri, String>{};
-
- /**
* The instance of the status helper.
*/
final StatusSupport _statusSupport = new StatusSupport();
/**
+ * The instance of the [Search] helper.
+ */
+ Search _search;
+
+ /**
* Create a new instance of [AnalysisDriver].
*
* The given [SourceFactory] is cloned to ensure that it does not contain a
@@ -202,9 +204,17 @@
: _sourceFactory = sourceFactory.clone() {
_fillSalt();
_sdkBundle = sourceFactory.dartSdk.getLinkedBundle();
- _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay,
- _resourceProvider, _sourceFactory, _analysisOptions, _salt);
+ _fsState = new FileSystemState(
+ _logger,
+ _byteStore,
+ _contentOverlay,
+ _resourceProvider,
+ _sourceFactory,
+ _analysisOptions,
+ _salt,
+ _sdkBundle.apiSignature);
_scheduler._add(this);
+ _search = new Search(this);
}
/**
@@ -258,6 +268,11 @@
Stream<AnalysisResult> get results => _resultController.stream;
/**
+ * Return the search support for the driver.
+ */
+ Search get search => _search;
+
+ /**
* Return the stream that produces [AnalysisStatus] events.
*/
Stream<AnalysisStatus> get status => _statusSupport.stream;
@@ -472,9 +487,9 @@
}
// Check for the cached result.
- AnalysisResult result = _getCachedAnalysisResult(file, key);
- if (result != null) {
- return result;
+ List<int> bytes = _byteStore.get(key);
+ if (bytes != null) {
+ return _getAnalysisResultFromBytes(file, bytes);
}
}
@@ -492,16 +507,15 @@
AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
try {
analysisContext.setContents(file.source, file.content);
- // TODO(scheglov) Add support for parts.
- CompilationUnit resolvedUnit = withUnit
- ? analysisContext.resolveCompilationUnit2(
- file.source, libraryFile.source)
- : null;
+ CompilationUnit resolvedUnit = analysisContext.resolveCompilationUnit2(
+ file.source, libraryFile.source);
List<AnalysisError> errors = analysisContext.computeErrors(file.source);
+ AnalysisDriverUnitIndexBuilder index = indexUnit(resolvedUnit);
// Store the result into the cache.
+ List<int> bytes;
{
- List<int> bytes = new AnalysisDriverResolvedUnitBuilder(
+ bytes = new AnalysisDriverResolvedUnitBuilder(
errors: errors
.map((error) => new AnalysisDriverUnitErrorBuilder(
offset: error.offset,
@@ -509,7 +523,8 @@
uniqueName: error.errorCode.uniqueName,
message: error.message,
correction: error.correction))
- .toList())
+ .toList(),
+ index: index)
.toBuffer();
String key = _getResolvedUnitKey(libraryFile, file);
_byteStore.put(key, bytes);
@@ -517,15 +532,9 @@
// Return the result, full or partial.
_logger.writeln('Computed new analysis result.');
- return new AnalysisResult(
- _sourceFactory,
- file.path,
- file.uri,
- withUnit ? file.content : null,
- file.contentHash,
- file.lineInfo,
- resolvedUnit,
- errors);
+ return _getAnalysisResultFromBytes(file, bytes,
+ content: withUnit ? file.content : null,
+ resolvedUnit: withUnit ? resolvedUnit : null);
} finally {
analysisContext.dispose();
}
@@ -659,26 +668,23 @@
}
/**
- * If we know the result [key] for the [file], try to load the analysis
- * result from the cache. Return `null` if not found.
+ * Load the [AnalysisResult] for the given [file] from the [bytes]. Set
+ * optional [content] and [resolvedUnit].
*/
- AnalysisResult _getCachedAnalysisResult(FileState file, String key) {
- List<int> bytes = _byteStore.get(key);
- if (bytes != null) {
- var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
- List<AnalysisError> errors = unit.errors
- .map((error) => new AnalysisError.forValues(
- file.source,
- error.offset,
- error.length,
- errorCodeByUniqueName(error.uniqueName),
- error.message,
- error.correction))
- .toList();
- return new AnalysisResult(_sourceFactory, file.path, file.uri, null,
- file.contentHash, file.lineInfo, null, errors);
- }
- return null;
+ AnalysisResult _getAnalysisResultFromBytes(FileState file, List<int> bytes,
+ {String content, CompilationUnit resolvedUnit}) {
+ var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
+ List<AnalysisError> errors = unit.errors
+ .map((error) => new AnalysisError.forValues(
+ file.source,
+ error.offset,
+ error.length,
+ errorCodeByUniqueName(error.uniqueName),
+ error.message,
+ error.correction))
+ .toList();
+ return new AnalysisResult(_sourceFactory, file.path, file.uri, content,
+ file.contentHash, file.lineInfo, resolvedUnit, errors, unit.index);
}
/**
@@ -687,15 +693,11 @@
* not known yet.
*/
String _getResolvedUnitKey(FileState library, FileState file) {
- String dependencyHash = _dependencySignatureMap[library.uri];
- if (dependencyHash != null) {
- ApiSignature signature = new ApiSignature();
- signature.addUint32List(_salt);
- signature.addString(dependencyHash);
- signature.addString(file.contentHash);
- return '${signature.toHex()}.resolved';
- }
- return null;
+ ApiSignature signature = new ApiSignature();
+ signature.addUint32List(_salt);
+ signature.addString(library.transitiveSignature);
+ signature.addString(file.contentHash);
+ return '${signature.toHex()}.resolved';
}
/**
@@ -799,7 +801,7 @@
}
if (anyApiChanged) {
_logger.writeln('API signatures mismatch found for $path');
- _dependencySignatureMap.clear();
+ // TODO(scheglov) schedule analysis of only affected files
_filesToAnalyze.addAll(_explicitFiles);
}
return files[0];
@@ -999,8 +1001,13 @@
*/
final List<AnalysisError> errors;
+ /**
+ * The index of the unit.
+ */
+ final AnalysisDriverUnitIndex index;
+
AnalysisResult(this.sourceFactory, this.path, this.uri, this.content,
- this.contentHash, this.lineInfo, this.unit, this.errors);
+ this.contentHash, this.lineInfo, this.unit, this.errors, this.index);
}
/**
@@ -1139,26 +1146,10 @@
final FileState file;
final Uri uri;
- String _dependencySignature;
-
_LibraryNode(this.driver, this.file, this.uri);
String get dependencySignature {
- return _dependencySignature ??=
- driver._dependencySignatureMap.putIfAbsent(uri, () {
- ApiSignature signature = new ApiSignature();
- signature.addUint32List(driver._salt);
- signature.addString(driver._sdkBundle.apiSignature);
-
- // Add all unlinked API signatures.
- file.transitiveFiles
- .map((file) => file.apiSignature)
- .forEach(signature.addBytes);
-
- // Combine into a single hash.
- signature.addString(uri.toString());
- return signature.toHex();
- });
+ return file.transitiveSignature;
}
@override
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index da38aca..3540d69 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/referenced_names.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -85,6 +86,7 @@
String _content;
String _contentHash;
LineInfo _lineInfo;
+ Set<String> _referencedNames;
UnlinkedUnit _unlinked;
List<int> _apiSignature;
@@ -93,6 +95,7 @@
List<FileState> _partedFiles;
Set<FileState> _directReferencedFiles = new Set<FileState>();
Set<FileState> _transitiveFiles;
+ String _transitiveSignature;
FileState._(this._fsState, this.path, this.uri, this.source);
@@ -160,6 +163,11 @@
List<FileState> get partedFiles => _partedFiles;
/**
+ * The external names referenced by the file.
+ */
+ Set<String> get referencedNames => _referencedNames;
+
+ /**
* Return the set of transitive files - the file itself and all of the
* directly or indirectly referenced files.
*/
@@ -179,6 +187,24 @@
}
/**
+ * Return the signature of the file, based on the [transitiveFiles].
+ */
+ String get transitiveSignature {
+ if (_transitiveSignature == null) {
+ ApiSignature signature = new ApiSignature();
+ signature.addUint32List(_fsState._salt);
+ signature.addString(_fsState._sdkApiSignature);
+ signature.addInt(transitiveFiles.length);
+ transitiveFiles
+ .map((file) => file.apiSignature)
+ .forEach(signature.addBytes);
+ signature.addString(uri.toString());
+ _transitiveSignature = signature.toHex();
+ }
+ return _transitiveSignature;
+ }
+
+ /**
* The [UnlinkedUnit] of the file.
*/
UnlinkedUnit get unlinked => _unlinked;
@@ -253,20 +279,35 @@
CompilationUnit unit = parse(AnalysisErrorListener.NULL_LISTENER);
_fsState._logger.run('Create unlinked for $path', () {
UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
- bytes = unlinkedUnit.toBuffer();
+ List<String> referencedNames = computeReferencedNames(unit).toList();
+ bytes = new AnalysisDriverUnlinkedUnitBuilder(
+ unit: unlinkedUnit, referencedNames: referencedNames)
+ .toBuffer();
_fsState._byteStore.put(unlinkedKey, bytes);
});
}
}
// Read the unlinked bundle.
- _unlinked = new UnlinkedUnit.fromBuffer(bytes);
+ var driverUnlinkedUnit = new AnalysisDriverUnlinkedUnit.fromBuffer(bytes);
+ _referencedNames = new Set<String>.from(driverUnlinkedUnit.referencedNames);
+ _unlinked = driverUnlinkedUnit.unit;
_lineInfo = new LineInfo(_unlinked.lineStarts);
List<int> newApiSignature = _unlinked.apiSignature;
bool apiSignatureChanged = _apiSignature != null &&
!_equalByteLists(_apiSignature, newApiSignature);
_apiSignature = newApiSignature;
+ // If the API signature changed, flush transitive signatures.
+ if (apiSignatureChanged) {
+ for (FileState file in _fsState._uriToFile.values) {
+ if (file._transitiveFiles != null &&
+ file._transitiveFiles.contains(this)) {
+ file._transitiveSignature = null;
+ }
+ }
+ }
+
// This file is potentially not a library for its previous parts anymore.
if (_partedFiles != null) {
for (FileState part in _partedFiles) {
@@ -382,6 +423,7 @@
final SourceFactory _sourceFactory;
final AnalysisOptions _analysisOptions;
final Uint32List _salt;
+ final String _sdkApiSignature;
/**
* Mapping from a URI to the corresponding [FileState].
@@ -412,7 +454,8 @@
this._resourceProvider,
this._sourceFactory,
this._analysisOptions,
- this._salt) {
+ this._salt,
+ this._sdkApiSignature) {
_testView = new FileSystemStateTestView(this);
}
@@ -502,9 +545,15 @@
FileSystemStateTestView(this.state);
- Set<FileState> get filesWithoutTransitive {
+ Set<FileState> get filesWithoutTransitiveFiles {
return state._uriToFile.values
.where((f) => f._transitiveFiles == null)
.toSet();
}
+
+ Set<FileState> get filesWithoutTransitiveSignature {
+ return state._uriToFile.values
+ .where((f) => f._transitiveSignature == null)
+ .toSet();
+ }
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
new file mode 100644
index 0000000..8191ca4
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -0,0 +1,800 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+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';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart'
+ show AnalysisDriverUnitIndexBuilder;
+import 'package:analyzer/src/summary/idl.dart';
+
+/**
+ * Return the [CompilationUnitElement] that should be used for [element].
+ * Throw [StateError] if the [element] is not linked into a unit.
+ */
+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 not contained in compilation unit: $element');
+}
+
+/**
+ * Index the [unit] into a new [AnalysisDriverUnitIndexBuilder].
+ */
+AnalysisDriverUnitIndexBuilder indexUnit(CompilationUnit unit) {
+ return new _IndexAssembler().assemble(unit);
+}
+
+/**
+ * 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 IndexElementInfo {
+ final Element element;
+ final IndexSyntheticElementKind kind;
+
+ factory IndexElementInfo(Element element) {
+ IndexSyntheticElementKind kind = IndexSyntheticElementKind.notSynthetic;
+ ElementKind elementKind = element.kind;
+ if (elementKind == ElementKind.LIBRARY ||
+ elementKind == ElementKind.COMPILATION_UNIT) {
+ kind = IndexSyntheticElementKind.unit;
+ } else if (element.isSynthetic) {
+ if (elementKind == ElementKind.CONSTRUCTOR) {
+ kind = IndexSyntheticElementKind.constructor;
+ element = element.enclosingElement;
+ } else if (elementKind == ElementKind.FUNCTION &&
+ element.name == 'loadLibrary') {
+ kind = IndexSyntheticElementKind.loadLibrary;
+ element = element.library;
+ } else if (elementKind == ElementKind.FIELD) {
+ FieldElement field = element;
+ kind = IndexSyntheticElementKind.field;
+ element = field.getter ?? field.setter;
+ } else if (elementKind == ElementKind.GETTER ||
+ elementKind == ElementKind.SETTER) {
+ PropertyAccessorElement accessor = element;
+ Element enclosing = element.enclosingElement;
+ bool isEnumGetter = enclosing is ClassElement && enclosing.isEnum;
+ if (isEnumGetter && accessor.name == 'index') {
+ kind = IndexSyntheticElementKind.enumIndex;
+ element = enclosing;
+ } else if (isEnumGetter && accessor.name == 'values') {
+ kind = IndexSyntheticElementKind.enumValues;
+ element = enclosing;
+ } else {
+ kind = accessor.isGetter
+ ? IndexSyntheticElementKind.getter
+ : IndexSyntheticElementKind.setter;
+ element = accessor.variable;
+ }
+ } else if (elementKind == ElementKind.TOP_LEVEL_VARIABLE) {
+ TopLevelVariableElement property = element;
+ kind = IndexSyntheticElementKind.topLevelVariable;
+ element = property.getter ?? property.setter;
+ } else {
+ throw new ArgumentError(
+ 'Unsupported synthetic element ${element.runtimeType}');
+ }
+ }
+ return new IndexElementInfo._(element, kind);
+ }
+
+ IndexElementInfo._(this.element, this.kind);
+}
+
+/**
+ * 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 in a single compilation unit.
+ */
+class _ElementRelationInfo {
+ final _ElementInfo elementInfo;
+ final IndexRelationKind kind;
+ final int offset;
+ final int length;
+ final bool isQualified;
+
+ _ElementRelationInfo(
+ this.elementInfo, this.kind, this.offset, this.length, this.isQualified);
+}
+
+/**
+ * Assembler of a single [CompilationUnit] index.
+ *
+ * The intended usage sequence:
+ *
+ * - Call [addElementRelation] for each element relation found in the unit.
+ * - Call [addNameRelation] for each name relation found in the unit.
+ * - Assign ids to all the [_ElementInfo] in [elementRelations].
+ * - Call [assemble] to produce the final unit index.
+ */
+class _IndexAssembler {
+ /**
+ * The string to use in place of the `null` string.
+ */
+ static const NULL_STRING = '--nullString--';
+
+ /**
+ * Map associating referenced elements with their [_ElementInfo]s.
+ */
+ final Map<Element, _ElementInfo> elementMap = {};
+
+ /**
+ * Map associating [CompilationUnitElement]s with their identifiers, which
+ * are indices into [unitLibraryUris] and [unitUnitUris].
+ */
+ final Map<CompilationUnitElement, int> unitMap = {};
+
+ /**
+ * The fields [unitLibraryUris] and [unitUnitUris] are used together to
+ * describe each unique [CompilationUnitElement].
+ *
+ * This field contains the library URI of a unit.
+ */
+ final List<_StringInfo> unitLibraryUris = [];
+
+ /**
+ * The fields [unitLibraryUris] and [unitUnitUris] are used together to
+ * describe each unique [CompilationUnitElement].
+ *
+ * This field contains the unit URI of a unit, which might be the same as
+ * the library URI for the defining unit, or a different one for a part.
+ */
+ final List<_StringInfo> unitUnitUris = [];
+
+ /**
+ * Map associating strings with their [_StringInfo]s.
+ */
+ final Map<String, _StringInfo> stringMap = {};
+
+ /**
+ * All element relations.
+ */
+ final List<_ElementRelationInfo> elementRelations = [];
+
+ /**
+ * All unresolved name relations.
+ */
+ final List<_NameRelationInfo> nameRelations = [];
+
+ /**
+ * The [_StringInfo] to use for `null` strings.
+ */
+ _StringInfo nullString;
+
+ _IndexAssembler() {
+ nullString = _getStringInfo(NULL_STRING);
+ }
+
+ void addElementRelation(Element element, IndexRelationKind kind, int offset,
+ int length, bool isQualified) {
+ _ElementInfo elementInfo = _getElementInfo(element);
+ elementRelations.add(new _ElementRelationInfo(
+ elementInfo, kind, offset, length, isQualified));
+ }
+
+ void addNameRelation(
+ String name, IndexRelationKind kind, int offset, bool isQualified) {
+ _StringInfo nameId = _getStringInfo(name);
+ nameRelations.add(new _NameRelationInfo(nameId, kind, offset, isQualified));
+ }
+
+ /**
+ * Index the [unit] and assemble a new [AnalysisDriverUnitIndexBuilder].
+ */
+ AnalysisDriverUnitIndexBuilder assemble(CompilationUnit unit) {
+ unit.accept(new _IndexContributor(this));
+ // 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;
+ }
+ // Sort element and name relations.
+ elementRelations.sort((a, b) {
+ return a.elementInfo.id - b.elementInfo.id;
+ });
+ nameRelations.sort((a, b) {
+ return a.nameInfo.id - b.nameInfo.id;
+ });
+ return new AnalysisDriverUnitIndexBuilder(
+ strings: stringInfoList.map((s) => s.value).toList(),
+ nullStringId: nullString.id,
+ unitLibraryUris: unitLibraryUris.map((s) => s.id).toList(),
+ unitUnitUris: unitUnitUris.map((s) => s.id).toList(),
+ elementKinds: elementInfoList.map((e) => e.kind).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(),
+ usedElements: elementRelations.map((r) => r.elementInfo.id).toList(),
+ usedElementKinds: elementRelations.map((r) => r.kind).toList(),
+ usedElementOffsets: elementRelations.map((r) => r.offset).toList(),
+ usedElementLengths: elementRelations.map((r) => r.length).toList(),
+ usedElementIsQualifiedFlags:
+ elementRelations.map((r) => r.isQualified).toList(),
+ usedNames: nameRelations.map((r) => r.nameInfo.id).toList(),
+ usedNameKinds: nameRelations.map((r) => r.kind).toList(),
+ usedNameOffsets: nameRelations.map((r) => r.offset).toList(),
+ usedNameIsQualifiedFlags:
+ nameRelations.map((r) => r.isQualified).toList());
+ }
+
+ /**
+ * 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 given [string]. The
+ * field [_StringInfo.id] is filled by [assemble] during final sorting.
+ */
+ _StringInfo _getStringInfo(String string) {
+ return stringMap.putIfAbsent(string, () {
+ return new _StringInfo(string);
+ });
+ }
+
+ /**
+ * 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);
+ }
+}
+
+/**
+ * Visits a resolved AST and adds relationships into the [assembler].
+ */
+class _IndexContributor extends GeneralizingAstVisitor {
+ final _IndexAssembler assembler;
+
+ _IndexContributor(this.assembler);
+
+ void recordIsAncestorOf(Element descendant) {
+ _recordIsAncestorOf(descendant, descendant, false, <ClassElement>[]);
+ }
+
+ /**
+ * Record that the name [node] has a relation of the given [kind].
+ */
+ void recordNameRelation(
+ SimpleIdentifier node, IndexRelationKind kind, bool isQualified) {
+ if (node != null) {
+ assembler.addNameRelation(node.name, kind, node.offset, isQualified);
+ }
+ }
+
+ /**
+ * Record reference to the given operator [Element].
+ */
+ void recordOperatorReference(Token operator, Element element) {
+ recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the location
+ * of the given [node]. The flag [isQualified] is `true` if [node] has an
+ * explicit or implicit qualifier, so cannot be shadowed by a local
+ * declaration.
+ */
+ void recordRelation(
+ Element element, IndexRelationKind kind, AstNode node, bool isQualified) {
+ if (element != null && node != null) {
+ recordRelationOffset(
+ element, kind, node.offset, node.length, isQualified);
+ }
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the given
+ * [offset] and [length]. The flag [isQualified] is `true` if the relation
+ * has an explicit or implicit qualifier, so [element] cannot be shadowed by
+ * a local declaration.
+ */
+ void recordRelationOffset(Element element, IndexRelationKind kind, int offset,
+ int length, bool isQualified) {
+ // Ignore elements that can't be referenced outside of the unit.
+ ElementKind elementKind = element?.kind;
+ if (elementKind == null ||
+ elementKind == ElementKind.DYNAMIC ||
+ elementKind == ElementKind.LABEL ||
+ elementKind == ElementKind.LOCAL_VARIABLE ||
+ elementKind == ElementKind.PREFIX ||
+ elementKind == ElementKind.TYPE_PARAMETER ||
+ elementKind == ElementKind.FUNCTION &&
+ element is FunctionElement &&
+ element.enclosingElement is ExecutableElement ||
+ elementKind == ElementKind.PARAMETER &&
+ element is ParameterElement &&
+ element.parameterKind != ParameterKind.NAMED ||
+ false) {
+ return;
+ }
+ // Add the relation.
+ assembler.addElementRelation(element, kind, offset, length, isQualified);
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the location
+ * of the given [token].
+ */
+ void recordRelationToken(
+ Element element, IndexRelationKind kind, Token token) {
+ if (element != null && token != null) {
+ recordRelationOffset(element, kind, token.offset, token.length, true);
+ }
+ }
+
+ /**
+ * Record a relation between a super [typeName] and its [Element].
+ */
+ void recordSuperType(TypeName typeName, IndexRelationKind kind) {
+ Identifier name = typeName?.name;
+ if (name != null) {
+ Element element = name.staticElement;
+ bool isQualified;
+ SimpleIdentifier relNode;
+ if (name is PrefixedIdentifier) {
+ isQualified = true;
+ relNode = name.identifier;
+ } else {
+ isQualified = false;
+ relNode = name;
+ }
+ recordRelation(element, kind, relNode, isQualified);
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, relNode, isQualified);
+ typeName.typeArguments?.accept(this);
+ }
+ }
+
+ void recordUriReference(Element element, UriBasedDirective directive) {
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, directive.uri, true);
+ }
+
+ @override
+ visitAssignmentExpression(AssignmentExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitAssignmentExpression(node);
+ }
+
+ @override
+ visitBinaryExpression(BinaryExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitBinaryExpression(node);
+ }
+
+ @override
+ visitClassDeclaration(ClassDeclaration node) {
+ if (node.extendsClause == null) {
+ ClassElement objectElement = node.element.supertype?.element;
+ recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
+ node.name.offset, 0, true);
+ }
+ recordIsAncestorOf(node.element);
+ super.visitClassDeclaration(node);
+ }
+
+ @override
+ visitClassTypeAlias(ClassTypeAlias node) {
+ recordIsAncestorOf(node.element);
+ super.visitClassTypeAlias(node);
+ }
+
+ @override
+ visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+ SimpleIdentifier fieldName = node.fieldName;
+ if (fieldName != null) {
+ Element element = fieldName.staticElement;
+ recordRelation(element, IndexRelationKind.IS_WRITTEN_BY, fieldName, true);
+ }
+ node.expression?.accept(this);
+ }
+
+ @override
+ visitConstructorName(ConstructorName node) {
+ ConstructorElement element = node.staticElement;
+ element = _getActualConstructorElement(element);
+ // record relation
+ if (node.name != null) {
+ int offset = node.period.offset;
+ int length = node.name.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.type.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ node.type.accept(this);
+ }
+
+ @override
+ visitExportDirective(ExportDirective node) {
+ ExportElement element = node.element;
+ recordUriReference(element?.exportedLibrary, node);
+ super.visitExportDirective(node);
+ }
+
+ @override
+ visitExtendsClause(ExtendsClause node) {
+ recordSuperType(node.superclass, IndexRelationKind.IS_EXTENDED_BY);
+ }
+
+ @override
+ visitImplementsClause(ImplementsClause node) {
+ for (TypeName typeName in node.interfaces) {
+ recordSuperType(typeName, IndexRelationKind.IS_IMPLEMENTED_BY);
+ }
+ }
+
+ @override
+ visitImportDirective(ImportDirective node) {
+ ImportElement element = node.element;
+ recordUriReference(element?.importedLibrary, node);
+ super.visitImportDirective(node);
+ }
+
+ @override
+ visitIndexExpression(IndexExpression node) {
+ MethodElement element = node.bestElement;
+ if (element is MethodElement) {
+ Token operator = node.leftBracket;
+ recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+ }
+ super.visitIndexExpression(node);
+ }
+
+ @override
+ visitLibraryIdentifier(LibraryIdentifier node) {}
+
+ @override
+ visitMethodInvocation(MethodInvocation node) {
+ SimpleIdentifier name = node.methodName;
+ Element element = name.bestElement;
+ // unresolved name invocation
+ bool isQualified = node.realTarget != null;
+ if (element == null) {
+ recordNameRelation(name, IndexRelationKind.IS_INVOKED_BY, isQualified);
+ }
+ // element invocation
+ IndexRelationKind kind = element is ClassElement
+ ? IndexRelationKind.IS_REFERENCED_BY
+ : IndexRelationKind.IS_INVOKED_BY;
+ recordRelation(element, kind, name, isQualified);
+ node.target?.accept(this);
+ node.argumentList?.accept(this);
+ }
+
+ @override
+ visitPartDirective(PartDirective node) {
+ Element element = node.element;
+ recordUriReference(element, node);
+ super.visitPartDirective(node);
+ }
+
+ @override
+ visitPostfixExpression(PostfixExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitPostfixExpression(node);
+ }
+
+ @override
+ visitPrefixExpression(PrefixExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitPrefixExpression(node);
+ }
+
+ @override
+ visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+ ConstructorElement element = node.staticElement;
+ if (node.constructorName != null) {
+ int offset = node.period.offset;
+ int length = node.constructorName.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.thisKeyword.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ super.visitRedirectingConstructorInvocation(node);
+ }
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ // name in declaration
+ if (node.inDeclarationContext()) {
+ return;
+ }
+ Element element = node.bestElement;
+ // record unresolved name reference
+ bool isQualified = _isQualified(node);
+ if (element == null) {
+ bool inGetterContext = node.inGetterContext();
+ bool inSetterContext = node.inSetterContext();
+ IndexRelationKind kind;
+ if (inGetterContext && inSetterContext) {
+ kind = IndexRelationKind.IS_READ_WRITTEN_BY;
+ } else if (inGetterContext) {
+ kind = IndexRelationKind.IS_READ_BY;
+ } else {
+ kind = IndexRelationKind.IS_WRITTEN_BY;
+ }
+ recordNameRelation(node, kind, isQualified);
+ }
+ // this.field parameter
+ if (element is FieldFormalParameterElement) {
+ AstNode parent = node.parent;
+ IndexRelationKind kind =
+ parent is FieldFormalParameter && parent.identifier == node
+ ? IndexRelationKind.IS_WRITTEN_BY
+ : IndexRelationKind.IS_REFERENCED_BY;
+ recordRelation(element.field, kind, node, true);
+ return;
+ }
+ // ignore a local reference to a parameter
+ if (element is ParameterElement && node.parent is! Label) {
+ return;
+ }
+ // record specific relations
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, node, isQualified);
+ }
+
+ @override
+ visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ ConstructorElement element = node.staticElement;
+ if (node.constructorName != null) {
+ int offset = node.period.offset;
+ int length = node.constructorName.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.superKeyword.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ node.argumentList?.accept(this);
+ }
+
+ @override
+ visitTypeName(TypeName node) {
+ AstNode parent = node.parent;
+ if (parent is ClassTypeAlias && parent.superclass == node) {
+ recordSuperType(node, IndexRelationKind.IS_EXTENDED_BY);
+ } else {
+ super.visitTypeName(node);
+ }
+ }
+
+ @override
+ visitWithClause(WithClause node) {
+ for (TypeName typeName in node.mixinTypes) {
+ recordSuperType(typeName, IndexRelationKind.IS_MIXED_IN_BY);
+ }
+ }
+
+ /**
+ * If the given [constructor] is a synthetic constructor created for a
+ * [ClassTypeAlias], return the actual constructor of a [ClassDeclaration]
+ * which is invoked. Return `null` if a redirection cycle is detected.
+ */
+ ConstructorElement _getActualConstructorElement(
+ ConstructorElement constructor) {
+ Set<ConstructorElement> seenConstructors = new Set<ConstructorElement>();
+ while (constructor != null &&
+ constructor.isSynthetic &&
+ constructor.redirectedConstructor != null) {
+ constructor = constructor.redirectedConstructor;
+ // fail if a cycle is detected
+ if (!seenConstructors.add(constructor)) {
+ return null;
+ }
+ }
+ return constructor;
+ }
+
+ /**
+ * Return `true` if [node] has an explicit or implicit qualifier, so that it
+ * cannot be shadowed by a local declaration.
+ */
+ bool _isQualified(SimpleIdentifier node) {
+ if (node.isQualified) {
+ return true;
+ }
+ AstNode parent = node.parent;
+ return parent is Combinator || parent is Label;
+ }
+
+ void _recordIsAncestorOf(Element descendant, ClassElement ancestor,
+ bool includeThis, List<ClassElement> visitedElements) {
+ if (ancestor == null) {
+ return;
+ }
+ if (visitedElements.contains(ancestor)) {
+ return;
+ }
+ visitedElements.add(ancestor);
+ if (includeThis) {
+ int offset = descendant.nameOffset;
+ int length = descendant.nameLength;
+ assembler.addElementRelation(
+ ancestor, IndexRelationKind.IS_ANCESTOR_OF, offset, length, false);
+ }
+ {
+ InterfaceType superType = ancestor.supertype;
+ if (superType != null) {
+ _recordIsAncestorOf(
+ descendant, superType.element, true, visitedElements);
+ }
+ }
+ for (InterfaceType mixinType in ancestor.mixins) {
+ _recordIsAncestorOf(descendant, mixinType.element, true, visitedElements);
+ }
+ for (InterfaceType implementedType in ancestor.interfaces) {
+ _recordIsAncestorOf(
+ descendant, implementedType.element, true, visitedElements);
+ }
+ }
+}
+
+/**
+ * Information about a single name relation in single compilation unit.
+ */
+class _NameRelationInfo {
+ final _StringInfo nameInfo;
+ final IndexRelationKind kind;
+ final int offset;
+ final bool isQualified;
+
+ _NameRelationInfo(this.nameInfo, this.kind, this.offset, this.isQualified);
+}
+
+/**
+ * Information about a string referenced in the index.
+ */
+class _StringInfo {
+ /**
+ * The value of the string.
+ */
+ final String value;
+
+ /**
+ * The unique id of the string. It is set after indexing of the whole
+ * package is done and we are assembling the full package index.
+ */
+ int id;
+
+ _StringInfo(this.value);
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
new file mode 100644
index 0000000..e28a5b6
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -0,0 +1,207 @@
+// 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 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+
+/**
+ * Search support for an [AnalysisDriver].
+ */
+class Search {
+ final AnalysisDriver _driver;
+
+ Search(this._driver);
+
+ /**
+ * Returns references to the element at the given [offset] in the file with
+ * the given [path].
+ */
+ Future<List<SearchResult>> references(String path, int offset) async {
+ // Search only in added files.
+ if (!_driver.addedFiles.contains(path)) {
+ return const <SearchResult>[];
+ }
+
+ AnalysisResult analysisResult = await _driver.getResult(path);
+ CompilationUnit unit = analysisResult.unit;
+
+ // Prepare the node.
+ AstNode node = new NodeLocator(offset).searchWithin(unit);
+ if (node == null) {
+ return const <SearchResult>[];
+ }
+
+ // Prepare the element.
+ Element element = ElementLocator.locate(node);
+ if (element == null) {
+ return const <SearchResult>[];
+ }
+
+ ElementKind kind = element.kind;
+ if (kind == ElementKind.LABEL || kind == ElementKind.LOCAL_VARIABLE) {
+ Block block = node.getAncestor((n) => n is Block);
+ return _searchReferences_Local(element, unit.element, block);
+ }
+ // TODO(scheglov) support other kinds
+ return [];
+ }
+
+ Future<List<SearchResult>> _searchReferences_Local(
+ Element element,
+ CompilationUnitElement enclosingUnitElement,
+ AstNode enclosingNode) async {
+ _LocalReferencesVisitor visitor =
+ new _LocalReferencesVisitor(element, enclosingUnitElement);
+ enclosingNode?.accept(visitor);
+ return visitor.matches;
+ }
+}
+
+/**
+ * A single search result.
+ */
+class SearchResult {
+ /**
+ * The element that is used at this result.
+ */
+ final Element element;
+
+ /**
+ * The deep most element that contains this result.
+ */
+ final Element enclosingElement;
+
+ /**
+ * The kind of the [element] usage.
+ */
+ final SearchResultKind kind;
+
+ /**
+ * The offset relative to the beginning of the containing file.
+ */
+ final int offset;
+
+ /**
+ * The length of the usage in the containing file context.
+ */
+ final int length;
+
+ /**
+ * Is `true` if a field or a method is using with a qualifier.
+ */
+ final bool isResolved;
+
+ /**
+ * Is `true` if the result is a resolved reference to [element].
+ */
+ final bool isQualified;
+
+ SearchResult._(this.element, this.enclosingElement, this.kind, this.offset,
+ this.length, this.isResolved, this.isQualified);
+
+ @override
+ String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.write("SearchResult(kind=");
+ buffer.write(kind);
+ buffer.write(", offset=");
+ buffer.write(offset);
+ buffer.write(", length=");
+ buffer.write(length);
+ buffer.write(", isResolved=");
+ buffer.write(isResolved);
+ buffer.write(", isQualified=");
+ buffer.write(isQualified);
+ buffer.write(", enclosingElement=");
+ buffer.write(enclosingElement);
+ buffer.write(")");
+ return buffer.toString();
+ }
+}
+
+/**
+ * The kind of reference in a [SearchResult].
+ */
+enum SearchResultKind { READ, READ_WRITE, WRITE, INVOCATION, REFERENCE }
+
+/**
+ * A visitor that finds the deep-most [Element] that contains the [offset].
+ */
+class _ContainingElementFinder extends GeneralizingElementVisitor {
+ final int offset;
+ Element containingElement;
+
+ _ContainingElementFinder(this.offset);
+
+ visitElement(Element element) {
+ if (element is ElementImpl) {
+ if (element.codeOffset != null &&
+ element.codeOffset <= offset &&
+ offset <= element.codeOffset + element.codeLength) {
+ containingElement = element;
+ super.visitElement(element);
+ }
+ }
+ }
+}
+
+/**
+ * Visitor that adds [SearchResult]s for local elements of a block, method,
+ * class or a library - labels, local functions, local variables and parameters,
+ * type parameters, import prefixes.
+ */
+class _LocalReferencesVisitor extends RecursiveAstVisitor {
+ final List<SearchResult> matches = <SearchResult>[];
+
+ final Element element;
+ final CompilationUnitElement enclosingUnitElement;
+
+ _LocalReferencesVisitor(this.element, this.enclosingUnitElement);
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.inDeclarationContext()) {
+ return;
+ }
+ if (node.staticElement == element) {
+ AstNode parent = node.parent;
+ SearchResultKind kind = SearchResultKind.REFERENCE;
+ if (element is FunctionElement) {
+ if (parent is MethodInvocation && parent.methodName == node) {
+ kind = SearchResultKind.INVOCATION;
+ }
+ } else if (element is VariableElement) {
+ bool isGet = node.inGetterContext();
+ bool isSet = node.inSetterContext();
+ if (isGet && isSet) {
+ kind = SearchResultKind.READ_WRITE;
+ } else if (isGet) {
+ if (parent is MethodInvocation && parent.methodName == node) {
+ kind = SearchResultKind.INVOCATION;
+ } else {
+ kind = SearchResultKind.READ;
+ }
+ } else if (isSet) {
+ kind = SearchResultKind.WRITE;
+ }
+ }
+ _addMatch(node, kind);
+ }
+ }
+
+ void _addMatch(AstNode node, SearchResultKind kind) {
+ bool isQualified = node.parent is Label;
+ var finder = new _ContainingElementFinder(node.offset);
+ enclosingUnitElement.accept(finder);
+ matches.add(new SearchResult._(element, finder.containingElement, kind,
+ node.offset, node.length, true, isQualified));
+ }
+}
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 1d91db3..655f5fd 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -131,6 +131,7 @@
class AnalysisDriverResolvedUnitBuilder extends Object with _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
List<AnalysisDriverUnitErrorBuilder> _errors;
+ AnalysisDriverUnitIndexBuilder _index;
@override
List<AnalysisDriverUnitErrorBuilder> get errors => _errors ??= <AnalysisDriverUnitErrorBuilder>[];
@@ -142,14 +143,26 @@
this._errors = value;
}
- AnalysisDriverResolvedUnitBuilder({List<AnalysisDriverUnitErrorBuilder> errors})
- : _errors = errors;
+ @override
+ AnalysisDriverUnitIndexBuilder get index => _index;
+
+ /**
+ * The index of the unit.
+ */
+ void set index(AnalysisDriverUnitIndexBuilder value) {
+ this._index = value;
+ }
+
+ AnalysisDriverResolvedUnitBuilder({List<AnalysisDriverUnitErrorBuilder> errors, AnalysisDriverUnitIndexBuilder index})
+ : _errors = errors,
+ _index = index;
/**
* Flush [informative] data recursively.
*/
void flushInformative() {
_errors?.forEach((b) => b.flushInformative());
+ _index?.flushInformative();
}
/**
@@ -164,6 +177,8 @@
x?.collectApiSignature(signature);
}
}
+ signature.addBool(this._index != null);
+ this._index?.collectApiSignature(signature);
}
List<int> toBuffer() {
@@ -173,13 +188,20 @@
fb.Offset finish(fb.Builder fbBuilder) {
fb.Offset offset_errors;
+ fb.Offset offset_index;
if (!(_errors == null || _errors.isEmpty)) {
offset_errors = fbBuilder.writeList(_errors.map((b) => b.finish(fbBuilder)).toList());
}
+ if (_index != null) {
+ offset_index = _index.finish(fbBuilder);
+ }
fbBuilder.startTable();
if (offset_errors != null) {
fbBuilder.addOffset(0, offset_errors);
}
+ if (offset_index != null) {
+ fbBuilder.addOffset(1, offset_index);
+ }
return fbBuilder.endTable();
}
}
@@ -203,12 +225,19 @@
_AnalysisDriverResolvedUnitImpl(this._bc, this._bcOffset);
List<idl.AnalysisDriverUnitError> _errors;
+ idl.AnalysisDriverUnitIndex _index;
@override
List<idl.AnalysisDriverUnitError> get errors {
_errors ??= const fb.ListReader<idl.AnalysisDriverUnitError>(const _AnalysisDriverUnitErrorReader()).vTableGet(_bc, _bcOffset, 0, const <idl.AnalysisDriverUnitError>[]);
return _errors;
}
+
+ @override
+ idl.AnalysisDriverUnitIndex get index {
+ _index ??= const _AnalysisDriverUnitIndexReader().vTableGet(_bc, _bcOffset, 1, null);
+ return _index;
+ }
}
abstract class _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
@@ -216,12 +245,14 @@
Map<String, Object> toJson() {
Map<String, Object> _result = <String, Object>{};
if (errors.isNotEmpty) _result["errors"] = errors.map((_value) => _value.toJson()).toList();
+ if (index != null) _result["index"] = index.toJson();
return _result;
}
@override
Map<String, Object> toMap() => {
"errors": errors,
+ "index": index,
};
@override
@@ -419,6 +450,871 @@
String toString() => convert.JSON.encode(toJson());
}
+class AnalysisDriverUnitIndexBuilder extends Object with _AnalysisDriverUnitIndexMixin implements idl.AnalysisDriverUnitIndex {
+ List<idl.IndexSyntheticElementKind> _elementKinds;
+ List<int> _elementNameClassMemberIds;
+ List<int> _elementNameParameterIds;
+ List<int> _elementNameUnitMemberIds;
+ List<int> _elementUnits;
+ int _nullStringId;
+ List<String> _strings;
+ List<int> _unitLibraryUris;
+ List<int> _unitUnitUris;
+ List<bool> _usedElementIsQualifiedFlags;
+ List<idl.IndexRelationKind> _usedElementKinds;
+ List<int> _usedElementLengths;
+ List<int> _usedElementOffsets;
+ List<int> _usedElements;
+ List<bool> _usedNameIsQualifiedFlags;
+ List<idl.IndexRelationKind> _usedNameKinds;
+ List<int> _usedNameOffsets;
+ List<int> _usedNames;
+
+ @override
+ List<idl.IndexSyntheticElementKind> get elementKinds => _elementKinds ??= <idl.IndexSyntheticElementKind>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the kind of the synthetic element.
+ */
+ void set elementKinds(List<idl.IndexSyntheticElementKind> value) {
+ this._elementKinds = value;
+ }
+
+ @override
+ List<int> get elementNameClassMemberIds => _elementNameClassMemberIds ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * 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 index.
+ */
+ void set elementNameClassMemberIds(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._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 index.
+ */
+ void set elementNameParameterIds(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._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 index.
+ */
+ void set elementNameUnitMemberIds(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._elementNameUnitMemberIds = value;
+ }
+
+ @override
+ List<int> get elementUnits => _elementUnits ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the index into [unitLibraryUris] and [unitUnitUris] for the library
+ * specific unit where the element is declared.
+ */
+ void set elementUnits(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._elementUnits = value;
+ }
+
+ @override
+ int get nullStringId => _nullStringId ??= 0;
+
+ /**
+ * Identifier of the null string in [strings].
+ */
+ void set nullStringId(int value) {
+ assert(value == null || value >= 0);
+ this._nullStringId = value;
+ }
+
+ @override
+ List<String> get strings => _strings ??= <String>[];
+
+ /**
+ * List of unique element strings used in this index. The list is sorted in
+ * ascending order, so that the client can quickly check the presence of a
+ * string in this index.
+ */
+ void set strings(List<String> value) {
+ this._strings = value;
+ }
+
+ @override
+ List<int> get unitLibraryUris => _unitLibraryUris ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique library
+ * specific unit referenced in the index. It is an index into [strings] list.
+ */
+ void set unitLibraryUris(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._unitLibraryUris = value;
+ }
+
+ @override
+ List<int> get unitUnitUris => _unitUnitUris ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique library
+ * specific unit referenced in the index. It is an index into [strings] list.
+ */
+ void set unitUnitUris(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._unitUnitUris = value;
+ }
+
+ @override
+ List<bool> get usedElementIsQualifiedFlags => _usedElementIsQualifiedFlags ??= <bool>[];
+
+ /**
+ * Each item of this list is the `true` if the corresponding element usage
+ * is qualified with some prefix.
+ */
+ void set usedElementIsQualifiedFlags(List<bool> value) {
+ this._usedElementIsQualifiedFlags = value;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedElementKinds => _usedElementKinds ??= <idl.IndexRelationKind>[];
+
+ /**
+ * Each item of this list is the kind of the element usage.
+ */
+ void set usedElementKinds(List<idl.IndexRelationKind> value) {
+ this._usedElementKinds = value;
+ }
+
+ @override
+ List<int> get usedElementLengths => _usedElementLengths ??= <int>[];
+
+ /**
+ * Each item of this list is the length of the element usage.
+ */
+ void set usedElementLengths(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._usedElementLengths = value;
+ }
+
+ @override
+ List<int> get usedElementOffsets => _usedElementOffsets ??= <int>[];
+
+ /**
+ * Each item of this list is the offset of the element usage relative to the
+ * beginning of the file.
+ */
+ void set usedElementOffsets(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._usedElementOffsets = value;
+ }
+
+ @override
+ List<int> get usedElements => _usedElements ??= <int>[];
+
+ /**
+ * Each item of this list is the index into [elementUnits],
+ * [elementNameUnitMemberIds], [elementNameClassMemberIds] and
+ * [elementNameParameterIds]. The list is sorted in ascending order, so
+ * that the client can quickly find element references in this index.
+ */
+ void set usedElements(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._usedElements = value;
+ }
+
+ @override
+ List<bool> get usedNameIsQualifiedFlags => _usedNameIsQualifiedFlags ??= <bool>[];
+
+ /**
+ * Each item of this list is the `true` if the corresponding name usage
+ * is qualified with some prefix.
+ */
+ void set usedNameIsQualifiedFlags(List<bool> value) {
+ this._usedNameIsQualifiedFlags = value;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedNameKinds => _usedNameKinds ??= <idl.IndexRelationKind>[];
+
+ /**
+ * Each item of this list is the kind of the name usage.
+ */
+ void set usedNameKinds(List<idl.IndexRelationKind> value) {
+ this._usedNameKinds = value;
+ }
+
+ @override
+ List<int> get usedNameOffsets => _usedNameOffsets ??= <int>[];
+
+ /**
+ * Each item of this list is the offset of the name usage relative to the
+ * beginning of the file.
+ */
+ void set usedNameOffsets(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._usedNameOffsets = value;
+ }
+
+ @override
+ List<int> get usedNames => _usedNames ??= <int>[];
+
+ /**
+ * Each item of this list is the index into [strings] for a used name. The
+ * list is sorted in ascending order, so that the client can quickly find
+ * whether a name is used in this index.
+ */
+ void set usedNames(List<int> value) {
+ assert(value == null || value.every((e) => e >= 0));
+ this._usedNames = value;
+ }
+
+ AnalysisDriverUnitIndexBuilder({List<idl.IndexSyntheticElementKind> elementKinds, List<int> elementNameClassMemberIds, List<int> elementNameParameterIds, List<int> elementNameUnitMemberIds, List<int> elementUnits, int nullStringId, List<String> strings, List<int> unitLibraryUris, List<int> unitUnitUris, List<bool> usedElementIsQualifiedFlags, List<idl.IndexRelationKind> usedElementKinds, List<int> usedElementLengths, List<int> usedElementOffsets, List<int> usedElements, List<bool> usedNameIsQualifiedFlags, List<idl.IndexRelationKind> usedNameKinds, List<int> usedNameOffsets, List<int> usedNames})
+ : _elementKinds = elementKinds,
+ _elementNameClassMemberIds = elementNameClassMemberIds,
+ _elementNameParameterIds = elementNameParameterIds,
+ _elementNameUnitMemberIds = elementNameUnitMemberIds,
+ _elementUnits = elementUnits,
+ _nullStringId = nullStringId,
+ _strings = strings,
+ _unitLibraryUris = unitLibraryUris,
+ _unitUnitUris = unitUnitUris,
+ _usedElementIsQualifiedFlags = usedElementIsQualifiedFlags,
+ _usedElementKinds = usedElementKinds,
+ _usedElementLengths = usedElementLengths,
+ _usedElementOffsets = usedElementOffsets,
+ _usedElements = usedElements,
+ _usedNameIsQualifiedFlags = usedNameIsQualifiedFlags,
+ _usedNameKinds = usedNameKinds,
+ _usedNameOffsets = usedNameOffsets,
+ _usedNames = usedNames;
+
+ /**
+ * Flush [informative] data recursively.
+ */
+ void flushInformative() {
+ }
+
+ /**
+ * Accumulate non-[informative] data into [signature].
+ */
+ void collectApiSignature(api_sig.ApiSignature signature) {
+ if (this._strings == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._strings.length);
+ for (var x in this._strings) {
+ signature.addString(x);
+ }
+ }
+ signature.addInt(this._nullStringId ?? 0);
+ if (this._unitLibraryUris == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._unitLibraryUris.length);
+ for (var x in this._unitLibraryUris) {
+ signature.addInt(x);
+ }
+ }
+ if (this._unitUnitUris == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._unitUnitUris.length);
+ for (var x in this._unitUnitUris) {
+ signature.addInt(x);
+ }
+ }
+ if (this._elementKinds == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._elementKinds.length);
+ for (var x in this._elementKinds) {
+ signature.addInt(x.index);
+ }
+ }
+ if (this._elementUnits == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._elementUnits.length);
+ for (var x in this._elementUnits) {
+ signature.addInt(x);
+ }
+ }
+ if (this._elementNameUnitMemberIds == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._elementNameUnitMemberIds.length);
+ for (var x in this._elementNameUnitMemberIds) {
+ signature.addInt(x);
+ }
+ }
+ if (this._elementNameClassMemberIds == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._elementNameClassMemberIds.length);
+ for (var x in this._elementNameClassMemberIds) {
+ signature.addInt(x);
+ }
+ }
+ if (this._elementNameParameterIds == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._elementNameParameterIds.length);
+ for (var x in this._elementNameParameterIds) {
+ signature.addInt(x);
+ }
+ }
+ if (this._usedElements == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedElements.length);
+ for (var x in this._usedElements) {
+ signature.addInt(x);
+ }
+ }
+ if (this._usedElementKinds == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedElementKinds.length);
+ for (var x in this._usedElementKinds) {
+ signature.addInt(x.index);
+ }
+ }
+ if (this._usedElementOffsets == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedElementOffsets.length);
+ for (var x in this._usedElementOffsets) {
+ signature.addInt(x);
+ }
+ }
+ if (this._usedElementLengths == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedElementLengths.length);
+ for (var x in this._usedElementLengths) {
+ signature.addInt(x);
+ }
+ }
+ if (this._usedElementIsQualifiedFlags == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedElementIsQualifiedFlags.length);
+ for (var x in this._usedElementIsQualifiedFlags) {
+ signature.addBool(x);
+ }
+ }
+ if (this._usedNames == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedNames.length);
+ for (var x in this._usedNames) {
+ signature.addInt(x);
+ }
+ }
+ if (this._usedNameKinds == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedNameKinds.length);
+ for (var x in this._usedNameKinds) {
+ signature.addInt(x.index);
+ }
+ }
+ if (this._usedNameOffsets == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedNameOffsets.length);
+ for (var x in this._usedNameOffsets) {
+ signature.addInt(x);
+ }
+ }
+ if (this._usedNameIsQualifiedFlags == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._usedNameIsQualifiedFlags.length);
+ for (var x in this._usedNameIsQualifiedFlags) {
+ signature.addBool(x);
+ }
+ }
+ }
+
+ List<int> toBuffer() {
+ fb.Builder fbBuilder = new fb.Builder();
+ return fbBuilder.finish(finish(fbBuilder), "ADUI");
+ }
+
+ fb.Offset finish(fb.Builder fbBuilder) {
+ fb.Offset offset_elementKinds;
+ fb.Offset offset_elementNameClassMemberIds;
+ fb.Offset offset_elementNameParameterIds;
+ fb.Offset offset_elementNameUnitMemberIds;
+ fb.Offset offset_elementUnits;
+ fb.Offset offset_strings;
+ fb.Offset offset_unitLibraryUris;
+ fb.Offset offset_unitUnitUris;
+ fb.Offset offset_usedElementIsQualifiedFlags;
+ fb.Offset offset_usedElementKinds;
+ fb.Offset offset_usedElementLengths;
+ fb.Offset offset_usedElementOffsets;
+ fb.Offset offset_usedElements;
+ fb.Offset offset_usedNameIsQualifiedFlags;
+ fb.Offset offset_usedNameKinds;
+ fb.Offset offset_usedNameOffsets;
+ fb.Offset offset_usedNames;
+ if (!(_elementKinds == null || _elementKinds.isEmpty)) {
+ offset_elementKinds = fbBuilder.writeListUint8(_elementKinds.map((b) => b.index).toList());
+ }
+ 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);
+ }
+ if (!(_strings == null || _strings.isEmpty)) {
+ offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
+ }
+ if (!(_unitLibraryUris == null || _unitLibraryUris.isEmpty)) {
+ offset_unitLibraryUris = fbBuilder.writeListUint32(_unitLibraryUris);
+ }
+ if (!(_unitUnitUris == null || _unitUnitUris.isEmpty)) {
+ offset_unitUnitUris = fbBuilder.writeListUint32(_unitUnitUris);
+ }
+ if (!(_usedElementIsQualifiedFlags == null || _usedElementIsQualifiedFlags.isEmpty)) {
+ offset_usedElementIsQualifiedFlags = fbBuilder.writeListBool(_usedElementIsQualifiedFlags);
+ }
+ if (!(_usedElementKinds == null || _usedElementKinds.isEmpty)) {
+ offset_usedElementKinds = fbBuilder.writeListUint8(_usedElementKinds.map((b) => b.index).toList());
+ }
+ if (!(_usedElementLengths == null || _usedElementLengths.isEmpty)) {
+ offset_usedElementLengths = fbBuilder.writeListUint32(_usedElementLengths);
+ }
+ if (!(_usedElementOffsets == null || _usedElementOffsets.isEmpty)) {
+ offset_usedElementOffsets = fbBuilder.writeListUint32(_usedElementOffsets);
+ }
+ if (!(_usedElements == null || _usedElements.isEmpty)) {
+ offset_usedElements = fbBuilder.writeListUint32(_usedElements);
+ }
+ if (!(_usedNameIsQualifiedFlags == null || _usedNameIsQualifiedFlags.isEmpty)) {
+ offset_usedNameIsQualifiedFlags = fbBuilder.writeListBool(_usedNameIsQualifiedFlags);
+ }
+ if (!(_usedNameKinds == null || _usedNameKinds.isEmpty)) {
+ offset_usedNameKinds = fbBuilder.writeListUint8(_usedNameKinds.map((b) => b.index).toList());
+ }
+ if (!(_usedNameOffsets == null || _usedNameOffsets.isEmpty)) {
+ offset_usedNameOffsets = fbBuilder.writeListUint32(_usedNameOffsets);
+ }
+ if (!(_usedNames == null || _usedNames.isEmpty)) {
+ offset_usedNames = fbBuilder.writeListUint32(_usedNames);
+ }
+ fbBuilder.startTable();
+ if (offset_elementKinds != null) {
+ fbBuilder.addOffset(4, offset_elementKinds);
+ }
+ if (offset_elementNameClassMemberIds != null) {
+ fbBuilder.addOffset(7, offset_elementNameClassMemberIds);
+ }
+ if (offset_elementNameParameterIds != null) {
+ fbBuilder.addOffset(8, offset_elementNameParameterIds);
+ }
+ if (offset_elementNameUnitMemberIds != null) {
+ fbBuilder.addOffset(6, offset_elementNameUnitMemberIds);
+ }
+ if (offset_elementUnits != null) {
+ fbBuilder.addOffset(5, offset_elementUnits);
+ }
+ if (_nullStringId != null && _nullStringId != 0) {
+ fbBuilder.addUint32(1, _nullStringId);
+ }
+ if (offset_strings != null) {
+ fbBuilder.addOffset(0, offset_strings);
+ }
+ if (offset_unitLibraryUris != null) {
+ fbBuilder.addOffset(2, offset_unitLibraryUris);
+ }
+ if (offset_unitUnitUris != null) {
+ fbBuilder.addOffset(3, offset_unitUnitUris);
+ }
+ if (offset_usedElementIsQualifiedFlags != null) {
+ fbBuilder.addOffset(13, offset_usedElementIsQualifiedFlags);
+ }
+ if (offset_usedElementKinds != null) {
+ fbBuilder.addOffset(10, offset_usedElementKinds);
+ }
+ if (offset_usedElementLengths != null) {
+ fbBuilder.addOffset(12, offset_usedElementLengths);
+ }
+ if (offset_usedElementOffsets != null) {
+ fbBuilder.addOffset(11, offset_usedElementOffsets);
+ }
+ if (offset_usedElements != null) {
+ fbBuilder.addOffset(9, offset_usedElements);
+ }
+ if (offset_usedNameIsQualifiedFlags != null) {
+ fbBuilder.addOffset(17, offset_usedNameIsQualifiedFlags);
+ }
+ if (offset_usedNameKinds != null) {
+ fbBuilder.addOffset(15, offset_usedNameKinds);
+ }
+ if (offset_usedNameOffsets != null) {
+ fbBuilder.addOffset(16, offset_usedNameOffsets);
+ }
+ if (offset_usedNames != null) {
+ fbBuilder.addOffset(14, offset_usedNames);
+ }
+ return fbBuilder.endTable();
+ }
+}
+
+idl.AnalysisDriverUnitIndex readAnalysisDriverUnitIndex(List<int> buffer) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(buffer);
+ return const _AnalysisDriverUnitIndexReader().read(rootRef, 0);
+}
+
+class _AnalysisDriverUnitIndexReader extends fb.TableReader<_AnalysisDriverUnitIndexImpl> {
+ const _AnalysisDriverUnitIndexReader();
+
+ @override
+ _AnalysisDriverUnitIndexImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverUnitIndexImpl(bc, offset);
+}
+
+class _AnalysisDriverUnitIndexImpl extends Object with _AnalysisDriverUnitIndexMixin implements idl.AnalysisDriverUnitIndex {
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ _AnalysisDriverUnitIndexImpl(this._bc, this._bcOffset);
+
+ List<idl.IndexSyntheticElementKind> _elementKinds;
+ List<int> _elementNameClassMemberIds;
+ List<int> _elementNameParameterIds;
+ List<int> _elementNameUnitMemberIds;
+ List<int> _elementUnits;
+ int _nullStringId;
+ List<String> _strings;
+ List<int> _unitLibraryUris;
+ List<int> _unitUnitUris;
+ List<bool> _usedElementIsQualifiedFlags;
+ List<idl.IndexRelationKind> _usedElementKinds;
+ List<int> _usedElementLengths;
+ List<int> _usedElementOffsets;
+ List<int> _usedElements;
+ List<bool> _usedNameIsQualifiedFlags;
+ List<idl.IndexRelationKind> _usedNameKinds;
+ List<int> _usedNameOffsets;
+ List<int> _usedNames;
+
+ @override
+ List<idl.IndexSyntheticElementKind> get elementKinds {
+ _elementKinds ??= const fb.ListReader<idl.IndexSyntheticElementKind>(const _IndexSyntheticElementKindReader()).vTableGet(_bc, _bcOffset, 4, const <idl.IndexSyntheticElementKind>[]);
+ return _elementKinds;
+ }
+
+ @override
+ 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, 6, const <int>[]);
+ return _elementNameUnitMemberIds;
+ }
+
+ @override
+ List<int> get elementUnits {
+ _elementUnits ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 5, const <int>[]);
+ return _elementUnits;
+ }
+
+ @override
+ int get nullStringId {
+ _nullStringId ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 1, 0);
+ return _nullStringId;
+ }
+
+ @override
+ List<String> get strings {
+ _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 0, const <String>[]);
+ return _strings;
+ }
+
+ @override
+ List<int> get unitLibraryUris {
+ _unitLibraryUris ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 2, const <int>[]);
+ return _unitLibraryUris;
+ }
+
+ @override
+ List<int> get unitUnitUris {
+ _unitUnitUris ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 3, const <int>[]);
+ return _unitUnitUris;
+ }
+
+ @override
+ List<bool> get usedElementIsQualifiedFlags {
+ _usedElementIsQualifiedFlags ??= const fb.BoolListReader().vTableGet(_bc, _bcOffset, 13, const <bool>[]);
+ return _usedElementIsQualifiedFlags;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedElementKinds {
+ _usedElementKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bc, _bcOffset, 10, const <idl.IndexRelationKind>[]);
+ return _usedElementKinds;
+ }
+
+ @override
+ List<int> get usedElementLengths {
+ _usedElementLengths ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 12, const <int>[]);
+ return _usedElementLengths;
+ }
+
+ @override
+ List<int> get usedElementOffsets {
+ _usedElementOffsets ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 11, const <int>[]);
+ return _usedElementOffsets;
+ }
+
+ @override
+ List<int> get usedElements {
+ _usedElements ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 9, const <int>[]);
+ return _usedElements;
+ }
+
+ @override
+ List<bool> get usedNameIsQualifiedFlags {
+ _usedNameIsQualifiedFlags ??= const fb.BoolListReader().vTableGet(_bc, _bcOffset, 17, const <bool>[]);
+ return _usedNameIsQualifiedFlags;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedNameKinds {
+ _usedNameKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bc, _bcOffset, 15, const <idl.IndexRelationKind>[]);
+ return _usedNameKinds;
+ }
+
+ @override
+ List<int> get usedNameOffsets {
+ _usedNameOffsets ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 16, const <int>[]);
+ return _usedNameOffsets;
+ }
+
+ @override
+ List<int> get usedNames {
+ _usedNames ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 14, const <int>[]);
+ return _usedNames;
+ }
+}
+
+abstract class _AnalysisDriverUnitIndexMixin implements idl.AnalysisDriverUnitIndex {
+ @override
+ Map<String, Object> toJson() {
+ Map<String, Object> _result = <String, Object>{};
+ if (elementKinds.isNotEmpty) _result["elementKinds"] = elementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+ 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 (nullStringId != 0) _result["nullStringId"] = nullStringId;
+ if (strings.isNotEmpty) _result["strings"] = strings;
+ if (unitLibraryUris.isNotEmpty) _result["unitLibraryUris"] = unitLibraryUris;
+ if (unitUnitUris.isNotEmpty) _result["unitUnitUris"] = unitUnitUris;
+ if (usedElementIsQualifiedFlags.isNotEmpty) _result["usedElementIsQualifiedFlags"] = usedElementIsQualifiedFlags;
+ if (usedElementKinds.isNotEmpty) _result["usedElementKinds"] = usedElementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+ if (usedElementLengths.isNotEmpty) _result["usedElementLengths"] = usedElementLengths;
+ if (usedElementOffsets.isNotEmpty) _result["usedElementOffsets"] = usedElementOffsets;
+ if (usedElements.isNotEmpty) _result["usedElements"] = usedElements;
+ if (usedNameIsQualifiedFlags.isNotEmpty) _result["usedNameIsQualifiedFlags"] = usedNameIsQualifiedFlags;
+ if (usedNameKinds.isNotEmpty) _result["usedNameKinds"] = usedNameKinds.map((_value) => _value.toString().split('.')[1]).toList();
+ if (usedNameOffsets.isNotEmpty) _result["usedNameOffsets"] = usedNameOffsets;
+ if (usedNames.isNotEmpty) _result["usedNames"] = usedNames;
+ return _result;
+ }
+
+ @override
+ Map<String, Object> toMap() => {
+ "elementKinds": elementKinds,
+ "elementNameClassMemberIds": elementNameClassMemberIds,
+ "elementNameParameterIds": elementNameParameterIds,
+ "elementNameUnitMemberIds": elementNameUnitMemberIds,
+ "elementUnits": elementUnits,
+ "nullStringId": nullStringId,
+ "strings": strings,
+ "unitLibraryUris": unitLibraryUris,
+ "unitUnitUris": unitUnitUris,
+ "usedElementIsQualifiedFlags": usedElementIsQualifiedFlags,
+ "usedElementKinds": usedElementKinds,
+ "usedElementLengths": usedElementLengths,
+ "usedElementOffsets": usedElementOffsets,
+ "usedElements": usedElements,
+ "usedNameIsQualifiedFlags": usedNameIsQualifiedFlags,
+ "usedNameKinds": usedNameKinds,
+ "usedNameOffsets": usedNameOffsets,
+ "usedNames": usedNames,
+ };
+
+ @override
+ String toString() => convert.JSON.encode(toJson());
+}
+
+class AnalysisDriverUnlinkedUnitBuilder extends Object with _AnalysisDriverUnlinkedUnitMixin implements idl.AnalysisDriverUnlinkedUnit {
+ List<String> _referencedNames;
+ UnlinkedUnitBuilder _unit;
+
+ @override
+ List<String> get referencedNames => _referencedNames ??= <String>[];
+
+ /**
+ * List of external names referenced by the unit.
+ */
+ void set referencedNames(List<String> value) {
+ this._referencedNames = value;
+ }
+
+ @override
+ UnlinkedUnitBuilder get unit => _unit;
+
+ /**
+ * Unlinked information for the unit.
+ */
+ void set unit(UnlinkedUnitBuilder value) {
+ this._unit = value;
+ }
+
+ AnalysisDriverUnlinkedUnitBuilder({List<String> referencedNames, UnlinkedUnitBuilder unit})
+ : _referencedNames = referencedNames,
+ _unit = unit;
+
+ /**
+ * Flush [informative] data recursively.
+ */
+ void flushInformative() {
+ _unit?.flushInformative();
+ }
+
+ /**
+ * Accumulate non-[informative] data into [signature].
+ */
+ void collectApiSignature(api_sig.ApiSignature signature) {
+ if (this._referencedNames == null) {
+ signature.addInt(0);
+ } else {
+ signature.addInt(this._referencedNames.length);
+ for (var x in this._referencedNames) {
+ signature.addString(x);
+ }
+ }
+ signature.addBool(this._unit != null);
+ this._unit?.collectApiSignature(signature);
+ }
+
+ List<int> toBuffer() {
+ fb.Builder fbBuilder = new fb.Builder();
+ return fbBuilder.finish(finish(fbBuilder), "ADUU");
+ }
+
+ fb.Offset finish(fb.Builder fbBuilder) {
+ fb.Offset offset_referencedNames;
+ fb.Offset offset_unit;
+ if (!(_referencedNames == null || _referencedNames.isEmpty)) {
+ offset_referencedNames = fbBuilder.writeList(_referencedNames.map((b) => fbBuilder.writeString(b)).toList());
+ }
+ if (_unit != null) {
+ offset_unit = _unit.finish(fbBuilder);
+ }
+ fbBuilder.startTable();
+ if (offset_referencedNames != null) {
+ fbBuilder.addOffset(0, offset_referencedNames);
+ }
+ if (offset_unit != null) {
+ fbBuilder.addOffset(1, offset_unit);
+ }
+ return fbBuilder.endTable();
+ }
+}
+
+idl.AnalysisDriverUnlinkedUnit readAnalysisDriverUnlinkedUnit(List<int> buffer) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(buffer);
+ return const _AnalysisDriverUnlinkedUnitReader().read(rootRef, 0);
+}
+
+class _AnalysisDriverUnlinkedUnitReader extends fb.TableReader<_AnalysisDriverUnlinkedUnitImpl> {
+ const _AnalysisDriverUnlinkedUnitReader();
+
+ @override
+ _AnalysisDriverUnlinkedUnitImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverUnlinkedUnitImpl(bc, offset);
+}
+
+class _AnalysisDriverUnlinkedUnitImpl extends Object with _AnalysisDriverUnlinkedUnitMixin implements idl.AnalysisDriverUnlinkedUnit {
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ _AnalysisDriverUnlinkedUnitImpl(this._bc, this._bcOffset);
+
+ List<String> _referencedNames;
+ idl.UnlinkedUnit _unit;
+
+ @override
+ List<String> get referencedNames {
+ _referencedNames ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 0, const <String>[]);
+ return _referencedNames;
+ }
+
+ @override
+ idl.UnlinkedUnit get unit {
+ _unit ??= const _UnlinkedUnitReader().vTableGet(_bc, _bcOffset, 1, null);
+ return _unit;
+ }
+}
+
+abstract class _AnalysisDriverUnlinkedUnitMixin implements idl.AnalysisDriverUnlinkedUnit {
+ @override
+ Map<String, Object> toJson() {
+ Map<String, Object> _result = <String, Object>{};
+ if (referencedNames.isNotEmpty) _result["referencedNames"] = referencedNames;
+ if (unit != null) _result["unit"] = unit.toJson();
+ return _result;
+ }
+
+ @override
+ Map<String, Object> toMap() => {
+ "referencedNames": referencedNames,
+ "unit": unit,
+ };
+
+ @override
+ String toString() => convert.JSON.encode(toJson());
+}
+
class CodeRangeBuilder extends Object with _CodeRangeMixin implements idl.CodeRange {
int _length;
int _offset;
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 09fbfe4..baf782a 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -789,6 +789,11 @@
* The full list of analysis errors, both syntactic and semantic.
*/
errors:[AnalysisDriverUnitError] (id: 0);
+
+ /**
+ * The index of the unit.
+ */
+ index:AnalysisDriverUnitIndex (id: 1);
}
/**
@@ -822,6 +827,141 @@
}
/**
+ * Information about a resolved unit.
+ */
+table AnalysisDriverUnitIndex {
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the kind of the synthetic element.
+ */
+ elementKinds:[IndexSyntheticElementKind] (id: 4);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * 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 index.
+ */
+ 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 index.
+ */
+ 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 index.
+ */
+ elementNameUnitMemberIds:[uint] (id: 6);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the index into [unitLibraryUris] and [unitUnitUris] for the library
+ * specific unit where the element is declared.
+ */
+ elementUnits:[uint] (id: 5);
+
+ /**
+ * Identifier of the null string in [strings].
+ */
+ nullStringId:uint (id: 1);
+
+ /**
+ * List of unique element strings used in this index. The list is sorted in
+ * ascending order, so that the client can quickly check the presence of a
+ * string in this index.
+ */
+ strings:[string] (id: 0);
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique library
+ * specific unit referenced in the index. It is an index into [strings] list.
+ */
+ unitLibraryUris:[uint] (id: 2);
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique library
+ * specific unit referenced in the index. It is an index into [strings] list.
+ */
+ unitUnitUris:[uint] (id: 3);
+
+ /**
+ * Each item of this list is the `true` if the corresponding element usage
+ * is qualified with some prefix.
+ */
+ usedElementIsQualifiedFlags:[ubyte] (id: 13);
+
+ /**
+ * Each item of this list is the kind of the element usage.
+ */
+ usedElementKinds:[IndexRelationKind] (id: 10);
+
+ /**
+ * Each item of this list is the length of the element usage.
+ */
+ usedElementLengths:[uint] (id: 12);
+
+ /**
+ * Each item of this list is the offset of the element usage relative to the
+ * beginning of the file.
+ */
+ usedElementOffsets:[uint] (id: 11);
+
+ /**
+ * Each item of this list is the index into [elementUnits],
+ * [elementNameUnitMemberIds], [elementNameClassMemberIds] and
+ * [elementNameParameterIds]. The list is sorted in ascending order, so
+ * that the client can quickly find element references in this index.
+ */
+ usedElements:[uint] (id: 9);
+
+ /**
+ * Each item of this list is the `true` if the corresponding name usage
+ * is qualified with some prefix.
+ */
+ usedNameIsQualifiedFlags:[ubyte] (id: 17);
+
+ /**
+ * Each item of this list is the kind of the name usage.
+ */
+ usedNameKinds:[IndexRelationKind] (id: 15);
+
+ /**
+ * Each item of this list is the offset of the name usage relative to the
+ * beginning of the file.
+ */
+ usedNameOffsets:[uint] (id: 16);
+
+ /**
+ * Each item of this list is the index into [strings] for a used name. The
+ * list is sorted in ascending order, so that the client can quickly find
+ * whether a name is used in this index.
+ */
+ usedNames:[uint] (id: 14);
+}
+
+/**
+ * Information about an unlinked unit.
+ */
+table AnalysisDriverUnlinkedUnit {
+ /**
+ * List of external names referenced by the unit.
+ */
+ referencedNames:[string] (id: 0);
+
+ /**
+ * Unlinked information for the unit.
+ */
+ unit:UnlinkedUnit (id: 1);
+}
+
+/**
* Information about an element code range.
*/
table CodeRange {
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index eeb604a..d960c4b 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -70,6 +70,12 @@
*/
@Id(0)
List<AnalysisDriverUnitError> get errors;
+
+ /**
+ * The index of the unit.
+ */
+ @Id(1)
+ AnalysisDriverUnitIndex get index;
}
/**
@@ -108,6 +114,169 @@
}
/**
+ * Information about a resolved unit.
+ */
+@TopLevel('ADUI')
+abstract class AnalysisDriverUnitIndex extends base.SummaryClass {
+ factory AnalysisDriverUnitIndex.fromBuffer(List<int> buffer) =>
+ generated.readAnalysisDriverUnitIndex(buffer);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the kind of the synthetic element.
+ */
+ @Id(4)
+ List<IndexSyntheticElementKind> get elementKinds;
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * 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 index.
+ */
+ @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 index.
+ */
+ @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 index.
+ */
+ @Id(6)
+ List<int> get elementNameUnitMemberIds;
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the index into [unitLibraryUris] and [unitUnitUris] for the library
+ * specific unit where the element is declared.
+ */
+ @Id(5)
+ List<int> get elementUnits;
+
+ /**
+ * Identifier of the null string in [strings].
+ */
+ @Id(1)
+ int get nullStringId;
+
+ /**
+ * List of unique element strings used in this index. The list is sorted in
+ * ascending order, so that the client can quickly check the presence of a
+ * string in this index.
+ */
+ @Id(0)
+ List<String> get strings;
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique library
+ * specific unit referenced in the index. It is an index into [strings] list.
+ */
+ @Id(2)
+ List<int> get unitLibraryUris;
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique library
+ * specific unit referenced in the index. It is an index into [strings] list.
+ */
+ @Id(3)
+ List<int> get unitUnitUris;
+
+ /**
+ * Each item of this list is the `true` if the corresponding element usage
+ * is qualified with some prefix.
+ */
+ @Id(13)
+ List<bool> get usedElementIsQualifiedFlags;
+
+ /**
+ * Each item of this list is the kind of the element usage.
+ */
+ @Id(10)
+ List<IndexRelationKind> get usedElementKinds;
+
+ /**
+ * Each item of this list is the length of the element usage.
+ */
+ @Id(12)
+ List<int> get usedElementLengths;
+
+ /**
+ * Each item of this list is the offset of the element usage relative to the
+ * beginning of the file.
+ */
+ @Id(11)
+ List<int> get usedElementOffsets;
+
+ /**
+ * Each item of this list is the index into [elementUnits],
+ * [elementNameUnitMemberIds], [elementNameClassMemberIds] and
+ * [elementNameParameterIds]. The list is sorted in ascending order, so
+ * that the client can quickly find element references in this index.
+ */
+ @Id(9)
+ List<int> get usedElements;
+
+ /**
+ * Each item of this list is the `true` if the corresponding name usage
+ * is qualified with some prefix.
+ */
+ @Id(17)
+ List<bool> get usedNameIsQualifiedFlags;
+
+ /**
+ * Each item of this list is the kind of the name usage.
+ */
+ @Id(15)
+ List<IndexRelationKind> get usedNameKinds;
+
+ /**
+ * Each item of this list is the offset of the name usage relative to the
+ * beginning of the file.
+ */
+ @Id(16)
+ List<int> get usedNameOffsets;
+
+ /**
+ * Each item of this list is the index into [strings] for a used name. The
+ * list is sorted in ascending order, so that the client can quickly find
+ * whether a name is used in this index.
+ */
+ @Id(14)
+ List<int> get usedNames;
+}
+
+/**
+ * Information about an unlinked unit.
+ */
+@TopLevel('ADUU')
+abstract class AnalysisDriverUnlinkedUnit extends base.SummaryClass {
+ factory AnalysisDriverUnlinkedUnit.fromBuffer(List<int> buffer) =>
+ generated.readAnalysisDriverUnlinkedUnit(buffer);
+
+ /**
+ * List of external names referenced by the unit.
+ */
+ @Id(0)
+ List<String> get referencedNames;
+
+ /**
+ * Unlinked information for the unit.
+ */
+ @Id(1)
+ UnlinkedUnit get unit;
+}
+
+/**
* Information about an element code range.
*/
abstract class CodeRange extends base.SummaryClass {
diff --git a/pkg/analyzer/lib/src/util/fast_uri.dart b/pkg/analyzer/lib/src/util/fast_uri.dart
index 40681bd..691a51d 100644
--- a/pkg/analyzer/lib/src/util/fast_uri.dart
+++ b/pkg/analyzer/lib/src/util/fast_uri.dart
@@ -183,7 +183,8 @@
}
if (refPath.startsWith('../') ||
refPath.contains('/../') ||
- refPath.contains('/./')) {
+ refPath.contains('/./') ||
+ refPath.startsWith('/')) {
Uri slowResult = _fallbackUri.resolveUri(reference);
return FastUri.parse(slowResult.toString());
}
diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart
new file mode 100644
index 0000000..796b9b8
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/base.dart
@@ -0,0 +1,124 @@
+// 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 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/status.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:test/test.dart';
+
+import '../../context/mock_sdk.dart';
+
+class BaseAnalysisDriverTest {
+ static final MockSdk sdk = new MockSdk();
+
+ final MemoryResourceProvider provider = new MemoryResourceProvider();
+ final ByteStore byteStore = new MemoryByteStore();
+ final FileContentOverlay contentOverlay = new FileContentOverlay();
+
+ final StringBuffer logBuffer = new StringBuffer();
+ PerformanceLog logger;
+
+ AnalysisDriverScheduler scheduler;
+ AnalysisDriver driver;
+ final _Monitor idleStatusMonitor = new _Monitor();
+ final List<AnalysisStatus> allStatuses = <AnalysisStatus>[];
+ final List<AnalysisResult> allResults = <AnalysisResult>[];
+
+ String testProject;
+ String testFile;
+ String testCode;
+
+ void addTestFile(String content, {bool priority: false}) {
+ testCode = content;
+ provider.newFile(testFile, content);
+ driver.addFile(testFile);
+ if (priority) {
+ driver.priorityFiles = [testFile];
+ }
+ }
+
+ int findOffset(String search) {
+ int offset = testCode.indexOf(search);
+ if (offset < 0) {
+ fail("Did not find '$search' in\n$testCode");
+ }
+ return offset;
+ }
+
+ int getLeadingIdentifierLength(String search) {
+ int length = 0;
+ while (length < search.length) {
+ int c = search.codeUnitAt(length);
+ if (c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0)) {
+ length++;
+ continue;
+ }
+ if (c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0)) {
+ length++;
+ continue;
+ }
+ if (c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0)) {
+ length++;
+ continue;
+ }
+ break;
+ }
+ return length;
+ }
+
+ void setUp() {
+ new MockSdk();
+ testProject = _p('/test/lib');
+ testFile = _p('/test/lib/test.dart');
+ logger = new PerformanceLog(logBuffer);
+ scheduler = new AnalysisDriverScheduler(logger);
+ driver = new AnalysisDriver(
+ scheduler,
+ logger,
+ provider,
+ byteStore,
+ contentOverlay,
+ new SourceFactory([
+ new DartUriResolver(sdk),
+ new PackageMapUriResolver(provider, <String, List<Folder>>{
+ 'test': [provider.getFolder(testProject)]
+ }),
+ new ResourceUriResolver(provider)
+ ], null, provider),
+ new AnalysisOptionsImpl()..strongMode = true);
+ scheduler.start();
+ driver.status.lastWhere((status) {
+ allStatuses.add(status);
+ if (status.isIdle) {
+ idleStatusMonitor.notify();
+ }
+ });
+ driver.results.listen(allResults.add);
+ }
+
+ String _p(String path) => provider.convertPath(path);
+}
+
+class _Monitor {
+ Completer<Null> _completer = new Completer<Null>();
+
+ Future<Null> get signal async {
+ await _completer.future;
+ _completer = new Completer<Null>();
+ }
+
+ void notify() {
+ if (!_completer.isCompleted) {
+ _completer.complete(null);
+ }
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index ec693f4..f4ee85b 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -12,7 +12,6 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
@@ -20,12 +19,14 @@
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/idl.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../context/mock_sdk.dart';
+import 'base.dart';
main() {
defineReflectiveSuite(() {
@@ -216,55 +217,7 @@
}
@reflectiveTest
-class AnalysisDriverTest {
- static final MockSdk sdk = new MockSdk();
-
- final MemoryResourceProvider provider = new MemoryResourceProvider();
- final ByteStore byteStore = new MemoryByteStore();
- final FileContentOverlay contentOverlay = new FileContentOverlay();
-
- final StringBuffer logBuffer = new StringBuffer();
- PerformanceLog logger;
-
- AnalysisDriverScheduler scheduler;
- AnalysisDriver driver;
- final _Monitor idleStatusMonitor = new _Monitor();
- final List<AnalysisStatus> allStatuses = <AnalysisStatus>[];
- final List<AnalysisResult> allResults = <AnalysisResult>[];
-
- String testProject;
- String testFile;
-
- void setUp() {
- new MockSdk();
- testProject = _p('/test/lib');
- testFile = _p('/test/lib/test.dart');
- logger = new PerformanceLog(logBuffer);
- scheduler = new AnalysisDriverScheduler(logger);
- driver = new AnalysisDriver(
- scheduler,
- logger,
- provider,
- byteStore,
- contentOverlay,
- new SourceFactory([
- new DartUriResolver(sdk),
- new PackageMapUriResolver(provider, <String, List<Folder>>{
- 'test': [provider.getFolder(testProject)]
- }),
- new ResourceUriResolver(provider)
- ], null, provider),
- new AnalysisOptionsImpl()..strongMode = true);
- scheduler.start();
- driver.status.lastWhere((status) {
- allStatuses.add(status);
- if (status.isIdle) {
- idleStatusMonitor.notify();
- }
- });
- driver.results.listen(allResults.add);
- }
-
+class AnalysisDriverTest extends BaseAnalysisDriverTest {
test_addedFiles() async {
var a = _p('/test/lib/a.dart');
var b = _p('/test/lib/b.dart');
@@ -394,7 +347,7 @@
}
test_changeFile_single() async {
- _addTestFile('var V = 1;', priority: true);
+ addTestFile('var V = 1;', priority: true);
// Initial analysis.
{
@@ -428,7 +381,7 @@
test_getResult() async {
String content = 'int f() => 42;';
- _addTestFile(content, priority: true);
+ addTestFile(content, priority: true);
AnalysisResult result = await driver.getResult(testFile);
expect(result.path, testFile);
@@ -470,7 +423,7 @@
test_getResult_errors() async {
String content = 'main() { int vv; }';
- _addTestFile(content, priority: true);
+ addTestFile(content, priority: true);
AnalysisResult result = await driver.getResult(testFile);
expect(result.path, testFile);
@@ -485,8 +438,26 @@
}
}
+ test_getResult_hasIndex() async {
+ String content = r'''
+foo(int p) {}
+main() {
+ foo(42);
+}
+''';
+ addTestFile(content);
+
+ AnalysisResult result = await driver.getResult(testFile);
+
+ AnalysisDriverUnitIndex index = result.index;
+ int unitId = index.strings.indexOf('package:test/test.dart');
+ int fooId = index.strings.indexOf('foo');
+ expect(unitId, isNonNegative);
+ expect(fooId, isNonNegative);
+ }
+
test_getResult_inferTypes_finalField() async {
- _addTestFile(
+ addTestFile(
r'''
class C {
final f = 42;
@@ -500,7 +471,7 @@
}
test_getResult_inferTypes_instanceMethod() async {
- _addTestFile(
+ addTestFile(
r'''
class A {
int m(double p) => 1;
@@ -523,7 +494,7 @@
export 'dart:noSuchLib';
export 'dart:math';
''';
- _addTestFile(content, priority: true);
+ addTestFile(content, priority: true);
AnalysisResult result = await driver.getResult(testFile);
expect(result.path, testFile);
@@ -540,7 +511,7 @@
import 'dart:noSuchLib';
import 'dart:math';
''';
- _addTestFile(content, priority: true);
+ addTestFile(content, priority: true);
AnalysisResult result = await driver.getResult(testFile);
expect(result.path, testFile);
@@ -699,7 +670,7 @@
}
test_getResult_thenRemove() async {
- _addTestFile('main() {}', priority: true);
+ addTestFile('main() {}', priority: true);
Future<AnalysisResult> resultFuture = driver.getResult(testFile);
driver.removeFile(testFile);
@@ -712,7 +683,7 @@
test_getResult_twoPendingFutures() async {
String content = 'main() {}';
- _addTestFile(content, priority: true);
+ addTestFile(content, priority: true);
Future<AnalysisResult> future1 = driver.getResult(testFile);
Future<AnalysisResult> future2 = driver.getResult(testFile);
@@ -1044,7 +1015,7 @@
}
test_removeFile_changeFile_notAnalyzed() async {
- _addTestFile('main() {}');
+ addTestFile('main() {}');
// We have a result.
await _waitForIdle();
@@ -1064,7 +1035,7 @@
test_results_priority() async {
String content = 'int f() => 42;';
- _addTestFile(content, priority: true);
+ addTestFile(content, priority: true);
await _waitForIdle();
@@ -1105,7 +1076,7 @@
test_results_regular() async {
String content = 'int f() => 42;';
- _addTestFile(content);
+ addTestFile(content);
await _waitForIdle();
expect(allResults, hasLength(1));
@@ -1116,10 +1087,11 @@
expect(result.contentHash, _md5(content));
expect(result.unit, isNull);
expect(result.errors, hasLength(0));
+ expect(result.index, isNotNull);
}
test_results_status() async {
- _addTestFile('int f() => 42;');
+ addTestFile('int f() => 42;');
await _waitForIdle();
expect(allStatuses, hasLength(2));
@@ -1129,14 +1101,6 @@
expect(allStatuses[1].isIdle, isTrue);
}
- void _addTestFile(String content, {bool priority: false}) {
- provider.newFile(testFile, content);
- driver.addFile(testFile);
- if (priority) {
- driver.priorityFiles = [testFile];
- }
- }
-
ClassDeclaration _getClass(CompilationUnit unit, String name) {
for (CompilationUnitMember declaration in unit.declarations) {
if (declaration is ClassDeclaration) {
@@ -1233,18 +1197,3 @@
return hex.encode(md5.convert(UTF8.encode(content)).bytes);
}
}
-
-class _Monitor {
- Completer<Null> _completer = new Completer<Null>();
-
- Future<Null> get signal async {
- await _completer.future;
- _completer = new Completer<Null>();
- }
-
- void notify() {
- if (!_completer.isCompleted) {
- _completer.complete(null);
- }
- }
-}
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 2ef6802..a97f9c3 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -54,7 +54,7 @@
AnalysisOptions analysisOptions = new AnalysisOptionsImpl()
..strongMode = true;
fileSystemState = new FileSystemState(logger, byteStore, contentOverlay,
- provider, sourceFactory, analysisOptions, new Uint32List(0));
+ provider, sourceFactory, analysisOptions, new Uint32List(0), '');
}
test_getFileForPath_doesNotExist() {
@@ -211,6 +211,21 @@
expect(files, [filePackageUri, fileFileUri]);
}
+ test_referencedNames() {
+ String path = _p('/aaa/lib/a.dart');
+ provider.newFile(
+ path,
+ r'''
+A foo(B p) {
+ foo(null);
+ C c = new C(p);
+ return c;
+}
+''');
+ FileState file = fileSystemState.getFileForPath(path);
+ expect(file.referencedNames, unorderedEquals(['A', 'B', 'C']));
+ }
+
test_refresh_differentApiSignature() {
String path = _p('/aaa/lib/a.dart');
provider.newFile(
@@ -281,7 +296,7 @@
fb.transitiveFiles;
fc.transitiveFiles;
fd.transitiveFiles;
- expect(fileSystemState.test.filesWithoutTransitive, isEmpty);
+ expect(fileSystemState.test.filesWithoutTransitiveFiles, isEmpty);
// No imports, so just a single file.
provider.newFile(pa, "");
@@ -290,29 +305,29 @@
// Import b.dart into a.dart, two files now.
provider.newFile(pa, "import 'b.dart';");
fa.refresh();
- _assertFilesWithoutTransitive([fa]);
+ _assertFilesWithoutTransitiveFiles([fa]);
_assertTransitiveFiles(fa, [fa, fb]);
// Update b.dart so that it imports c.dart now.
provider.newFile(pb, "import 'c.dart';");
fb.refresh();
- _assertFilesWithoutTransitive([fa, fb]);
+ _assertFilesWithoutTransitiveFiles([fa, fb]);
_assertTransitiveFiles(fa, [fa, fb, fc]);
_assertTransitiveFiles(fb, [fb, fc]);
- _assertFilesWithoutTransitive([]);
+ _assertFilesWithoutTransitiveFiles([]);
// Update b.dart so that it exports d.dart instead.
provider.newFile(pb, "export 'd.dart';");
fb.refresh();
- _assertFilesWithoutTransitive([fa, fb]);
+ _assertFilesWithoutTransitiveFiles([fa, fb]);
_assertTransitiveFiles(fa, [fa, fb, fd]);
_assertTransitiveFiles(fb, [fb, fd]);
- _assertFilesWithoutTransitive([]);
+ _assertFilesWithoutTransitiveFiles([]);
// Update a.dart so that it does not import b.dart anymore.
provider.newFile(pa, "");
fa.refresh();
- _assertFilesWithoutTransitive([fa]);
+ _assertFilesWithoutTransitiveFiles([fa]);
_assertTransitiveFiles(fa, [fa]);
}
@@ -329,7 +344,7 @@
// Compute transitive closures for all files.
fa.transitiveFiles;
fb.transitiveFiles;
- _assertFilesWithoutTransitive([]);
+ _assertFilesWithoutTransitiveFiles([]);
// It's a cycle.
_assertTransitiveFiles(fa, [fa, fb]);
@@ -338,13 +353,54 @@
// Update a.dart so that it does not import b.dart anymore.
provider.newFile(pa, "");
fa.refresh();
- _assertFilesWithoutTransitive([fa, fb]);
+ _assertFilesWithoutTransitiveFiles([fa, fb]);
_assertTransitiveFiles(fa, [fa]);
_assertTransitiveFiles(fb, [fa, fb]);
}
- void _assertFilesWithoutTransitive(List<FileState> expected) {
- var actual = fileSystemState.test.filesWithoutTransitive;
+ test_transitiveSignature() {
+ String pa = _p('/aaa/lib/a.dart');
+ String pb = _p('/aaa/lib/b.dart');
+ String pc = _p('/aaa/lib/c.dart');
+ String pd = _p('/aaa/lib/d.dart');
+
+ provider.newFile(pa, "class A {}");
+ provider.newFile(pb, "import 'a.dart';");
+ provider.newFile(pc, "import 'b.dart';");
+ provider.newFile(pd, "class D {}");
+
+ FileState fa = fileSystemState.getFileForPath(pa);
+ FileState fb = fileSystemState.getFileForPath(pb);
+ FileState fc = fileSystemState.getFileForPath(pc);
+ FileState fd = fileSystemState.getFileForPath(pd);
+
+ // Compute transitive closures for all files.
+ expect(fa.transitiveSignature, isNotNull);
+ expect(fb.transitiveSignature, isNotNull);
+ expect(fc.transitiveSignature, isNotNull);
+ expect(fd.transitiveSignature, isNotNull);
+ expect(fileSystemState.test.filesWithoutTransitiveFiles, isEmpty);
+
+ // Make an update to a.dart that does not change its API signature.
+ // All transitive signatures are still valid.
+ provider.newFile(pa, "class A {} // the same API signature");
+ fa.refresh();
+ expect(fileSystemState.test.filesWithoutTransitiveFiles, isEmpty);
+
+ // Change a.dart API signature, also flush signatures of b.dart and c.dart,
+ // but d.dart is still OK.
+ provider.newFile(pa, "class A2 {}");
+ fa.refresh();
+ _assertFilesWithoutTransitiveSignatures([fa, fb, fc]);
+ }
+
+ void _assertFilesWithoutTransitiveFiles(List<FileState> expected) {
+ var actual = fileSystemState.test.filesWithoutTransitiveFiles;
+ expect(actual, unorderedEquals(expected));
+ }
+
+ void _assertFilesWithoutTransitiveSignatures(List<FileState> expected) {
+ var actual = fileSystemState.test.filesWithoutTransitiveSignature;
expect(actual, unorderedEquals(expected));
}
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
new file mode 100644
index 0000000..8c544c7
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -0,0 +1,1267 @@
+// 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:convert';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/index.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'base.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(IndexTest);
+ });
+}
+
+/**
+ * Finds an [Element] with the given [name].
+ */
+Element findChildElement(Element root, String name, [ElementKind kind]) {
+ Element result = null;
+ root.accept(new _ElementVisitorFunctionWrapper((Element element) {
+ if (element.name != name) {
+ return;
+ }
+ if (kind != null && element.kind != kind) {
+ return;
+ }
+ result = element;
+ }));
+ return result;
+}
+
+/**
+ * A function to be called for every [Element].
+ */
+typedef void _ElementVisitorFunction(Element element);
+
+class ExpectedLocation {
+ final CompilationUnitElement unitElement;
+ final int offset;
+ final int length;
+ final bool isQualified;
+
+ ExpectedLocation(
+ this.unitElement, this.offset, this.length, this.isQualified);
+
+ @override
+ String toString() {
+ return '(unit=$unitElement; offset=$offset; length=$length;'
+ ' isQualified=$isQualified)';
+ }
+}
+
+@reflectiveTest
+class IndexTest extends BaseAnalysisDriverTest {
+ CompilationUnit testUnit;
+ CompilationUnitElement testUnitElement;
+ LibraryElement testLibraryElement;
+
+ AnalysisDriverUnitIndex index;
+
+ _ElementIndexAssert assertThat(Element element) {
+ List<_Relation> relations = _getElementRelations(element);
+ return new _ElementIndexAssert(this, element, relations);
+ }
+
+ _NameIndexAssert assertThatName(String name) {
+ return new _NameIndexAssert(this, name);
+ }
+
+ Element findElement(String name, [ElementKind kind]) {
+ return findChildElement(testUnitElement, name, kind);
+ }
+
+ CompilationUnitElement importedUnit({int index: 0}) {
+ List<ImportElement> imports = testLibraryElement.imports;
+ return imports[index].importedLibrary.definingCompilationUnit;
+ }
+
+ test_hasAncestor_ClassDeclaration() async {
+ await _indexTestUnit('''
+class A {}
+class B1 extends A {}
+class B2 implements A {}
+class C1 extends B1 {}
+class C2 extends B2 {}
+class C3 implements B1 {}
+class C4 implements B2 {}
+class M extends Object with A {}
+''');
+ ClassElement classElementA = findElement("A");
+ assertThat(classElementA)
+ ..isAncestorOf('B1 extends A')
+ ..isAncestorOf('B2 implements A')
+ ..isAncestorOf('C1 extends B1')
+ ..isAncestorOf('C2 extends B2')
+ ..isAncestorOf('C3 implements B1')
+ ..isAncestorOf('C4 implements B2')
+ ..isAncestorOf('M extends Object with A');
+ }
+
+ test_hasAncestor_ClassTypeAlias() async {
+ await _indexTestUnit('''
+class A {}
+class B extends A {}
+class C1 = Object with A;
+class C2 = Object with B;
+''');
+ ClassElement classElementA = findElement('A');
+ ClassElement classElementB = findElement('B');
+ assertThat(classElementA)
+ ..isAncestorOf('C1 = Object with A')
+ ..isAncestorOf('C2 = Object with B');
+ assertThat(classElementB)..isAncestorOf('C2 = Object with B');
+ }
+
+ test_isExtendedBy_ClassDeclaration() async {
+ await _indexTestUnit('''
+class A {} // 1
+class B extends A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isExtendedAt('A {} // 2', false)
+ ..isReferencedAt('A {} // 2', false);
+ }
+
+ test_isExtendedBy_ClassDeclaration_isQualified() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+class A {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends p.A {} // 2
+''');
+ ClassElement elementA = importedUnit().getType('A');
+ assertThat(elementA).isExtendedAt('A {} // 2', true);
+ }
+
+ test_isExtendedBy_ClassDeclaration_Object() async {
+ await _indexTestUnit('''
+class A {}
+''');
+ ClassElement elementA = findElement('A');
+ ClassElement elementObject = elementA.supertype.element;
+ assertThat(elementObject).isExtendedAt('A {}', true, length: 0);
+ }
+
+ test_isExtendedBy_ClassTypeAlias() async {
+ await _indexTestUnit('''
+class A {}
+class B {}
+class C = A with B;
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isExtendedAt('A with', false)
+ ..isReferencedAt('A with', false);
+ }
+
+ test_isExtendedBy_ClassTypeAlias_isQualified() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+class A {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart' as p;
+class B {}
+class C = p.A with B;
+''');
+ ClassElement elementA = importedUnit().getType('A');
+ assertThat(elementA)
+ ..isExtendedAt('A with', true)
+ ..isReferencedAt('A with', true);
+ }
+
+ test_isImplementedBy_ClassDeclaration() async {
+ await _indexTestUnit('''
+class A {} // 1
+class B implements A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isImplementedAt('A {} // 2', false)
+ ..isReferencedAt('A {} // 2', false);
+ }
+
+ test_isImplementedBy_ClassDeclaration_isQualified() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+class A {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart' as p;
+class B implements p.A {} // 2
+''');
+ ClassElement elementA = importedUnit().getType('A');
+ assertThat(elementA)
+ ..isImplementedAt('A {} // 2', true)
+ ..isReferencedAt('A {} // 2', true);
+ }
+
+ test_isImplementedBy_ClassTypeAlias() async {
+ await _indexTestUnit('''
+class A {} // 1
+class B {} // 2
+class C = Object with A implements B; // 3
+''');
+ ClassElement elementB = findElement('B');
+ assertThat(elementB)
+ ..isImplementedAt('B; // 3', false)
+ ..isReferencedAt('B; // 3', false);
+ }
+
+ test_isInvokedBy_FieldElement() async {
+ await _indexTestUnit('''
+class A {
+ var field;
+ main() {
+ this.field(); // q
+ field(); // nq
+ }
+}''');
+ FieldElement field = findElement('field');
+ assertThat(field.getter)
+ ..isInvokedAt('field(); // q', true)
+ ..isInvokedAt('field(); // nq', false);
+ }
+
+ test_isInvokedBy_FunctionElement() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+library lib;
+foo() {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart';
+import 'lib.dart' as pref;
+main() {
+ pref.foo(); // q
+ foo(); // nq
+}''');
+ FunctionElement element = importedUnit().functions[0];
+ assertThat(element)
+ ..isInvokedAt('foo(); // q', true)
+ ..isInvokedAt('foo(); // nq', false);
+ }
+
+ test_isInvokedBy_FunctionElement_synthetic_loadLibrary() async {
+ await _indexTestUnit('''
+import 'dart:math' deferred as math;
+main() {
+ math.loadLibrary(); // 1
+ math.loadLibrary(); // 2
+}
+''');
+ LibraryElement mathLib = testLibraryElement.imports[0].importedLibrary;
+ FunctionElement element = mathLib.loadLibraryFunction;
+ assertThat(element).isInvokedAt('loadLibrary(); // 1', true);
+ assertThat(element).isInvokedAt('loadLibrary(); // 2', true);
+ }
+
+ test_isInvokedBy_MethodElement() async {
+ await _indexTestUnit('''
+class A {
+ foo() {}
+ main() {
+ this.foo(); // q
+ foo(); // nq
+ }
+}''');
+ Element element = findElement('foo');
+ assertThat(element)
+ ..isInvokedAt('foo(); // q', true)
+ ..isInvokedAt('foo(); // nq', false);
+ }
+
+ test_isInvokedBy_MethodElement_propagatedType() async {
+ await _indexTestUnit('''
+class A {
+ foo() {}
+}
+main() {
+ var a = new A();
+ a.foo();
+}
+''');
+ Element element = findElement('foo');
+ assertThat(element).isInvokedAt('foo();', true);
+ }
+
+ test_isInvokedBy_operator_binary() async {
+ await _indexTestUnit('''
+class A {
+ operator +(other) => this;
+}
+main(A a) {
+ print(a + 1);
+ a += 2;
+ ++a;
+ a++;
+}
+''');
+ MethodElement element = findElement('+');
+ assertThat(element)
+ ..isInvokedAt('+ 1', true, length: 1)
+ ..isInvokedAt('+= 2', true, length: 2)
+ ..isInvokedAt('++a', true, length: 2)
+ ..isInvokedAt('++;', true, length: 2);
+ }
+
+ test_isInvokedBy_operator_index() async {
+ await _indexTestUnit('''
+class A {
+ operator [](i) => null;
+ operator []=(i, v) {}
+}
+main(A a) {
+ print(a[0]);
+ a[1] = 42;
+}
+''');
+ MethodElement readElement = findElement('[]');
+ MethodElement writeElement = findElement('[]=');
+ assertThat(readElement).isInvokedAt('[0]', true, length: 1);
+ assertThat(writeElement).isInvokedAt('[1]', true, length: 1);
+ }
+
+ test_isInvokedBy_operator_prefix() async {
+ await _indexTestUnit('''
+class A {
+ A operator ~() => this;
+}
+main(A a) {
+ print(~a);
+}
+''');
+ MethodElement element = findElement('~');
+ assertThat(element).isInvokedAt('~a', true, length: 1);
+ }
+
+ test_isInvokedBy_PropertyAccessorElement_getter() async {
+ await _indexTestUnit('''
+class A {
+ get ggg => null;
+ main() {
+ this.ggg(); // q
+ ggg(); // nq
+ }
+}''');
+ PropertyAccessorElement element = findElement('ggg', ElementKind.GETTER);
+ assertThat(element)
+ ..isInvokedAt('ggg(); // q', true)
+ ..isInvokedAt('ggg(); // nq', false);
+ }
+
+ test_isMixedInBy_ClassDeclaration() async {
+ await _indexTestUnit('''
+class A {} // 1
+class B extends Object with A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isMixedInAt('A {} // 2', false)
+ ..isReferencedAt('A {} // 2', false);
+ }
+
+ test_isMixedInBy_ClassDeclaration_isQualified() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+class A {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends Object with p.A {} // 2
+''');
+ ClassElement elementA = importedUnit().getType('A');
+ assertThat(elementA).isMixedInAt('A {} // 2', true);
+ }
+
+ test_isMixedInBy_ClassTypeAlias() async {
+ await _indexTestUnit('''
+class A {} // 1
+class B = Object with A; // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isMixedInAt('A; // 2', false);
+ }
+
+ test_isReferencedBy_ClassElement() async {
+ await _indexTestUnit('''
+class A {
+ static var field;
+}
+main(A p) {
+ A v;
+ new A(); // 2
+ A.field = 1;
+ print(A.field); // 3
+}
+''');
+ ClassElement element = findElement('A');
+ assertThat(element)
+ ..isReferencedAt('A p) {', false)
+ ..isReferencedAt('A v;', false)
+ ..isReferencedAt('A(); // 2', false)
+ ..isReferencedAt('A.field = 1;', false)
+ ..isReferencedAt('A.field); // 3', false);
+ }
+
+ test_isReferencedBy_ClassElement_invocation() async {
+ await _indexTestUnit('''
+class A {}
+main() {
+ A(); // invalid code, but still a reference
+}''');
+ Element element = findElement('A');
+ assertThat(element).isReferencedAt('A();', false);
+ }
+
+ test_isReferencedBy_ClassElement_invocation_isQualified() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+class A {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart' as p;
+main() {
+ p.A(); // invalid code, but still a reference
+}''');
+ Element element = importedUnit().getType('A');
+ assertThat(element).isReferencedAt('A();', true);
+ }
+
+ test_isReferencedBy_ClassTypeAlias() async {
+ await _indexTestUnit('''
+class A {}
+class B = Object with A;
+main(B p) {
+ B v;
+}
+''');
+ ClassElement element = findElement('B');
+ assertThat(element)
+ ..isReferencedAt('B p) {', false)
+ ..isReferencedAt('B v;', false);
+ }
+
+ test_isReferencedBy_CompilationUnitElement_export() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+library lib;
+''');
+ await _indexTestUnit('''
+export 'lib.dart';
+''');
+ LibraryElement element = testLibraryElement.exports[0].exportedLibrary;
+ assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+ }
+
+ test_isReferencedBy_CompilationUnitElement_import() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+library lib;
+''');
+ await _indexTestUnit('''
+import 'lib.dart';
+''');
+ LibraryElement element = testLibraryElement.imports[0].importedLibrary;
+ assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+ }
+
+ test_isReferencedBy_CompilationUnitElement_part() async {
+ provider.newFile(_p('$testProject/my_unit.dart'), 'part of my_lib;');
+ await _indexTestUnit('''
+library my_lib;
+part 'my_unit.dart';
+''');
+ CompilationUnitElement element = testLibraryElement.parts[0];
+ assertThat(element)..isReferencedAt("'my_unit.dart';", true, length: 14);
+ }
+
+ test_isReferencedBy_ConstructorElement() async {
+ await _indexTestUnit('''
+class A implements B {
+ A() {}
+ A.foo() {}
+}
+class B extends A {
+ B() : super(); // 1
+ B.foo() : super.foo(); // 2
+ factory B.bar() = A.foo; // 3
+}
+main() {
+ new A(); // 4
+ new A.foo(); // 5
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_foo = classA.constructors[1];
+ // A()
+ assertThat(constA)
+ ..hasRelationCount(2)
+ ..isReferencedAt('(); // 1', true, length: 0)
+ ..isReferencedAt('(); // 4', true, length: 0);
+ // A.foo()
+ assertThat(constA_foo)
+ ..hasRelationCount(3)
+ ..isReferencedAt('.foo(); // 2', true, length: 4)
+ ..isReferencedAt('.foo; // 3', true, length: 4)
+ ..isReferencedAt('.foo(); // 5', true, length: 4);
+ }
+
+ test_isReferencedBy_ConstructorElement_classTypeAlias() async {
+ await _indexTestUnit('''
+class M {}
+class A implements B {
+ A() {}
+ A.named() {}
+}
+class B = A with M;
+class C = B with M;
+main() {
+ new B(); // B1
+ new B.named(); // B2
+ new C(); // C1
+ new C.named(); // C2
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_named = classA.constructors[1];
+ assertThat(constA)
+ ..isReferencedAt('(); // B1', true, length: 0)
+ ..isReferencedAt('(); // C1', true, length: 0);
+ assertThat(constA_named)
+ ..isReferencedAt('.named(); // B2', true, length: 6)
+ ..isReferencedAt('.named(); // C2', true, length: 6);
+ }
+
+ test_isReferencedBy_ConstructorElement_classTypeAlias_cycle() async {
+ await _indexTestUnit('''
+class M {}
+class A = B with M;
+class B = A with M;
+main() {
+ new A();
+ new B();
+}
+''');
+ // No additional validation, but it should not fail with stack overflow.
+ }
+
+ test_isReferencedBy_ConstructorElement_namedOnlyWithDot() async {
+ await _indexTestUnit('''
+class A {
+ A.named() {}
+}
+main() {
+ new A.named();
+}
+''');
+ // has ".named()", but does not have "named()"
+ int offsetWithoutDot = findOffset('named();');
+ int offsetWithDot = findOffset('.named();');
+ expect(index.usedElementOffsets, isNot(contains(offsetWithoutDot)));
+ expect(index.usedElementOffsets, contains(offsetWithDot));
+ }
+
+ test_isReferencedBy_ConstructorElement_redirection() async {
+ await _indexTestUnit('''
+class A {
+ A() : this.bar(); // 1
+ A.foo() : this(); // 2
+ A.bar();
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_bar = classA.constructors[2];
+ assertThat(constA).isReferencedAt('(); // 2', true, length: 0);
+ assertThat(constA_bar).isReferencedAt('.bar(); // 1', true, length: 4);
+ }
+
+ test_isReferencedBy_ConstructorElement_synthetic() async {
+ await _indexTestUnit('''
+class A {}
+main() {
+ new A(); // 1
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ // A()
+ assertThat(constA)..isReferencedAt('(); // 1', true, length: 0);
+ }
+
+ test_isReferencedBy_DynamicElement() async {
+ await _indexTestUnit('''
+dynamic f() {
+}''');
+ expect(index.usedElementOffsets, isEmpty);
+ }
+
+ test_isReferencedBy_FieldElement() async {
+ await _indexTestUnit('''
+class A {
+ var field;
+ A({this.field});
+ m() {
+ field = 2; // nq
+ print(field); // nq
+ }
+}
+main(A a) {
+ a.field = 3; // q
+ print(a.field); // q
+ new A(field: 4);
+}
+''');
+ FieldElement field = findElement('field', ElementKind.FIELD);
+ PropertyAccessorElement getter = field.getter;
+ PropertyAccessorElement setter = field.setter;
+ // A()
+ assertThat(field)..isWrittenAt('field});', true);
+ // m()
+ assertThat(setter)..isReferencedAt('field = 2; // nq', false);
+ assertThat(getter)..isReferencedAt('field); // nq', false);
+ // main()
+ assertThat(setter)..isReferencedAt('field = 3; // q', true);
+ assertThat(getter)..isReferencedAt('field); // q', true);
+ assertThat(field)..isReferencedAt('field: 4', true);
+ }
+
+ test_isReferencedBy_FieldElement_multiple() async {
+ await _indexTestUnit('''
+class A {
+ var aaa;
+ var bbb;
+ A(this.aaa, this.bbb) {}
+ m() {
+ print(aaa);
+ aaa = 1;
+ print(bbb);
+ bbb = 2;
+ }
+}
+''');
+ // aaa
+ {
+ FieldElement field = findElement('aaa', ElementKind.FIELD);
+ PropertyAccessorElement getter = field.getter;
+ PropertyAccessorElement setter = field.setter;
+ assertThat(field)..isWrittenAt('aaa, ', true);
+ assertThat(getter)..isReferencedAt('aaa);', false);
+ assertThat(setter)..isReferencedAt('aaa = 1;', false);
+ }
+ // bbb
+ {
+ FieldElement field = findElement('bbb', ElementKind.FIELD);
+ PropertyAccessorElement getter = field.getter;
+ PropertyAccessorElement setter = field.setter;
+ assertThat(field)..isWrittenAt('bbb) {}', true);
+ assertThat(getter)..isReferencedAt('bbb);', false);
+ assertThat(setter)..isReferencedAt('bbb = 2;', false);
+ }
+ }
+
+ test_isReferencedBy_FieldElement_ofEnum() async {
+ await _indexTestUnit('''
+enum MyEnum {
+ A, B, C
+}
+main() {
+ print(MyEnum.values);
+ print(MyEnum.A.index);
+ print(MyEnum.A);
+ print(MyEnum.B);
+}
+''');
+ ClassElement enumElement = findElement('MyEnum');
+ assertThat(enumElement.getGetter('values'))
+ ..isReferencedAt('values);', true);
+ assertThat(enumElement.getGetter('index'))..isReferencedAt('index);', true);
+ assertThat(enumElement.getGetter('A'))..isReferencedAt('A);', true);
+ assertThat(enumElement.getGetter('B'))..isReferencedAt('B);', true);
+ }
+
+ test_isReferencedBy_FieldElement_synthetic_hasGetter() async {
+ await _indexTestUnit('''
+class A {
+ A() : f = 42;
+ int get f => 0;
+}
+''');
+ ClassElement element2 = findElement('A');
+ assertThat(element2.getField('f')).isWrittenAt('f = 42', true);
+ }
+
+ test_isReferencedBy_FieldElement_synthetic_hasGetterSetter() async {
+ await _indexTestUnit('''
+class A {
+ A() : f = 42;
+ int get f => 0;
+ set f(_) {}
+}
+''');
+ ClassElement element2 = findElement('A');
+ assertThat(element2.getField('f')).isWrittenAt('f = 42', true);
+ }
+
+ test_isReferencedBy_FieldElement_synthetic_hasSetter() async {
+ await _indexTestUnit('''
+class A {
+ A() : f = 42;
+ set f(_) {}
+}
+''');
+ ClassElement element2 = findElement('A');
+ assertThat(element2.getField('f')).isWrittenAt('f = 42', true);
+ }
+
+ test_isReferencedBy_FunctionElement() async {
+ await _indexTestUnit('''
+foo() {}
+main() {
+ print(foo);
+ print(foo());
+}
+''');
+ FunctionElement element = findElement('foo');
+ assertThat(element)
+ ..isReferencedAt('foo);', false)
+ ..isInvokedAt('foo());', false);
+ }
+
+ test_isReferencedBy_FunctionElement_with_LibraryElement() async {
+ provider.newFile(
+ _p('$testProject/foo.dart'),
+ r'''
+bar() {}
+''');
+ await _indexTestUnit('''
+import "foo.dart";
+main() {
+ bar();
+}
+''');
+ LibraryElement fooLibrary = testLibraryElement.imports[0].importedLibrary;
+ assertThat(fooLibrary)..isReferencedAt('"foo.dart";', true, length: 10);
+ {
+ FunctionElement bar = fooLibrary.definingCompilationUnit.functions[0];
+ assertThat(bar)..isInvokedAt('bar();', false);
+ }
+ }
+
+ test_isReferencedBy_FunctionTypeAliasElement() async {
+ await _indexTestUnit('''
+typedef A();
+main(A p) {
+}
+''');
+ Element element = findElement('A');
+ assertThat(element)..isReferencedAt('A p) {', false);
+ }
+
+ /**
+ * There was a bug in the AST structure, when single [Comment] was cloned and
+ * assigned to both [FieldDeclaration] and [VariableDeclaration].
+ *
+ * This caused duplicate indexing.
+ * Here we test that the problem is fixed one way or another.
+ */
+ test_isReferencedBy_identifierInComment() async {
+ await _indexTestUnit('''
+class A {}
+/// [A] text
+var myVariable = null;
+''');
+ Element element = findElement('A');
+ assertThat(element)..isReferencedAt('A] text', false);
+ }
+
+ test_isReferencedBy_MethodElement() async {
+ await _indexTestUnit('''
+class A {
+ method() {}
+ main() {
+ print(this.method); // q
+ print(method); // nq
+ }
+}''');
+ MethodElement element = findElement('method');
+ assertThat(element)
+ ..isReferencedAt('method); // q', true)
+ ..isReferencedAt('method); // nq', false);
+ }
+
+ test_isReferencedBy_ParameterElement() async {
+ await _indexTestUnit('''
+foo({var p}) {}
+main() {
+ foo(p: 1);
+}
+''');
+ Element element = findElement('p');
+ assertThat(element)..isReferencedAt('p: 1', true);
+ }
+
+ test_isReferencedBy_TopLevelVariableElement() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+library lib;
+var V;
+''');
+ await _indexTestUnit('''
+import 'lib.dart' show V; // imp
+import 'lib.dart' as pref;
+main() {
+ pref.V = 5; // q
+ print(pref.V); // q
+ V = 5; // nq
+ print(V); // nq
+}''');
+ TopLevelVariableElement variable = importedUnit().topLevelVariables[0];
+ assertThat(variable)..isReferencedAt('V; // imp', true);
+ assertThat(variable.getter)
+ ..isReferencedAt('V); // q', true)
+ ..isReferencedAt('V); // nq', false);
+ assertThat(variable.setter)
+ ..isReferencedAt('V = 5; // q', true)
+ ..isReferencedAt('V = 5; // nq', false);
+ }
+
+ test_isReferencedBy_TopLevelVariableElement_synthetic_hasGetterSetter() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+int get V => 0;
+void set V(_) {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart' show V;
+''');
+ TopLevelVariableElement element = importedUnit().topLevelVariables[0];
+ assertThat(element).isReferencedAt('V;', true);
+ }
+
+ test_isReferencedBy_TopLevelVariableElement_synthetic_hasSetter() async {
+ provider.newFile(
+ _p('$testProject/lib.dart'),
+ '''
+void set V(_) {}
+''');
+ await _indexTestUnit('''
+import 'lib.dart' show V;
+''');
+ TopLevelVariableElement element = importedUnit().topLevelVariables[0];
+ assertThat(element).isReferencedAt('V;', true);
+ }
+
+ test_isReferencedBy_typeInVariableList() async {
+ await _indexTestUnit('''
+class A {}
+A myVariable = null;
+''');
+ Element element = findElement('A');
+ assertThat(element).isReferencedAt('A myVariable', false);
+ }
+
+ test_isWrittenBy_FieldElement() async {
+ await _indexTestUnit('''
+class A {
+ int field;
+ A.foo({this.field});
+ A.bar() : field = 5;
+}
+''');
+ FieldElement element = findElement('field', ElementKind.FIELD);
+ assertThat(element)
+ ..isWrittenAt('field})', true)
+ ..isWrittenAt('field = 5', true);
+ }
+
+ test_usedName_inLibraryIdentifier() async {
+ await _indexTestUnit('''
+library aaa.bbb.ccc;
+class C {
+ var bbb;
+}
+main(p) {
+ p.bbb = 1;
+}
+''');
+ assertThatName('bbb')
+ ..isNotUsed('bbb.ccc', IndexRelationKind.IS_READ_BY)
+ ..isUsedQ('bbb = 1;', IndexRelationKind.IS_WRITTEN_BY);
+ }
+
+ test_usedName_qualified_resolved() async {
+ await _indexTestUnit('''
+class C {
+ var x;
+}
+main(C c) {
+ c.x;
+ c.x = 1;
+ c.x += 2;
+ c.x();
+}
+''');
+ assertThatName('x')
+ ..isNotUsedQ('x;', IndexRelationKind.IS_READ_BY)
+ ..isNotUsedQ('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+ ..isNotUsedQ('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+ ..isNotUsedQ('x();', IndexRelationKind.IS_INVOKED_BY);
+ }
+
+ test_usedName_qualified_unresolved() async {
+ await _indexTestUnit('''
+main(p) {
+ p.x;
+ p.x = 1;
+ p.x += 2;
+ p.x();
+}
+''');
+ assertThatName('x')
+ ..isUsedQ('x;', IndexRelationKind.IS_READ_BY)
+ ..isUsedQ('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+ ..isUsedQ('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+ ..isUsedQ('x();', IndexRelationKind.IS_INVOKED_BY);
+ }
+
+ test_usedName_unqualified_resolved() async {
+ await _indexTestUnit('''
+class C {
+ var x;
+ m() {
+ x;
+ x = 1;
+ x += 2;
+ x();
+ }
+}
+''');
+ assertThatName('x')
+ ..isNotUsedQ('x;', IndexRelationKind.IS_READ_BY)
+ ..isNotUsedQ('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+ ..isNotUsedQ('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+ ..isNotUsedQ('x();', IndexRelationKind.IS_INVOKED_BY);
+ }
+
+ test_usedName_unqualified_unresolved() async {
+ await _indexTestUnit('''
+main() {
+ x;
+ x = 1;
+ x += 2;
+ x();
+}
+''');
+ assertThatName('x')
+ ..isUsed('x;', IndexRelationKind.IS_READ_BY)
+ ..isUsed('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+ ..isUsed('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+ ..isUsed('x();', IndexRelationKind.IS_INVOKED_BY);
+ }
+
+ /**
+ * Asserts that [index] has an item with the expected properties.
+ */
+ void _assertHasRelation(
+ Element element,
+ List<_Relation> relations,
+ IndexRelationKind expectedRelationKind,
+ ExpectedLocation expectedLocation) {
+ for (_Relation relation in relations) {
+ if (relation.kind == expectedRelationKind &&
+ relation.offset == expectedLocation.offset &&
+ relation.length == expectedLocation.length &&
+ relation.isQualified == expectedLocation.isQualified) {
+ return;
+ }
+ }
+ _failWithIndexDump(
+ 'not found\n$element $expectedRelationKind at $expectedLocation');
+ }
+
+ void _assertUsedName(String name, IndexRelationKind kind,
+ ExpectedLocation expectedLocation, bool isNot) {
+ int nameId = _getStringId(name);
+ for (int i = 0; i < index.usedNames.length; i++) {
+ if (index.usedNames[i] == nameId &&
+ index.usedNameKinds[i] == kind &&
+ index.usedNameOffsets[i] == expectedLocation.offset &&
+ index.usedNameIsQualifiedFlags[i] == expectedLocation.isQualified) {
+ if (isNot) {
+ _failWithIndexDump('Unexpected $name $kind at $expectedLocation');
+ }
+ return;
+ }
+ }
+ if (isNot) {
+ return;
+ }
+ _failWithIndexDump('Not found $name $kind at $expectedLocation');
+ }
+
+ ExpectedLocation _expectedLocation(String search, bool isQualified,
+ {int length}) {
+ int offset = findOffset(search);
+ if (length == null) {
+ length = getLeadingIdentifierLength(search);
+ }
+ return new ExpectedLocation(testUnitElement, offset, length, isQualified);
+ }
+
+ void _failWithIndexDump(String msg) {
+ String packageIndexJsonString =
+ new JsonEncoder.withIndent(' ').convert(index.toJson());
+ fail('$msg in\n' + packageIndexJsonString);
+ }
+
+ /**
+ * Return the [element] identifier in [index] or fail.
+ */
+ int _findElementId(Element element) {
+ int unitId = _getUnitId(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 = index.nullStringId;
+ int classMemberId = index.nullStringId;
+ int parameterId = index.nullStringId;
+ for (Element e = element; e != null; e = e.enclosingElement) {
+ if (e.enclosingElement is CompilationUnitElement) {
+ unitMemberId = _getStringId(e.name);
+ break;
+ }
+ }
+ for (Element e = element; e != null; e = e.enclosingElement) {
+ if (e.enclosingElement is ClassElement) {
+ classMemberId = _getStringId(e.name);
+ break;
+ }
+ }
+ if (element is ParameterElement) {
+ parameterId = _getStringId(element.name);
+ }
+ // Find the element's id.
+ for (int elementId = 0;
+ elementId < index.elementUnits.length;
+ elementId++) {
+ if (index.elementUnits[elementId] == unitId &&
+ index.elementNameUnitMemberIds[elementId] == unitMemberId &&
+ index.elementNameClassMemberIds[elementId] == classMemberId &&
+ index.elementNameParameterIds[elementId] == parameterId &&
+ index.elementKinds[elementId] == info.kind) {
+ return elementId;
+ }
+ }
+ _failWithIndexDump('Element $element is not referenced');
+ return 0;
+ }
+
+ /**
+ * Return all relations with [element] in [index].
+ */
+ List<_Relation> _getElementRelations(Element element) {
+ int elementId = _findElementId(element);
+ List<_Relation> relations = <_Relation>[];
+ for (int i = 0; i < index.usedElementOffsets.length; i++) {
+ if (index.usedElements[i] == elementId) {
+ relations.add(new _Relation(
+ index.usedElementKinds[i],
+ index.usedElementOffsets[i],
+ index.usedElementLengths[i],
+ index.usedElementIsQualifiedFlags[i]));
+ }
+ }
+ return relations;
+ }
+
+ int _getStringId(String str) {
+ int id = index.strings.indexOf(str);
+ if (id < 0) {
+ _failWithIndexDump('String "$str" is not referenced');
+ }
+ return id;
+ }
+
+ int _getUnitId(Element element) {
+ CompilationUnitElement unitElement = getUnitElement(element);
+ int libraryUriId = _getUriId(unitElement.library.source.uri);
+ int unitUriId = _getUriId(unitElement.source.uri);
+ expect(index.unitLibraryUris, hasLength(index.unitUnitUris.length));
+ for (int i = 0; i < index.unitLibraryUris.length; i++) {
+ if (index.unitLibraryUris[i] == libraryUriId &&
+ index.unitUnitUris[i] == unitUriId) {
+ return i;
+ }
+ }
+ _failWithIndexDump('Unit $unitElement of $element is not referenced');
+ return -1;
+ }
+
+ int _getUriId(Uri uri) {
+ String str = uri.toString();
+ return _getStringId(str);
+ }
+
+ Future<Null> _indexTestUnit(String code) async {
+ addTestFile(code);
+
+ AnalysisResult result = await driver.getResult(testFile);
+ testUnit = result.unit;
+ testUnitElement = testUnit.element;
+ testLibraryElement = testUnitElement.library;
+
+ AnalysisDriverUnitIndexBuilder indexBuilder = indexUnit(testUnit);
+ List<int> indexBytes = indexBuilder.toBuffer();
+ index = new AnalysisDriverUnitIndex.fromBuffer(indexBytes);
+ }
+
+ String _p(String path) => provider.convertPath(path);
+}
+
+class _ElementIndexAssert {
+ final IndexTest test;
+ final Element element;
+ final List<_Relation> relations;
+
+ _ElementIndexAssert(this.test, this.element, this.relations);
+
+ void hasRelationCount(int expectedCount) {
+ expect(relations, hasLength(expectedCount));
+ }
+
+ void isAncestorOf(String search, {int length}) {
+ test._assertHasRelation(
+ element,
+ relations,
+ IndexRelationKind.IS_ANCESTOR_OF,
+ test._expectedLocation(search, false, length: length));
+ }
+
+ void isExtendedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(
+ element,
+ relations,
+ IndexRelationKind.IS_EXTENDED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isImplementedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(
+ element,
+ relations,
+ IndexRelationKind.IS_IMPLEMENTED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isInvokedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(element, relations, IndexRelationKind.IS_INVOKED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isMixedInAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(
+ element,
+ relations,
+ IndexRelationKind.IS_MIXED_IN_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isReferencedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(
+ element,
+ relations,
+ IndexRelationKind.IS_REFERENCED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isWrittenAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(element, relations, IndexRelationKind.IS_WRITTEN_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+}
+
+/**
+ * Wraps an [_ElementVisitorFunction] into a [GeneralizingElementVisitor].
+ */
+class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor {
+ final _ElementVisitorFunction function;
+
+ _ElementVisitorFunctionWrapper(this.function);
+
+ visitElement(Element element) {
+ function(element);
+ super.visitElement(element);
+ }
+}
+
+class _NameIndexAssert {
+ final IndexTest test;
+ final String name;
+
+ _NameIndexAssert(this.test, this.name);
+
+ void isNotUsed(String search, IndexRelationKind kind) {
+ test._assertUsedName(
+ name, kind, test._expectedLocation(search, false), true);
+ }
+
+ void isNotUsedQ(String search, IndexRelationKind kind) {
+ test._assertUsedName(
+ name, kind, test._expectedLocation(search, true), true);
+ }
+
+ void isUsed(String search, IndexRelationKind kind) {
+ test._assertUsedName(
+ name, kind, test._expectedLocation(search, false), false);
+ }
+
+ void isUsedQ(String search, IndexRelationKind kind) {
+ test._assertUsedName(
+ name, kind, test._expectedLocation(search, true), false);
+ }
+}
+
+class _Relation {
+ final IndexRelationKind kind;
+ final int offset;
+ final int length;
+ final bool isQualified;
+
+ _Relation(this.kind, this.offset, this.length, this.isQualified);
+
+ @override
+ String toString() {
+ return '_Relation{kind: $kind, offset: $offset, length: $length, '
+ 'isQualified: $isQualified}lified)';
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
new file mode 100644
index 0000000..03a2a53
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -0,0 +1,168 @@
+// 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 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/search.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'base.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(SearchTest);
+ });
+}
+
+class ExpectedResult {
+ final List<String> enclosingComponents;
+ final SearchResultKind kind;
+ final int offset;
+ final int length;
+ final bool isResolved;
+ final bool isQualified;
+
+ ExpectedResult(this.enclosingComponents, this.kind, this.offset, this.length,
+ {this.isResolved: true, this.isQualified: false});
+
+ bool operator ==(Object result) {
+ return result is SearchResult &&
+ result.kind == this.kind &&
+ result.isResolved == this.isResolved &&
+ result.isQualified == this.isQualified &&
+ result.offset == this.offset &&
+ hasExpectedComponents(result.enclosingElement);
+ }
+
+ bool hasExpectedComponents(Element element) {
+ for (int i = enclosingComponents.length - 1; i >= 0; i--) {
+ if (element == null) {
+ return false;
+ }
+ if (element is CompilationUnitElement) {
+ if (element.source.uri.toString() != enclosingComponents[0]) {
+ return false;
+ }
+ } else if (element.name != enclosingComponents[i]) {
+ return false;
+ }
+ element = element.enclosingElement;
+ }
+ return true;
+ }
+
+ @override
+ String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.write("ExpectedResult(kind=");
+ buffer.write(kind);
+ buffer.write(", enclosingComponents=");
+ buffer.write(enclosingComponents);
+ buffer.write(", offset=");
+ buffer.write(offset);
+ buffer.write(", length=");
+ buffer.write(length);
+ buffer.write(", isResolved=");
+ buffer.write(isResolved);
+ buffer.write(", isQualified=");
+ buffer.write(isQualified);
+ buffer.write(")");
+ return buffer.toString();
+ }
+}
+
+@reflectiveTest
+class SearchTest extends BaseAnalysisDriverTest {
+ static const testUri = 'package:test/test.dart';
+
+ test_searchReferences_Label() async {
+ addTestFile('''
+main() {
+label:
+ while (true) {
+ if (true) {
+ break label; // 1
+ }
+ break label; // 2
+ }
+}
+''');
+ int offset = findOffset('label:');
+ List<String> main = [testUri, 'main'];
+ var expected = [
+ _expectId(main, SearchResultKind.REFERENCE, 'label; // 1'),
+ _expectId(main, SearchResultKind.REFERENCE, 'label; // 2')
+ ];
+ await _verifyReferences(offset, expected);
+ }
+
+ test_searchReferences_localVariable() async {
+ addTestFile(r'''
+main() {
+ var v;
+ v = 1;
+ v += 2;
+ print(v);
+ v();
+}
+''');
+ int offset = findOffset('v;');
+ List<String> main = [testUri, 'main'];
+ var expected = [
+ _expectId(main, SearchResultKind.WRITE, 'v = 1;'),
+ _expectId(main, SearchResultKind.READ_WRITE, 'v += 2;'),
+ _expectId(main, SearchResultKind.READ, 'v);'),
+ _expectId(main, SearchResultKind.INVOCATION, 'v();')
+ ];
+ await _verifyReferences(offset, expected);
+ }
+
+ test_searchReferences_localVariable_inForEachLoop() async {
+ addTestFile('''
+main() {
+ for (var v in []) {
+ v = 1;
+ v += 2;
+ print(v);
+ v();
+ }
+}
+''');
+ int offset = findOffset('v in []');
+ List<String> main = [testUri, 'main'];
+ var expected = [
+ _expectId(main, SearchResultKind.WRITE, 'v = 1;'),
+ _expectId(main, SearchResultKind.READ_WRITE, 'v += 2;'),
+ _expectId(main, SearchResultKind.READ, 'v);'),
+ _expectId(main, SearchResultKind.INVOCATION, 'v();')
+ ];
+ await _verifyReferences(offset, expected);
+ }
+
+ ExpectedResult _expectId(
+ List<String> enclosingComponents, SearchResultKind kind, String search,
+ {int length, bool isResolved: true, bool isQualified: false}) {
+ int offset = findOffset(search);
+ if (length == null) {
+ length = getLeadingIdentifierLength(search);
+ }
+ return new ExpectedResult(enclosingComponents, kind, offset, length,
+ isResolved: isResolved, isQualified: isQualified);
+ }
+
+ Future _verifyReferences(
+ int offset, List<ExpectedResult> expectedMatches) async {
+ List<SearchResult> results =
+ await driver.search.references(testFile, offset);
+ _assertResults(results, expectedMatches);
+ expect(results, hasLength(expectedMatches.length));
+ }
+
+ static void _assertResults(
+ List<SearchResult> matches, List<ExpectedResult> expectedMatches) {
+ expect(matches, unorderedEquals(expectedMatches));
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/test_all.dart b/pkg/analyzer/test/src/dart/analysis/test_all.dart
index 0ba933e..9abcfca 100644
--- a/pkg/analyzer/test/src/dart/analysis/test_all.dart
+++ b/pkg/analyzer/test/src/dart/analysis/test_all.dart
@@ -9,7 +9,9 @@
import 'byte_store_test.dart' as byte_store;
import 'driver_test.dart' as driver;
import 'file_state_test.dart' as file_state;
+import 'index_test.dart' as index;
import 'referenced_names_test.dart' as referenced_names;
+import 'search_test.dart' as search_test;
/// Utility for manually running all tests.
main() {
@@ -17,6 +19,8 @@
byte_store.main();
driver.main();
file_state.main();
+ index.main();
referenced_names.main();
+ search_test.main();
}, name: 'analysis');
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 664882b..be1ba73 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -3433,6 +3433,12 @@
expect(resynthesized.imports[1].importedLibrary.isDartCore, true);
}
+ test_import_short_absolute() {
+ testFile = '/my/project/bin/test.dart';
+ addLibrarySource('/a.dart', 'class C {}');
+ checkLibrary('import "/a.dart"; C c;');
+ }
+
test_import_show() {
addLibrary('dart:async');
checkLibrary('''
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 f38f362..ae546d5 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -4608,6 +4608,37 @@
expect(v.name, 'v');
expect(v.type.toString(), 'double');
}
+
+ void test_voidReturnTypeSubtypesDynamic() {
+ var unit = checkFile(r'''
+/*=T*/ run/*<T>*/(/*=T*/ f()) {
+ print("running");
+ var t = f();
+ print("done running");
+ return t;
+}
+
+
+void printRunning() { print("running"); }
+var x = run/*<dynamic>*/(printRunning);
+var y = run(printRunning);
+
+main() {
+ void printRunning() { print("running"); }
+ var x = run/*<dynamic>*/(printRunning);
+ var y = run(printRunning);
+ x = 123;
+ x = 'hi';
+ y = 123;
+ y = 'hi';
+}
+ ''');
+
+ var x = unit.topLevelVariables[0];
+ var y = unit.topLevelVariables[1];
+ expect(x.type.toString(), 'dynamic');
+ expect(y.type.toString(), 'dynamic');
+ }
}
@reflectiveTest
diff --git a/pkg/analyzer/test/src/util/fast_uri_test.dart b/pkg/analyzer/test/src/util/fast_uri_test.dart
index 8ed7be6..f04dcb4 100644
--- a/pkg/analyzer/test/src/util/fast_uri_test.dart
+++ b/pkg/analyzer/test/src/util/fast_uri_test.dart
@@ -117,6 +117,17 @@
_compareUris(uri3, Uri.parse('package:analyzer/aaa/bbbb/dd/eeee.dart'));
}
+ void test_resolveUri_short_absolute() {
+ // Check the case where the URI being resolved is a "short absolute" uri
+ // (starts with a "/" but doesn't start with "file://"). Such URIs are not
+ // actually valid URIs but we still want to handle them in a way that's
+ // consistent with the behavior of Uri.
+ String containing = 'file:///foo/bar';
+ String relative = '/a.dart';
+ String expectedResult = Uri.parse(containing).resolve(relative).toString();
+ _checkResolveUri(containing, relative, expectedResult);
+ }
+
void _checkResolveUri(String srcText, String relText, String targetText) {
Uri src = FastUri.parse(srcText);
Uri rel = FastUri.parse(relText);
diff --git a/pkg/analyzer_cli/BUILD.gn b/pkg/analyzer_cli/BUILD.gn
new file mode 100644
index 0000000..69993f0
--- /dev/null
+++ b/pkg/analyzer_cli/BUILD.gn
@@ -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.
+
+import("//build/dart/dart_package.gni")
+
+dart_package("analyzer_cli") {
+ package_name = "analyzer_cli"
+
+ source_dir = "lib"
+
+ deps = [
+ "//dart/pkg/analyzer",
+ "//third_party/dart-pkg/pub/args",
+ "//third_party/dart-pkg/pub/bazel_worker",
+ "//third_party/dart-pkg/pub/cli_util",
+ "//third_party/dart-pkg/pub/linter",
+ "//third_party/dart-pkg/pub/package_config",
+ "//third_party/dart-pkg/pub/plugin",
+ "//third_party/dart-pkg/pub/protobuf",
+ "//third_party/dart-pkg/pub/yaml",
+ ]
+}
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 94a751c..8d7b735 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -51,11 +51,17 @@
static const String conditionalDirectives = '--conditional-directives';
- // Experimental flags.
-
- // Considerations about this feature (esp. locations where generalizations
- // or changes are required for full support of generic methods) are marked
- // with 'GENERIC_METHODS'. The approach taken is to parse generic methods,
+ // The syntax-only level of support for generic methods is included in the
+ // 1.50 milestone for Dart. It is not experimental, but also not permanent:
+ // a full implementation is expected in the future. Hence, the
+ // 'GENERIC_METHODS' comments which were added when this feature was
+ // experimental have been preserved, such that it will be easy to find the
+ // relevant locations to update when generic methods are implemented fully.
+ //
+ // The option is still accepted, but it has no effect: The feature is enabled
+ // by default and it cannot be disabled.
+ //
+ // The approach taken in the implementation is to parse generic methods,
// introduce AST nodes for them, generate corresponding types (such that
// front end treatment is consistent with the code that programmers wrote),
// but considering all method type variables to have bound `dynamic` no
@@ -63,7 +69,12 @@
// is unchecked), and then replacing method type variables by a `DynamicType`
// (such that the backend does not need to take method type arguments into
// account).
+ //
+ // The feature has an informal specification which is available at
+ // https://gist.github.com/eernstg/4353d7b4f669745bed3a5423e04a453c.
static const String genericMethodSyntax = '--generic-method-syntax';
+
+ // Experimental flags.
static const String resolveOnly = '--resolve-only';
static const String initializingFormalAccess = '--initializing-formal-access';
}
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index a5e4003..a65c6ef 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -1221,7 +1221,6 @@
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED: const MessageTemplate(
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED,
"Method type variables do not have a runtime value.",
- options: const ["--generic-method-syntax"],
howToFix: "Try using the upper bound of the type variable, "
"or refactor the code to avoid needing this runtime value.",
examples: const [
@@ -1243,7 +1242,6 @@
const MessageTemplate(
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC,
"Method type variables are treated as `dynamic` in `as` expressions.",
- options: const ["--generic-method-syntax"],
howToFix: "Try using the upper bound of the type variable, or check "
"that the blind success of the test does not introduce bugs.",
examples: const [
diff --git a/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart b/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
index 93344f6..c66c8f1 100644
--- a/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
@@ -4,6 +4,7 @@
library dart2js.mirrors_handler;
+import '../common.dart';
import '../common/resolution.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../elements/elements.dart';
@@ -189,8 +190,13 @@
lib.forEachLocalMember((Element member) {
if (member.isInjected) return;
if (member.isClass) {
- _enqueueReflectiveElementsInClass(member, recents,
- enclosingWasIncluded: includeLibrary);
+ ClassElement cls = member;
+ cls.ensureResolved(_resolution);
+ do {
+ _enqueueReflectiveElementsInClass(cls, recents,
+ enclosingWasIncluded: includeLibrary);
+ cls = cls.superclass;
+ } while (cls != null && cls.isUnnamedMixinApplication);
} else {
_enqueueReflectiveMember(member, includeLibrary);
}
diff --git a/pkg/compiler/lib/src/kernel/kernel.dart b/pkg/compiler/lib/src/kernel/kernel.dart
index a4da817..3b403b7 100644
--- a/pkg/compiler/lib/src/kernel/kernel.dart
+++ b/pkg/compiler/lib/src/kernel/kernel.dart
@@ -192,11 +192,11 @@
fields: null);
addWork(cls, () {
if (cls.supertype != null) {
- classNode.supertype = interfaceTypeToIr(cls.supertype);
+ classNode.supertype = supertypeToIr(cls.supertype);
}
if (cls.isMixinApplication) {
MixinApplicationElement mixinApplication = cls;
- classNode.mixedInType = interfaceTypeToIr(mixinApplication.mixinType);
+ classNode.mixedInType = supertypeToIr(mixinApplication.mixinType);
}
classNode.parent = libraryToIr(cls.library);
if (cls.isUnnamedMixinApplication) {
@@ -222,10 +222,10 @@
}
});
classNode.typeParameters.addAll(typeVariablesToIr(cls.typeVariables));
- for (ir.InterfaceType interface
- in typesToIr(cls.interfaces.reverse().toList())) {
- if (interface != classNode.mixedInType) {
- classNode.implementedTypes.add(interface);
+ for (ir.Supertype supertype
+ in supertypesToIr(cls.interfaces.reverse().toList())) {
+ if (supertype != classNode.mixedInType) {
+ classNode.implementedTypes.add(supertype);
}
}
addWork(cls, () {
@@ -284,6 +284,15 @@
}
}
+ ir.Supertype supertypeToIr(InterfaceType type) {
+ ir.Class cls = classToIr(type.element);
+ if (type.typeArguments.isEmpty) {
+ return cls.asRawSupertype;
+ } else {
+ return new ir.Supertype(cls, typesToIr(type.typeArguments));
+ }
+ }
+
// TODO(ahe): Remove this method when dart2js support generic type arguments.
List<ir.TypeParameter> typeParametersNotImplemented() {
return const <ir.TypeParameter>[];
@@ -295,11 +304,10 @@
List<ir.DartType> positionalParameters =
new List<ir.DartType>.from(typesToIr(type.parameterTypes))
..addAll(typesToIr(type.optionalParameterTypes));
- Map<String, ir.DartType> namedParameters = <String, ir.DartType>{};
- for (int i = 0; i < type.namedParameters.length; i++) {
- namedParameters[type.namedParameters[i]] =
- typeToIr(type.namedParameterTypes[i]);
- }
+ List<ir.NamedType> namedParameters = new List<ir.NamedType>.generate(
+ type.namedParameters.length,
+ (i) => new ir.NamedType(
+ type.namedParameters[i], typeToIr(type.namedParameterTypes[i])));
ir.DartType returnType = typeToIr(type.returnType);
return new ir.FunctionType(positionalParameters, returnType,
@@ -320,6 +328,14 @@
return result;
}
+ List<ir.Supertype> supertypesToIr(List<DartType> types) {
+ List<ir.Supertype> result = new List<ir.Supertype>(types.length);
+ for (int i = 0; i < types.length; i++) {
+ result[i] = supertypeToIr(types[i]);
+ }
+ return result;
+ }
+
ir.DartType typeToIr(DartType type) {
switch (type.kind) {
case TypeKind.FUNCTION:
diff --git a/pkg/compiler/lib/src/kernel/kernel_visitor.dart b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
index 39a1a8d..d4d6216 100644
--- a/pkg/compiler/lib/src/kernel/kernel_visitor.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
@@ -710,7 +710,8 @@
return new ir.ConditionalExpression(
visitForValue(node.condition),
visitWithCurrentContext(node.thenExpression),
- visitWithCurrentContext(node.elseExpression));
+ visitWithCurrentContext(node.elseExpression),
+ null);
}
@override
@@ -1312,7 +1313,7 @@
Accessor accessor = (receiver == null)
? new ThisPropertyAccessor(irName, null, null)
: PropertyAccessor.make(visitForValue(receiver), irName, null, null);
- return accessor.buildNullAwareAssignment(visitForValue(rhs),
+ return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -1504,7 +1505,7 @@
Accessor buildNullAwarePropertyAccessor(Node receiver, Name name) {
return new NullAwarePropertyAccessor(
- visitForValue(receiver), nameToIrName(name), null, null);
+ visitForValue(receiver), nameToIrName(name), null, null, null);
}
@override
@@ -1524,7 +1525,8 @@
buildIsNull(new ir.VariableGet(receiver)),
new ir.NullLiteral(),
buildInvokeSelector(new ir.VariableGet(receiver), selector,
- buildArguments(arguments))));
+ buildArguments(arguments)),
+ null));
}
@override
@@ -1538,7 +1540,7 @@
ir.Expression visitIfNotNullDynamicPropertySetIfNull(
Send node, Node receiver, Name name, Node rhs, _) {
return buildNullAwarePropertyAccessor(receiver, name)
- .buildNullAwareAssignment(visitForValue(rhs),
+ .buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -1549,8 +1551,12 @@
}
@override
- ir.LogicalExpression visitIfNull(Send node, Node left, Node right, _) {
- return buildLogicalExpression(left, node.selector, right);
+ ir.Expression visitIfNull(Send node, Node left, Node right, _) {
+ var leftValue = new ir.VariableDeclaration.forValue(visitForValue(left));
+ return new ir.Let(
+ leftValue,
+ new ir.ConditionalExpression(buildIsNull(new ir.VariableGet(leftValue)),
+ visitForValue(right), new ir.VariableGet(leftValue), null));
}
@override
@@ -1837,7 +1843,7 @@
SendSet node, LocalElement local, Node rhs, _,
{bool isSetterValid}) {
return new VariableAccessor(getLocal(local)).buildNullAwareAssignment(
- visitForValue(rhs),
+ visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -1925,7 +1931,7 @@
@override
ir.Expression handleStaticFieldGet(Send node, FieldElement field, _) {
- return buildStaticGet(field);
+ return associateNode(buildStaticGet(field), node);
}
@override
@@ -1954,7 +1960,7 @@
setter = null;
}
return buildStaticAccessor(getter, setter).buildNullAwareAssignment(
- visitForValue(rhs),
+ visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -1991,6 +1997,7 @@
positionalParameters.add(variable);
}
});
+ namedParameters.sort();
signature.forEachParameter((ParameterElement parameter) {
if (!parameter.isOptional) return;
ir.Expression initializer = visitForValue(parameter.initializer);
@@ -2132,7 +2139,8 @@
NodeList arguments,
CallStructure callStructure,
_) {
- return buildStaticInvoke(function, arguments, isConst: false);
+ return associateNode(
+ buildStaticInvoke(function, arguments, isConst: false), node);
}
@override
@@ -2394,7 +2402,7 @@
setter = null;
}
return buildSuperPropertyAccessor(getter, setter).buildNullAwareAssignment(
- visitForValue(rhs),
+ visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -2623,7 +2631,7 @@
ir.Expression visitTypeVariableTypeLiteralSetIfNull(
Send node, TypeVariableElement element, Node rhs, _) {
return new ReadOnlyAccessor(buildTypeVariable(element))
- .buildNullAwareAssignment(visitForValue(rhs),
+ .buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -2689,7 +2697,7 @@
ir.Expression visitIndexSetIfNull(
SendSet node, Node receiver, Node index, Node rhs, _) {
return buildIndexAccessor(receiver, index).buildNullAwareAssignment(
- visitForValue(rhs),
+ visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -2697,7 +2705,7 @@
ir.Expression visitSuperIndexSetIfNull(SendSet node, MethodElement getter,
MethodElement setter, Node index, Node rhs, _) {
return buildSuperIndexAccessor(index, getter, setter)
- .buildNullAwareAssignment(visitForValue(rhs),
+ .buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -2757,7 +2765,7 @@
FieldElement field = currentElement;
return field.isMalformed
? new ir.InvalidExpression()
- : visitForValue(field.initializer);
+ : associateNode(visitForValue(field.initializer), field.initializer);
});
}
}
diff --git a/pkg/compiler/lib/src/kernel/unresolved.dart b/pkg/compiler/lib/src/kernel/unresolved.dart
index c1e332d..04632b7 100644
--- a/pkg/compiler/lib/src/kernel/unresolved.dart
+++ b/pkg/compiler/lib/src/kernel/unresolved.dart
@@ -272,7 +272,7 @@
Send node, MethodElement getter, Element element, Node rhs, _) {
var accessor = new ClassStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
- return accessor.buildNullAwareAssignment(visitForValue(rhs),
+ return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
@@ -457,7 +457,7 @@
ir.Expression visitUnresolvedSuperSetterSetIfNull(
Send node, MethodElement getter, Element element, Node rhs, _) {
return buildUnresolvedSuperPropertyAccessor('${node.selector}', getter)
- .buildNullAwareAssignment(visitForValue(rhs));
+ .buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperUnary(
@@ -533,26 +533,26 @@
Send node, MethodElement getter, Element element, Node rhs, _) {
var accessor = new TopLevelStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
- return accessor.buildNullAwareAssignment(visitForValue(rhs),
+ return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
ir.Expression visitUnresolvedSuperGetterIndexSetIfNull(Send node,
Element element, MethodElement setter, Node index, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
- .buildNullAwareAssignment(visitForValue(rhs));
+ .buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperSetterIndexSetIfNull(Send node,
MethodElement getter, Element element, Node index, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
- .buildNullAwareAssignment(visitForValue(rhs));
+ .buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperIndexSetIfNull(
Send node, Element element, Node index, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
- .buildNullAwareAssignment(visitForValue(rhs));
+ .buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperSet(
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 65ea1b8..f490329 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -289,7 +289,7 @@
dumpInfo: _hasOption(options, Flags.dumpInfo),
enableAssertMessage: _hasOption(options, Flags.enableAssertMessage),
enableGenericMethodSyntax:
- _hasOption(options, Flags.genericMethodSyntax),
+ true, // No check for `Flags.genericMethodSyntax`: always enabled.
enableInitializingFormalAccess:
_hasOption(options, Flags.initializingFormalAccess),
enableExperimentalMirrors:
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 16843b3..27f164f 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -1310,6 +1310,8 @@
Node right = node.arguments.head;
visitExpression(left);
visitExpression(right);
+ registry.registerConstantLiteral(new NullConstantExpression());
+ registry.registerDynamicUse(new DynamicUse(Selectors.equals, null));
registry.registerSendStructure(node, const IfNullStructure());
return const NoneResult();
}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 1c922e5..8ea98e3 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -9,11 +9,14 @@
import '../common/names.dart';
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart';
+import '../constants/values.dart' show StringConstantValue;
import '../dart_types.dart';
import '../elements/elements.dart';
import '../io/source_information.dart';
+import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../kernel/kernel.dart';
+import '../native/native.dart' as native;
import '../resolution/tree_elements.dart';
import '../tree/dartstring.dart';
import '../tree/nodes.dart' show FunctionExpression, Node;
@@ -21,6 +24,7 @@
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart';
import '../universe/use.dart' show TypeUse;
+import '../universe/side_effects.dart' show SideEffects;
import 'graph_builder.dart';
import 'kernel_ast_adapter.dart';
import 'kernel_string_builder.dart';
@@ -865,12 +869,16 @@
@override
void visitStaticGet(ir.StaticGet staticGet) {
- var staticTarget = staticGet.target;
+ ir.Member staticTarget = staticGet.target;
if (staticTarget is ir.Procedure &&
staticTarget.kind == ir.ProcedureKind.Getter) {
// Invoke the getter
_pushStaticInvocation(staticTarget, const <HInstruction>[],
astAdapter.returnTypeOf(staticTarget));
+ } else if (staticTarget is ir.Field && staticTarget.isConst) {
+ assert(staticTarget.initializer != null);
+ stack.add(graph.addConstant(
+ astAdapter.getConstantFor(staticTarget.initializer), compiler));
} else {
push(new HStatic(astAdapter.getMember(staticTarget),
astAdapter.inferredTypeOf(staticTarget)));
@@ -973,6 +981,10 @@
@override
void visitStaticInvocation(ir.StaticInvocation invocation) {
ir.Procedure target = invocation.target;
+ if (astAdapter.isInForeignLibrary(target)) {
+ handleInvokeStaticForeign(invocation, target);
+ return;
+ }
TypeMask typeMask = astAdapter.returnTypeOf(target);
List<HInstruction> arguments = _visitArguments(invocation.arguments);
@@ -980,6 +992,378 @@
_pushStaticInvocation(target, arguments, typeMask);
}
+ void handleInvokeStaticForeign(
+ ir.StaticInvocation invocation, ir.Procedure target) {
+ String name = target.name.name;
+ if (name == 'JS') {
+ handleForeignJs(invocation);
+ } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
+ handleForeignJsCurrentIsolateContext(invocation);
+ } else if (name == 'JS_CALL_IN_ISOLATE') {
+ handleForeignJsCallInIsolate(invocation);
+ } else if (name == 'DART_CLOSURE_TO_JS') {
+ handleForeignDartClosureToJs(invocation, 'DART_CLOSURE_TO_JS');
+ } else if (name == 'RAW_DART_FUNCTION_REF') {
+ handleForeignRawFunctionRef(invocation, 'RAW_DART_FUNCTION_REF');
+ } else if (name == 'JS_SET_STATIC_STATE') {
+ handleForeignJsSetStaticState(invocation);
+ } else if (name == 'JS_GET_STATIC_STATE') {
+ handleForeignJsGetStaticState(invocation);
+ } else if (name == 'JS_GET_NAME') {
+ handleForeignJsGetName(invocation);
+ } else if (name == 'JS_EMBEDDED_GLOBAL') {
+ handleForeignJsEmbeddedGlobal(invocation);
+ } else if (name == 'JS_BUILTIN') {
+ handleForeignJsBuiltin(invocation);
+ } else if (name == 'JS_GET_FLAG') {
+ handleForeignJsGetFlag(invocation);
+ } else if (name == 'JS_EFFECT') {
+ stack.add(graph.addConstantNull(compiler));
+ } else if (name == 'JS_INTERCEPTOR_CONSTANT') {
+ handleJsInterceptorConstant(invocation);
+ } else if (name == 'JS_STRING_CONCAT') {
+ handleJsStringConcat(invocation);
+ } else {
+ compiler.reporter.internalError(
+ astAdapter.getNode(invocation), "Unknown foreign: ${name}");
+ }
+ }
+
+ bool _unexpectedForeignArguments(
+ ir.StaticInvocation invocation, int minPositional,
+ [int maxPositional]) {
+ String pluralizeArguments(int count) {
+ if (count == 0) return 'no arguments';
+ if (count == 1) return 'one argument';
+ if (count == 2) return 'two arguments';
+ return '$count arguments';
+ }
+
+ String name() => invocation.target.name.name;
+
+ ir.Arguments arguments = invocation.arguments;
+ bool bad = false;
+ if (arguments.types.isNotEmpty) {
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(invocation),
+ MessageKind.GENERIC,
+ {'text': "Error: '${name()}' does not take type arguments."});
+ bad = true;
+ }
+ if (arguments.positional.length < minPositional) {
+ String phrase = pluralizeArguments(minPositional);
+ if (maxPositional != minPositional) phrase = 'at least $phrase';
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(invocation),
+ MessageKind.GENERIC,
+ {'text': "Error: Too few arguments. '${name()}' takes $phrase."});
+ bad = true;
+ }
+ if (maxPositional != null && arguments.positional.length > maxPositional) {
+ String phrase = pluralizeArguments(maxPositional);
+ if (maxPositional != minPositional) phrase = 'at most $phrase';
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(invocation),
+ MessageKind.GENERIC,
+ {'text': "Error: Too many arguments. '${name()}' takes $phrase."});
+ bad = true;
+ }
+ if (arguments.named.isNotEmpty) {
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(invocation),
+ MessageKind.GENERIC,
+ {'text': "Error: '${name()}' does not take named arguments."});
+ bad = true;
+ }
+ return bad;
+ }
+
+ /// Returns the value of the string argument. The argument must evaluate to a
+ /// constant. If there is an error, the error is reported and `null` is
+ /// returned.
+ String _foreignConstantStringArgument(
+ ir.StaticInvocation invocation, int position, String methodName,
+ [String adjective = '']) {
+ ir.Expression argument = invocation.arguments.positional[position];
+ argument.accept(this);
+ HInstruction instruction = pop();
+
+ if (!instruction.isConstantString()) {
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(argument), MessageKind.GENERIC, {
+ 'text': "Error: Expected String constant as ${adjective}argument "
+ "to '$methodName'."
+ });
+ return null;
+ }
+
+ HConstant hConstant = instruction;
+ StringConstantValue stringConstant = hConstant.constant;
+ return stringConstant.primitiveValue.slowToString();
+ }
+
+ // TODO(sra): Remove when handleInvokeStaticForeign fully implemented.
+ void unhandledForeign(ir.StaticInvocation invocation) {
+ ir.Procedure target = invocation.target;
+ TypeMask typeMask = astAdapter.returnTypeOf(target);
+ List<HInstruction> arguments = _visitArguments(invocation.arguments);
+ _pushStaticInvocation(target, arguments, typeMask);
+ }
+
+ void handleForeignJsCurrentIsolateContext(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 0, 0)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+
+ if (!compiler.hasIsolateSupport) {
+ // If the isolate library is not used, we just generate code
+ // to fetch the static state.
+ String name = backend.namer.staticStateHolder;
+ push(new HForeignCode(
+ js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[],
+ nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
+ } else {
+ // Call a helper method from the isolate library. The isolate library uses
+ // its own isolate structure that encapsulates the isolate structure used
+ // for binding to methods.
+ ir.Procedure target = astAdapter.currentIsolate;
+ if (target == null) {
+ compiler.reporter.internalError(astAdapter.getNode(invocation),
+ 'Isolate library and compiler mismatch.');
+ }
+ _pushStaticInvocation(target, <HInstruction>[], backend.dynamicType);
+ }
+
+ /*
+ if (!node.arguments.isEmpty) {
+ reporter.internalError(
+ node, 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.');
+ }
+
+ if (!compiler.hasIsolateSupport) {
+ // If the isolate library is not used, we just generate code
+ // to fetch the static state.
+ String name = backend.namer.staticStateHolder;
+ push(new HForeignCode(
+ js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[],
+ nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
+ } else {
+ // Call a helper method from the isolate library. The isolate
+ // library uses its own isolate structure, that encapsulates
+ // Leg's isolate.
+ Element element = helpers.currentIsolate;
+ if (element == null) {
+ reporter.internalError(node, 'Isolate library and compiler mismatch.');
+ }
+ pushInvokeStatic(null, element, [], typeMask: backend.dynamicType);
+ }
+ */
+ }
+
+ void handleForeignJsCallInIsolate(ir.StaticInvocation invocation) {
+ unhandledForeign(invocation);
+ }
+
+ void handleForeignDartClosureToJs(
+ ir.StaticInvocation invocation, String name) {
+ unhandledForeign(invocation);
+ }
+
+ void handleForeignRawFunctionRef(
+ ir.StaticInvocation invocation, String name) {
+ unhandledForeign(invocation);
+ }
+
+ void handleForeignJsSetStaticState(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 0, 0)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+ _visitArguments(invocation.arguments);
+ String isolateName = backend.namer.staticStateHolder;
+ SideEffects sideEffects = new SideEffects.empty();
+ sideEffects.setAllSideEffects();
+ push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
+ backend.dynamicType, <HInstruction>[pop()],
+ nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
+ effects: sideEffects));
+ }
+
+ void handleForeignJsGetStaticState(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 0, 0)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+
+ push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
+ backend.dynamicType, <HInstruction>[],
+ nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
+ }
+
+ void handleForeignJsGetName(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 1, 1)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+
+ ir.Node argument = invocation.arguments.positional.first;
+ argument.accept(this);
+ HInstruction instruction = pop();
+
+ if (instruction is HConstant) {
+ js.Name name =
+ astAdapter.getNameForJsGetName(argument, instruction.constant);
+ stack.add(graph.addConstantStringFromName(name, compiler));
+ return;
+ }
+
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(argument),
+ MessageKind.GENERIC,
+ {'text': 'Error: Expected a JsGetName enum value.'});
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ }
+
+ void handleForeignJsEmbeddedGlobal(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 2, 2)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+ String globalName = _foreignConstantStringArgument(
+ invocation, 1, 'JS_EMBEDDED_GLOBAL', 'second ');
+ js.Template expr = js.js.expressionTemplateYielding(
+ backend.emitter.generateEmbeddedGlobalAccess(globalName));
+
+ native.NativeBehavior nativeBehavior =
+ astAdapter.getNativeBehavior(invocation);
+ assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
+ message: "No NativeBehavior for $invocation"));
+
+ TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
+ push(new HForeignCode(expr, ssaType, const <HInstruction>[],
+ nativeBehavior: nativeBehavior));
+ }
+
+ void handleForeignJsBuiltin(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 2)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+
+ List<ir.Expression> arguments = invocation.arguments.positional;
+ ir.Expression nameArgument = arguments[1];
+
+ nameArgument.accept(this);
+ HInstruction instruction = pop();
+
+ js.Template template;
+ if (instruction is HConstant) {
+ template = astAdapter.getJsBuiltinTemplate(instruction.constant);
+ }
+ if (template == null) {
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(nameArgument),
+ MessageKind.GENERIC,
+ {'text': 'Error: Expected a JsBuiltin enum value.'});
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+
+ List<HInstruction> inputs = <HInstruction>[];
+ for (ir.Expression argument in arguments.skip(2)) {
+ argument.accept(this);
+ inputs.add(pop());
+ }
+
+ native.NativeBehavior nativeBehavior =
+ astAdapter.getNativeBehavior(invocation);
+ assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
+ message: "No NativeBehavior for $invocation"));
+
+ TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
+ push(new HForeignCode(template, ssaType, inputs,
+ nativeBehavior: nativeBehavior));
+ }
+
+ void handleForeignJsGetFlag(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 1, 1)) {
+ stack.add(
+ graph.addConstantBool(false, compiler)); // Result expected on stack.
+ return;
+ }
+ String name = _foreignConstantStringArgument(invocation, 0, 'JS_GET_FLAG');
+ bool value = false;
+ switch (name) {
+ case 'MUST_RETAIN_METADATA':
+ value = backend.mustRetainMetadata;
+ break;
+ case 'USE_CONTENT_SECURITY_POLICY':
+ value = compiler.options.useContentSecurityPolicy;
+ break;
+ default:
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(invocation),
+ MessageKind.GENERIC,
+ {'text': 'Error: Unknown internal flag "$name".'});
+ }
+ stack.add(graph.addConstantBool(value, compiler));
+ }
+
+ void handleJsInterceptorConstant(ir.StaticInvocation invocation) {
+ unhandledForeign(invocation);
+ }
+
+ void handleForeignJs(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 2)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+
+ native.NativeBehavior nativeBehavior =
+ astAdapter.getNativeBehavior(invocation);
+ assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
+ message: "No NativeBehavior for $invocation"));
+
+ List<HInstruction> inputs = <HInstruction>[];
+ for (ir.Expression argument in invocation.arguments.positional.skip(2)) {
+ argument.accept(this);
+ inputs.add(pop());
+ }
+
+ if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) {
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(invocation), MessageKind.GENERIC, {
+ 'text': 'Mismatch between number of placeholders'
+ ' and number of arguments.'
+ });
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+
+ if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) {
+ compiler.reporter.reportErrorMessage(
+ astAdapter.getNode(invocation), MessageKind.JS_PLACEHOLDER_CAPTURE);
+ }
+
+ TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
+
+ SourceInformation sourceInformation = null;
+ push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs,
+ isStatement: !nativeBehavior.codeTemplate.isExpression,
+ effects: nativeBehavior.sideEffects,
+ nativeBehavior: nativeBehavior)..sourceInformation = sourceInformation);
+ }
+
+ void handleJsStringConcat(ir.StaticInvocation invocation) {
+ if (_unexpectedForeignArguments(invocation, 2, 2)) {
+ stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+ return;
+ }
+ List<HInstruction> inputs = _visitArguments(invocation.arguments);
+ push(new HStringConcat(inputs[0], inputs[1], backend.stringType));
+ }
+
void _pushStaticInvocation(
ir.Node target, List<HInstruction> arguments, TypeMask typeMask) {
HInvokeStatic instruction = new HInvokeStatic(
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index cf58dce..028b7a8 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:js_runtime/shared/embedded_names.dart';
import 'package:kernel/ast.dart' as ir;
import '../constants/expressions.dart';
@@ -11,11 +12,12 @@
import '../constants/values.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
+import '../js/js.dart' as js;
import '../js_backend/backend_helpers.dart';
import '../js_backend/js_backend.dart';
import '../kernel/kernel.dart';
import '../kernel/kernel_debug.dart';
-import '../native/native.dart' show NativeBehavior, TypeLookup;
+import '../native/native.dart' as native;
import '../resolution/tree_elements.dart';
import '../tree/tree.dart' as ast;
import '../types/masks.dart';
@@ -241,6 +243,10 @@
return TypeMaskFactory.inferredTypeForSelector(selector, mask, _compiler);
}
+ TypeMask typeFromNativeBehavior(native.NativeBehavior nativeBehavior) {
+ return TypeMaskFactory.fromNativeBehavior(nativeBehavior, _compiler);
+ }
+
ConstantValue getConstantFor(ir.Node node) {
ConstantValue constantValue =
_backend.constants.getConstantValueForNode(getNode(node), elements);
@@ -309,6 +315,45 @@
ir.Class get objectClass => kernel.classes[_compiler.coreClasses.objectClass];
+ ir.Procedure get currentIsolate =>
+ kernel.functions[_backend.helpers.currentIsolate];
+
+ bool isInForeignLibrary(ir.Member member) =>
+ _backend.isForeign(getElement(member));
+
+ native.NativeBehavior getNativeBehavior(ir.Node node) {
+ return elements.getNativeData(getNode(node));
+ }
+
+ js.Name getNameForJsGetName(ir.Node argument, ConstantValue constant) {
+ int index = _extractEnumIndexFromConstantValue(
+ constant, _backend.helpers.jsGetNameEnum);
+ if (index == null) return null;
+ return _backend.namer
+ .getNameForJsGetName(getNode(argument), JsGetName.values[index]);
+ }
+
+ js.Template getJsBuiltinTemplate(ConstantValue constant) {
+ int index = _extractEnumIndexFromConstantValue(
+ constant, _backend.helpers.jsBuiltinEnum);
+ if (index == null) return null;
+ return _backend.emitter.builtinTemplateFor(JsBuiltin.values[index]);
+ }
+
+ int _extractEnumIndexFromConstantValue(
+ ConstantValue constant, Element classElement) {
+ if (constant is ConstructedConstantValue) {
+ if (constant.type.element == classElement) {
+ assert(constant.fields.length == 1);
+ ConstantValue indexConstant = constant.fields.values.single;
+ if (indexConstant is IntConstantValue) {
+ return indexConstant.primitiveValue;
+ }
+ }
+ }
+ return null;
+ }
+
DartType getDartType(ir.DartType type) {
return type.accept(_typeConverter);
}
@@ -382,10 +427,10 @@
}
/// Looks up [typeName] for use in the spec-string of a `JS` called.
- // TODO(johnniwinther): Use this in [NativeBehavior] instead of calling the
+ // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling the
// `ForeignResolver`.
// TODO(johnniwinther): Cache the result to avoid redundant lookups?
- TypeLookup _typeLookup({bool resolveAsRaw: true}) {
+ native.TypeLookup _typeLookup({bool resolveAsRaw: true}) {
return (String typeName) {
DartType findIn(Uri uri) {
LibraryElement library = _compiler.libraryLoader.lookupLibrary(uri);
@@ -417,30 +462,30 @@
return node.arguments.positional[index].accept(new Stringifier());
}
- /// Computes the [NativeBehavior] for a call to the [JS] function.
+ /// Computes the [native.NativeBehavior] for a call to the [JS] function.
// TODO(johnniwinther): Cache this for later use.
- NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
+ native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
if (node.arguments.positional.length < 2 ||
node.arguments.named.isNotEmpty) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
String codeString = _getStringArgument(node, 1);
if (codeString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
- return NativeBehavior.ofJsCall(
+ return native.NativeBehavior.ofJsCall(
specString,
codeString,
_typeLookup(resolveAsRaw: true),
@@ -449,26 +494,27 @@
_compiler.coreTypes);
}
- /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN] function.
+ /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN] function.
// TODO(johnniwinther): Cache this for later use.
- NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) {
+ native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
+ ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
- return NativeBehavior.ofJsBuiltinCall(
+ return native.NativeBehavior.ofJsBuiltinCall(
specString,
_typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
@@ -476,34 +522,34 @@
_compiler.coreTypes);
}
- /// Computes the [NativeBehavior] for a call to the [JS_EMBEDDED_GLOBAL]
+ /// Computes the [native.NativeBehavior] for a call to the [JS_EMBEDDED_GLOBAL]
/// function.
// TODO(johnniwinther): Cache this for later use.
- NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+ native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global expression has no type.");
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
if (node.arguments.positional.length > 2 ||
node.arguments.named.isNotEmpty) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global has more than 2 arguments.");
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
- return new NativeBehavior();
+ return new native.NativeBehavior();
}
- return NativeBehavior.ofJsEmbeddedGlobalCall(
+ return native.NativeBehavior.ofJsEmbeddedGlobalCall(
specString,
_typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
@@ -528,28 +574,28 @@
/// Computes the native behavior for reading the native [field].
// TODO(johnniwinther): Cache this for later use.
- NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
+ native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
DartType type = getDartType(field.type);
List<ConstantExpression> metadata = getMetadata(field.annotations);
- return NativeBehavior.ofFieldLoad(CURRENT_ELEMENT_SPANNABLE, type, metadata,
- _typeLookup(resolveAsRaw: false), _compiler,
+ return native.NativeBehavior.ofFieldLoad(CURRENT_ELEMENT_SPANNABLE, type,
+ metadata, _typeLookup(resolveAsRaw: false), _compiler,
isJsInterop: false);
}
/// Computes the native behavior for writing to the native [field].
// TODO(johnniwinther): Cache this for later use.
- NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
+ native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
DartType type = getDartType(field.type);
- return NativeBehavior.ofFieldStore(type, _compiler.resolution);
+ return native.NativeBehavior.ofFieldStore(type, _compiler.resolution);
}
/// Computes the native behavior for calling [procedure].
// TODO(johnniwinther): Cache this for later use.
- NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
+ native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
DartType type = getFunctionType(procedure.function);
List<ConstantExpression> metadata = getMetadata(procedure.annotations);
- return NativeBehavior.ofMethod(CURRENT_ELEMENT_SPANNABLE, type, metadata,
- _typeLookup(resolveAsRaw: false), _compiler,
+ return native.NativeBehavior.ofMethod(CURRENT_ELEMENT_SPANNABLE, type,
+ metadata, _typeLookup(resolveAsRaw: false), _compiler,
isJsInterop: false);
}
}
@@ -603,8 +649,8 @@
visitTypes(node.positionalParameters
.skip(node.requiredParameterCount)
.toList()),
- node.namedParameters.keys.toList(),
- visitTypes(node.namedParameters.values.toList()));
+ node.namedParameters.map((n) => n.name).toList(),
+ node.namedParameters.map((n) => visitType(n.type)).toList());
}
@override
diff --git a/pkg/dev_compiler/lib/js/amd/dart_sdk.js b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
index 2ed8598..2b7e741 100644
--- a/pkg/dev_compiler/lib/js/amd/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
@@ -1420,24 +1420,31 @@
return true;
};
dart.throwCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwUnimplementedError = function(message) {
+ debugger;
dart.throw(new core.UnimplementedError(message));
};
dart.throwAssertionError = function() {
+ debugger;
dart.throw(new core.AssertionError());
};
dart.throwNullValueError = function() {
+ debugger;
dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
};
dart.syncStar = function(gen, E, ...args) {
@@ -1968,9 +1975,11 @@
return Object.getOwnPropertySymbols(obj);
};
dart.throwStrongModeError = function(message) {
+ debugger;
throw new _js_helper.StrongModeErrorImplementation(message);
};
dart.throwInternalError = function(message) {
+ debugger;
throw Error(message);
};
dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/lib/js/common/dart_sdk.js b/pkg/dev_compiler/lib/js/common/dart_sdk.js
index f853c40..274a113 100644
--- a/pkg/dev_compiler/lib/js/common/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/common/dart_sdk.js
@@ -1420,24 +1420,31 @@
return true;
};
dart.throwCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwUnimplementedError = function(message) {
+ debugger;
dart.throw(new core.UnimplementedError(message));
};
dart.throwAssertionError = function() {
+ debugger;
dart.throw(new core.AssertionError());
};
dart.throwNullValueError = function() {
+ debugger;
dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
};
dart.syncStar = function(gen, E, ...args) {
@@ -1968,9 +1975,11 @@
return Object.getOwnPropertySymbols(obj);
};
dart.throwStrongModeError = function(message) {
+ debugger;
throw new _js_helper.StrongModeErrorImplementation(message);
};
dart.throwInternalError = function(message) {
+ debugger;
throw Error(message);
};
dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/lib/js/es6/dart_sdk.js b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
index bb1cb35..17bea27 100644
--- a/pkg/dev_compiler/lib/js/es6/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
@@ -1418,24 +1418,31 @@
return true;
};
dart.throwCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwUnimplementedError = function(message) {
+ debugger;
dart.throw(new core.UnimplementedError(message));
};
dart.throwAssertionError = function() {
+ debugger;
dart.throw(new core.AssertionError());
};
dart.throwNullValueError = function() {
+ debugger;
dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
};
dart.syncStar = function(gen, E, ...args) {
@@ -1966,9 +1973,11 @@
return Object.getOwnPropertySymbols(obj);
};
dart.throwStrongModeError = function(message) {
+ debugger;
throw new _js_helper.StrongModeErrorImplementation(message);
};
dart.throwInternalError = function(message) {
+ debugger;
throw Error(message);
};
dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
index 09a7b16..8a6f13e 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
@@ -1421,24 +1421,31 @@
return true;
};
dart.throwCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeCastError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwStrongModeTypeError = function(object, actual, type) {
+ debugger;
dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
};
dart.throwUnimplementedError = function(message) {
+ debugger;
dart.throw(new core.UnimplementedError(message));
};
dart.throwAssertionError = function() {
+ debugger;
dart.throw(new core.AssertionError());
};
dart.throwNullValueError = function() {
+ debugger;
dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
};
dart.syncStar = function(gen, E, ...args) {
@@ -1969,9 +1976,11 @@
return Object.getOwnPropertySymbols(obj);
};
dart.throwStrongModeError = function(message) {
+ debugger;
throw new _js_helper.StrongModeErrorImplementation(message);
};
dart.throwInternalError = function(message) {
+ debugger;
throw Error(message);
};
dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/test/codegen/language/void_subtype_test.dart b/pkg/dev_compiler/test/codegen/language/void_subtype_test.dart
new file mode 100644
index 0000000..f626232
--- /dev/null
+++ b/pkg/dev_compiler/test/codegen/language/void_subtype_test.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.
+// Dart test for type checks involving the void type.
+
+import "package:expect/expect.dart";
+
+var _str = new StringBuffer();
+
+/*=T*/ run/*<T>*/(/*=T*/ f()) {
+ _str.write("+");
+ var t = f();
+ _str.write("-");
+ return t;
+}
+
+void writeV() { _str.write("V"); }
+
+main() {
+ {
+ var x = run/*<dynamic>*/(writeV);
+ Expect.equals('+V-', _str.toString());
+ Expect.equals(null, x);
+ _str.clear();
+
+ var y = run(writeV);
+ Expect.equals('+V-', _str.toString());
+ Expect.equals(null, y);
+ _str.clear();
+ }
+
+ // implicit cast
+ {
+ dynamic d = writeV;
+ var x = run/*<dynamic>*/(d);
+ Expect.equals('+V-', _str.toString());
+ Expect.equals(null, x);
+ _str.clear();
+
+ var y = run(d);
+ Expect.equals('+V-', _str.toString());
+ Expect.equals(null, y);
+ _str.clear();
+ }
+
+ // dynamic dispatch
+ {
+ dynamic d = run;
+ var x = d/*<dynamic>*/(writeV);
+ Expect.equals('+V-', _str.toString());
+ Expect.equals(null, x);
+ _str.clear();
+
+ var y = d(writeV);
+ Expect.equals('+V-', _str.toString());
+ Expect.equals(null, y);
+ _str.clear();
+ }
+}
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
index 8b77035..244a603 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
@@ -4,34 +4,40 @@
part of dart._runtime;
throwCastError(object, actual, type) => JS('', '''(() => {
+ debugger;
$throw_(new $CastErrorImplementation($object,
$typeName($actual),
$typeName($type)));
})()''');
throwTypeError(object, actual, type) => JS('', '''(() => {
+ debugger;
$throw_(new $TypeErrorImplementation($object,
$typeName($actual),
$typeName($type)));
})()''');
throwStrongModeCastError(object, actual, type) => JS('', '''(() => {
+ debugger;
$throw_(new $StrongModeCastError($object,
$typeName($actual),
$typeName($type)));
})()''');
throwStrongModeTypeError(object, actual, type) => JS('', '''(() => {
+ debugger;
$throw_(new $StrongModeTypeError($object,
$typeName($actual),
$typeName($type)));
})()''');
throwUnimplementedError(message) => JS('', '''(() => {
+ debugger;
$throw_(new $UnimplementedError($message));
})()''');
throwAssertionError() => JS('', '''(() => {
+ debugger;
$throw_(new $AssertionError());
})()''');
@@ -39,6 +45,7 @@
// TODO(vsm): Per spec, we should throw an NSM here. Technically, we ought
// to thread through method info, but that uglifies the code and can't
// actually be queried ... it only affects how the error is printed.
+ debugger;
$throw_(new $NoSuchMethodError(null,
new $Symbol('<Unexpected Null Value>'), null, null, null));
})()''');
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
index 0a3e176..a604423 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
@@ -24,11 +24,13 @@
/// This error indicates a strong mode specific failure, other than a type
/// assertion failure (TypeError) or CastError.
void throwStrongModeError(String message) {
+ JS('', 'debugger');
JS('', 'throw new #(#);', StrongModeErrorImplementation, message);
}
/// This error indicates a bug in the runtime or the compiler.
void throwInternalError(String message) {
+ JS('', 'debugger');
JS('', 'throw Error(#)', message);
}
diff --git a/runtime/observatory/tests/service/complex_reload_test.dart b/runtime/observatory/tests/service/complex_reload_test.dart
index 0b94084..f3fd806 100644
--- a/runtime/observatory/tests/service/complex_reload_test.dart
+++ b/runtime/observatory/tests/service/complex_reload_test.dart
@@ -46,6 +46,10 @@
// Stop at 'debugger' statement.
hasStoppedAtBreakpoint,
(Isolate mainIsolate) async {
+ for (var i = 0; i < Platform.script.pathSegments.length; i++) {
+ print('segment $i: "${Platform.script.pathSegments[i]}"');
+ }
+ print('Directory: $directory');
// Grab the VM.
VM vm = mainIsolate.vm;
await vm.reloadIsolates();
@@ -62,7 +66,10 @@
// Reload to v2.
var response = await slaveIsolate.reloadSources(
- rootLibUri: '$directory/complex_reload/v2/main.dart',
+ rootLibUri: '$directory${Platform.pathSeparator}'
+ 'complex_reload${Platform.pathSeparator}'
+ 'v2${Platform.pathSeparator}'
+ 'main.dart',
);
expect(response['success'], isTrue);
@@ -72,7 +79,10 @@
// Reload to v3.
response = await slaveIsolate.reloadSources(
- rootLibUri: '$directory/complex_reload/v3/main.dart',
+ rootLibUri: '$directory${Platform.pathSeparator}'
+ 'complex_reload${Platform.pathSeparator}'
+ 'v3${Platform.pathSeparator}'
+ 'main.dart',
);
expect(response['success'], isTrue);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 52be6ac..bb0c433 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -45,6 +45,7 @@
[ $runtime == dart_app ]
address_mapper_test: CompileTimeError # Issue 27806
capture_stdio_test: CompileTimeError # Issue 27806
+complex_reload_test: RuntimeError # Issue 27806
debugger_location_second_test: RuntimeError # Issue 27806
dev_fs_spawn_test: RuntimeError # Issue 27806
developer_extension_test: RuntimeError # Issue 27806
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index a354ddc..84b528d 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -321,7 +321,7 @@
const uint8_t* buffer,
intptr_t buffer_size) {
Zone* zone = thread->zone();
- kernel::KernelReader reader(buffer, buffer_size, true);
+ kernel::KernelReader reader(buffer, buffer_size);
kernel::Program* program = reader.ReadPrecompiledProgram();
if (program == NULL) {
const String& message =
diff --git a/runtime/vm/bootstrap_nocore.cc b/runtime/vm/bootstrap_nocore.cc
index 9fda4b3..cd49589 100644
--- a/runtime/vm/bootstrap_nocore.cc
+++ b/runtime/vm/bootstrap_nocore.cc
@@ -59,7 +59,7 @@
const uint8_t* buffer,
intptr_t buffer_length) {
Zone* zone = thread->zone();
- kernel::KernelReader reader(buffer, buffer_length, true);
+ kernel::KernelReader reader(buffer, buffer_length);
kernel::Program* program = reader.ReadPrecompiledProgram();
if (program == NULL) {
const String& message =
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index c8683ee..61660f0 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1468,6 +1468,7 @@
/* is_native = */ false, cls, field.token_pos()));
getter.set_result_type(type);
getter.set_is_debuggable(false);
+ getter.set_kernel_function(field.kernel_field());
cls.AddFunction(getter);
field.SetStaticValue(Object::sentinel(), true);
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 545e001..5c5628f 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -1714,29 +1714,7 @@
// Create a one-time-use function to evaluate the initializer and invoke
// it immediately.
if (field.kernel_field() != NULL) {
- // kImplicitStaticFinalGetter is used for both implicit static getters
- // and static initializers. The Kernel graph builder will tell the
- // difference by pattern matching on the name.
- const String& name = String::Handle(
- zone, Symbols::FromConcat(thread, Symbols::InitPrefix(),
- String::Handle(zone, field.name())));
- const Script& script = Script::Handle(zone, field.Script());
- Object& owner = Object::Handle(zone, field.Owner());
- owner = PatchClass::New(Class::Cast(owner), script);
- const Function& function = Function::ZoneHandle(
- zone, Function::New(name, RawFunction::kImplicitStaticFinalGetter,
- true, // is_static
- false, // is_const
- false, // is_abstract
- false, // is_external
- false, // is_native
- owner, TokenPosition::kNoSource));
- function.set_kernel_function(field.kernel_field());
- function.set_result_type(AbstractType::Handle(zone, field.type()));
- function.set_is_reflectable(false);
- function.set_is_debuggable(false);
- function.set_is_inlinable(false);
- parsed_function = new (zone) ParsedFunction(thread, function);
+ parsed_function = kernel::ParseStaticFieldInitializer(zone, field);
} else {
parsed_function = Parser::ParseStaticFieldInitializer(field);
parsed_function->AllocateVariables();
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index beb0155..71610d2 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -173,6 +173,8 @@
if (isolate_event_handler != NULL) {
(*isolate_event_handler)(event->isolate_id(), kShutdown);
}
+ } else if (event->kind() == ServiceEvent::kPausePostRequest) {
+ // Ignore.
} else {
UNIMPLEMENTED();
}
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index f1334b8..71eb55a 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -204,18 +204,9 @@
}
-static void JumpToExceptionHandler(Thread* thread,
- uword program_counter,
- uword stack_pointer,
- uword frame_pointer,
- const Object& exception_object,
- const Object& stacktrace_object) {
- // The no_gc StackResource is unwound through the tear down of
- // stack resources below.
- NoSafepointScope no_safepoint;
- RawObject* raw_exception = exception_object.raw();
- RawObject* raw_stacktrace = stacktrace_object.raw();
-
+static uword RemapExceptionPCForDeopt(Thread* thread,
+ uword program_counter,
+ uword frame_pointer) {
#if !defined(TARGET_ARCH_DBC)
MallocGrowableArray<PendingLazyDeopt>* pending_deopts =
thread->isolate()->pending_deopts();
@@ -273,8 +264,31 @@
#endif
}
#endif // !DBC
+ return program_counter;
+}
+static void JumpToExceptionHandler(Thread* thread,
+ uword program_counter,
+ uword stack_pointer,
+ uword frame_pointer,
+ const Object& exception_object,
+ const Object& stacktrace_object) {
+ uword remapped_pc =
+ RemapExceptionPCForDeopt(thread, program_counter, frame_pointer);
+ thread->set_active_exception(exception_object);
+ thread->set_active_stacktrace(stacktrace_object);
+ thread->set_resume_pc(remapped_pc);
+ uword run_exception_pc = StubCode::RunExceptionHandler_entry()->EntryPoint();
+ Exceptions::JumpToFrame(thread, run_exception_pc, stack_pointer,
+ frame_pointer);
+}
+
+
+void Exceptions::JumpToFrame(Thread* thread,
+ uword program_counter,
+ uword stack_pointer,
+ uword frame_pointer) {
#if defined(USING_SIMULATOR)
// Unwinding of the C++ frames and destroying of their stack resources is done
// by the simulator, because the target stack_pointer is a simulated stack
@@ -284,8 +298,8 @@
// exception object in the kExceptionObjectReg register and the stacktrace
// object (may be raw null) in the kStackTraceObjectReg register.
- Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer,
- raw_exception, raw_stacktrace, thread);
+ Simulator::Current()->JumpToFrame(program_counter, stack_pointer,
+ frame_pointer, thread);
#else
// Prepare for unwinding frames by destroying all the stack resources
// in the previous frames.
@@ -294,18 +308,16 @@
// Call a stub to set up the exception object in kExceptionObjectReg,
// to set up the stacktrace object in kStackTraceObjectReg, and to
// continue execution at the given pc in the given frame.
- typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*,
- Thread*);
+ typedef void (*ExcpHandler)(uword, uword, uword, Thread*);
ExcpHandler func = reinterpret_cast<ExcpHandler>(
- StubCode::JumpToExceptionHandler_entry()->EntryPoint());
+ StubCode::JumpToFrame_entry()->EntryPoint());
// Unpoison the stack before we tear it down in the generated stub code.
uword current_sp = Thread::GetCurrentStackPointer() - 1024;
ASAN_UNPOISON(reinterpret_cast<void*>(current_sp),
stack_pointer - current_sp);
- func(program_counter, stack_pointer, frame_pointer, raw_exception,
- raw_stacktrace, thread);
+ func(program_counter, stack_pointer, frame_pointer, thread);
#endif
UNREACHABLE();
}
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index eaf6194..c3fc408 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -80,6 +80,11 @@
// otherwise returns a RawError.
static RawObject* Create(ExceptionType type, const Array& arguments);
+ static void JumpToFrame(Thread* thread,
+ uword program_counter,
+ uword stack_pointer,
+ uword frame_pointer);
+
private:
DISALLOW_COPY_AND_ASSIGN(Exceptions);
};
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index a66bc10..4e61306 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -798,9 +798,6 @@
}
// Generate code handling each optional parameter in alphabetical order.
__ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
- __ ldr(R6,
- FieldAddress(R4, ArgumentsDescriptor::positional_count_offset()));
- __ SmiUntag(R6);
// Let NOTFP point to the first passed argument, i.e. to
// fp[kParamEndSlotFromFp + num_args - 0]; num_args (NOTFP) is Smi.
__ add(NOTFP, FP, Operand(NOTFP, LSL, 1));
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 862221e..85c0a76f 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -791,9 +791,6 @@
}
// Generate code handling each optional parameter in alphabetical order.
__ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
- __ LoadFieldFromOffset(R8, R4,
- ArgumentsDescriptor::positional_count_offset());
- __ SmiUntag(R8);
// Let R7 point to the first passed argument, i.e. to
// fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi.
__ add(R7, FP, Operand(R7, LSL, 2));
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 729608f..fbc891e 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -809,9 +809,6 @@
}
// Generate code handling each optional parameter in alphabetical order.
__ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
- __ movl(ECX,
- FieldAddress(EDX, ArgumentsDescriptor::positional_count_offset()));
- __ SmiUntag(ECX);
// Let EBX point to the first passed argument, i.e. to
// fp[kParamEndSlotFromFp + num_args - 0]; num_args (EBX) is Smi.
__ leal(EBX, Address(EBP, EBX, TIMES_2, kParamEndSlotFromFp * kWordSize));
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index ef95a0e..fddc901 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -808,8 +808,6 @@
}
// Generate code handling each optional parameter in alphabetical order.
__ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
- __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::positional_count_offset()));
- __ SmiUntag(T2);
// Let T1 point to the first passed argument, i.e. to
// fp[kParamEndSlotFromFp + num_args - 0]; num_args (T1) is Smi.
__ sll(T3, T1, 1);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index a4b1288..0944b5e 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -800,9 +800,6 @@
}
// Generate code handling each optional parameter in alphabetical order.
__ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
- __ movq(RCX,
- FieldAddress(R10, ArgumentsDescriptor::positional_count_offset()));
- __ SmiUntag(RCX);
// Let RBX point to the first passed argument, i.e. to
// fp[kParamEndSlotFromFp + num_args]; num_args (RBX) is Smi.
__ leaq(RBX, Address(RBP, RBX, TIMES_4, kParamEndSlotFromFp * kWordSize));
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index 8e96941..15bf633 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -126,6 +126,10 @@
namespace dart {
+class Field;
+class ParsedFunction;
+class Zone;
+
namespace kernel {
@@ -3237,6 +3241,9 @@
return IT::Cast(member);
}
+ParsedFunction* ParseStaticFieldInitializer(Zone* zone,
+ const dart::Field& field);
+
} // namespace kernel
kernel::Program* ReadPrecompiledKernelFromBuffer(const uint8_t* buffer,
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index a870dd9..25b8899 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -294,25 +294,43 @@
};
+// Unlike other scopes, labels from enclosing functions are not visible in
+// nested functions. The LabelScope class is used to hide outer labels.
+template <typename Builder, typename Block>
+class LabelScope {
+ public:
+ explicit LabelScope(Builder* builder) : builder_(builder) {
+ outer_block_ = builder_->labels();
+ builder_->set_labels(&block_);
+ }
+ ~LabelScope() { builder_->set_labels(outer_block_); }
+
+ private:
+ Builder* builder_;
+ Block block_;
+ Block* outer_block_;
+};
+
class ReaderHelper {
public:
- ReaderHelper() : program_(NULL) {}
- ~ReaderHelper() {}
+ ReaderHelper() : program_(NULL), labels_(NULL) {}
Program* program() { return program_; }
void set_program(Program* program) { program_ = program; }
BlockStack<VariableDeclaration>& variables() { return scope_; }
BlockStack<TypeParameter>& type_parameters() { return type_parameters_; }
- BlockStack<LabeledStatement>& lables() { return labels_; }
BlockStack<SwitchCase>& switch_cases() { return switch_cases_; }
+ BlockStack<LabeledStatement>* labels() { return labels_; }
+ void set_labels(BlockStack<LabeledStatement>* labels) { labels_ = labels; }
+
private:
Program* program_;
BlockStack<VariableDeclaration> scope_;
BlockStack<TypeParameter> type_parameters_;
- BlockStack<LabeledStatement> labels_;
BlockStack<SwitchCase> switch_cases_;
+ BlockStack<LabeledStatement>* labels_;
};
@@ -430,6 +448,8 @@
class WriterHelper {
public:
+ WriterHelper() : labels_(NULL) {}
+
void SetProgram(Program* program) {
program_ = program;
for (int i = 0; i < program->libraries().length(); i++) {
@@ -477,9 +497,11 @@
BlockMap<VariableDeclaration>& variables() { return scope_; }
BlockMap<TypeParameter>& type_parameters() { return type_parameters_; }
- BlockMap<LabeledStatement>& lables() { return labels_; }
BlockMap<SwitchCase>& switch_cases() { return switch_cases_; }
+ BlockMap<LabeledStatement>* labels() { return labels_; }
+ void set_labels(BlockMap<LabeledStatement>* labels) { labels_ = labels; }
+
private:
Program* program_;
@@ -492,8 +514,8 @@
BlockMap<VariableDeclaration> scope_;
BlockMap<TypeParameter> type_parameters_;
- BlockMap<LabeledStatement> labels_;
BlockMap<SwitchCase> switch_cases_;
+ BlockMap<LabeledStatement>* labels_;
};
@@ -2253,9 +2275,9 @@
LabeledStatement* LabeledStatement::ReadFrom(Reader* reader) {
TRACE_READ_OFFSET();
LabeledStatement* stmt = new LabeledStatement();
- reader->helper()->lables().Push(stmt);
+ reader->helper()->labels()->Push(stmt);
stmt->body_ = Statement::ReadFrom(reader);
- reader->helper()->lables().Pop(stmt);
+ reader->helper()->labels()->Pop(stmt);
return stmt;
}
@@ -2263,16 +2285,16 @@
void LabeledStatement::WriteTo(Writer* writer) {
TRACE_WRITE_OFFSET();
writer->WriteTag(kLabeledStatement);
- writer->helper()->lables().Push(this);
+ writer->helper()->labels()->Push(this);
body_->WriteTo(writer);
- writer->helper()->lables().Pop(this);
+ writer->helper()->labels()->Pop(this);
}
BreakStatement* BreakStatement::ReadFrom(Reader* reader) {
TRACE_READ_OFFSET();
BreakStatement* stmt = new BreakStatement();
- stmt->target_ = reader->helper()->lables().Lookup(reader->ReadUInt());
+ stmt->target_ = reader->helper()->labels()->Lookup(reader->ReadUInt());
return stmt;
}
@@ -2280,7 +2302,7 @@
void BreakStatement::WriteTo(Writer* writer) {
TRACE_WRITE_OFFSET();
writer->WriteTag(kBreakStatement);
- writer->WriteUInt(writer->helper()->lables().Lookup(target_));
+ writer->WriteUInt(writer->helper()->labels()->Lookup(target_));
}
@@ -2853,6 +2875,8 @@
function->return_type_ = DartType::ReadFrom(reader);
function->inferred_return_value_ = reader->ReadOptional<InferredValue>();
+ LabelScope<ReaderHelper, BlockStack<LabeledStatement> > labels(
+ reader->helper());
VariableScope<ReaderHelper> vars(reader->helper());
function->body_ = reader->ReadOptional<Statement>();
return function;
@@ -2871,6 +2895,8 @@
return_type_->WriteTo(writer);
writer->WriteOptional<InferredValue>(inferred_return_value_);
+ LabelScope<WriterHelper, BlockMap<LabeledStatement> > labels(
+ writer->helper());
VariableScope<WriterHelper> vars(writer->helper());
writer->WriteOptional<Statement>(body_);
}
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index 356d19c..22f5568 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -103,7 +103,6 @@
}
Object& KernelReader::ReadProgram() {
- ASSERT(!bootstrapping_);
Program* program = ReadPrecompiledProgram();
if (program == NULL) {
const dart::String& error = H.DartString("Failed to read .kernell file");
@@ -174,10 +173,6 @@
TokenPosition::kNoSource));
toplevel_class.set_is_cycle_free();
library.set_toplevel_class(toplevel_class);
- if (bootstrapping_) {
- GrowableObjectArray::Handle(Z, I->object_store()->pending_classes())
- .Add(toplevel_class, Heap::kOld);
- }
ActiveClassScope active_class_scope(&active_class_, NULL, &toplevel_class);
// Load toplevel fields.
@@ -215,6 +210,8 @@
Class* kernel_klass = kernel_library->classes()[i];
classes.Add(ReadClass(library, kernel_klass), Heap::kOld);
}
+
+ classes.Add(toplevel_class, Heap::kOld);
}
@@ -350,10 +347,8 @@
ReadProcedure(library, klass, kernel_procedure, kernel_klass);
}
- if (bootstrapping_ && !klass.is_marked_for_parsing()) {
+ if (!klass.is_marked_for_parsing()) {
klass.set_is_marked_for_parsing();
- GrowableObjectArray::Handle(Z, I->object_store()->pending_classes())
- .Add(klass, Heap::kOld);
}
return klass;
@@ -581,8 +576,8 @@
}
for (intptr_t i = 0; i < node->positional_parameters().length(); i++, pos++) {
VariableDeclaration* kernel_variable = node->positional_parameters()[i];
- const AbstractType& type =
- type_translator.TranslateType(kernel_variable->type());
+ const AbstractType& type = type_translator.TranslateTypeWithoutFinalization(
+ kernel_variable->type());
function.SetParameterTypeAt(
pos, type.IsMalformed() ? Type::dynamic_type() : type);
function.SetParameterNameAt(
@@ -590,18 +585,21 @@
}
for (intptr_t i = 0; i < node->named_parameters().length(); i++, pos++) {
VariableDeclaration* named_expression = node->named_parameters()[i];
- const AbstractType& type =
- type_translator.TranslateType(named_expression->type());
+ const AbstractType& type = type_translator.TranslateTypeWithoutFinalization(
+ named_expression->type());
function.SetParameterTypeAt(
pos, type.IsMalformed() ? Type::dynamic_type() : type);
function.SetParameterNameAt(
pos, translation_helper.DartSymbol(named_expression->name()));
}
- const AbstractType& return_type =
- type_translator.TranslateType(node->return_type());
- function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type()
- : return_type);
+ // The result type for generative constructors has already been set.
+ if (!function.IsGenerativeConstructor()) {
+ const AbstractType& return_type =
+ type_translator.TranslateTypeWithoutFinalization(node->return_type());
+ function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type()
+ : return_type);
+ }
}
@@ -672,7 +670,7 @@
// we do not risk allocating the class again by calling LookupClass
// recursively from ReadPreliminaryClass for the same class.
classes_.Insert(klass, handle);
- if (!handle->is_type_finalized()) {
+ if (!handle->is_cycle_free()) {
ReadPreliminaryClass(handle, klass);
}
}
@@ -698,6 +696,35 @@
}
+ParsedFunction* ParseStaticFieldInitializer(Zone* zone,
+ const dart::Field& field) {
+ Thread* thread = Thread::Current();
+ kernel::Field* kernel_field = kernel::Field::Cast(
+ reinterpret_cast<kernel::Node*>(field.kernel_field()));
+
+ dart::String& init_name = dart::String::Handle(zone, field.name());
+ init_name = Symbols::FromConcat(thread, Symbols::InitPrefix(), init_name);
+
+ // Create a static initializer.
+ const dart::Class& owner = dart::Class::Handle(zone, field.Owner());
+ const Function& initializer_fun = Function::ZoneHandle(
+ zone,
+ dart::Function::New(init_name, RawFunction::kImplicitStaticFinalGetter,
+ true, // is_static
+ false, // is_const
+ false, // is_abstract
+ false, // is_external
+ false, // is_native
+ owner, TokenPosition::kNoSource));
+ initializer_fun.set_kernel_function(kernel_field);
+ initializer_fun.set_result_type(AbstractType::Handle(zone, field.type()));
+ initializer_fun.set_is_debuggable(false);
+ initializer_fun.set_is_reflectable(false);
+ initializer_fun.set_is_inlinable(false);
+ return new (zone) ParsedFunction(thread, initializer_fun);
+}
+
+
} // namespace kernel
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/kernel_reader.h b/runtime/vm/kernel_reader.h
index a361c14..60c8de9 100644
--- a/runtime/vm/kernel_reader.h
+++ b/runtime/vm/kernel_reader.h
@@ -54,7 +54,7 @@
class KernelReader {
public:
- KernelReader(const uint8_t* buffer, intptr_t len, bool bootstrapping = false)
+ KernelReader(const uint8_t* buffer, intptr_t len)
: thread_(dart::Thread::Current()),
zone_(thread_->zone()),
isolate_(thread_->isolate()),
@@ -64,7 +64,6 @@
type_translator_(&translation_helper_,
&active_class_,
/*finalize=*/false),
- bootstrapping_(bootstrapping),
buffer_(buffer),
buffer_length_(len) {}
@@ -122,8 +121,6 @@
BuildingTranslationHelper translation_helper_;
DartTypeTranslator type_translator_;
- bool bootstrapping_;
-
const uint8_t* buffer_;
intptr_t buffer_length_;
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 9ebcfc1..ff7c1cd 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -4154,6 +4154,11 @@
}
type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
klass.token_pos());
+ if (klass.is_type_finalized()) {
+ type ^= ClassFinalizer::FinalizeType(
+ klass, type, ClassFinalizer::kCanonicalizeWellFormed);
+ klass.SetCanonicalType(type);
+ }
return type;
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 0cfa413..920b9bd 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -545,6 +545,7 @@
cls.set_state_bits(0);
cls.set_is_finalized();
cls.set_is_type_finalized();
+ cls.set_is_cycle_free();
cls.set_type_arguments_field_offset_in_words(Class::kNoTypeArguments);
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
@@ -565,6 +566,7 @@
cls.set_num_own_type_arguments(0);
cls.set_is_finalized();
cls.set_is_type_finalized();
+ cls.set_is_cycle_free();
// Allocate and initialize the forwarding corpse class.
cls = Class::New<ForwardingCorpse::FakeInstance>(kForwardingCorpse);
@@ -572,6 +574,7 @@
cls.set_num_own_type_arguments(0);
cls.set_is_finalized();
cls.set_is_type_finalized();
+ cls.set_is_cycle_free();
// Allocate and initialize the sentinel values of Null class.
{
@@ -824,20 +827,23 @@
cls.set_is_abstract();
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
- cls.set_is_type_finalized();
cls.set_is_finalized();
+ cls.set_is_type_finalized();
+ cls.set_is_cycle_free();
dynamic_class_ = cls.raw();
cls = Class::New<Instance>(kVoidCid);
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
- cls.set_is_type_finalized();
cls.set_is_finalized();
+ cls.set_is_type_finalized();
+ cls.set_is_cycle_free();
void_class_ = cls.raw();
cls = Class::New<Type>();
- cls.set_is_type_finalized();
cls.set_is_finalized();
+ cls.set_is_type_finalized();
+ cls.set_is_cycle_free();
cls = dynamic_class_;
*dynamic_type_ = Type::NewNonParameterizedType(cls);
@@ -3187,6 +3193,7 @@
cls.set_is_finalized();
cls.set_is_type_finalized();
cls.set_is_synthesized_class();
+ cls.set_is_cycle_free();
library.AddClass(cls);
return cls.raw();
} else {
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 4bad386..7829fd6 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -52,7 +52,7 @@
conditional_directives,
true,
"Enable conditional directives");
-DEFINE_FLAG(bool, generic_method_syntax, false, "Enable generic functions.");
+DEFINE_FLAG(bool, generic_method_syntax, true, "Enable generic functions.");
DEFINE_FLAG(bool,
initializing_formal_access,
false,
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 5c50458..8d72d929a 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -1118,12 +1118,20 @@
bool compute_type) {
ASSERT(field.is_static());
Thread* thread = Thread::Current();
- StackZone zone(thread);
+ StackZone stack_zone(thread);
+ Zone* zone = stack_zone.GetZone();
- ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
+ ParsedFunction* parsed_function;
+ // Check if this field is comming from the Kernel binary.
+ if (field.kernel_field() != NULL) {
+ parsed_function = kernel::ParseStaticFieldInitializer(zone, field);
+ } else {
+ parsed_function = Parser::ParseStaticFieldInitializer(field);
+ parsed_function->AllocateVariables();
+ }
- parsed_function->AllocateVariables();
- DartPrecompilationPipeline pipeline(zone.GetZone());
+
+ DartPrecompilationPipeline pipeline(zone);
PrecompileParsedFunctionHelper helper(/* precompiler = */ NULL,
parsed_function,
/* optimized = */ true);
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 05f8302..22febb0 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -1104,11 +1104,10 @@
return;
}
- if (StubCode::HasBeenInitialized() &&
- StubCode::InJumpToExceptionHandlerStub(state.pc)) {
- // The JumpToExceptionHandler stub manually adjusts the stack pointer,
- // frame pointer, and some isolate state before jumping to a catch entry.
- // It is not safe to walk the stack when executing this stub.
+ if (StubCode::HasBeenInitialized() && StubCode::InJumpToFrameStub(state.pc)) {
+ // The JumpToFrame stub manually adjusts the stack pointer, frame
+ // pointer, and some isolate state. It is not safe to walk the
+ // stack when executing this stub.
AtomicOperations::IncrementInt64By(
&counters_.bail_out_jump_to_exception_handler, 1);
return;
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 232b1a4..2b64e48 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3891,12 +3891,7 @@
}
-void Simulator::Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -3919,10 +3914,6 @@
thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
-
- ASSERT(raw_exception != Object::null());
- set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
- set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
// Restore pool pointer.
int32_t code =
*reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h
index 605ccec..5a59f5bc 100644
--- a/runtime/vm/simulator_arm.h
+++ b/runtime/vm/simulator_arm.h
@@ -127,12 +127,7 @@
static uword FunctionForRedirect(uword redirect);
- void Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread);
+ void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
private:
// Known bad pc value to ensure that the simulator does not execute
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index a055567..65a2034 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3602,12 +3602,7 @@
}
-void Simulator::Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -3630,10 +3625,6 @@
thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
-
- ASSERT(raw_exception != Object::null());
- set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception));
- set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace));
// Restore pool pointer.
int64_t code =
*reinterpret_cast<int64_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index 79f9ced..43c0571 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -124,12 +124,7 @@
static uword FunctionForRedirect(uword redirect);
- void Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread);
+ void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
private:
// Known bad pc value to ensure that the simulator does not execute
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index ae9eaf8..8febf13 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -3691,12 +3691,7 @@
}
-void Simulator::Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -3716,12 +3711,22 @@
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
- ASSERT(raw_exception != Object::null());
sp_ = reinterpret_cast<RawObject**>(sp);
fp_ = reinterpret_cast<RawObject**>(fp);
- pc_ = pc;
- special_[kExceptionSpecialIndex] = raw_exception;
- special_[kStacktraceSpecialIndex] = raw_stacktrace;
+
+ if (pc == StubCode::RunExceptionHandler_entry()->EntryPoint()) {
+ // Instead of executing the RunException stub, we implement its
+ // behavior here.
+ RawObject* raw_exception = thread->active_exception();
+ RawObject* raw_stacktrace = thread->active_stacktrace();
+ ASSERT(raw_exception != Object::null());
+ special_[kExceptionSpecialIndex] = raw_exception;
+ special_[kStacktraceSpecialIndex] = raw_stacktrace;
+ pc_ = thread->resume_pc();
+ } else {
+ pc_ = pc;
+ }
+
buf->Longjmp();
UNREACHABLE();
}
diff --git a/runtime/vm/simulator_dbc.h b/runtime/vm/simulator_dbc.h
index 8acdbce..e0570b7 100644
--- a/runtime/vm/simulator_dbc.h
+++ b/runtime/vm/simulator_dbc.h
@@ -64,12 +64,7 @@
const Array& arguments,
Thread* thread);
- void Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread);
+ void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
uword get_sp() const { return reinterpret_cast<uword>(sp_); }
uword get_fp() const { return reinterpret_cast<uword>(fp_); }
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index f65b9ed..f3c325f 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -2479,12 +2479,7 @@
}
-void Simulator::Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -2507,10 +2502,6 @@
thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
-
- ASSERT(raw_exception != Object::null());
- set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
- set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
// Restore pool pointer.
int32_t code =
*reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index d6b5323..00d93ec 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -139,12 +139,7 @@
static uword FunctionForRedirect(uword redirect);
- void Longjmp(uword pc,
- uword sp,
- uword fp,
- RawObject* raw_exception,
- RawObject* raw_stacktrace,
- Thread* thread);
+ void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
private:
// A pc value used to signal the simulator to stop execution. Generally
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 0418da8..5b6a5f5 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -91,8 +91,8 @@
bool StubCode::HasBeenInitialized() {
#if !defined(TARGET_ARCH_DBC)
- // Use JumpToExceptionHandler and InvokeDart as canaries.
- const StubEntry* entry_1 = StubCode::JumpToExceptionHandler_entry();
+ // Use JumpToHandler and InvokeDart as canaries.
+ const StubEntry* entry_1 = StubCode::JumpToFrame_entry();
const StubEntry* entry_2 = StubCode::InvokeDartCode_entry();
return (entry_1 != NULL) && (entry_2 != NULL);
#else
@@ -115,11 +115,11 @@
}
-bool StubCode::InJumpToExceptionHandlerStub(uword pc) {
+bool StubCode::InJumpToFrameStub(uword pc) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
- uword entry = StubCode::JumpToExceptionHandler_entry()->EntryPoint();
- uword size = StubCode::JumpToExceptionHandlerSize();
+ uword entry = StubCode::JumpToFrame_entry()->EntryPoint();
+ uword size = StubCode::JumpToFrameSize();
return (pc >= entry) && (pc < (entry + size));
#else
// This stub does not exist on DBC.
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index 7d0dd14..3a2cea0 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -25,7 +25,8 @@
#if !defined(TARGET_ARCH_DBC)
#define VM_STUB_CODE_LIST(V) \
V(GetStackPointer) \
- V(JumpToExceptionHandler) \
+ V(JumpToFrame) \
+ V(RunExceptionHandler) \
V(UpdateStoreBuffer) \
V(PrintStopMessage) \
V(CallToRuntime) \
@@ -73,6 +74,7 @@
#define VM_STUB_CODE_LIST(V) \
V(LazyCompile) \
V(OptimizeFunction) \
+ V(RunExceptionHandler) \
V(FixCallersTarget) \
V(Deoptimize) \
V(DeoptimizeLazyFromReturn) \
@@ -138,8 +140,8 @@
// transitioning into dart code.
static bool InInvocationStub(uword pc);
- // Check if the specified pc is in the jump to exception handler stub.
- static bool InJumpToExceptionHandlerStub(uword pc);
+ // Check if the specified pc is in the jump to frame stub.
+ static bool InJumpToFrameStub(uword pc);
// Returns NULL if no stub found.
static const char* NameOfStub(uword entry_point);
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 10722cc..87b054d 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1850,23 +1850,19 @@
}
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
// LR: return address.
// R0: program_counter.
// R1: stack_pointer.
// R2: frame_pointer.
-// R3: error object.
-// SP + 0: address of stacktrace object.
-// SP + 4: thread.
+// R3: thread.
// Does not return.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == R0);
ASSERT(kStackTraceObjectReg == R1);
__ mov(IP, Operand(R1)); // Copy Stack pointer into IP.
__ mov(LR, Operand(R0)); // Program counter.
- __ mov(R0, Operand(R3)); // Exception object.
- __ ldr(R1, Address(SP, 0)); // StackTrace object.
- __ ldr(THR, Address(SP, 4)); // Thread.
+ __ mov(THR, Operand(R3)); // Thread.
__ mov(FP, Operand(R2)); // Frame_pointer.
__ mov(SP, Operand(IP)); // Set Stack pointer.
// Set the tag.
@@ -1878,6 +1874,27 @@
// Restore the pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer();
+ __ bx(LR); // Jump to continuation point.
+}
+
+
+// Run an exception handler. Execution comes from JumpToFrame
+// stub or from the simulator.
+//
+// The arguments are stored in the Thread object.
+// Does not return.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+ __ LoadFromOffset(kWord, LR, THR, Thread::resume_pc_offset());
+ __ LoadImmediate(R2, 0);
+
+ // Exception object.
+ __ LoadFromOffset(kWord, R0, THR, Thread::active_exception_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::active_exception_offset());
+
+ // Stacktrace object.
+ __ LoadFromOffset(kWord, R1, THR, Thread::active_stacktrace_offset());
+ __ StoreToOffset(kWord, R2, THR, Thread::active_stacktrace_offset());
+
__ bx(LR); // Jump to the exception handler code.
}
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 71dae4b..5a5a156 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -1902,24 +1902,20 @@
}
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
// LR: return address.
// R0: program_counter.
// R1: stack_pointer.
// R2: frame_pointer.
-// R3: error object.
-// R4: address of stacktrace object.
-// R5: thread.
+// R3: thread.
// Does not return.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == R0);
ASSERT(kStackTraceObjectReg == R1);
__ mov(LR, R0); // Program counter.
__ mov(SP, R1); // Stack pointer.
__ mov(FP, R2); // Frame_pointer.
- __ mov(R0, R3); // Exception object.
- __ mov(R1, R4); // StackTrace object.
- __ mov(THR, R5);
+ __ mov(THR, R3);
// Set the tag.
__ LoadImmediate(R2, VMTag::kDartTagId);
__ StoreToOffset(R2, THR, Thread::vm_tag_offset());
@@ -1928,6 +1924,27 @@
// Restore the pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer();
+ __ ret(); // Jump to continuation point.
+}
+
+
+// Run an exception handler. Execution comes from JumpToFrame
+// stub or from the simulator.
+//
+// The arguments are stored in the Thread object.
+// Does not return.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+ __ LoadFromOffset(LR, THR, Thread::resume_pc_offset());
+ __ LoadImmediate(R2, 0);
+
+ // Exception object.
+ __ LoadFromOffset(R0, THR, Thread::active_exception_offset());
+ __ StoreToOffset(R2, THR, Thread::active_exception_offset());
+
+ // Stacktrace object.
+ __ LoadFromOffset(R1, THR, Thread::active_stacktrace_offset());
+ __ StoreToOffset(R2, THR, Thread::active_stacktrace_offset());
+
__ ret(); // Jump to the exception handler code.
}
diff --git a/runtime/vm/stub_code_dbc.cc b/runtime/vm/stub_code_dbc.cc
index 54711516..da24e19 100644
--- a/runtime/vm/stub_code_dbc.cc
+++ b/runtime/vm/stub_code_dbc.cc
@@ -41,6 +41,12 @@
}
+// Not executed, but used as a sentinel in Simulator::JumpToFrame.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+ __ Trap();
+}
+
+
// TODO(vegorov) Don't generate this stub.
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
__ Trap();
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 1de178a8..ca70617 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1792,21 +1792,15 @@
}
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
// TOS + 0: return address
// TOS + 1: program_counter
// TOS + 2: stack_pointer
// TOS + 3: frame_pointer
-// TOS + 4: exception object
-// TOS + 5: stacktrace object
-// TOS + 6: thread
+// TOS + 4: thread
// No Result.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
- ASSERT(kExceptionObjectReg == EAX);
- ASSERT(kStackTraceObjectReg == EDX);
- __ movl(THR, Address(ESP, 6 * kWordSize)); // Load target thread.
- __ movl(kStackTraceObjectReg, Address(ESP, 5 * kWordSize));
- __ movl(kExceptionObjectReg, Address(ESP, 4 * kWordSize));
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
+ __ movl(THR, Address(ESP, 4 * kWordSize)); // Load target thread.
__ movl(EBP, Address(ESP, 3 * kWordSize)); // Load target frame_pointer.
__ movl(EBX, Address(ESP, 1 * kWordSize)); // Load target PC into EBX.
__ movl(ESP, Address(ESP, 2 * kWordSize)); // Load target stack_pointer.
@@ -1818,6 +1812,29 @@
}
+// Run an exception handler. Execution comes from JumpToFrame stub.
+//
+// The arguments are stored in the Thread object.
+// No result.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+ ASSERT(kExceptionObjectReg == EAX);
+ ASSERT(kStackTraceObjectReg == EDX);
+ __ movl(EBX, Address(THR, Thread::resume_pc_offset()));
+
+ // Load the exception from the current thread.
+ Address exception_addr(THR, Thread::active_exception_offset());
+ __ movl(kExceptionObjectReg, exception_addr);
+ __ movl(exception_addr, Immediate(0));
+
+ // Load the stacktrace from the current thread.
+ Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
+ __ movl(kStackTraceObjectReg, stacktrace_addr);
+ __ movl(stacktrace_addr, Immediate(0));
+
+ __ jmp(EBX); // Jump to continuation point.
+}
+
+
// Calls to the runtime to optimize the given function.
// EBX: function to be reoptimized.
// EDX: argument descriptor (preserved).
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 40c8bb8..d52e6cc 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -1985,19 +1985,13 @@
// A0: program_counter.
// A1: stack_pointer.
// A2: frame_pointer.
-// A3: error object.
-// SP + 4*kWordSize: address of stacktrace object.
-// SP + 5*kWordSize: address of thread.
+// A3: thread.
// Does not return.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == V0);
ASSERT(kStackTraceObjectReg == V1);
- __ mov(V0, A3); // Exception object.
- // MIPS ABI reserves stack space for all arguments. The StackTrace object is
- // the last of five arguments, so it is first pushed on the stack.
- __ lw(V1, Address(SP, 4 * kWordSize)); // StackTrace object.
- __ mov(FP, A2); // Frame_pointer.
- __ lw(THR, Address(SP, 5 * kWordSize)); // Thread.
+ __ mov(FP, A2); // Frame_pointer.
+ __ mov(THR, A3); // Thread.
// Set tag.
__ LoadImmediate(A2, VMTag::kDartTagId);
__ sw(A2, Assembler::VMTagAddress());
@@ -2006,11 +2000,34 @@
// Restore pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer();
- __ jr(A0); // Jump to the exception handler code.
+ __ jr(A0); // Jump to the program counter.
__ delay_slot()->mov(SP, A1); // Stack pointer.
}
+// Run an exception handler. Execution comes from JumpToFrame
+// stub or from the simulator.
+//
+// The arguments are stored in the Thread object.
+// Does not return.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+ __ lw(A0, Address(THR, Thread::resume_pc_offset()));
+ __ LoadImmediate(A2, 0);
+
+ // Load the exception from the current thread.
+ Address exception_addr(THR, Thread::active_exception_offset());
+ __ lw(V0, exception_addr);
+ __ sw(A2, exception_addr);
+
+ // Load the stacktrace from the current thread.
+ Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
+ __ lw(V1, stacktrace_addr);
+
+ __ jr(A0); // Jump to continuation point.
+ __ delay_slot()->sw(A2, stacktrace_addr);
+}
+
+
// Calls to the runtime to optimize the given function.
// T0: function to be reoptimized.
// S4: argument descriptor (preserved).
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 9ca6a6e2..167154b 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -1845,33 +1845,17 @@
}
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
// TOS + 0: return address
// Arg1: program counter
// Arg2: stack pointer
// Arg3: frame_pointer
-// Arg4: exception object
-// Arg5: stacktrace object
-// Arg6: thread
+// Arg4: thread
// No Result.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
- ASSERT(kExceptionObjectReg == RAX);
- ASSERT(kStackTraceObjectReg == RDX);
- ASSERT(CallingConventions::kArg4Reg != kStackTraceObjectReg);
- ASSERT(CallingConventions::kArg1Reg != kStackTraceObjectReg);
-
-#if defined(_WIN64)
- Register stacktrace_reg = RBX;
- __ movq(stacktrace_reg, Address(RSP, 5 * kWordSize));
- __ movq(THR, Address(RSP, 6 * kWordSize));
-#else
- Register stacktrace_reg = CallingConventions::kArg5Reg;
- __ movq(THR, CallingConventions::kArg6Reg);
-#endif
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
+ __ movq(THR, CallingConventions::kArg4Reg);
__ movq(RBP, CallingConventions::kArg3Reg);
__ movq(RSP, CallingConventions::kArg2Reg);
- __ movq(kStackTraceObjectReg, stacktrace_reg);
- __ movq(kExceptionObjectReg, CallingConventions::kArg4Reg);
// Set the tag.
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Clear top exit frame.
@@ -1879,7 +1863,31 @@
// Restore the pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer(PP);
- __ jmp(CallingConventions::kArg1Reg); // Jump to the exception handler code.
+ __ jmp(CallingConventions::kArg1Reg); // Jump to program counter.
+}
+
+
+// Run an exception handler. Execution comes from JumpToFrame stub.
+//
+// The arguments are stored in the Thread object.
+// No result.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+ ASSERT(kExceptionObjectReg == RAX);
+ ASSERT(kStackTraceObjectReg == RDX);
+ __ movq(CallingConventions::kArg1Reg,
+ Address(THR, Thread::resume_pc_offset()));
+
+ // Load the exception from the current thread.
+ Address exception_addr(THR, Thread::active_exception_offset());
+ __ movq(kExceptionObjectReg, exception_addr);
+ __ movq(exception_addr, Immediate(0));
+
+ // Load the stacktrace from the current thread.
+ Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
+ __ movq(kStackTraceObjectReg, stacktrace_addr);
+ __ movq(stacktrace_addr, Immediate(0));
+
+ __ jmp(CallingConventions::kArg1Reg); // Jump to continuation point.
}
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index dc4e1ca..709d735 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -93,6 +93,9 @@
type_range_cache_(NULL),
deopt_id_(0),
pending_functions_(GrowableObjectArray::null()),
+ active_exception_(Object::null()),
+ active_stacktrace_(Object::null()),
+ resume_pc_(0),
sticky_error_(Error::null()),
compiler_stats_(NULL),
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
@@ -215,6 +218,17 @@
}
+void Thread::set_active_exception(const Object& value) {
+ ASSERT(!value.IsNull());
+ active_exception_ = value.raw();
+}
+
+
+void Thread::set_active_stacktrace(const Object& value) {
+ active_stacktrace_ = value.raw();
+}
+
+
RawError* Thread::sticky_error() const {
return sticky_error_;
}
@@ -606,6 +620,8 @@
reusable_handles_.VisitObjectPointers(visitor);
visitor->VisitPointer(reinterpret_cast<RawObject**>(&pending_functions_));
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_exception_));
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_stacktrace_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&sticky_error_));
// Visit the api local scope as it has all the api local handles.
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 95d04b2..a9fb55f 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -471,6 +471,22 @@
RawGrowableObjectArray* pending_functions();
void clear_pending_functions();
+ RawObject* active_exception() const { return active_exception_; }
+ void set_active_exception(const Object& value);
+ static intptr_t active_exception_offset() {
+ return OFFSET_OF(Thread, active_exception_);
+ }
+
+ RawObject* active_stacktrace() const { return active_stacktrace_; }
+ void set_active_stacktrace(const Object& value);
+ static intptr_t active_stacktrace_offset() {
+ return OFFSET_OF(Thread, active_stacktrace_);
+ }
+
+ uword resume_pc() const { return resume_pc_; }
+ void set_resume_pc(uword value) { resume_pc_ = value; }
+ static uword resume_pc_offset() { return OFFSET_OF(Thread, resume_pc_); }
+
RawError* sticky_error() const;
void set_sticky_error(const Error& value);
void clear_sticky_error();
@@ -684,6 +700,11 @@
intptr_t deopt_id_; // Compilation specific counter.
RawGrowableObjectArray* pending_functions_;
+ // JumpToExceptionHandler state:
+ RawObject* active_exception_;
+ RawObject* active_stacktrace_;
+ uword resume_pc_;
+
RawError* sticky_error_;
CompilerStats* compiler_stats_;
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 49a7ba9..722e628 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -11,6 +11,7 @@
# Override tests marked as failing elsewhere.
[ $compiler == dartk || $compiler == dartkp ]
Language/Libraries_and_Scripts/Exports/reexport_t01: Pass
+Language/Functions/Formal_Parameters/Optional_Formals/syntax_t14: Pass
# dartk: JIT failures
[ $compiler == dartk && $runtime == vm ]
@@ -36,9 +37,6 @@
Language/Enums/declaration_equivalent_t01: RuntimeError
Language/Enums/syntax_t08: MissingCompileTimeError
Language/Enums/syntax_t09: MissingCompileTimeError
-Language/Expressions/Await_Expressions/syntax_t01: RuntimeError
-Language/Expressions/Await_Expressions/syntax_t02: RuntimeError
-Language/Expressions/Await_Expressions/syntax_t10: RuntimeError
Language/Expressions/Constants/exception_t01: MissingCompileTimeError
Language/Expressions/Constants/exception_t02: MissingCompileTimeError
Language/Expressions/Constants/string_length_t01: Crash
@@ -49,15 +47,11 @@
Language/Expressions/Function_Invocation/Unqualified_Invocation/instance_context_invocation_t03: MissingCompileTimeError
Language/Expressions/Function_Invocation/Unqualified_Invocation/instance_context_invocation_t04: MissingCompileTimeError
Language/Expressions/Function_Invocation/Unqualified_Invocation/static_method_invocation_t02: RuntimeError
-Language/Expressions/Function_Invocation/async_cleanup_t01: RuntimeError
-Language/Expressions/Function_Invocation/async_cleanup_t02: RuntimeError
-Language/Expressions/Function_Invocation/async_cleanup_t04: Crash
Language/Expressions/Function_Invocation/async_cleanup_t07: Fail
Language/Expressions/Function_Invocation/async_cleanup_t08: Fail
Language/Expressions/Function_Invocation/async_generator_invokation_t05: RuntimeError
Language/Expressions/Function_Invocation/async_generator_invokation_t06: RuntimeError
Language/Expressions/Function_Invocation/async_generator_invokation_t09: RuntimeError
-Language/Expressions/Function_Invocation/async_invokation_t05: RuntimeError
Language/Expressions/Identifier_Reference/built_in_identifier_t35: Pass
Language/Expressions/Identifier_Reference/built_in_identifier_t36: Pass
Language/Expressions/Identifier_Reference/built_in_identifier_t37: Pass
@@ -327,6 +321,19 @@
Language/Libraries_and_Scripts/Imports/static_type_t01/03: Pass
Language/Libraries_and_Scripts/Imports/static_type_t01/07: Pass
Language/Libraries_and_Scripts/Imports/static_type_t01/02: Pass
+LibTest/core/Match/operator_subscript_A01_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A01_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A02_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A03_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A03_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A06_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClass_A02_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Disjunction_A01_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t02: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Quantifier_A03_t01: RuntimeError
+LibTest/core/RegExp/firstMatch_A02_t01: RuntimeError
+LibTest/core/RegExp/hasMatch_A01_t02: RuntimeError
+LibTest/core/RegExp/stringMatch_A01_t01: RuntimeError
# dartk: JIT failures (debug)
[ $compiler == dartk && $runtime == vm && $mode == debug ]
@@ -638,4 +645,4 @@
LibTest/core/Invocation/isSetter_A01_t02: Crash
LibTest/core/Invocation/memberName_A01_t01: RuntimeError
LibTest/core/Invocation/namedArguments_A01_t01: Crash
-LibTest/core/Invocation/positionalArguments_A01_t01: Crash
+LibTest/core/Invocation/positionalArguments_A01_t01: Crash
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
index 8ece3d4..89d1ff7 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
@@ -116,7 +116,8 @@
'''
import 'package:expect/expect.dart';
main() {
- test(); // This call is no longer on the stack when the error is thrown.
+ // This call is no longer on the stack when the error is thrown.
+ @{:main}test();
}
@NoInline()
test() async {
@@ -131,7 +132,7 @@
@NoInline()
test1() async {
// This call is no longer on the stack when the error is thrown.
- await test2();
+ await @{:test1}test2();
}
@NoInline()
test2() async {
@@ -152,13 +153,30 @@
@{2:test2}throw '$EXCEPTION_MARKER';
}
''',
+ '''
+import 'package:expect/expect.dart';
+main() {
+ // This call is no longer on the stack when the error is thrown.
+ @{:main}test();
+}
+test() async {
+ var c = @{1:test}new Class();
+}
+class Class {
+ @NoInline()
+ Class() {
+ @{2:Class}throw '$EXCEPTION_MARKER';
+ }
+}
+''',
];
class Test {
final String code;
final List<StackTraceLine> expectedLines;
+ final List<StackTraceLine> unexpectedLines;
- Test(this.code, this.expectedLines);
+ Test(this.code, this.expectedLines, this.unexpectedLines);
}
const int _LF = 0x0A;
@@ -168,6 +186,7 @@
Test processTestCode(String code) {
StringBuffer codeBuffer = new StringBuffer();
Map<int, StackTraceLine> stackTraceMap = <int, StackTraceLine>{};
+ List<StackTraceLine> unexpectedLines = <StackTraceLine>[];
int index = 0;
int lineNo = 1;
int columnNo = 1;
@@ -191,12 +210,17 @@
if (index + 1 < code.length && code.codeUnitAt(index + 1) == _LBRACE) {
int colonIndex = code.indexOf(':', index);
int endIndex = code.indexOf('}', index);
- int stackTraceIndex =
- int.parse(code.substring(index + 2, colonIndex));
String methodName = code.substring(colonIndex + 1, endIndex);
- assert(!stackTraceMap.containsKey(stackTraceIndex));
- stackTraceMap[stackTraceIndex] =
+ String indexText = code.substring(index + 2, colonIndex);
+ StackTraceLine stackTraceLine =
new StackTraceLine(methodName, INPUT_FILE_NAME, lineNo, columnNo);
+ if (indexText == '') {
+ unexpectedLines.add(stackTraceLine);
+ } else {
+ int stackTraceIndex = int.parse(indexText);
+ assert(!stackTraceMap.containsKey(stackTraceIndex));
+ stackTraceMap[stackTraceIndex] = stackTraceLine;
+ }
index = endIndex;
} else {
codeBuffer.writeCharCode(charCode);
@@ -213,18 +237,43 @@
for (int stackTraceIndex in (stackTraceMap.keys.toList()..sort()).reversed) {
expectedLines.add(stackTraceMap[stackTraceIndex]);
}
- return new Test(codeBuffer.toString(), expectedLines);
+ return new Test(codeBuffer.toString(), expectedLines, unexpectedLines);
}
void main(List<String> arguments) {
+ bool verbose = false;
+ bool printJs = false;
+ List<int> indices;
+ for (String arg in arguments) {
+ if (arg == '-v') {
+ verbose = true;
+ } else if (arg == '--print-js') {
+ printJs = true;
+ } else {
+ int index = int.parse(arg, onError: (_) => null);
+ if (index != null) {
+ indices ??= <int>[];
+ if (index < 0 || index >= TESTS.length) {
+ print('Index $index out of bounds: [0;${TESTS.length - 1}]');
+ } else {
+ indices.add(index);
+ }
+ }
+ }
+ }
+ if (indices == null) {
+ indices = new List<int>.generate(TESTS.length, (i) => i);
+ }
asyncTest(() async {
- for (String code in TESTS) {
- await runTest(processTestCode(code), verbose: arguments.contains('-v'));
+ for (int index in indices) {
+ await runTest(index, processTestCode(TESTS[index]),
+ printJs: printJs, verbose: verbose);
}
});
}
-Future runTest(Test test, {bool verbose: false}) async {
+Future runTest(int index, Test test,
+ {bool printJs: false, bool verbose: false}) async {
Directory tmpDir = await createTempDir();
String input = '${tmpDir.path}/$INPUT_FILE_NAME';
new File(input).writeAsStringSync(test.code);
@@ -236,7 +285,7 @@
Flags.useNewSourceInfo,
input,
];
- print("--------------------------------------------------------------------");
+ print("--$index------------------------------------------------------------");
print("Compiling dart2js ${arguments.join(' ')}\n${test.code}");
CompilationResult compilationResult = await entry.internalMain(arguments);
Expect.isTrue(compilationResult.isSuccess,
@@ -245,6 +294,10 @@
SingleMapping sourceMap = new SingleMapping.fromJson(
JSON.decode(new File('$output.map').readAsStringSync()));
+ if (printJs) {
+ print('JavaScript output:');
+ print(new File(output).readAsStringSync());
+ }
print("Running d8 $output");
ProcessResult runResult = Process.runSync(d8executable,
['sdk/lib/_internal/js_runtime/lib/preambles/d8.js', output]);
@@ -288,6 +341,7 @@
}
int expectedIndex = 0;
+ List<StackTraceLine> unexpectedLines = <StackTraceLine>[];
for (StackTraceLine line in dartStackTrace) {
if (expectedIndex < test.expectedLines.length) {
StackTraceLine expectedLine = test.expectedLines[expectedIndex];
@@ -297,6 +351,13 @@
expectedIndex++;
}
}
+ for (StackTraceLine unexpectedLine in test.unexpectedLines) {
+ if (line.methodName == unexpectedLine.methodName &&
+ line.lineNo == unexpectedLine.lineNo &&
+ line.columnNo == unexpectedLine.columnNo) {
+ unexpectedLines.add(line);
+ }
+ }
}
if (verbose) {
print('JavaScript stacktrace:');
@@ -310,6 +371,11 @@
"Missing stack trace lines for test:\n${test.code}\n"
"Actual:\n${dartStackTrace.join('\n')}\n"
"Expected:\n${test.expectedLines.join('\n')}\n");
+ Expect.isTrue(
+ unexpectedLines.isEmpty,
+ "Unexpected stack trace lines for test:\n${test.code}\n"
+ "Actual:\n${dartStackTrace.join('\n')}\n"
+ "Unexpected:\n${test.unexpectedLines.join('\n')}\n");
print("Deleting '${tmpDir.path}'.");
tmpDir.deleteSync(recursive: true);
diff --git a/tests/language/generic_functions_test.dart b/tests/language/generic_functions_test.dart
index 0e6d5b3..f7ae6bb 100644
--- a/tests/language/generic_functions_test.dart
+++ b/tests/language/generic_functions_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle type parameterization of
diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart
index 1b363d1..7b85297 100644
--- a/tests/language/generic_local_functions_test.dart
+++ b/tests/language/generic_local_functions_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle type parameterization of
diff --git a/tests/language/generic_methods_function_type_test.dart b/tests/language/generic_methods_function_type_test.dart
index 23c1992..d82a0b4 100644
--- a/tests/language/generic_methods_function_type_test.dart
+++ b/tests/language/generic_methods_function_type_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
/// Dart test on the usage of method type arguments in a function typed
diff --git a/tests/language/generic_methods_generic_function_parameter_test.dart b/tests/language/generic_methods_generic_function_parameter_test.dart
index 81eeade..45014c4 100644
--- a/tests/language/generic_methods_generic_function_parameter_test.dart
+++ b/tests/language/generic_methods_generic_function_parameter_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
import "package:expect/expect.dart";
diff --git a/tests/language/generic_methods_new_test.dart b/tests/language/generic_methods_new_test.dart
index 0836fd5..83359f1 100644
--- a/tests/language/generic_methods_new_test.dart
+++ b/tests/language/generic_methods_new_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
/// Dart test on the usage of method type arguments in object creation. With
diff --git a/tests/language/generic_methods_test.dart b/tests/language/generic_methods_test.dart
index ec7d488..e32526a 100644
--- a/tests/language/generic_methods_test.dart
+++ b/tests/language/generic_methods_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle type parameterization of
diff --git a/tests/language/generic_methods_type_expression_test.dart b/tests/language/generic_methods_type_expression_test.dart
index fadd7e9..ccf24bc 100644
--- a/tests/language/generic_methods_type_expression_test.dart
+++ b/tests/language/generic_methods_type_expression_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
/// Dart test on the usage of method type arguments in type expressions. With
diff --git a/tests/language/generic_sends_test.dart b/tests/language/generic_sends_test.dart
index 75c7dc9..68e50fe 100644
--- a/tests/language/generic_sends_test.dart
+++ b/tests/language/generic_sends_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// DartOptions=--generic-method-syntax
// VMOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle certain cases where
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 5891891..7a10bf8 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -80,16 +80,6 @@
[ $compiler == dart2js && $browser ]
config_import_test: Fail # Test flag is not passed to the compiler.
-# Experimental feature: Syntactic support for generic methods.
-generic_functions_test: CompileTimeError # DartOptions not passed to compiler.
-generic_local_functions_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_test: CompileTimeError # DartOptions not passed to compiler.
-generic_sends_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_new_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_function_type_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_type_expression_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_generic_function_parameter_test: CompileTimeError # DartOptions not passed to compiler.
-
# Experimental feature: Use initializing formals in initializers and constructor body.
initializing_formal_access_test: CompileTimeError # DartOptions not passed to compiler.
initializing_formal_capture_test: CompileTimeError # DartOptions not passed to compiler.
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index 3d87904..133e4c0 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -17,24 +17,17 @@
accessor_conflict_import_prefixed_test: RuntimeError
accessor_conflict_import_test: RuntimeError
assertion_test: RuntimeError
-async_await_test: Crash
-async_break_in_finally_test: RuntimeError
-async_control_structures_test: RuntimeError
+async_await_test: RuntimeError
async_star_cancel_and_throw_in_finally_test: RuntimeError
async_star_cancel_while_paused_test: RuntimeError
async_star_pause_test: RuntimeError
-async_star_regression_fisk_test: RuntimeError
+async_star_regression_fisk_test: Timeout
async_star_stream_take_test: Timeout
async_star_take_reyield_test: Timeout
async_star_test: Timeout
-async_throw_in_catch_test/forceAwait: RuntimeError
-async_throw_in_catch_test/none: RuntimeError
asyncstar_throw_in_catch_test: Timeout
asyncstar_yield_test: Timeout
asyncstar_yieldstar_test: Timeout
-await_exceptions_test: RuntimeError
-await_future_test: RuntimeError
-await_regression_test: RuntimeError
bad_constructor_test/05: CompileTimeError
bad_raw_string_negative_test: Fail
cha_deopt1_test: RuntimeError
@@ -331,7 +324,6 @@
try_finally_regress_25654_test: RuntimeError
type_checks_in_factory_method_test: RuntimeError
type_parameter_literal_test: RuntimeError
-type_parameter_test/04: Crash
type_variable_conflict2_test/02: MissingCompileTimeError
type_variable_conflict2_test/06: MissingCompileTimeError
type_variable_conflict2_test/08: MissingCompileTimeError
@@ -697,11 +689,10 @@
try_finally_regress_25654_test: RuntimeError
type_checks_in_factory_method_test: RuntimeError
type_parameter_literal_test: RuntimeError
-type_parameter_test/04: Crash
type_variable_conflict2_test/02: MissingCompileTimeError
type_variable_function_type_test: RuntimeError
vm/debug_break_enabled_vm_test/01: CompileTimeError
vm/debug_break_enabled_vm_test/none: CompileTimeError
vm/reflect_core_vm_test: CompileTimeError
vm/type_cast_vm_test: RuntimeError
-vm/type_vm_test: RuntimeError
+vm/type_vm_test: RuntimeError
\ No newline at end of file
diff --git a/tests/lib/mirrors/unnamed_mixin_application_test.dart b/tests/lib/mirrors/unnamed_mixin_application_test.dart
new file mode 100644
index 0000000..782774b
--- /dev/null
+++ b/tests/lib/mirrors/unnamed_mixin_application_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Test that the forwarding constructors of unnamed mixin applications are
+/// included for reflection.
+
+import 'dart:mirrors';
+
+class S {
+ S();
+ S.anUnusedName();
+}
+class M {}
+class C extends S with M {
+ C();
+}
+
+main() {
+ // Use 'C#', 'S+M#' and 'S#' but not 'S#anUnusedName' nor 'S+M#anUnusedName'.
+ new C();
+ // Disable tree shaking making 'S+M#anUnusedName' live.
+ reflectClass(C);
+}
\ No newline at end of file
diff --git a/tools/VERSION b/tools/VERSION
index b4d1f0b..6f94e01 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,5 +28,5 @@
MAJOR 1
MINOR 21
PATCH 0
-PRERELEASE 8
+PRERELEASE 9
PRERELEASE_PATCH 0
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 25c7aba..160844c 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -54,6 +54,7 @@
# ......collection/
# ......convert/
# ......core/
+# ......front_end/
# ......html/
# ......internal/
# ......io/
@@ -145,7 +146,7 @@
join(sdk_root, 'bin', 'snapshots', snapshot))
def CopyAnalyzerSources(home, lib_dir):
- for library in ['analyzer', 'analysis_server']:
+ for library in ['analyzer', 'analysis_server', 'front_end']:
copytree(join(home, 'pkg', library), join(lib_dir, library),
ignore=ignore_patterns('*.svn', 'doc', '*.py', '*.gypi', '*.sh',
'.gitignore', 'packages'))
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index bee1a2c..e9802e9 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -83,8 +83,16 @@
dartkp: Compiler the Dart source into Kernel and then Kernel into AOT
snapshot before running the test.''',
['-c', '--compiler'],
- ['none', 'precompiler', 'dart2js', 'dart2analyzer', 'dart2app',
- 'dart2appjit', 'dartk', 'dartkp'],
+ [
+ 'none',
+ 'precompiler',
+ 'dart2js',
+ 'dart2analyzer',
+ 'dart2app',
+ 'dart2appjit',
+ 'dartk',
+ 'dartkp'
+ ],
'none'),
// TODO(antonm): fix the option drt.
new _TestOptionSpecification(
@@ -198,21 +206,29 @@
'noopt', 'Run an in-place precompilation', ['--noopt'], [], false,
type: 'bool'),
new _TestOptionSpecification(
- 'fast_startup', 'Pass the --fast-startup flag to dart2js',
- ['--fast-startup'], [], false,
+ 'fast_startup',
+ 'Pass the --fast-startup flag to dart2js',
+ ['--fast-startup'],
+ [],
+ false,
+ type: 'bool'),
+ new _TestOptionSpecification('hot_reload', 'Run hot reload stress tests',
+ ['--hot-reload'], [], false,
type: 'bool'),
new _TestOptionSpecification(
- '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'],
+ 'Run hot reload rollback stress tests',
+ ['--hot-reload-rollback'],
[],
- false, type: 'bool'),
+ false,
+ type: 'bool'),
new _TestOptionSpecification(
'use_blobs',
'Use mmap instead of shared libraries for precompilation',
- ['--use-blobs'], [], false, type: 'bool'),
+ ['--use-blobs'],
+ [],
+ false,
+ type: 'bool'),
new _TestOptionSpecification(
'timeout', 'Timeout in seconds', ['-t', '--timeout'], [], -1,
type: 'int'),
@@ -611,34 +627,30 @@
List<String> _constructReproducingCommandArguments(Map config) {
var arguments = new List<String>();
- for (var configKey in config.keys) {
- if (!_blacklistedOptions.contains(configKey)) {
- for (var option in _options) {
- var configValue = config[configKey];
- // We only include entries of [conf] if we find an option for it.
- if (configKey == option.name && configValue != option.defaultValue) {
- var isBooleanOption = option.type == 'bool';
- // Sort by length, so we get the shortest variant.
- var possibleOptions = new List.from(option.keys);
- possibleOptions.sort((a, b) => (a.length < b.length ? -1 : 1));
- var key = possibleOptions[0];
- if (key.startsWith('--')) {
- // long version
- arguments.add(key);
- if (!isBooleanOption) {
- arguments.add("$configValue");
- }
- } else {
- // short version
- assert(key.startsWith('-'));
- if (!isBooleanOption) {
- arguments.add("$key$configValue");
- } else {
- arguments.add(key);
- }
- }
- }
- }
+ for (var option in _options) {
+ var name = option.name;
+ if (!config.containsKey(name) || _blacklistedOptions.contains(name)) {
+ continue;
+ }
+ var value = config[name];
+ if (config[name] == option.defaultValue ||
+ (name == 'packages' &&
+ value ==
+ TestUtils.dartDirUri.resolve('.packages').toFilePath())) {
+ continue;
+ }
+ shortest(String a, String b) => a.length <= b.length ? a : b;
+ var key = option.keys.reduce(shortest);
+ if (option.type == 'bool') {
+ arguments.add(key);
+ } else if (key.startsWith('--')) {
+ // long version
+ arguments.add(key);
+ arguments.add("$value");
+ } else {
+ // short version
+ assert(key.startsWith('-'));
+ arguments.add("$key$value");
}
}
return arguments;
@@ -826,20 +838,23 @@
if (selectors.containsKey('observatory_ui')) {
if (selectors.length == 1) {
configuration['packages'] = TestUtils.dartDirUri
- .resolve('runtime/observatory/.packages').toFilePath();
+ .resolve('runtime/observatory/.packages')
+ .toFilePath();
} else {
// Make a new configuration whose selectors map only contains
// observatory_ui, and remove the key from the original selectors.
// The only mutable value in the map is the selectors, so a
// shallow copy is safe.
var observatoryConfiguration = new Map.from(configuration);
- observatoryConfiguration['selectors'] =
- {'observatory_ui': selectors['observatory_ui']};
+ observatoryConfiguration['selectors'] = {
+ 'observatory_ui': selectors['observatory_ui']
+ };
selectors.remove('observatory_ui');
// Set the packages flag.
observatoryConfiguration['packages'] = TestUtils.dartDirUri
- .resolve('runtime/observatory/.packages').toFilePath();
+ .resolve('runtime/observatory/.packages')
+ .toFilePath();
// Return the expansions of both configurations. Neither will reach
// this line in the recursive call to _expandConfigurations.
@@ -851,7 +866,7 @@
if (configuration['package_root'] == null &&
configuration['packages'] == null) {
configuration['packages'] =
- TestUtils.dartDirUri.resolve('.packages').toFilePath();
+ TestUtils.dartDirUri.resolve('.packages').toFilePath();
}
// Expand the architectures.
@@ -883,8 +898,8 @@
// Adjust default timeout based on mode, compiler, and sometimes runtime.
if (configuration['timeout'] == -1) {
- var isReload = configuration['hot_reload'] ||
- configuration['hot_reload_rollback'];
+ var isReload =
+ configuration['hot_reload'] || configuration['hot_reload_rollback'];
int compilerMulitiplier =
new CompilerConfiguration(configuration).computeTimeoutMultiplier();
int runtimeMultiplier = new RuntimeConfiguration(configuration)