Version 1.6.0-dev.5.0
svn merge -r 38367:38486 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@38487 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/driver.dart b/pkg/analysis_server/lib/driver.dart
index c3c6f24..e210777 100644
--- a/pkg/analysis_server/lib/driver.dart
+++ b/pkg/analysis_server/lib/driver.dart
@@ -9,6 +9,9 @@
import 'package:analysis_server/http_server.dart';
import 'package:analysis_server/src/socket_server.dart';
import 'package:analysis_server/stdio_server.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:args/args.dart';
import 'package:logging/logging.dart';
@@ -39,15 +42,20 @@
*/
static const String LOG_FILE_OPTION = "log";
- SocketServer socketServer = new SocketServer();
+ /**
+ * The path to the SDK.
+ * TODO(paulberry): get rid of this once the 'analysis.updateSdks' request is
+ * operational.
+ */
+ static const String SDK_OPTION = 'sdk';
+
+ SocketServer socketServer;
HttpAnalysisServer httpServer;
StdioAnalysisServer stdioServer;
Driver() {
- httpServer = new HttpAnalysisServer(socketServer);
- stdioServer = new StdioAnalysisServer(socketServer);
}
/**
@@ -62,6 +70,8 @@
"[port] the port on which the server will listen");
parser.addOption(LOG_FILE_OPTION, help:
"[path] file to log debugging messages to");
+ parser.addOption(SDK_OPTION, help:
+ "[path] path to the sdk");
ArgResults results = parser.parse(args);
if (results[HELP_OPTION]) {
@@ -95,6 +105,18 @@
return;
}
}
+ DartSdk defaultSdk;
+ if (results[SDK_OPTION] != null) {
+ defaultSdk = new DirectoryBasedDartSdk(new JavaFile(results[SDK_OPTION]));
+ } else {
+ // No path to the SDK provided; use DirectoryBasedDartSdk.defaultSdk,
+ // which will make a guess.
+ defaultSdk = DirectoryBasedDartSdk.defaultSdk;
+ }
+
+ socketServer = new SocketServer(defaultSdk);
+ httpServer = new HttpAnalysisServer(socketServer);
+ stdioServer = new StdioAnalysisServer(socketServer);
if (serve_http) {
httpServer.serveHttp(port);
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 975a911..285e82f 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -24,7 +24,6 @@
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analysis_services/index/index.dart';
@@ -32,12 +31,6 @@
import 'package:analyzer/src/generated/element.dart';
-/**
- * An instance of [DirectoryBasedDartSdk] that is shared between
- * [AnalysisServer] instances to improve performance.
- */
-final DirectoryBasedDartSdk SHARED_SDK = DirectoryBasedDartSdk.defaultSdk;
-
class AnalysisServerContextDirectoryManager extends ContextDirectoryManager {
final AnalysisServer analysisServer;
@@ -143,7 +136,7 @@
/**
* The current default [DartSdk].
*/
- DartSdk defaultSdk = SHARED_SDK;
+ final DartSdk defaultSdk;
/**
* A table mapping [Folder]s to the [AnalysisContext]s associated with them.
@@ -173,6 +166,13 @@
new HashMap<AnalysisService, Set<String>>();
/**
+ * A table mapping [AnalysisContext]s to the completers that should be
+ * completed when analysis of this context is finished.
+ */
+ Map<AnalysisContext, Completer> contextAnalysisDoneCompleters =
+ new HashMap<AnalysisContext, Completer>();
+
+ /**
* True if any exceptions thrown by analysis should be propagated up the call
* stack.
*/
@@ -188,7 +188,7 @@
* running a full analysis server.
*/
AnalysisServer(this.channel, ResourceProvider resourceProvider,
- PackageMapProvider packageMapProvider, this.index,
+ PackageMapProvider packageMapProvider, this.index, this.defaultSdk,
{this.rethrowExceptions: true}) {
searchEngine = createSearchEngine(index);
operationQueue = new ServerOperationQueue(this);
@@ -227,6 +227,13 @@
}
/**
+ * Send the given [response] to the client.
+ */
+ void sendResponse(Response response) {
+ channel.sendResponse(response);
+ }
+
+ /**
* Set the priority files to the given [files].
*/
void setPriorityFiles(Request request, List<String> files) {
@@ -334,6 +341,9 @@
for (int i = 0; i < count; i++) {
try {
Response response = handlers[i].handleRequest(request);
+ if (response == Response.DELAYED_RESPONSE) {
+ return;
+ }
if (response != null) {
channel.sendResponse(response);
return;
@@ -562,6 +572,24 @@
}
/**
+ * Returns all the [AnalysisErrorInfo] for [file].
+ * It does not wait for all errors to be computed, and returns just the
+ * current state.
+ *
+ * May return `null`.
+ */
+ AnalysisErrorInfo getErrors(String file) {
+ // prepare AnalysisContext
+ AnalysisContext context = getAnalysisContext(file);
+ if (context == null) {
+ return null;
+ }
+ // get errors for the file
+ Source source = getSource(file);
+ return context.getErrors(source);
+ }
+
+ /**
* Returns resolved [CompilationUnit]s of the Dart file with the given [path].
*
* May be empty, but not `null`.
@@ -606,6 +634,51 @@
}
/**
+ * Returns a [Future] completing when [file] has been completely analyzed, in
+ * particular, all its errors have been computed.
+ *
+ * TODO(scheglov) this method should be improved.
+ *
+ * 1. The analysis context should be told to analyze this particular file ASAP.
+ *
+ * 2. We should complete the future as soon as the file is analyzed (not wait
+ * until the context is completely finished)
+ *
+ * 3. Since contexts can be created and deleted asynchronously as a result of
+ * changes to the filesystem, there's a danger that the future might never
+ * get completed. We should add a mechanism to make sure that we return an
+ * error for any getErrors request that is unsatisfiable due to its context
+ * being deleted.
+ */
+ Future onFileAnalysisComplete(String file) {
+ // prepare AnalysisContext
+ AnalysisContext context = getAnalysisContext(file);
+ if (context == null) {
+ return new Future.value();
+ }
+ // schedule context analysis
+ schedulePerformAnalysisOperation(context);
+ // associate with the context completer
+ Completer completer = contextAnalysisDoneCompleters[context];
+ if (completer == null) {
+ completer = new Completer();
+ contextAnalysisDoneCompleters[context] = completer;
+ }
+ return completer.future;
+ }
+
+ /**
+ * This method is called when analysis of the given [AnalysisContext] is
+ * done.
+ */
+ void sendContextAnalysisDoneNotifications(AnalysisContext context) {
+ Completer completer = contextAnalysisDoneCompleters[context];
+ if (completer != null) {
+ completer.complete();
+ }
+ }
+
+ /**
* Return the [CompilationUnit] of the Dart file with the given [path].
* Return `null` if the file is not a part of any context.
*/
diff --git a/pkg/analysis_server/lib/src/collections.dart b/pkg/analysis_server/lib/src/collections.dart
index 1c5fefc..f85bc97 100644
--- a/pkg/analysis_server/lib/src/collections.dart
+++ b/pkg/analysis_server/lib/src/collections.dart
@@ -16,15 +16,3 @@
* Returns the concatentation of the input iterables as a [List].
*/
List concatToList(Iterable<Iterable> iterables) => concat(iterables).toList();
-
-
-/**
- * Instances of the class [HasToJson] implement [toJson] method that returns
- * a JSON presentation.
- */
-abstract class HasToJson {
- /**
- * Returns a JSON presentation of the object.
- */
- Map<String, Object> toJson();
-}
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 9a16c80..4d71907 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -4,8 +4,8 @@
library computer.highlights;
-import 'package:analysis_server/src/collections.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 79215d3..960129f 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -6,8 +6,8 @@
import 'dart:collection';
-import 'package:analysis_server/src/collections.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_navigation.dart b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
index 768622b..98c2280 100644
--- a/pkg/analysis_server/lib/src/computer/computer_navigation.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
@@ -4,7 +4,7 @@
library computer.navigation;
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart b/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
index 86427f8..0a87298 100644
--- a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
@@ -6,9 +6,9 @@
import 'dart:collection';
-import 'package:analysis_server/src/collections.dart';
import 'package:analysis_server/src/computer/element.dart' as server;
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart
index 6414c32..4e58235 100644
--- a/pkg/analysis_server/lib/src/computer/computer_outline.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart
@@ -4,9 +4,9 @@
library computer.outline;
-import 'package:analysis_server/src/collections.dart';
import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart' as engine;
import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index a0cf035..429c778 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -4,9 +4,9 @@
library computer.overrides;
-import 'package:analysis_server/src/collections.dart';
import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart' as engine;
diff --git a/pkg/analysis_server/lib/src/computer/element.dart b/pkg/analysis_server/lib/src/computer/element.dart
index 5ceac10..fb9943a 100644
--- a/pkg/analysis_server/lib/src/computer/element.dart
+++ b/pkg/analysis_server/lib/src/computer/element.dart
@@ -4,7 +4,7 @@
library computer.element;
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analyzer/src/generated/element.dart' as engine;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
diff --git a/pkg/analysis_server/lib/src/computer/error.dart b/pkg/analysis_server/lib/src/computer/error.dart
new file mode 100644
index 0000000..5db2e2a
--- /dev/null
+++ b/pkg/analysis_server/lib/src/computer/error.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library computer.error;
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/source.dart' as engine;
+
+
+/**
+ * An indication of an error, warning, or hint that was produced by the
+ * analysis.
+ */
+class AnalysisError implements HasToJson {
+ final String severity;
+ final String type;
+ final Location location;
+ final String message;
+ final String correction;
+
+ AnalysisError(this.severity, this.type, this.location, this.message,
+ this.correction);
+
+ factory AnalysisError.fromEngine(engine.LineInfo lineInfo,
+ engine.AnalysisError error) {
+ engine.ErrorCode errorCode = error.errorCode;
+ // prepare location
+ Location location;
+ {
+ String file = error.source.fullName;
+ int offset = error.offset;
+ int length = error.length;
+ int startLine = -1;
+ int startColumn = -1;
+ if (lineInfo != null) {
+ engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset);
+ if (lineLocation != null) {
+ startLine = lineLocation.lineNumber;
+ startColumn = lineLocation.columnNumber;
+ }
+ }
+ location = new Location(file, offset, length, startLine, startColumn);
+ }
+ // done
+ String severity = errorCode.errorSeverity.toString();
+ String type = errorCode.type.toString();
+ String message = error.message;
+ String correction = errorCode.correction;
+ return new AnalysisError(severity, type, location, message, correction);
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ Map<String, Object> json = {
+ SEVERITY: severity,
+ TYPE: type,
+ LOCATION: location.toJson(),
+ MESSAGE: message
+ };
+ if (correction != null) {
+ json[CORRECTION] = correction;
+ }
+ return json;
+ }
+
+ @override
+ String toString() {
+ return 'AnalysisError(location=$location message=$message; '
+ 'severity=$severity; type=$type; correction=$correction';
+ }
+
+ static AnalysisError fromJson(Map<String, Object> json) {
+ return new AnalysisError(
+ json[SEVERITY],
+ json[TYPE],
+ new Location.fromJson(json[LOCATION]),
+ json[MESSAGE],
+ json[CORRECTION]);
+ }
+}
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index 735d384..0285b10 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library constants;
+library server.constants;
//
// Server methods
@@ -21,6 +21,7 @@
//
// Analysis methods
//
+const String ANALYSIS_GET_ERRORS = 'analysis.getErrors';
const String ANALYSIS_GET_HOVER = 'analysis.getHover';
const String ANALYSIS_SET_ANALYSIS_ROOTS = 'analysis.setAnalysisRoots';
const String ANALYSIS_SET_PRIORITY_FILES = 'analysis.setPriorityFiles';
@@ -75,69 +76,6 @@
const String EDIT_SET_REFACTORING_OPTIONS = 'edit.setRefactoringOptions';
//
-// Property names
-//
-const String ADDED = 'added';
-const String CHILDREN = 'children';
-const String COMPLETION = 'completion';
-const String CONTAINING_LIBRARY_NAME = 'containingLibraryName';
-const String CONTAINING_LIBRARY_PATH = 'containingLibraryPath';
-const String CONTENT = 'content';
-const String CORRECTION = 'correction';
-const String DART_DOC = 'dartdoc';
-const String DEFAULT = 'default';
-const String ELEMENT = 'element';
-const String ELEMENT_DESCRIPTION = 'elementDescription';
-const String ELEMENT_KIND = 'elementKind';
-const String EXCLUDED = 'excluded';
-const String ERRORS = 'errors';
-const String FILE = 'file';
-const String FILES = 'files';
-const String FIXES = 'fixes';
-const String FLAGS = 'flags';
-const String HOVERS = 'hovers';
-const String ID = 'id';
-const String INCLUDE_POTENTIAL = 'includePotential';
-const String INCLUDED = 'included';
-const String INTERFACE_ELEMENTS = 'interfaceElements';
-const String IS_ABSTRACT = 'isAbstract';
-const String IS_POTENTIAL = 'isPotential';
-const String IS_STATIC = 'isStatic';
-const String KIND = 'kind';
-const String LAST = 'last';
-const String LENGTH = 'length';
-const String LOCATION = 'location';
-const String MESSAGE = 'message';
-const String NAME = 'name';
-const String NEW_LENGTH = 'newLength';
-const String OCCURRENCES = 'occurrences';
-const String OFFSET = 'offset';
-const String OFFSETS = 'offsets';
-const String OLD_LENGTH = 'oldLength';
-const String OPTIONS = 'options';
-const String OUTLINE = 'outline';
-const String OVERRIDES = 'overrides';
-const String PARAMETER = 'parameter';
-const String PARAMETERS = 'parameters';
-const String PATH = 'path';
-const String PATTERN = 'pattern';
-const String PROPAGATED_TYPE = 'propagatedType';
-const String REFACTORINGS = 'refactorings';
-const String REGIONS = 'regions';
-const String REMOVED = 'removed';
-const String RETURN_TYPE = 'returnType';
-const String RESULTS = 'results';
-const String SEVERITY = 'severity';
-const String START_COLUMN = 'startColumn';
-const String START_LINE = 'startLine';
-const String STATIC_TYPE = 'staticType';
-const String SUBSCRIPTIONS = 'subscriptions';
-const String SUPER_CLASS_ELEMENT = 'superclassElement';
-const String TARGETS = 'targets';
-const String TYPE = 'type';
-const String VERSION = 'version';
-
-//
// Analysis option names
//
const String ANALYZE_ANGULAR = 'analyzeAngular'; // boolean
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index d26aead..ef166c8 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -7,11 +7,14 @@
import 'dart:collection';
import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/constants.dart';
-import 'package:analysis_server/src/protocol.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/ast.dart';
import 'package:analysis_server/src/computer/computer_hover.dart';
+import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/operation/operation_analysis.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
/**
* Instances of the class [AnalysisDomainHandler] implement a [RequestHandler]
@@ -29,9 +32,30 @@
AnalysisDomainHandler(this.server);
/**
+ * Implement the `analysis.getErrors` request.
+ */
+ Response getErrors(Request request) {
+ String file = request.getRequiredParameter(FILE).asString();
+ server.onFileAnalysisComplete(file).then((_) {
+ Response response = new Response(request.id);
+ AnalysisErrorInfo errorInfo = server.getErrors(file);
+ if (errorInfo == null) {
+ response.setResult(ERRORS, []);
+ } else {
+ response.setResult(ERRORS, errorInfo.errors.map((AnalysisError error) {
+ return errorToJson(errorInfo.lineInfo, error);
+ }).toList());
+ }
+ server.sendResponse(response);
+ });
+ // delay response
+ return Response.DELAYED_RESPONSE;
+ }
+
+ /**
* Implement the `analysis.getHover` request.
*/
- Response getAnalysisHover(Request request) {
+ Response getHover(Request request) {
// prepare parameters
String file = request.getRequiredParameter(FILE).asString();
int offset = request.getRequiredParameter(OFFSET).asInt();
@@ -39,7 +63,8 @@
List<Hover> hovers = <Hover>[];
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
for (CompilationUnit unit in units) {
- Hover hoverInformation = new DartUnitHoverComputer(unit, offset).compute();
+ Hover hoverInformation =
+ new DartUnitHoverComputer(unit, offset).compute();
if (hoverInformation != null) {
hovers.add(hoverInformation);
}
@@ -54,8 +79,10 @@
Response handleRequest(Request request) {
try {
String requestName = request.method;
- if (requestName == ANALYSIS_GET_HOVER) {
- return getAnalysisHover(request);
+ if (requestName == ANALYSIS_GET_ERRORS) {
+ return getErrors(request);
+ } else if (requestName == ANALYSIS_GET_HOVER) {
+ return getHover(request);
} else if (requestName == ANALYSIS_SET_ANALYSIS_ROOTS) {
return setAnalysisRoots(request);
} else if (requestName == ANALYSIS_SET_PRIORITY_FILES) {
@@ -112,11 +139,11 @@
Map<String, List<String>> subStringMap = subDatum.asStringListMap();
subMap = new HashMap<AnalysisService, Set<String>>();
subStringMap.forEach((String serviceName, List<String> paths) {
- AnalysisService service = Enum2.valueOf(AnalysisService.VALUES,
- serviceName);
+ AnalysisService service =
+ Enum2.valueOf(AnalysisService.VALUES, serviceName);
if (service == null) {
- throw new RequestFailure(new Response.unknownAnalysisService(request,
- serviceName));
+ throw new RequestFailure(
+ new Response.unknownAnalysisService(request, serviceName));
}
subMap[service] = new HashSet.from(paths);
});
@@ -133,7 +160,8 @@
RequestDatum filesDatum = request.getRequiredParameter(FILES);
filesDatum.forEachMap((file, changeDatum) {
var change = new ContentChange();
- change.content = changeDatum[CONTENT].isNull ? null :
+ change.content = changeDatum[CONTENT].isNull ?
+ null :
changeDatum[CONTENT].asString();
if (changeDatum.hasKey(OFFSET)) {
change.offset = changeDatum[OFFSET].asInt();
@@ -192,8 +220,8 @@
options.hint = optionValue;
});
} else {
- throw new RequestFailure(new Response.unknownOptionName(request,
- optionName));
+ throw new RequestFailure(
+ new Response.unknownOptionName(request, optionName));
}
});
server.updateOptions(updaters);
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index d3ab0d0..5196d67a 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -9,8 +9,10 @@
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/completion/completion_suggestion.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_services/search/search_engine.dart';
-import 'package:analysis_server/src/collections.dart';
+import 'package:analyzer/src/generated/element.dart';
/**
* Instances of the class [CompletionDomainHandler] implement a [RequestHandler]
@@ -90,28 +92,18 @@
var future = searchEngine.searchTopLevelDeclarations('');
return future.then((List<SearchMatch> matches) {
return matches.map((SearchMatch match) {
- return new CompletionSuggestion(match.element.displayName);
+ Element element = match.element;
+ String completion = element.displayName;
+ return new CompletionSuggestion(
+ CompletionSuggestionKind.fromElementKind(element.kind),
+ CompletionRelevance.DEFAULT,
+ completion,
+ completion.length,
+ 0,
+ element.isDeprecated,
+ false // isPotential
+ );
}).toList();
});
}
}
-
-/**
- * A single completion suggestion.
- */
-class CompletionSuggestion implements HasToJson {
- final String completion;
-
- CompletionSuggestion(this.completion);
-
- factory CompletionSuggestion.fromJson(Map<String, Object> json) {
- return new CompletionSuggestion(json[COMPLETION]);
- }
-
- @override
- Map<String, Object> toJson() {
- return {
- COMPLETION: completion
- };
- }
-}
diff --git a/pkg/analysis_server/lib/src/domain_server.dart b/pkg/analysis_server/lib/src/domain_server.dart
index 6c0126c..cfa7588 100644
--- a/pkg/analysis_server/lib/src/domain_server.dart
+++ b/pkg/analysis_server/lib/src/domain_server.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
/**
* Instances of the class [ServerDomainHandler] implement a [RequestHandler]
diff --git a/pkg/analysis_server/lib/src/domain_edit.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
similarity index 69%
rename from pkg/analysis_server/lib/src/domain_edit.dart
rename to pkg/analysis_server/lib/src/edit/edit_domain.dart
index fbca9d6..68a3dbc 100644
--- a/pkg/analysis_server/lib/src/domain_edit.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -2,11 +2,20 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library domain.edit;
+library edit.domain;
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/fix.dart';
+import 'package:analysis_services/search/search_engine.dart';
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/edit/fix.dart';
+
/**
* Instances of the class [EditDomainHandler] implement a [RequestHandler]
@@ -19,33 +28,15 @@
final AnalysisServer server;
/**
+ * The [SearchEngine] for this server.
+ */
+ SearchEngine searchEngine;
+
+ /**
* Initialize a newly created handler to handle requests for the given [server].
*/
- EditDomainHandler(this.server);
-
- @override
- Response handleRequest(Request request) {
- try {
- String requestName = request.method;
- if (requestName == EDIT_APPLY_REFACTORING) {
- return applyRefactoring(request);
- } else if (requestName == EDIT_CREATE_REFACTORING) {
- return createRefactoring(request);
- } else if (requestName == EDIT_DELETE_REFACTORING) {
- return deleteRefactoring(request);
- } else if (requestName == EDIT_GET_ASSISTS) {
- return getAssists(request);
- } else if (requestName == EDIT_GET_FIXES) {
- return getFixes(request);
- } else if (requestName == EDIT_GET_REFACTORINGS) {
- return getRefactorings(request);
- } else if (requestName == EDIT_SET_REFACTORING_OPTIONS) {
- return setRefactoringOptions(request);
- }
- } on RequestFailure catch (exception) {
- return exception.response;
- }
- return null;
+ EditDomainHandler(this.server) {
+ searchEngine = server.searchEngine;
}
Response applyRefactoring(Request request) {
@@ -96,19 +87,29 @@
}
Response getFixes(Request request) {
- // errors
- RequestDatum errorsDatum = request.getRequiredParameter(ERRORS);
- // TODO(paulberry): the API for edit.getFixes should be changed to so that
- // it doesn't use AnalysisError as an input type. This is necessary
- // because the JSON protocol for an AnalysisError doesn't contain the
- // errorCode, so we don't have enough information to reconstitute the error
- // object.
- // List<AnalysisError> errors = errorsDatum.asList((RequestDatum datum) {
- // return _createAnalysisError(request, datum);
- // });
-
- // TODO(brianwilkerson) implement
- return null;
+ String file = request.getRequiredParameter(FILE).asString();
+ int offset = request.getRequiredParameter(OFFSET).asInt();
+ List<ErrorFixes> errorFixesList = <ErrorFixes>[];
+ List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
+ for (CompilationUnit unit in units) {
+ engine.AnalysisErrorInfo errorInfo = server.getErrors(file);
+ if (errorInfo != null) {
+ for (engine.AnalysisError error in errorInfo.errors) {
+ List<Fix> fixes = computeFixes(searchEngine, file, unit, error);
+ if (fixes.isNotEmpty) {
+ AnalysisError serverError =
+ new AnalysisError.fromEngine(errorInfo.lineInfo, error);
+ ErrorFixes errorFixes = new ErrorFixes(serverError);
+ errorFixesList.add(errorFixes);
+ fixes.forEach((fix) {
+ return errorFixes.addFix(fix);
+ });
+ }
+ }
+ }
+ }
+ // respond
+ return new Response(request.id)..setResult(FIXES, errorFixesList);
}
Response getRefactorings(Request request) {
@@ -125,6 +126,31 @@
return null;
}
+ @override
+ Response handleRequest(Request request) {
+ try {
+ String requestName = request.method;
+ if (requestName == EDIT_APPLY_REFACTORING) {
+ return applyRefactoring(request);
+ } else if (requestName == EDIT_CREATE_REFACTORING) {
+ return createRefactoring(request);
+ } else if (requestName == EDIT_DELETE_REFACTORING) {
+ return deleteRefactoring(request);
+ } else if (requestName == EDIT_GET_ASSISTS) {
+ return getAssists(request);
+ } else if (requestName == EDIT_GET_FIXES) {
+ return getFixes(request);
+ } else if (requestName == EDIT_GET_REFACTORINGS) {
+ return getRefactorings(request);
+ } else if (requestName == EDIT_SET_REFACTORING_OPTIONS) {
+ return setRefactoringOptions(request);
+ }
+ } on RequestFailure catch (exception) {
+ return exception.response;
+ }
+ return null;
+ }
+
Response setRefactoringOptions(Request request) {
// id
RequestDatum idDatum = request.getRequiredParameter(ID);
diff --git a/pkg/analysis_server/lib/src/edit/fix.dart b/pkg/analysis_server/lib/src/edit/fix.dart
new file mode 100644
index 0000000..5e765d4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/fix.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library edit.fix;
+
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_services/correction/fix.dart';
+import 'package:analysis_services/json.dart';
+
+
+class ErrorFixes implements HasToJson {
+ final AnalysisError error;
+ final List<Change> fixes = <Change>[];
+
+ ErrorFixes(this.error);
+
+ void addFix(Fix fix) {
+ Change change = fix.change;
+ fixes.add(change);
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ return {
+ ERROR: error.toJson(),
+ FIXES: objectToJson(fixes)
+ };
+ }
+
+ @override
+ String toString() => 'ErrorFixes(error=$error, fixes=$fixes)';
+
+ static ErrorFixes fromJson(Map<String, Object> json) {
+ AnalysisError error = AnalysisError.fromJson(json[ERROR]);
+ ErrorFixes errorFixes = new ErrorFixes(error);
+ errorFixes.fixes.addAll((json[FIXES] as List).map((json) {
+ return Change.fromJson(json);
+ }));
+ return errorFixes;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 27e2e8e..c4ccdc2 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -13,6 +13,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/operation/operation.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_services/index/index.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -146,6 +147,7 @@
AnalysisResult result = context.performAnalysisTask();
List<ChangeNotice> notices = result.changeNotices;
if (notices == null) {
+ server.sendContextAnalysisDoneNotifications(context);
return;
}
// process results
diff --git a/pkg/analysis_server/lib/src/package_map_provider.dart b/pkg/analysis_server/lib/src/package_map_provider.dart
index bf031c4..a345bf2 100644
--- a/pkg/analysis_server/lib/src/package_map_provider.dart
+++ b/pkg/analysis_server/lib/src/package_map_provider.dart
@@ -8,9 +8,9 @@
import 'dart:convert';
import 'dart:io' as io;
-import 'package:analysis_server/src/analysis_server.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:path/path.dart';
/**
@@ -68,14 +68,19 @@
*/
final ResourceProvider resourceProvider;
- PubPackageMapProvider(this.resourceProvider);
+ /**
+ * Sdk that we use to find the pub executable.
+ */
+ final DirectoryBasedDartSdk sdk;
+
+ PubPackageMapProvider(this.resourceProvider, this.sdk);
@override
PackageMapInfo computePackageMap(Folder folder) {
// TODO(paulberry) make this asynchronous so that we can (a) do other
// analysis while it's in progress, and (b) time out if it takes too long
// to respond.
- String executable = SHARED_SDK.pubExecutable.getAbsolutePath();
+ String executable = sdk.pubExecutable.getAbsolutePath();
io.ProcessResult result;
try {
result = io.Process.runSync(
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index ee53942..fdfdba9 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -7,7 +7,7 @@
import 'dart:collection';
import 'dart:convert' show JsonDecoder;
-import 'package:analysis_server/src/collections.dart';
+import 'package:analysis_services/json.dart';
/**
* An abstract enumeration.
@@ -462,6 +462,12 @@
*/
class Response {
/**
+ * The [Response] instance that is returned when a real [Response] cannot
+ * be provided at the moment.
+ */
+ static final Response DELAYED_RESPONSE = new Response('DELAYED_RESPONSE');
+
+ /**
* The name of the JSON attribute containing the id of the request for which
* this is a response.
*/
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 1a7ff06..53572e1 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -12,6 +12,7 @@
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/element_references.dart';
import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_services/search/search_engine.dart';
import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/src/search/search_result.dart b/pkg/analysis_server/lib/src/search/search_result.dart
index cc366d0..8170e8f 100644
--- a/pkg/analysis_server/lib/src/search/search_result.dart
+++ b/pkg/analysis_server/lib/src/search/search_result.dart
@@ -4,9 +4,9 @@
library search.search_result;
-import 'package:analysis_server/src/collections.dart';
import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
import 'package:analysis_services/search/search_engine.dart';
import 'package:analyzer/src/generated/element.dart' as engine;
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index f5ea822..16fd27b 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -10,12 +10,13 @@
import 'package:analysis_server/src/channel.dart';
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/domain_completion.dart';
-import 'package:analysis_server/src/domain_edit.dart';
+import 'package:analysis_server/src/edit/edit_domain.dart';
import 'package:analysis_server/src/search/search_domain.dart';
import 'package:analysis_server/src/domain_server.dart';
import 'package:analysis_server/src/package_map_provider.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:path/path.dart' as pathos;
import 'package:analysis_services/index/index.dart';
import 'package:analysis_services/index/local_file_index.dart';
@@ -53,6 +54,10 @@
*/
AnalysisServer analysisServer;
+ final DirectoryBasedDartSdk defaultSdk;
+
+ SocketServer(this.defaultSdk);
+
/**
* Create an analysis server which will communicate with the client using the
* given serverChannel.
@@ -70,8 +75,9 @@
analysisServer = new AnalysisServer(
serverChannel,
resourceProvider,
- new PubPackageMapProvider(resourceProvider),
+ new PubPackageMapProvider(resourceProvider, defaultSdk),
_createIndex(),
+ defaultSdk,
rethrowExceptions: false);
_initializeHandlers(analysisServer);
}
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
new file mode 100644
index 0000000..2c261e5
--- /dev/null
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.analysis.get_errors;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart';
+
+import '../analysis_abstract.dart';
+
+
+main() {
+ group('notification.hover', () {
+ runReflectiveTests(GetErrorsTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class GetErrorsTest extends AbstractAnalysisTest {
+ Future<List<AnalysisError>> getErrors() {
+ return getErrorsForFile(testFile);
+ }
+
+ Future<List<AnalysisError>> getErrorsForFile(String file) {
+ return waitForTasksFinished().then((_) {
+ String requestId = 'test-getError';
+ // send the Request
+ Request request = new Request(requestId, ANALYSIS_GET_ERRORS);
+ request.setParameter(FILE, file);
+ server.handleRequest(request);
+ // wait for the Response
+ waitForResponse() {
+ for (Response response in serverChannel.responsesReceived) {
+ if (response.id == requestId) {
+ List errorsJsons = response.getResult(ERRORS);
+ return errorsJsons.map(AnalysisError.fromJson).toList();
+ }
+ }
+ return new Future(waitForResponse);
+ }
+ return new Future(waitForResponse);
+ });
+ }
+
+ @override
+ void setUp() {
+ super.setUp();
+ server.handlers = [new AnalysisDomainHandler(server),];
+ createProject();
+ }
+
+ test_hasErrors() {
+ addTestFile('''
+main() {
+ print(42)
+}
+''');
+ return getErrors().then((List<AnalysisError> errors) {
+ expect(errors, hasLength(1));
+ {
+ AnalysisError error = errors[0];
+ expect(error.severity, 'ERROR');
+ expect(error.type, 'SYNTACTIC_ERROR');
+ expect(error.location.file, testFile);
+ expect(error.location.startLine, 2);
+ }
+ });
+ }
+
+ test_noErrors() {
+ addTestFile('''
+main() {
+ print(42);
+}
+''');
+ return getErrors().then((List<AnalysisError> errors) {
+ expect(errors, isEmpty);
+ });
+ }
+
+ test_fileWithoutContext() {
+ String file = '/outside.dart';
+ addFile(file, '''
+main() {
+ print(42);
+}
+''');
+ return getErrorsForFile(file).then((List<AnalysisError> errors) {
+ expect(errors, isEmpty);
+ });
+ }
+}
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
new file mode 100644
index 0000000..92917cb
--- /dev/null
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library test.analysis;
+
+import 'package:unittest/unittest.dart';
+
+import 'get_errors_test.dart' as get_errors_test;
+
+/**
+ * Utility for manually running all tests.
+ */
+main() {
+ groupSep = ' | ';
+ group('search', () {
+ get_errors_test.main();
+ });
+}
\ No newline at end of file
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index a6e006c..0cf7558 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_services/index/index.dart';
import 'package:analysis_testing/mock_sdk.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -227,8 +228,8 @@
packageMapProvider = new MockPackageMapProvider();
Index index = createIndex();
server = new AnalysisServer(
- serverChannel, resourceProvider, packageMapProvider, index);
- server.defaultSdk = new MockSdk();
+ serverChannel, resourceProvider, packageMapProvider, index,
+ new MockSdk());
handler = new AnalysisDomainHandler(server);
// listen for notifications
Stream<Notification> notificationStream = serverChannel.notificationController.stream;
@@ -260,21 +261,3 @@
return code as String;
}
}
-
-
-class AnalysisError {
- final String file;
- final String errorCode;
- final int offset;
- final int length;
- final String message;
- final String correction;
- AnalysisError(this.file, this.errorCode, this.offset, this.length,
- this.message, this.correction);
-
- @override
- String toString() {
- return 'NotificationError(file=$file; errorCode=$errorCode; '
- 'offset=$offset; length=$length; message=$message)';
- }
-}
diff --git a/pkg/analysis_server/test/analysis_hover_test.dart b/pkg/analysis_server/test/analysis_hover_test.dart
index 6b09ce1..1b53eb2 100644
--- a/pkg/analysis_server/test/analysis_hover_test.dart
+++ b/pkg/analysis_server/test/analysis_hover_test.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/computer/computer_hover.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/analysis_notification_highlights_test.dart b/pkg/analysis_server/test/analysis_notification_highlights_test.dart
index 496b941..0d2a202 100644
--- a/pkg/analysis_server/test/analysis_notification_highlights_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_highlights_test.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/computer/computer_highlights.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
@@ -32,13 +33,15 @@
void assertHasRawRegion(HighlightType type, int offset, int length) {
for (HighlightRegion region in regions) {
- if (region.offset == offset && region.length == length && region.type ==
- type) {
+ if (region.offset == offset &&
+ region.length == length &&
+ region.type == type) {
return;
}
}
- fail('Expected to find (offset=$offset; length=$length; type=$type) in\n'
- '${regions.join('\n')}');
+ fail(
+ 'Expected to find (offset=$offset; length=$length; type=$type) in\n'
+ '${regions.join('\n')}');
}
void assertHasRegion(HighlightType type, String search, [int length = -1]) {
@@ -49,11 +52,12 @@
void assertNoRawRegion(HighlightType type, int offset, int length) {
for (HighlightRegion region in regions) {
- if (region.offset == offset && region.length == length && region.type ==
- type) {
+ if (region.offset == offset &&
+ region.length == length &&
+ region.type == type) {
fail(
'Not expected to find (offset=$offset; length=$length; type=$type) in\n'
- '${regions.join('\n')}');
+ '${regions.join('\n')}');
}
}
}
@@ -74,9 +78,9 @@
length++;
continue;
}
- if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) || c >=
- 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) || c >= '0'.codeUnitAt(0) && c <=
- '9'.codeUnitAt(0))) {
+ if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
+ c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
+ c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
break;
}
length++;
@@ -85,11 +89,9 @@
return length;
}
- Future prepareHighlights(then()) {
+ Future prepareHighlights() {
addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
- return waitForTasksFinished().then((_) {
- then();
- });
+ return waitForTasksFinished();
}
void processNotification(Notification notification) {
@@ -97,8 +99,8 @@
String file = notification.getParameter(FILE);
if (file == testFile) {
regions = [];
- List<Map<String, Object>> regionsJson = notification.getParameter(
- REGIONS);
+ List<Map<String, Object>> regionsJson =
+ notification.getParameter(REGIONS);
for (Map<String, Object> regionJson in regionsJson) {
regions.add(new HighlightRegion.fromJson(regionJson));
}
@@ -119,7 +121,7 @@
}
@AAA(1, 2, 3) main() {}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.ANNOTATION, '@AAA(', '@AAA('.length);
assertHasRegion(HighlightType.ANNOTATION, ') main', ')'.length);
});
@@ -130,7 +132,7 @@
const AAA = 42;
@AAA main() {}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.ANNOTATION, '@AAA');
});
}
@@ -141,7 +143,7 @@
main() {
var abstract = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'abstract class');
assertNoRegion(HighlightType.BUILT_IN, 'abstract = 42');
});
@@ -154,7 +156,7 @@
p as int;
var as = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'as math');
assertHasRegion(HighlightType.BUILT_IN, 'as int');
assertNoRegion(HighlightType.BUILT_IN, 'as = 42');
@@ -167,7 +169,7 @@
main() {
var deferred = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'deferred as math');
assertNoRegion(HighlightType.BUILT_IN, 'deferred = 42');
});
@@ -179,7 +181,7 @@
main() {
var export = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'export "dart:');
assertNoRegion(HighlightType.BUILT_IN, 'export = 42');
});
@@ -194,7 +196,7 @@
external main() {
var external = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'external A()');
assertHasRegion(HighlightType.BUILT_IN, 'external aaa()');
assertHasRegion(HighlightType.BUILT_IN, 'external main()');
@@ -210,7 +212,7 @@
main() {
var factory = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'factory A()');
assertNoRegion(HighlightType.BUILT_IN, 'factory = 42');
});
@@ -225,7 +227,7 @@
main() {
var get = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'get aaa =>');
assertHasRegion(HighlightType.BUILT_IN, 'get bbb =>');
assertNoRegion(HighlightType.BUILT_IN, 'get = 42');
@@ -238,7 +240,7 @@
main() {
var hide = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'hide Foo');
assertNoRegion(HighlightType.BUILT_IN, 'hide = 42');
});
@@ -251,7 +253,7 @@
main() {
var implements = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'implements A {}');
assertNoRegion(HighlightType.BUILT_IN, 'implements = 42');
});
@@ -263,7 +265,7 @@
main() {
var import = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'import "');
assertNoRegion(HighlightType.BUILT_IN, 'import = 42');
});
@@ -275,7 +277,7 @@
main() {
var library = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'library lib;');
assertNoRegion(HighlightType.BUILT_IN, 'library = 42');
});
@@ -290,7 +292,7 @@
main() {
var native = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'native "A_');
assertHasRegion(HighlightType.BUILT_IN, 'native "bbb_');
assertNoRegion(HighlightType.BUILT_IN, 'native = 42');
@@ -305,7 +307,7 @@
}
var on = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'on int');
assertNoRegion(HighlightType.BUILT_IN, 'on = 42');
});
@@ -319,7 +321,7 @@
main() {
var operator = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'operator +(');
assertNoRegion(HighlightType.BUILT_IN, 'operator = 42');
});
@@ -332,7 +334,7 @@
var part = 42;
}''');
addFile('/project/bin/my_part.dart', 'part of lib;');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'part "my_');
assertNoRegion(HighlightType.BUILT_IN, 'part = 42');
});
@@ -349,7 +351,7 @@
library lib;
part 'test.dart';
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'part of', 'part of'.length);
assertNoRegion(HighlightType.BUILT_IN, 'part = 1');
assertNoRegion(HighlightType.BUILT_IN, 'of = 2');
@@ -365,7 +367,7 @@
main() {
var set = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'set aaa(');
assertHasRegion(HighlightType.BUILT_IN, 'set bbb(');
assertNoRegion(HighlightType.BUILT_IN, 'set = 42');
@@ -378,7 +380,7 @@
main() {
var show = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'show Foo');
assertNoRegion(HighlightType.BUILT_IN, 'show = 42');
});
@@ -393,7 +395,7 @@
main() {
var static = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'static aaa;');
assertHasRegion(HighlightType.BUILT_IN, 'static bbb()');
assertNoRegion(HighlightType.BUILT_IN, 'static = 42');
@@ -406,7 +408,7 @@
main() {
var typedef = 42;
}''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.BUILT_IN, 'typedef A();');
assertNoRegion(HighlightType.BUILT_IN, 'typedef = 42');
});
@@ -417,7 +419,7 @@
class AAA {}
AAA aaa;
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.CLASS, 'AAA {}');
assertHasRegion(HighlightType.CLASS, 'AAA aaa');
});
@@ -427,7 +429,7 @@
addTestFile('''
dynamic f() {}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertNoRegion(HighlightType.CLASS, 'dynamic f()');
});
}
@@ -436,7 +438,7 @@
addTestFile('''
void f() {}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertNoRegion(HighlightType.CLASS, 'void f()');
});
}
@@ -455,7 +457,7 @@
/* block comment */
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.COMMENT_DOCUMENTATION, '/**', 32);
assertHasRegion(HighlightType.COMMENT_END_OF_LINE, '//', 22);
assertHasRegion(HighlightType.COMMENT_BLOCK, '/* b', 19);
@@ -473,7 +475,7 @@
new AAA.name(42);
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.CONSTRUCTOR, 'name(p)');
assertHasRegion(HighlightType.CONSTRUCTOR, 'name(42)');
assertNoRegion(HighlightType.CONSTRUCTOR, 'AAA() {}');
@@ -491,7 +493,7 @@
var v3 = v2;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.DYNAMIC_TYPE, 'p)');
assertHasRegion(HighlightType.DYNAMIC_TYPE, 'v1 =');
assertNoRegion(HighlightType.DYNAMIC_TYPE, 'v2;');
@@ -511,7 +513,7 @@
a.bbb = 5;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.FIELD, 'aaa = 1');
assertHasRegion(HighlightType.FIELD, 'bbb = 2');
assertHasRegion(HighlightType.FIELD, 'bbb = 3');
@@ -533,7 +535,7 @@
A.ccc = 3;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.FIELD_STATIC, 'aaa = 1');
assertHasRegion(HighlightType.FIELD_STATIC, 'aaa = 2');
assertHasRegion(HighlightType.FIELD_STATIC, 'bbb;');
@@ -548,7 +550,7 @@
fff(42);
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.FUNCTION_DECLARATION, 'fff(p) {}');
assertHasRegion(HighlightType.FUNCTION, 'fff(42)');
});
@@ -560,7 +562,7 @@
main(FFF fff) {
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
assertHasRegion(HighlightType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
});
@@ -577,7 +579,7 @@
a.bbb;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.GETTER_DECLARATION, 'aaa => null');
assertHasRegion(HighlightType.GETTER_DECLARATION, 'bbb => null');
assertHasRegion(HighlightType.FIELD_STATIC, 'aaa;');
@@ -593,7 +595,7 @@
CCC ccc;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.IDENTIFIER_DEFAULT, 'aaa = 42');
assertHasRegion(HighlightType.IDENTIFIER_DEFAULT, 'bbb(84)');
assertHasRegion(HighlightType.IDENTIFIER_DEFAULT, 'CCC ccc');
@@ -607,7 +609,7 @@
ma.max(1, 2);
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.IMPORT_PREFIX, 'ma;');
assertHasRegion(HighlightType.IMPORT_PREFIX, 'ma.max');
});
@@ -618,35 +620,35 @@
void main() {
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.KEYWORD, 'void main()');
});
}
test_LITERAL_BOOLEAN() {
addTestFile('var V = true;');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.LITERAL_BOOLEAN, 'true;');
});
}
test_LITERAL_DOUBLE() {
addTestFile('var V = 4.2;');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
});
}
test_LITERAL_INTEGER() {
addTestFile('var V = 42;');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.LITERAL_INTEGER, '42;');
});
}
test_LITERAL_STRING() {
addTestFile('var V = "abc";');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.LITERAL_STRING, '"abc";', '"abc"'.length);
});
}
@@ -659,7 +661,7 @@
vvv = 1;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
assertHasRegion(HighlightType.LOCAL_VARIABLE, 'vvv;');
assertHasRegion(HighlightType.LOCAL_VARIABLE, 'vvv = 1;');
@@ -679,7 +681,7 @@
A.bbb;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.METHOD_DECLARATION, 'aaa() {}');
assertHasRegion(HighlightType.METHOD_DECLARATION_STATIC, 'bbb() {}');
assertHasRegion(HighlightType.METHOD, 'aaa();');
@@ -697,7 +699,7 @@
}
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.METHOD, 'add(null)');
});
}
@@ -709,7 +711,7 @@
p = 42;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.PARAMETER, 'p) {');
assertHasRegion(HighlightType.PARAMETER, 'p;');
assertHasRegion(HighlightType.PARAMETER, 'p = 42');
@@ -727,7 +729,7 @@
a.bbb = 2;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.SETTER_DECLARATION, 'aaa(x)');
assertHasRegion(HighlightType.SETTER_DECLARATION, 'bbb(x)');
assertHasRegion(HighlightType.FIELD_STATIC, 'aaa = 1');
@@ -743,7 +745,7 @@
VVV = 1;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.TOP_LEVEL_VARIABLE, 'VVV = 0');
assertHasRegion(HighlightType.FIELD_STATIC, 'VVV);');
assertHasRegion(HighlightType.FIELD_STATIC, 'VVV = 1');
@@ -756,7 +758,7 @@
dynamic = 42;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.TYPE_NAME_DYNAMIC, 'dynamic main()');
assertNoRegion(HighlightType.IDENTIFIER_DEFAULT, 'dynamic main()');
assertNoRegion(HighlightType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
@@ -770,7 +772,7 @@
T mmm(T p) => null;
}
''');
- return prepareHighlights(() {
+ return prepareHighlights().then((_) {
assertHasRegion(HighlightType.TYPE_PARAMETER, 'T> {');
assertHasRegion(HighlightType.TYPE_PARAMETER, 'T fff;');
assertHasRegion(HighlightType.TYPE_PARAMETER, 'T mmm(');
@@ -787,8 +789,9 @@
}
void test_valueOf() {
- expect(HighlightType.CLASS, HighlightType.valueOf(
- HighlightType.CLASS.name));
+ expect(
+ HighlightType.CLASS,
+ HighlightType.valueOf(HighlightType.CLASS.name));
}
void test_valueOf_unknown() {
diff --git a/pkg/analysis_server/test/analysis_notification_navigation_test.dart b/pkg/analysis_server/test/analysis_notification_navigation_test.dart
index 188cb39c..df89aea 100644
--- a/pkg/analysis_server/test/analysis_notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_navigation_test.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/computer/element.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
@@ -37,15 +38,16 @@
void assertHasFileTarget(String file, int offset, int length) {
for (Element target in testTargets) {
Location location = target.location;
- if (location.file == file && location.offset == offset && location.length ==
- length) {
+ if (location.file == file &&
+ location.offset == offset &&
+ location.length == length) {
testTarget = target;
return;
}
}
fail(
'Expected to find target (file=$file; offset=$offset; length=$length) in\n'
- '${testRegion} in\n' '${regions.join('\n')}');
+ '${testRegion} in\n' '${regions.join('\n')}');
}
void assertHasOperatorRegion(String regionSearch, int regionLength,
@@ -137,11 +139,12 @@
*/
void findRegion(int offset, int length, [bool exists]) {
for (NavigationRegion region in regions) {
- if (region.offset == offset && (length == -1 || region.length == length))
- {
+ if (region.offset == offset &&
+ (length == -1 || region.length == length)) {
if (exists == false) {
- fail('Not expected to find (offset=$offset; length=$length) in\n'
- '${regions.join('\n')}');
+ fail(
+ 'Not expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
}
testRegion = region;
testTargets = region.targets;
@@ -149,16 +152,15 @@
}
}
if (exists == true) {
- fail('Expected to find (offset=$offset; length=$length) in\n'
- '${regions.join('\n')}');
+ fail(
+ 'Expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
}
}
- Future prepareNavigation(then()) {
+ Future prepareNavigation() {
addAnalysisSubscription(AnalysisService.NAVIGATION, testFile);
- return waitForTasksFinished().then((_) {
- then();
- });
+ return waitForTasksFinished();
}
void processNotification(Notification notification) {
@@ -166,8 +168,8 @@
String file = notification.getParameter(FILE);
if (file == testFile) {
regions = <NavigationRegion>[];
- List<Map<String, Object>> regionsJson = notification.getParameter(
- REGIONS);
+ List<Map<String, Object>> regionsJson =
+ notification.getParameter(REGIONS);
for (Map<String, Object> regionJson in regionsJson) {
var regionOffset = regionJson[OFFSET];
var regionLength = regionJson[LENGTH];
@@ -175,8 +177,8 @@
for (Map<String, Object> targetJson in regionJson[TARGETS]) {
targets.add(new Element.fromJson(targetJson));
}
- var region = new NavigationRegion(regionOffset, regionLength,
- targets);
+ var region =
+ new NavigationRegion(regionOffset, regionLength, targets);
regions.add(region);
}
}
@@ -195,7 +197,7 @@
AAA aaa;
''');
return waitForTasksFinished().then((_) {
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionTarget('AAA aaa;', 'AAA {}');
});
});
@@ -208,7 +210,7 @@
}
class BBB {}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
// has region for complete "A.named"
assertHasRegionString('A.named');
assertHasTarget('named(BBB');
@@ -227,7 +229,7 @@
}
class BBB {}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
// has region for complete "A.named"
assertHasRegion("A(BBB");
assertHasTarget("A(BBB", 0);
@@ -243,7 +245,7 @@
AAA(this.fff);
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionTarget('fff);', 'fff = 123');
});
}
@@ -256,7 +258,7 @@
print(aaa);
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionTarget('AAA aaa', 'AAA {}');
assertHasRegionTarget('aaa);', 'aaa = null');
assertHasRegionTarget('main() {', 'main() {');
@@ -269,7 +271,7 @@
print(vvv);
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertNoRegionString('vvv');
});
}
@@ -282,7 +284,7 @@
new A();
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionString('new A');
assertHasTarget('A {');
});
@@ -297,7 +299,7 @@
new A.named();
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionString('new A.named');
assertHasTarget('named() {}');
});
@@ -312,7 +314,7 @@
new A();
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionString('new A');
assertHasTarget("A() {}", 0);
});
@@ -342,7 +344,7 @@
a /= 6;
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasOperatorRegion('- 1', 1, '-(other) => null', 1);
assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1);
assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1);
@@ -373,7 +375,7 @@
b[2] += 2;
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasOperatorRegion('] // []', 1, '[](index)', 2);
assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3);
assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3);
@@ -385,7 +387,7 @@
var libCode = 'library lib; part "test.dart";';
var libFile = addFile('$projectPath/bin/lib.dart', libCode);
addTestFile('part of lib;');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionString('part of lib');
assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
});
@@ -395,7 +397,7 @@
var libCode = 'library lib;';
var libFile = addFile('$projectPath/bin/lib.dart', libCode);
addTestFile('export "lib.dart";');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionString('export "lib.dart"');
assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
});
@@ -403,7 +405,7 @@
test_string_export_unresolvedUri() {
addTestFile('export "no.dart";');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertNoRegionString('export "no.dart"');
});
}
@@ -412,7 +414,7 @@
var libCode = 'library lib;';
var libFile = addFile('$projectPath/bin/lib.dart', libCode);
addTestFile('import "lib.dart";');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionString('import "lib.dart"');
assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
});
@@ -420,14 +422,14 @@
test_string_import_noUri() {
addTestFile('import ;');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertNoRegionAt('import ;');
});
}
test_string_import_unresolvedUri() {
addTestFile('import "no.dart";');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertNoRegionString('import "no.dart"');
});
}
@@ -439,7 +441,7 @@
library lib;
part "test_unit.dart";
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionString('part "test_unit.dart"');
assertHasFileTarget(unitFile, 0, 0);
});
@@ -450,7 +452,7 @@
library lib;
part "test_unit.dart";
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertNoRegionString('part "test_unit.dart"');
});
}
@@ -462,7 +464,7 @@
AAA aaa = null;
}
''');
- return prepareNavigation(() {
+ return prepareNavigation().then((_) {
assertHasRegionTarget('AAA aaa', 'AAA {}');
expect(testTarget.kind, ElementKind.CLASS);
expect(testTarget.name, 'AAA');
diff --git a/pkg/analysis_server/test/analysis_notification_occurrences_test.dart b/pkg/analysis_server/test/analysis_notification_occurrences_test.dart
index 8f65214..46dd37f 100644
--- a/pkg/analysis_server/test/analysis_notification_occurrences_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_occurrences_test.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/computer/element.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
@@ -82,11 +83,9 @@
}
}
- Future prepareOccurrences(then()) {
+ Future prepareOccurrences() {
addAnalysisSubscription(AnalysisService.OCCURRENCES, testFile);
- return waitForTasksFinished().then((_) {
- then();
- });
+ return waitForTasksFinished();
}
void processNotification(Notification notification) {
@@ -117,7 +116,7 @@
}
''');
return waitForTasksFinished().then((_) {
- return prepareOccurrences(() {
+ return prepareOccurrences().then((_) {
assertHasRegion('vvv =');
expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
expect(testOccurences.element.name, 'vvv');
@@ -136,7 +135,7 @@
}
int VVV = 4;
''');
- return prepareOccurrences(() {
+ return prepareOccurrences().then((_) {
assertHasRegion('int a');
expect(testOccurences.element.kind, ElementKind.CLASS);
expect(testOccurences.element.name, 'int');
@@ -158,7 +157,7 @@
}
}
''');
- return prepareOccurrences(() {
+ return prepareOccurrences().then((_) {
assertHasRegion('fff;');
expect(testOccurences.element.kind, ElementKind.FIELD);
assertHasOffset('fff); // constructor');
@@ -175,7 +174,7 @@
print(vvv);
}
''');
- return prepareOccurrences(() {
+ return prepareOccurrences().then((_) {
assertHasRegion('vvv =');
expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
expect(testOccurences.element.name, 'vvv');
@@ -197,7 +196,7 @@
b.fff = 2;
}
''');
- return prepareOccurrences(() {
+ return prepareOccurrences().then((_) {
assertHasRegion('fff;');
expect(testOccurences.element.kind, ElementKind.FIELD);
assertHasOffset('fff = 1;');
@@ -217,7 +216,7 @@
b.mmm(); // b
}
''');
- return prepareOccurrences(() {
+ return prepareOccurrences().then((_) {
assertHasRegion('mmm() {}');
expect(testOccurences.element.kind, ElementKind.METHOD);
assertHasOffset('mmm(); // a');
@@ -233,7 +232,7 @@
print(VVV);
}
''');
- return prepareOccurrences(() {
+ return prepareOccurrences().then((_) {
assertHasRegion('VVV = 1;');
expect(testOccurences.element.kind, ElementKind.TOP_LEVEL_VARIABLE);
assertHasOffset('VVV = 2;');
diff --git a/pkg/analysis_server/test/analysis_notification_outline_test.dart b/pkg/analysis_server/test/analysis_notification_outline_test.dart
index caa3f12..f8909d4 100644
--- a/pkg/analysis_server/test/analysis_notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_outline_test.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/computer/element.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
@@ -28,11 +29,9 @@
class _AnalysisNotificationOutlineTest extends AbstractAnalysisTest {
Outline outline;
- Future prepareOutline(then()) {
+ Future prepareOutline() {
addAnalysisSubscription(AnalysisService.OUTLINE, testFile);
- return waitForTasksFinished().then((_) {
- then();
- });
+ return waitForTasksFinished();
}
void processNotification(Notification notification) {
@@ -60,7 +59,7 @@
''');
return waitForTasksFinished().then((_) {
expect(outline, isNull);
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> outlines = unitOutline.children;
expect(outlines, hasLength(2));
@@ -85,7 +84,7 @@
B(int p);
}");
''');
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> topOutlines = unitOutline.children;
expect(topOutlines, hasLength(2));
@@ -281,7 +280,7 @@
}
}
''');
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> topOutlines = unitOutline.children;
expect(topOutlines, hasLength(2));
@@ -429,7 +428,7 @@
int methodB() {} // endB
}
''');
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> outlines = unitOutline.children[0].children;
expect(outlines, hasLength(2));
@@ -469,7 +468,7 @@
int fieldD; // marker2
}
''');
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> outlines = unitOutline.children[0].children;
expect(outlines, hasLength(4));
@@ -535,7 +534,7 @@
class B {
} // endB
''');
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> topOutlines = unitOutline.children;
expect(topOutlines, hasLength(2));
@@ -573,7 +572,7 @@
int fieldA, fieldB, fieldC; // marker
int fieldD; // marker2
''');
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> outlines = unitOutline.children;
expect(outlines, hasLength(4));
@@ -644,7 +643,7 @@
String get propA => null;
set propB(int v) {}
''');
- return prepareOutline(() {
+ return prepareOutline().then((_) {
Outline unitOutline = outline;
List<Outline> topOutlines = unitOutline.children;
expect(topOutlines, hasLength(9));
diff --git a/pkg/analysis_server/test/analysis_notification_overrides_test.dart b/pkg/analysis_server/test/analysis_notification_overrides_test.dart
index 34ca127..34888f0 100644
--- a/pkg/analysis_server/test/analysis_notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_overrides_test.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/computer/element.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
@@ -40,8 +41,9 @@
return;
}
}
- fail('Expect to find an overridden interface elements at $offset in '
- '${override.interfaceElements.join('\n')}');
+ fail(
+ 'Expect to find an overridden interface elements at $offset in '
+ '${override.interfaceElements.join('\n')}');
}
/**
@@ -94,24 +96,24 @@
for (Override override in overridesList) {
if (override.offset == offset && override.length == length) {
if (exists == false) {
- fail('Not expected to find (offset=$offset; length=$length) in\n'
- '${overridesList.join('\n')}');
+ fail(
+ 'Not expected to find (offset=$offset; length=$length) in\n'
+ '${overridesList.join('\n')}');
}
this.override = override;
return;
}
}
if (exists == true) {
- fail('Expected to find (offset=$offset; length=$length) in\n'
- '${overridesList.join('\n')}');
+ fail(
+ 'Expected to find (offset=$offset; length=$length) in\n'
+ '${overridesList.join('\n')}');
}
}
- Future prepareOverrides(then()) {
+ Future prepareOverrides() {
addAnalysisSubscription(AnalysisService.OVERRIDES, testFile);
- return waitForTasksFinished().then((_) {
- then();
- });
+ return waitForTasksFinished();
}
void processNotification(Notification notification) {
@@ -119,8 +121,8 @@
String file = notification.getParameter(FILE);
if (file == testFile) {
overridesList = <Override>[];
- List<Map<String, Object>> jsonList = notification.getParameter(
- OVERRIDES);
+ List<Map<String, Object>> jsonList =
+ notification.getParameter(OVERRIDES);
for (Map<String, Object> json in jsonList) {
overridesList.add(new Override.fromJson(json));
}
@@ -143,7 +145,7 @@
}
''');
return waitForTasksFinished().then((_) {
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('m() {} // in B');
assertNoSuperElement();
assertHasInterfaceElement('m() {} // in A');
@@ -163,7 +165,7 @@
m() {} // in A
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('m() {} // in A');
assertNoSuperElement();
assertHasInterfaceElement('m() {} // in IA');
@@ -180,7 +182,7 @@
m() {} // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('m() {} // in B');
assertNoSuperElement();
assertHasInterfaceElement('m() {} // in A');
@@ -198,7 +200,7 @@
m() {} // in C
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('m() {} // in C');
assertNoSuperElement();
assertHasInterfaceElement('m() {} // in A');
@@ -214,7 +216,7 @@
int fff; // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('fff; // in B');
assertHasSuperElement('fff; // in A');
assertNoInterfaceElements();
@@ -230,7 +232,7 @@
get fff => 0; // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('fff => 0; // in B');
assertHasSuperElement('fff; // in A');
assertNoInterfaceElements();
@@ -246,7 +248,7 @@
fff() {} // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('fff() {} // in B');
assertHasSuperElement('fff; // in A');
assertNoInterfaceElements();
@@ -262,7 +264,7 @@
set fff(x) {} // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('fff(x) {} // in B');
assertHasSuperElement('fff; // in A');
assertNoInterfaceElements();
@@ -279,7 +281,7 @@
int fff; // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('fff; // in B');
assertHasSuperElement('fff => 0; // in A');
assertNoInterfaceElements();
@@ -295,7 +297,7 @@
get fff => 0; // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('fff => 0; // in B');
assertHasSuperElement('fff => 0; // in A');
assertNoInterfaceElements();
@@ -311,7 +313,7 @@
m() {} // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('m() {} // in B');
assertHasSuperElement('m() {} // in A');
assertNoInterfaceElements();
@@ -329,7 +331,7 @@
m() {} // in C
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('m() {} // in C');
assertHasSuperElement('m() {} // in A');
assertNoInterfaceElements();
@@ -345,7 +347,7 @@
set fff(x) {} // in B
}
''');
- return prepareOverrides(() {
+ return prepareOverrides().then((_) {
assertHasOverride('fff(x) {} // in B');
assertHasSuperElement('fff(x) {} // in A');
assertNoInterfaceElements();
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 57a2e1d..2df3b59 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/domain_server.dart';
import 'package:analysis_server/src/operation/operation.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_testing/mock_sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -110,7 +111,7 @@
AnalysisServerTestHelper({bool rethrowExceptions: true}) {
channel = new MockServerChannel();
server = new AnalysisServer(channel, PhysicalResourceProvider.INSTANCE,
- new MockPackageMapProvider(), null,
+ new MockPackageMapProvider(), null, new MockSdk(),
rethrowExceptions: rethrowExceptions);
}
}
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index f43b9d5..a78605c 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -9,6 +9,8 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_completion.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/completion/completion_suggestion.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_services/index/index.dart' show Index;
import 'package:analysis_services/index/local_memory_index.dart';
import 'package:analysis_testing/reflective_tests.dart';
@@ -39,11 +41,19 @@
+ content.substring(completionOffset + 1));
}
- void assertHasResult(String completion) {
+ void assertHasResult(CompletionSuggestionKind kind,
+ CompletionRelevance relevance, String completion,
+ bool isDeprecated, bool isPotential) {
var cs = suggestions.firstWhere((cs) => cs.completion == completion, orElse: () {
var completions = suggestions.map((s) => s.completion).toList();
fail('expected "$completion" but found\n $completions');
});
+ expect(cs.kind, equals(kind));
+ expect(cs.relevance, equals(relevance));
+ expect(cs.selectionOffset, equals(completion.length));
+ expect(cs.selectionLength, equals(0));
+ expect(cs.isDeprecated, equals(isDeprecated));
+ expect(cs.isPotential, equals(isPotential));
}
void assertValidId(String id) {
@@ -104,8 +114,10 @@
main() {^}
''');
return getSuggestions().then((_) {
- assertHasResult('Object');
- assertHasResult('HtmlElement');
+ assertHasResult(CompletionSuggestionKind.CLASS,
+ CompletionRelevance.DEFAULT, 'Object', false, false);
+ assertHasResult(CompletionSuggestionKind.CLASS,
+ CompletionRelevance.DEFAULT, 'HtmlElement', false, false);
});
}
}
diff --git a/pkg/analysis_server/test/computer/element_test.dart b/pkg/analysis_server/test/computer/element_test.dart
index 0ca2bfe..9dfb2c5 100644
--- a/pkg/analysis_server/test/computer/element_test.dart
+++ b/pkg/analysis_server/test/computer/element_test.dart
@@ -5,7 +5,7 @@
library test.computer.element;
import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/abstract_context.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/ast.dart';
diff --git a/pkg/analysis_server/test/computer/error_test.dart b/pkg/analysis_server/test/computer/error_test.dart
new file mode 100644
index 0000000..10848ba
--- /dev/null
+++ b/pkg/analysis_server/test/computer/error_test.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.computer.error;
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/element.dart' as engine;
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
+import 'package:unittest/unittest.dart';
+
+
+
+main() {
+ groupSep = ' | ';
+ group('AnalysisError', () {
+ runReflectiveTests(AnalysisErrorTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class AnalysisErrorTest extends AbstractSingleUnitTest {
+ void test_fromEngine() {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main() {
+ print(42)
+}
+''');
+ engine.AnalysisErrorInfo errors = context.getErrors(testSource);
+ engine.AnalysisError engineError = errors.errors[0];
+ AnalysisError error =
+ new AnalysisError.fromEngine(errors.lineInfo, engineError);
+ {
+ Location location = error.location;
+ expect(location.file, testFile);
+ expect(location.offset, 19);
+ expect(location.length, 1);
+ expect(location.startLine, 2);
+ expect(location.startColumn, 11);
+ }
+ expect(error.message, "Expected to find ';'");
+ expect(error.severity, "ERROR");
+ expect(error.type, "SYNTACTIC_ERROR");
+ expect(
+ error.toString(),
+ 'AnalysisError(location=Location(file=/test.dart; offset=19; '
+ 'length=1; startLine=2; startColumn=11) '
+ 'message=Expected to find \';\'; severity=ERROR; '
+ 'type=SYNTACTIC_ERROR; correction=null');
+ }
+
+ void test_fromJson() {
+ var json = {
+ SEVERITY: 'ERROR',
+ TYPE: 'SYNTACTIC_ERROR',
+ LOCATION: {
+ FILE: '/test.dart',
+ OFFSET: 19,
+ LENGTH: 1,
+ START_LINE: 2,
+ START_COLUMN: 11
+ },
+ MESSAGE: 'Expected to find \';\''
+ };
+ AnalysisError error = AnalysisError.fromJson(json);
+ {
+ Location location = error.location;
+ expect(location.file, testFile);
+ expect(location.offset, 19);
+ expect(location.length, 1);
+ expect(location.startLine, 2);
+ expect(location.startColumn, 11);
+ }
+ expect(error.message, "Expected to find ';'");
+ expect(error.severity, "ERROR");
+ expect(error.type, "SYNTACTIC_ERROR");
+ }
+
+ void test_toJson() {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main() {
+ print(42)
+}
+''');
+ engine.AnalysisErrorInfo errors = context.getErrors(testSource);
+ engine.AnalysisError engineError = errors.errors[0];
+ AnalysisError error =
+ new AnalysisError.fromEngine(errors.lineInfo, engineError);
+ expect(error.toJson(), {
+ SEVERITY: 'ERROR',
+ TYPE: 'SYNTACTIC_ERROR',
+ LOCATION: {
+ FILE: '/test.dart',
+ OFFSET: 19,
+ LENGTH: 1,
+ START_LINE: 2,
+ START_COLUMN: 11
+ },
+ MESSAGE: 'Expected to find \';\''
+ });
+ }
+}
diff --git a/pkg/analysis_server/test/computer/test_all.dart b/pkg/analysis_server/test/computer/test_all.dart
index 2badfdf..9122f14 100644
--- a/pkg/analysis_server/test/computer/test_all.dart
+++ b/pkg/analysis_server/test/computer/test_all.dart
@@ -7,6 +7,7 @@
import 'package:unittest/unittest.dart';
import 'element_test.dart' as element_test;
+import 'error_test.dart' as error_test;
/**
@@ -14,7 +15,8 @@
*/
main() {
groupSep = ' | ';
- group('index', () {
+ group('computer', () {
element_test.main();
+ error_test.main();
});
}
\ No newline at end of file
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 8b80cd7..58c04db 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -7,10 +7,11 @@
import 'dart:async';
import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/mock_sdk.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
@@ -22,16 +23,6 @@
import 'mocks.dart';
-AnalysisError jsonToAnalysisError(Map<String, Object> json) {
- Map<String, Object> jsonLocation = json[LOCATION];
- Location location = new Location(jsonLocation[FILE], _getSafeInt(jsonLocation,
- OFFSET, -1), _getSafeInt(jsonLocation, LENGTH, -1), _getSafeInt(jsonLocation,
- START_LINE, -1), _getSafeInt(jsonLocation, START_COLUMN, -1));
- return new AnalysisError('unknown error code', json[SEVERITY], json[TYPE], location,
- json['message'], json['correction']);
-}
-
-
main() {
groupSep = ' | ';
@@ -46,8 +37,7 @@
serverChannel = new MockServerChannel();
resourceProvider = new MemoryResourceProvider();
server = new AnalysisServer(serverChannel, resourceProvider,
- new MockPackageMapProvider(), null);
- server.defaultSdk = new MockSdk();
+ new MockPackageMapProvider(), null, new MockSdk());
handler = new AnalysisDomainHandler(server);
});
@@ -358,7 +348,7 @@
if (notification.event == ANALYSIS_ERRORS) {
String file = notification.getParameter(FILE);
List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS);
- filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList();
+ filesErrors[file] = errorMaps.map(AnalysisError.fromJson).toList();
}
}
@@ -420,23 +410,6 @@
}
}
-class AnalysisError {
- final String errorCode;
- final String severity;
- final String type;
- final Location location;
- final String message;
- final String correction;
- AnalysisError(this.errorCode, this.severity, this.type, this.location,
- this.message, this.correction);
-
- @override
- String toString() {
- return 'AnalysisError(location=$location message=$message); '
- 'errorCode=$errorCode; severity=$separator type=$type';
- }
-}
-
/**
* A helper to test 'analysis.*' requests.
@@ -460,8 +433,7 @@
serverChannel = new MockServerChannel();
resourceProvider = new MemoryResourceProvider();
server = new AnalysisServer(serverChannel, resourceProvider,
- new MockPackageMapProvider(), null);
- server.defaultSdk = new MockSdk();
+ new MockPackageMapProvider(), null, new MockSdk());
handler = new AnalysisDomainHandler(server);
// listen for notifications
Stream<Notification> notificationStream =
@@ -470,7 +442,7 @@
if (notification.event == ANALYSIS_ERRORS) {
String file = notification.getParameter(FILE);
List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS);
- filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList();
+ filesErrors[file] = errorMaps.map(AnalysisError.fromJson).toList();
}
if (notification.event == ANALYSIS_HIGHLIGHTS) {
String file = notification.getParameter(FILE);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
deleted file mode 100644
index c45db47..0000000
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.domain.completion;
-
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/constants.dart';
-import 'package:analysis_server/src/domain_completion.dart';
-import 'package:analysis_server/src/protocol.dart';
-import 'package:analysis_testing/mock_sdk.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:unittest/unittest.dart';
-
-import 'mocks.dart';
-
-main() {
- groupSep = ' | ';
-
- MockServerChannel serverChannel;
- MemoryResourceProvider resourceProvider;
- AnalysisServer server;
- CompletionDomainHandler handler;
-
- setUp(() {
- serverChannel = new MockServerChannel();
- resourceProvider = new MemoryResourceProvider();
- server = new AnalysisServer(
- serverChannel, resourceProvider, new MockPackageMapProvider(), null);
- server.defaultSdk = new MockSdk();
- handler = new CompletionDomainHandler(server);
- });
-
- group('CompletionDomainHandler', () {
- test('getSuggestions', () {
- var request = new Request('0', COMPLETION_GET_SUGGESTIONS);
- request.setParameter(FILE, null);
- request.setParameter(OFFSET, null);
- var response = handler.handleRequest(request);
- // TODO(brianwilkerson) implement
- //expect(response, isNull);
- });
- });
-}
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 90f36e6..71088dd 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -9,6 +9,8 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_server.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_testing/mock_sdk.dart';
import 'package:unittest/unittest.dart';
import 'mocks.dart';
@@ -21,7 +23,8 @@
var serverChannel = new MockServerChannel();
var resourceProvider = PhysicalResourceProvider.INSTANCE;
server = new AnalysisServer(
- serverChannel, resourceProvider, new MockPackageMapProvider(), null);
+ serverChannel, resourceProvider, new MockPackageMapProvider(), null,
+ new MockSdk());
handler = new ServerDomainHandler(server);
});
diff --git a/pkg/analysis_server/test/domain_edit_test.dart b/pkg/analysis_server/test/edit/edit_domain_test.dart
similarity index 94%
rename from pkg/analysis_server/test/domain_edit_test.dart
rename to pkg/analysis_server/test/edit/edit_domain_test.dart
index d9dd424..6e0b421 100644
--- a/pkg/analysis_server/test/domain_edit_test.dart
+++ b/pkg/analysis_server/test/edit/edit_domain_test.dart
@@ -6,13 +6,14 @@
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/constants.dart';
-import 'package:analysis_server/src/domain_edit.dart';
+import 'package:analysis_server/src/edit/edit_domain.dart';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/mock_sdk.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:unittest/unittest.dart';
-import 'mocks.dart';
+import '../mocks.dart';
main() {
groupSep = ' | ';
@@ -26,8 +27,8 @@
serverChannel = new MockServerChannel();
resourceProvider = new MemoryResourceProvider();
server = new AnalysisServer(
- serverChannel, resourceProvider, new MockPackageMapProvider(), null);
- server.defaultSdk = new MockSdk();
+ serverChannel, resourceProvider, new MockPackageMapProvider(), null,
+ new MockSdk());
handler = new EditDomainHandler(server);
});
diff --git a/pkg/analysis_server/test/edit/fix_test.dart b/pkg/analysis_server/test/edit/fix_test.dart
new file mode 100644
index 0000000..879efcf
--- /dev/null
+++ b/pkg/analysis_server/test/edit/fix_test.dart
@@ -0,0 +1,154 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.edit.fix;
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/edit/fix.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_services/correction/fix.dart' as services;
+import 'package:analysis_services/index/index.dart' hide Location;
+import 'package:analysis_services/index/local_memory_index.dart';
+import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/element.dart' as engine;
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
+import 'package:unittest/unittest.dart' hide ERROR;
+
+
+
+main() {
+ groupSep = ' | ';
+ group('ErrorFixes', () {
+ runReflectiveTests(ErrorFixesTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class ErrorFixesTest extends AbstractSingleUnitTest {
+ Index index;
+ SearchEngineImpl searchEngine;
+
+ void setUp() {
+ super.setUp();
+ index = createLocalMemoryIndex();
+ searchEngine = new SearchEngineImpl(index);
+ verifyNoTestUnitErrors = false;
+ }
+
+ void test_fromJson() {
+ var json = {
+ ERROR: {
+ SEVERITY: 'ERROR',
+ TYPE: 'SYNTACTIC_ERROR',
+ LOCATION: {
+ FILE: '/test.dart',
+ OFFSET: 19,
+ LENGTH: 1,
+ START_LINE: 2,
+ START_COLUMN: 11
+ },
+ MESSAGE: 'Expected to find \';\''
+ },
+ FIXES: [{
+ MESSAGE: 'Insert \';\'',
+ EDITS: [{
+ FILE: '/test.dart',
+ EDITS: [{
+ OFFSET: 20,
+ LENGTH: 0,
+ REPLACEMENT: ';'
+ }]
+ }],
+ LINKED_POSITION_GROUPS: []
+ }]
+ };
+ ErrorFixes errorFixes = ErrorFixes.fromJson(json);
+ {
+ AnalysisError error = errorFixes.error;
+ expect(error.severity, 'ERROR');
+ expect(error.type, 'SYNTACTIC_ERROR');
+ expect(error.message, "Expected to find ';'");
+ {
+ Location location = error.location;
+ expect(location.file, testFile);
+ expect(location.offset, 19);
+ expect(location.length, 1);
+ expect(location.startLine, 2);
+ expect(location.startColumn, 11);
+ }
+ }
+ expect(errorFixes.fixes, hasLength(1));
+ {
+ Change change = errorFixes.fixes[0];
+ expect(change.message, "Insert ';'");
+ expect(change.edits, hasLength(1));
+ {
+ FileEdit fileEdit = change.edits[0];
+ expect(fileEdit.file, testFile);
+ expect(
+ fileEdit.edits.toString(),
+ "[Edit(offset=20, length=0, replacement=:>;<:)]");
+ }
+ }
+ expect(
+ errorFixes.toString(),
+ 'ErrorFixes(error=AnalysisError('
+ 'location=Location(file=/test.dart; offset=19; length=1; '
+ 'startLine=2; startColumn=11) message=Expected to find \';\'; '
+ 'severity=ERROR; type=SYNTACTIC_ERROR; correction=null, '
+ 'fixes=[Change(message=Insert \';\', '
+ 'edits=[FileEdit(file=/test.dart, edits=[Edit(offset=20, length=0, '
+ 'replacement=:>;<:)])], linkedPositionGroups=[])])');
+ }
+
+ void test_fromService() {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main() {
+ print(42)
+}
+''');
+ engine.AnalysisErrorInfo errors = context.getErrors(testSource);
+ engine.AnalysisError engineError = errors.errors[0];
+ List<services.Fix> servicesFixes =
+ services.computeFixes(searchEngine, testFile, testUnit, engineError);
+ AnalysisError error =
+ new AnalysisError.fromEngine(errors.lineInfo, engineError);
+ ErrorFixes fixes = new ErrorFixes(error);
+ servicesFixes.forEach((fix) => fixes.addFix(fix));
+ expect(fixes.toJson(), {
+ ERROR: {
+ SEVERITY: 'ERROR',
+ TYPE: 'SYNTACTIC_ERROR',
+ LOCATION: {
+ FILE: '/test.dart',
+ OFFSET: 19,
+ LENGTH: 1,
+ START_LINE: 2,
+ START_COLUMN: 11
+ },
+ MESSAGE: 'Expected to find \';\''
+ },
+ FIXES: [{
+ MESSAGE: 'Insert \';\'',
+ EDITS: [{
+ FILE: '/test.dart',
+ EDITS: [{
+ OFFSET: 20,
+ LENGTH: 0,
+ REPLACEMENT: ';'
+ }]
+ }],
+ LINKED_POSITION_GROUPS: []
+ }]
+ });
+ }
+}
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
new file mode 100644
index 0000000..2a8a96e
--- /dev/null
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.edit.fixes;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/edit/edit_domain.dart';
+import 'package:analysis_server/src/edit/fix.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart';
+
+import '../analysis_abstract.dart';
+
+
+main() {
+ groupSep = ' | ';
+ group('getFixes', () {
+ runReflectiveTests(FixesTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class FixesTest extends AbstractAnalysisTest {
+ @override
+ void setUp() {
+ super.setUp();
+ createProject();
+ handler = new EditDomainHandler(server);
+ }
+
+ Future test_hasFixes() {
+ addTestFile('''
+main() {
+ print(42)
+}
+''');
+ return waitForTasksFinished().then((_) {
+ Request request = new Request('0', EDIT_GET_FIXES);
+ request.setParameter(FILE, testFile);
+ request.setParameter(OFFSET, findOffset('print'));
+ Response response = handleSuccessfulRequest(request);
+ List<Map<String, Object>> errorFixesJsonList = response.getResult(FIXES);
+ List<ErrorFixes> errorFixesList = errorFixesJsonList.map(ErrorFixes.fromJson).toList();
+ expect(errorFixesList, hasLength(1));
+ {
+ ErrorFixes errorFixes = errorFixesList[0];
+ {
+ AnalysisError error = errorFixes.error;
+ expect(error.severity, 'ERROR');
+ expect(error.type, 'SYNTACTIC_ERROR');
+ expect(error.message, "Expected to find ';'");
+ {
+ Location location = error.location;
+ expect(location.file, testFile);
+ expect(location.offset, 19);
+ expect(location.length, 1);
+ expect(location.startLine, 2);
+ expect(location.startColumn, 11);
+ }
+ }
+ expect(errorFixes.fixes, hasLength(1));
+ {
+ Change change = errorFixes.fixes[0];
+ expect(change.message, "Insert ';'");
+ expect(change.edits, hasLength(1));
+ {
+ FileEdit fileEdit = change.edits[0];
+ expect(fileEdit.file, testFile);
+ expect(
+ fileEdit.edits.toString(),
+ "[Edit(offset=20, length=0, replacement=:>;<:)]");
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/pkg/analysis_server/test/edit/test_all.dart b/pkg/analysis_server/test/edit/test_all.dart
new file mode 100644
index 0000000..7c513b6
--- /dev/null
+++ b/pkg/analysis_server/test/edit/test_all.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.edit.all;
+
+import 'package:unittest/unittest.dart';
+
+import 'edit_domain_test.dart' as domain_edit_test;
+import 'fix_test.dart' as fix_test;
+
+/**
+ * Utility for manually running all tests.
+ */
+main() {
+ groupSep = ' | ';
+ group('edit', () {
+ domain_edit_test.main();
+ fix_test.main();
+ });
+}
\ No newline at end of file
diff --git a/pkg/analysis_server/test/operation/operation_analysis_test.dart b/pkg/analysis_server/test/operation/operation_analysis_test.dart
index aad7147..0619238 100644
--- a/pkg/analysis_server/test/operation/operation_analysis_test.dart
+++ b/pkg/analysis_server/test/operation/operation_analysis_test.dart
@@ -4,8 +4,8 @@
library test.operation.analysis;
-import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/operation/operation_analysis.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/mocks.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/error.dart';
diff --git a/pkg/analysis_server/test/package_map_provider_test.dart b/pkg/analysis_server/test/package_map_provider_test.dart
index 52708c0..cec1e2c 100644
--- a/pkg/analysis_server/test/package_map_provider_test.dart
+++ b/pkg/analysis_server/test/package_map_provider_test.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/package_map_provider.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:unittest/unittest.dart';
main() {
@@ -23,7 +24,7 @@
setUp(() {
resourceProvider = new MemoryResourceProvider();
- packageMapProvider = new PubPackageMapProvider(resourceProvider);
+ packageMapProvider = new PubPackageMapProvider(resourceProvider, DirectoryBasedDartSdk.defaultSdk);
projectFolder = resourceProvider.newFolder(projectPath);
});
diff --git a/pkg/analysis_server/test/protocol_test.dart b/pkg/analysis_server/test/protocol_test.dart
index 8813a68..8d69c6d 100644
--- a/pkg/analysis_server/test/protocol_test.dart
+++ b/pkg/analysis_server/test/protocol_test.dart
@@ -7,9 +7,9 @@
import 'dart:convert';
import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/json.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
-import 'package:analysis_server/src/collections.dart';
Matcher _throwsRequestFailure = throwsA(new isInstanceOf<RequestFailure>());
diff --git a/pkg/analysis_server/test/search/abstract_search_domain.dart b/pkg/analysis_server/test/search/abstract_search_domain.dart
index 5464311..2e33967 100644
--- a/pkg/analysis_server/test/search/abstract_search_domain.dart
+++ b/pkg/analysis_server/test/search/abstract_search_domain.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/search_domain.dart';
import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_services/index/index.dart' show Index;
import 'package:analysis_services/index/local_memory_index.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index e60eab7..3d35469 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/search/member_declarations_test.dart b/pkg/analysis_server/test/search/member_declarations_test.dart
index bad6bc5..9f349a7 100644
--- a/pkg/analysis_server/test/search/member_declarations_test.dart
+++ b/pkg/analysis_server/test/search/member_declarations_test.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/search/member_references_test.dart b/pkg/analysis_server/test/search/member_references_test.dart
index c09fe13..e247ad5 100644
--- a/pkg/analysis_server/test/search/member_references_test.dart
+++ b/pkg/analysis_server/test/search/member_references_test.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/search/search_domain_test.dart b/pkg/analysis_server/test/search/search_domain_test.dart
index d97ccd7..c8409b8 100644
--- a/pkg/analysis_server/test/search/search_domain_test.dart
+++ b/pkg/analysis_server/test/search/search_domain_test.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/search_domain.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/mock_sdk.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:unittest/unittest.dart';
@@ -30,8 +31,8 @@
serverChannel,
resourceProvider,
new MockPackageMapProvider(),
- null);
- server.defaultSdk = new MockSdk();
+ null,
+ new MockSdk());
handler = new SearchDomainHandler(server);
});
diff --git a/pkg/analysis_server/test/search/search_result_test.dart b/pkg/analysis_server/test/search/search_result_test.dart
index ea2dc8c..f8100f1 100644
--- a/pkg/analysis_server/test/search/search_result_test.dart
+++ b/pkg/analysis_server/test/search/search_result_test.dart
@@ -5,8 +5,8 @@
library test.search.search_result;
import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_services/search/search_engine.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/search/top_level_declarations_test.dart b/pkg/analysis_server/test/search/top_level_declarations_test.dart
index 6c1fb83..7931ae1 100644
--- a/pkg/analysis_server/test/search/top_level_declarations_test.dart
+++ b/pkg/analysis_server/test/search/top_level_declarations_test.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 67c6c2e..4f39c6a 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/socket_server.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:unittest/unittest.dart';
main() {
@@ -24,7 +25,7 @@
class SocketServerTest {
static Future createAnalysisServer_successful() {
- SocketServer server = new SocketServer();
+ SocketServer server = new SocketServer(DirectoryBasedDartSdk.defaultSdk);
MockServerChannel channel = new MockServerChannel();
server.createAnalysisServer(channel);
channel.expectMsgCount(notificationCount: 1);
@@ -40,7 +41,7 @@
}
static void createAnalysisServer_alreadyStarted() {
- SocketServer server = new SocketServer();
+ SocketServer server = new SocketServer(DirectoryBasedDartSdk.defaultSdk);
MockServerChannel channel1 = new MockServerChannel();
MockServerChannel channel2 = new MockServerChannel();
server.createAnalysisServer(channel1);
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart
index 6871fba..42730f9 100644
--- a/pkg/analysis_server/test/test_all.dart
+++ b/pkg/analysis_server/test/test_all.dart
@@ -4,6 +4,7 @@
import 'package:unittest/unittest.dart';
+import 'analysis/test_all.dart' as analysis_all;
import 'analysis_hover_test.dart' as analysis_hover_test;
import 'analysis_notification_highlights_test.dart' as analysis_notification_highlights_test;
import 'analysis_notification_navigation_test.dart' as analysis_notification_navigation_test;
@@ -16,9 +17,8 @@
import 'computer/test_all.dart' as computer_test_all;
import 'context_directory_manager_test.dart' as context_directory_manager_test;
import 'domain_analysis_test.dart' as domain_analysis_test;
-import 'domain_completion_test.dart' as domain_completion_test;
-import 'domain_edit_test.dart' as domain_edit_test;
import 'domain_server_test.dart' as domain_server_test;
+import 'edit/test_all.dart' as edit_all;
import 'operation/test_all.dart' as operation_test_all;
import 'package_map_provider_test.dart' as package_map_provider_test;
import 'package_uri_resolver_test.dart' as package_uri_resolver_test;
@@ -32,6 +32,7 @@
main() {
groupSep = ' | ';
group('analysis_server', () {
+ analysis_all.main();
analysis_hover_test.main();
analysis_notification_highlights_test.main();
analysis_notification_navigation_test.main();
@@ -44,9 +45,8 @@
computer_test_all.main();
context_directory_manager_test.main();
domain_analysis_test.main();
- domain_completion_test.main();
- domain_edit_test.main();
domain_server_test.main();
+ edit_all.main();
operation_test_all.main();
package_map_provider_test.main();
package_uri_resolver_test.main();
diff --git a/pkg/analysis_services/lib/completion/completion_suggestion.dart b/pkg/analysis_services/lib/completion/completion_suggestion.dart
new file mode 100644
index 0000000..14e9fcb
--- /dev/null
+++ b/pkg/analysis_services/lib/completion/completion_suggestion.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.suggestion;
+
+import 'package:analysis_services/json.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analyzer/src/generated/element.dart';
+
+/**
+ * A single completion suggestion.
+ */
+class CompletionSuggestion implements HasToJson {
+ final CompletionSuggestionKind kind;
+ final CompletionRelevance relevance;
+ final String completion;
+ final int selectionOffset;
+ final int selectionLength;
+ final bool isDeprecated;
+ final bool isPotential;
+
+ CompletionSuggestion(this.kind, this.relevance, this.completion,
+ this.selectionOffset, this.selectionLength, this.isDeprecated,
+ this.isPotential);
+
+ factory CompletionSuggestion.fromJson(Map<String, Object> json) {
+ return new CompletionSuggestion(
+ CompletionSuggestionKind.valueOf(json[KIND]),
+ CompletionRelevance.value(json[RELEVANCE]),
+ json[COMPLETION],
+ json[SELECTION_OFFSET],
+ json[SELECTION_LENGTH],
+ json[IS_DEPRECATED],
+ json[IS_POTENTIAL]);
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ return {
+ KIND: kind.name,
+ RELEVANCE: relevance.name,
+ COMPLETION: completion,
+ SELECTION_OFFSET: selectionOffset,
+ SELECTION_LENGTH: selectionLength,
+ IS_DEPRECATED: isDeprecated,
+ IS_POTENTIAL: isPotential
+ };
+ }
+}
+
+/**
+ * An enumeration of the kinds of elements that can be included
+ * in a completion suggestion.
+ */
+class CompletionSuggestionKind {
+ static const CompletionSuggestionKind CLASS =
+ const CompletionSuggestionKind('CLASS');
+ static const CompletionSuggestionKind CLASS_ALIAS =
+ const CompletionSuggestionKind('CLASS_ALIAS');
+ static const CompletionSuggestionKind CONSTRUCTOR =
+ const CompletionSuggestionKind('CONSTRUCTOR');
+ static const CompletionSuggestionKind FIELD =
+ const CompletionSuggestionKind('FIELD');
+ static const CompletionSuggestionKind FUNCTION =
+ const CompletionSuggestionKind('FUNCTION');
+ static const CompletionSuggestionKind FUNCTION_ALIAS =
+ const CompletionSuggestionKind('FUNCTION_ALIAS');
+ static const CompletionSuggestionKind GETTER =
+ const CompletionSuggestionKind('GETTER');
+ static const CompletionSuggestionKind IMPORT =
+ const CompletionSuggestionKind('IMPORT');
+ static const CompletionSuggestionKind LIBRARY_PREFIX =
+ const CompletionSuggestionKind('LIBRARY_PREFIX');
+ static const CompletionSuggestionKind METHOD =
+ const CompletionSuggestionKind('METHOD');
+ static const CompletionSuggestionKind METHOD_NAME =
+ const CompletionSuggestionKind('METHOD_NAME');
+ static const CompletionSuggestionKind PARAMETER =
+ const CompletionSuggestionKind('PARAMETER');
+ static const CompletionSuggestionKind SETTER =
+ const CompletionSuggestionKind('SETTER');
+ static const CompletionSuggestionKind VARIABLE =
+ const CompletionSuggestionKind('VARIABLE');
+ static const CompletionSuggestionKind TYPE_PARAMETER =
+ const CompletionSuggestionKind('TYPE_PARAMETER');
+ static const CompletionSuggestionKind ARGUMENT_LIST =
+ const CompletionSuggestionKind('ARGUMENT_LIST');
+ static const CompletionSuggestionKind OPTIONAL_ARGUMENT =
+ const CompletionSuggestionKind('OPTIONAL_ARGUMENT');
+ static const CompletionSuggestionKind NAMED_ARGUMENT =
+ const CompletionSuggestionKind('NAMED_ARGUMENT');
+ static const CompletionSuggestionKind TOP_LEVEL_VARIABLE =
+ const CompletionSuggestionKind('TOP_LEVEL_VARIABLE');
+
+ final String name;
+
+ const CompletionSuggestionKind(this.name);
+
+ @override
+ String toString() => name;
+
+ static CompletionSuggestionKind valueOf(String name) {
+ if (CLASS.name == name) return CLASS;
+ if (CLASS_ALIAS.name == name) return CLASS_ALIAS;
+ if (CONSTRUCTOR.name == name) return CONSTRUCTOR;
+ if (FIELD.name == name) return FIELD;
+ if (FUNCTION.name == name) return FUNCTION;
+ if (FUNCTION_ALIAS.name == name) return FUNCTION_ALIAS;
+ if (GETTER.name == name) return GETTER;
+ if (IMPORT.name == name) return IMPORT;
+ if (LIBRARY_PREFIX.name == name) return LIBRARY_PREFIX;
+ if (METHOD.name == name) return METHOD;
+ if (METHOD_NAME.name == name) return METHOD_NAME;
+ if (PARAMETER.name == name) return PARAMETER;
+ if (SETTER.name == name) return SETTER;
+ if (VARIABLE.name == name) return VARIABLE;
+ if (TYPE_PARAMETER.name == name) return TYPE_PARAMETER;
+ if (ARGUMENT_LIST.name == name) return ARGUMENT_LIST;
+ if (OPTIONAL_ARGUMENT.name == name) return OPTIONAL_ARGUMENT;
+ if (NAMED_ARGUMENT.name == name) return NAMED_ARGUMENT;
+ if (TOP_LEVEL_VARIABLE.name == name) return TOP_LEVEL_VARIABLE;
+ throw new ArgumentError('Unknown CompletionSuggestionKind: $name');
+ }
+
+ static CompletionSuggestionKind fromElementKind(ElementKind kind) {
+ // ElementKind.ANGULAR_FORMATTER,
+ // ElementKind.ANGULAR_COMPONENT,
+ // ElementKind.ANGULAR_CONTROLLER,
+ // ElementKind.ANGULAR_DIRECTIVE,
+ // ElementKind.ANGULAR_PROPERTY,
+ // ElementKind.ANGULAR_SCOPE_PROPERTY,
+ // ElementKind.ANGULAR_SELECTOR,
+ // ElementKind.ANGULAR_VIEW,
+ if (kind == ElementKind.CLASS) return CLASS;
+ // ElementKind.COMPILATION_UNIT,
+ if (kind == ElementKind.CONSTRUCTOR) return CONSTRUCTOR;
+ // ElementKind.DYNAMIC,
+ // ElementKind.EMBEDDED_HTML_SCRIPT,
+ // ElementKind.ERROR,
+ // ElementKind.EXPORT,
+ // ElementKind.EXTERNAL_HTML_SCRIPT,
+ if (kind == ElementKind.FIELD) return FIELD;
+ if (kind == ElementKind.FUNCTION) return FUNCTION;
+ if (kind == ElementKind.GETTER) return GETTER;
+ // ElementKind.HTML,
+ if (kind == ElementKind.IMPORT) return IMPORT;
+ // ElementKind.LABEL,
+ // ElementKind.LIBRARY,
+ // ElementKind.LOCAL_VARIABLE,
+ if (kind == ElementKind.METHOD) return METHOD;
+ // ElementKind.METHOD,
+ // ElementKind.NAME,
+ if (kind == ElementKind.PARAMETER) return PARAMETER;
+ // ElementKind.POLYMER_ATTRIBUTE,
+ // ElementKind.POLYMER_TAG_DART,
+ // ElementKind.POLYMER_TAG_HTML,
+ // ElementKind.PREFIX,
+ if (kind == ElementKind.SETTER) return SETTER;
+ if (kind == ElementKind.TOP_LEVEL_VARIABLE) return TOP_LEVEL_VARIABLE;
+ // ElementKind.FUNCTION_TYPE_ALIAS,
+ // ElementKind.TYPE_PARAMETER,
+ // ElementKind.UNIVERSE
+ throw new ArgumentError('Unknown CompletionSuggestionKind for: $kind');
+ }
+}
+
+/**
+ * An enumeration of the relevance of a completion suggestion.
+ */
+class CompletionRelevance {
+ static const CompletionRelevance LOW = const CompletionRelevance('LOW');
+ static const CompletionRelevance DEFAULT =
+ const CompletionRelevance('DEFAULT');
+ static const CompletionRelevance HIGH = const CompletionRelevance('HIGH');
+
+ final String name;
+
+ const CompletionRelevance(this.name);
+
+ static CompletionRelevance value(String name) {
+ if (LOW.name == name) return LOW;
+ if (DEFAULT.name == name) return DEFAULT;
+ if (HIGH.name == name) return HIGH;
+ throw new ArgumentError('Unknown CompletionRelevance: $name');
+ }
+}
diff --git a/pkg/analysis_services/lib/constants.dart b/pkg/analysis_services/lib/constants.dart
new file mode 100644
index 0000000..dab2e6e
--- /dev/null
+++ b/pkg/analysis_services/lib/constants.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.constants;
+
+//
+// Property names
+//
+const String ADDED = 'added';
+const String CHILDREN = 'children';
+const String COMPLETION = 'completion';
+const String CONTAINING_LIBRARY_NAME = 'containingLibraryName';
+const String CONTAINING_LIBRARY_PATH = 'containingLibraryPath';
+const String CONTENT = 'content';
+const String CORRECTION = 'correction';
+const String DART_DOC = 'dartdoc';
+const String DEFAULT = 'default';
+const String EDITS = 'edits';
+const String ELEMENT = 'element';
+const String ELEMENT_DESCRIPTION = 'elementDescription';
+const String ELEMENT_KIND = 'elementKind';
+const String EXCLUDED = 'excluded';
+const String ERROR = 'error';
+const String ERRORS = 'errors';
+const String FILE = 'file';
+const String FILES = 'files';
+const String FIXES = 'fixes';
+const String FLAGS = 'flags';
+const String HOVERS = 'hovers';
+const String ID = 'id';
+const String INCLUDE_POTENTIAL = 'includePotential';
+const String INCLUDED = 'included';
+const String INTERFACE_ELEMENTS = 'interfaceElements';
+const String IS_ABSTRACT = 'isAbstract';
+const String IS_DEPRECATED = 'isDeprecated';
+const String IS_POTENTIAL = 'isPotential';
+const String IS_STATIC = 'isStatic';
+const String KIND = 'kind';
+const String LAST = 'last';
+const String LENGTH = 'length';
+const String LINKED_POSITION_GROUPS = 'linkedPositionGroups';
+const String LOCATION = 'location';
+const String MESSAGE = 'message';
+const String NAME = 'name';
+const String NEW_LENGTH = 'newLength';
+const String OCCURRENCES = 'occurrences';
+const String OFFSET = 'offset';
+const String OFFSETS = 'offsets';
+const String OLD_LENGTH = 'oldLength';
+const String OPTIONS = 'options';
+const String OUTLINE = 'outline';
+const String OVERRIDES = 'overrides';
+const String PARAMETER = 'parameter';
+const String PARAMETERS = 'parameters';
+const String PATH = 'path';
+const String PATTERN = 'pattern';
+const String POSITIONS = 'positions';
+const String PROPAGATED_TYPE = 'propagatedType';
+const String REFACTORINGS = 'refactorings';
+const String REGIONS = 'regions';
+const String RELEVANCE = 'relevance';
+const String REMOVED = 'removed';
+const String REPLACEMENT = 'relacement';
+const String RETURN_TYPE = 'returnType';
+const String RESULTS = 'results';
+const String SEVERITY = 'severity';
+const String SELECTION_LENGTH = 'selectionLength';
+const String SELECTION_OFFSET = 'selectionOffset';
+const String START_COLUMN = 'startColumn';
+const String START_LINE = 'startLine';
+const String STATIC_TYPE = 'staticType';
+const String SUBSCRIPTIONS = 'subscriptions';
+const String SUPER_CLASS_ELEMENT = 'superclassElement';
+const String TARGETS = 'targets';
+const String TYPE = 'type';
+const String VERSION = 'version';
diff --git a/pkg/analysis_services/lib/correction/change.dart b/pkg/analysis_services/lib/correction/change.dart
index aead362..a352855 100644
--- a/pkg/analysis_services/lib/correction/change.dart
+++ b/pkg/analysis_services/lib/correction/change.dart
@@ -7,13 +7,20 @@
library services.correction.change;
-import 'package:analyzer/src/generated/source.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
+
+
+_fromJsonList(List target, List<Map<String, Object>> jsonList,
+ decoder(Map<String, Object> json)) {
+ target.addAll(jsonList.map(decoder));
+}
/**
* A description of a single change to one or more files.
*/
-class Change {
+class Change implements HasToJson {
/**
* A textual description of the change to be applied.
*/
@@ -24,24 +31,59 @@
*/
final List<FileEdit> edits = <FileEdit>[];
+ /**
+ * A list of the [LinkedPositionGroup]s in the change.
+ */
+ final List<LinkedPositionGroup> linkedPositionGroups = <LinkedPositionGroup>[
+ ];
+
Change(this.message);
/**
- * Adds the given [FileEdit] to the list.
+ * Adds the given [FileEdit].
*/
void add(FileEdit edit) {
edits.add(edit);
}
+ /**
+ * Adds the given [LinkedPositionGroup].
+ */
+ void addLinkedPositionGroup(LinkedPositionGroup linkedPositionGroup) {
+ linkedPositionGroups.add(linkedPositionGroup);
+ }
+
@override
- String toString() => "Change(message=$message, edits=${edits.join(' ')})";
+ Map<String, Object> toJson() {
+ return {
+ MESSAGE: message,
+ EDITS: objectToJson(edits),
+ LINKED_POSITION_GROUPS: objectToJson(linkedPositionGroups)
+ };
+ }
+
+ @override
+ String toString() =>
+ 'Change(message=$message, edits=$edits, '
+ 'linkedPositionGroups=$linkedPositionGroups)';
+
+ static Change fromJson(Map<String, Object> json) {
+ String message = json[MESSAGE];
+ Change change = new Change(message);
+ _fromJsonList(change.edits, json[EDITS], FileEdit.fromJson);
+ _fromJsonList(
+ change.linkedPositionGroups,
+ json[LINKED_POSITION_GROUPS],
+ LinkedPositionGroup.fromJson);
+ return change;
+ }
}
/**
* A description of a single change to a single file.
*/
-class Edit {
+class Edit implements HasToJson {
/**
* The offset of the region to be modified.
*/
@@ -59,26 +101,46 @@
Edit(this.offset, this.length, this.replacement);
- Edit.range(SourceRange range, String replacement) : this(
- range.offset,
- range.length,
- replacement);
-
/**
* The offset of a character immediately after the region to be modified.
*/
int get end => offset + length;
+ bool operator ==(other) {
+ if (other is Edit) {
+ return other.offset == offset &&
+ other.length == length &&
+ other.replacement == replacement;
+ }
+ return false;
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ return {
+ OFFSET: offset,
+ LENGTH: length,
+ REPLACEMENT: replacement
+ };
+ }
+
@override
String toString() =>
- "(offset=$offset, length=$length, replacement=:>$replacement<:)";
+ "Edit(offset=$offset, length=$length, replacement=:>$replacement<:)";
+
+ static Edit fromJson(Map<String, Object> json) {
+ int offset = json[OFFSET];
+ int length = json[LENGTH];
+ String replacement = json[REPLACEMENT];
+ return new Edit(offset, length, replacement);
+ }
}
/**
* A description of a set of changes to a single file.
*/
-class FileEdit {
+class FileEdit implements HasToJson {
/**
* The file to be modified.
*/
@@ -99,5 +161,107 @@
}
@override
- String toString() => "FileEdit(file=$file, edits=${edits.join(' ')})";
+ Map<String, Object> toJson() {
+ return {
+ FILE: file,
+ EDITS: objectToJson(edits)
+ };
+ }
+
+ @override
+ String toString() => "FileEdit(file=$file, edits=$edits)";
+
+ static FileEdit fromJson(Map<String, Object> json) {
+ String file = json[FILE];
+ FileEdit fileEdit = new FileEdit(file);
+ _fromJsonList(fileEdit.edits, json[EDITS], Edit.fromJson);
+ return fileEdit;
+ }
+}
+
+
+/**
+ * A group of linked [Position]s in multiple files that are simultaneously
+ * modified - if one gets edited, all other positions in a group are edited the
+ * same way. All linked positions in a group have the same content.
+ */
+class LinkedPositionGroup implements HasToJson {
+ final String id;
+ final List<Position> positions = <Position>[];
+
+ LinkedPositionGroup(this.id);
+
+ void add(Position position) {
+ if (positions.isNotEmpty && position.length != positions[0].length) {
+ throw new ArgumentError(
+ 'All positions should have the same length. '
+ 'Was: ${positions[0].length}. New: ${position.length}');
+ }
+ positions.add(position);
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ return {
+ ID: id,
+ POSITIONS: objectToJson(positions)
+ };
+ }
+
+ @override
+ String toString() => 'LinkedPositionGroup(id=$id, positions=$positions)';
+
+ static LinkedPositionGroup fromJson(Map<String, Object> json) {
+ String id = json[ID];
+ LinkedPositionGroup group = new LinkedPositionGroup(id);
+ _fromJsonList(group.positions, json[POSITIONS], Position.fromJson);
+ return group;
+ }
+}
+
+
+/**
+ * A position in a file.
+ */
+class Position implements HasToJson {
+ final String file;
+ final int offset;
+ final int length;
+
+ Position(this.file, this.offset, this.length);
+
+ int get hashCode {
+ int hash = file.hashCode;
+ hash = hash * 31 + offset;
+ hash = hash * 31 + length;
+ return hash;
+ }
+
+ bool operator ==(other) {
+ if (other is Position) {
+ return other.file == file &&
+ other.offset == offset &&
+ other.length == length;
+ }
+ return false;
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ return {
+ FILE: file,
+ OFFSET: offset,
+ LENGTH: length
+ };
+ }
+
+ @override
+ String toString() => 'Position(file=$file, offset=$offset, length=$length)';
+
+ static Position fromJson(Map<String, Object> json) {
+ String file = json[FILE];
+ int offset = json[OFFSET];
+ int length = json[LENGTH];
+ return new Position(file, offset, length);
+ }
}
diff --git a/pkg/analysis_services/lib/correction/fix.dart b/pkg/analysis_services/lib/correction/fix.dart
index 7ff90d2..f165213 100644
--- a/pkg/analysis_services/lib/correction/fix.dart
+++ b/pkg/analysis_services/lib/correction/fix.dart
@@ -5,12 +5,10 @@
library services.correction.fix;
import 'package:analysis_services/correction/change.dart';
-import 'package:analysis_services/correction/source_range_factory.dart' as rf;
import 'package:analysis_services/search/search_engine.dart';
+import 'package:analysis_services/src/correction/fix.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/source.dart';
/**
@@ -20,7 +18,7 @@
*/
List<Fix> computeFixes(SearchEngine searchEngine, String file,
CompilationUnit unit, AnalysisError error) {
- var processor = new _FixProcessor(searchEngine, file, unit, error);
+ var processor = new FixProcessor(searchEngine, file, unit, error);
return processor.compute();
}
@@ -46,145 +44,84 @@
*/
class FixKind {
static const ADD_PACKAGE_DEPENDENCY =
- const FixKind(
- 'QF_ADD_PACKAGE_DEPENDENCY',
- 50,
- "Add dependency on package '%s'");
+ const FixKind('ADD_PACKAGE_DEPENDENCY', 50, "Add dependency on package '%s'");
static const ADD_SUPER_CONSTRUCTOR_INVOCATION =
const FixKind(
- 'QF_ADD_SUPER_CONSTRUCTOR_INVOCATION',
+ 'ADD_SUPER_CONSTRUCTOR_INVOCATION',
50,
"Add super constructor %s invocation");
- static const CHANGE_TO = const FixKind('QF_CHANGE_TO', 51, "Change to '%s'");
+ static const CHANGE_TO = const FixKind('CHANGE_TO', 51, "Change to '%s'");
static const CHANGE_TO_STATIC_ACCESS =
const FixKind(
- 'QF_CHANGE_TO_STATIC_ACCESS',
+ 'CHANGE_TO_STATIC_ACCESS',
50,
"Change access to static using '%s'");
static const CREATE_CLASS =
- const FixKind('QF_CREATE_CLASS', 50, "Create class '%s'");
+ const FixKind('CREATE_CLASS', 50, "Create class '%s'");
static const CREATE_CONSTRUCTOR =
- const FixKind('QF_CREATE_CONSTRUCTOR', 50, "Create constructor '%s'");
+ const FixKind('CREATE_CONSTRUCTOR', 50, "Create constructor '%s'");
static const CREATE_CONSTRUCTOR_SUPER =
- const FixKind(
- 'QF_CREATE_CONSTRUCTOR_SUPER',
- 50,
- "Create constructor to call %s");
+ const FixKind('CREATE_CONSTRUCTOR_SUPER', 50, "Create constructor to call %s");
static const CREATE_FUNCTION =
- const FixKind('QF_CREATE_FUNCTION', 49, "Create function '%s'");
+ const FixKind('CREATE_FUNCTION', 49, "Create function '%s'");
static const CREATE_METHOD =
- const FixKind('QF_CREATE_METHOD', 50, "Create method '%s'");
+ const FixKind('CREATE_METHOD', 50, "Create method '%s'");
static const CREATE_MISSING_OVERRIDES =
- const FixKind(
- 'QF_CREATE_MISSING_OVERRIDES',
- 50,
- "Create %d missing override(s)");
+ const FixKind('CREATE_MISSING_OVERRIDES', 50, "Create %d missing override(s)");
static const CREATE_NO_SUCH_METHOD =
- const FixKind('QF_CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' method");
+ const FixKind('CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' method");
static const CREATE_PART =
- const FixKind('QF_CREATE_PART', 50, "Create part '%s'");
+ const FixKind('CREATE_PART', 50, "Create part '%s'");
static const IMPORT_LIBRARY_PREFIX =
const FixKind(
- 'QF_IMPORT_LIBRARY_PREFIX',
+ 'IMPORT_LIBRARY_PREFIX',
51,
"Use imported library '%s' with prefix '%s'");
static const IMPORT_LIBRARY_PROJECT =
- const FixKind('QF_IMPORT_LIBRARY_PROJECT', 51, "Import library '%s'");
+ const FixKind('IMPORT_LIBRARY_PROJECT', 51, "Import library '%s'");
static const IMPORT_LIBRARY_SDK =
- const FixKind('QF_IMPORT_LIBRARY_SDK', 51, "Import library '%s'");
+ const FixKind('IMPORT_LIBRARY_SDK', 51, "Import library '%s'");
static const IMPORT_LIBRARY_SHOW =
- const FixKind('QF_IMPORT_LIBRARY_SHOW', 51, "Update library '%s' import");
+ const FixKind('IMPORT_LIBRARY_SHOW', 51, "Update library '%s' import");
static const INSERT_SEMICOLON =
- const FixKind('QF_INSERT_SEMICOLON', 50, "Insert ';'");
+ const FixKind('INSERT_SEMICOLON', 50, "Insert ';'");
static const MAKE_CLASS_ABSTRACT =
- const FixKind('QF_MAKE_CLASS_ABSTRACT', 50, "Make class '%s' abstract");
+ const FixKind('MAKE_CLASS_ABSTRACT', 50, "Make class '%s' abstract");
static const REMOVE_PARAMETERS_IN_GETTER_DECLARATION =
const FixKind(
- 'QF_REMOVE_PARAMETERS_IN_GETTER_DECLARATION',
+ 'REMOVE_PARAMETERS_IN_GETTER_DECLARATION',
50,
"Remove parameters in getter declaration");
static const REMOVE_PARENTHESIS_IN_GETTER_INVOCATION =
const FixKind(
- 'QF_REMOVE_PARENTHESIS_IN_GETTER_INVOCATION',
+ 'REMOVE_PARENTHESIS_IN_GETTER_INVOCATION',
50,
"Remove parentheses in getter invocation");
static const REMOVE_UNNECASSARY_CAST =
- const FixKind('QF_REMOVE_UNNECASSARY_CAST', 50, "Remove unnecessary cast");
+ const FixKind('REMOVE_UNNECASSARY_CAST', 50, "Remove unnecessary cast");
static const REMOVE_UNUSED_IMPORT =
- const FixKind('QF_REMOVE_UNUSED_IMPORT', 50, "Remove unused import");
+ const FixKind('REMOVE_UNUSED_IMPORT', 50, "Remove unused import");
static const REPLACE_BOOLEAN_WITH_BOOL =
- const FixKind(
- 'QF_REPLACE_BOOLEAN_WITH_BOOL',
- 50,
- "Replace 'boolean' with 'bool'");
- static const USE_CONST =
- const FixKind('QF_USE_CONST', 50, "Change to constant");
+ const FixKind('REPLACE_BOOLEAN_WITH_BOOL', 50, "Replace 'boolean' with 'bool'");
+ static const USE_CONST = const FixKind('USE_CONST', 50, "Change to constant");
static const USE_EFFECTIVE_INTEGER_DIVISION =
const FixKind(
- 'QF_USE_EFFECTIVE_INTEGER_DIVISION',
+ 'USE_EFFECTIVE_INTEGER_DIVISION',
50,
"Use effective integer division ~/");
static const USE_EQ_EQ_NULL =
- const FixKind('QF_USE_EQ_EQ_NULL', 50, "Use == null instead of 'is Null'");
+ const FixKind('USE_EQ_EQ_NULL', 50, "Use == null instead of 'is Null'");
static const USE_NOT_EQ_NULL =
- const FixKind('QF_USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'");
+ const FixKind('USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'");
final name;
final int relevance;
final String message;
const FixKind(this.name, this.relevance, this.message);
-}
-
-/**
- * The computer for Dart fixes.
- */
-class _FixProcessor {
- final SearchEngine searchEngine;
- final String file;
- final CompilationUnit unit;
- final AnalysisError error;
-
- final List<Fix> fixes = <Fix>[];
- final List<Edit> edits = <Edit>[];
-
-
- _FixProcessor(this.searchEngine, this.file, this.unit, this.error);
-
- List<Fix> compute() {
- ErrorCode errorCode = error.errorCode;
- if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) {
- _addFix_boolInsteadOfBoolean();
- }
- return fixes;
- }
-
- void _addFix(FixKind kind, List args) {
- FileEdit fileEdit = new FileEdit(file);
- edits.forEach((edit) => fileEdit.add(edit));
- // prepare Change
- String message = JavaString.format(kind.message, args);
- Change change = new Change(message);
- change.add(fileEdit);
- // add Fix
- var fix = new Fix(kind, change);
- fixes.add(fix);
- }
-
- void _addFix_boolInsteadOfBoolean() {
- SourceRange range = rf.rangeError(error);
- _addReplaceEdit(range, "bool");
- _addFix(FixKind.REPLACE_BOOLEAN_WITH_BOOL, []);
- }
-
- /**
- * Adds a new [Edit] to [edits].
- */
- void _addReplaceEdit(SourceRange range, String text) {
- Edit edit = new Edit.range(range, text);
- edits.add(edit);
- }
+ @override
+ String toString() => name;
}
diff --git a/pkg/analysis_services/lib/json.dart b/pkg/analysis_services/lib/json.dart
new file mode 100644
index 0000000..1727d5e
--- /dev/null
+++ b/pkg/analysis_services/lib/json.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.json;
+
+/**
+ * Instances of the class [HasToJson] implement [toJson] method that returns
+ * a JSON presentation.
+ */
+abstract class HasToJson {
+ /**
+ * Returns a JSON presentation of the object.
+ */
+ Map<String, Object> toJson();
+}
+
+
+/**
+ * Returns a JSON presention of [value].
+ */
+objectToJson(Object value) {
+ if (value is HasToJson) {
+ return value.toJson();
+ }
+ if (value is Iterable) {
+ return value.map((item) => objectToJson(item)).toList();
+ }
+ return value;
+}
diff --git a/pkg/analysis_services/lib/src/correction/fix.dart b/pkg/analysis_services/lib/src/correction/fix.dart
new file mode 100644
index 0000000..fe24a14
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/fix.dart
@@ -0,0 +1,1738 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.fix;
+
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_services/correction/fix.dart';
+import 'package:analysis_services/search/search_engine.dart';
+import 'package:analysis_services/src/correction/name_suggestion.dart';
+import 'package:analysis_services/src/correction/source_buffer.dart';
+import 'package:analysis_services/src/correction/source_range.dart' as rf;
+import 'package:analysis_services/src/correction/util.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+
+/**
+ * The computer for Dart fixes.
+ */
+class FixProcessor {
+ final SearchEngine searchEngine;
+ final String file;
+ final CompilationUnit unit;
+ final AnalysisError error;
+
+ final List<Edit> edits = <Edit>[];
+ final Map<String, LinkedPositionGroup> linkedPositionGroups = <String,
+ LinkedPositionGroup>{};
+ final List<Fix> fixes = <Fix>[];
+
+ CorrectionUtils utils;
+ int errorOffset;
+ int errorLength;
+ int errorEnd;
+ AstNode node;
+ AstNode coveredNode;
+
+
+ FixProcessor(this.searchEngine, this.file, this.unit, this.error);
+
+ List<Fix> compute() {
+ utils = new CorrectionUtils(unit);
+ errorOffset = error.offset;
+ errorLength = error.length;
+ errorEnd = errorOffset + errorLength;
+ node = new NodeLocator.con1(errorOffset).searchWithin(unit);
+ coveredNode = new NodeLocator.con2(
+ errorOffset,
+ errorOffset + errorLength).searchWithin(unit);
+ // analyze ErrorCode
+ ErrorCode errorCode = error.errorCode;
+ if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) {
+ _addFix_boolInsteadOfBoolean();
+ }
+ if (errorCode ==
+ CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE) {
+ _addFix_replaceWithConstInstanceCreation();
+ }
+ if (errorCode ==
+ CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT) {
+ _addFix_createConstructorSuperExplicit();
+ }
+// if (identical(
+// errorCode,
+// CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT)) {
+// _addFix_createConstructorSuperImplicit();
+// }
+ if (errorCode ==
+ CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT) {
+ _addFix_createConstructorSuperExplicit();
+ }
+// if (identical(errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST)) {
+// _addFix_createPart();
+// _addFix_addPackageDependency();
+// }
+ if (errorCode == HintCode.DIVISION_OPTIMIZATION) {
+ _addFix_useEffectiveIntegerDivision();
+ }
+ if (errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL) {
+ _addFix_isNotNull();
+ }
+ if (errorCode == HintCode.TYPE_CHECK_IS_NULL) {
+ _addFix_isNull();
+ }
+ if (errorCode == HintCode.UNNECESSARY_CAST) {
+ _addFix_removeUnnecessaryCast();
+ }
+ if (errorCode == HintCode.UNUSED_IMPORT) {
+ _addFix_removeUnusedImport();
+ }
+ if (errorCode == ParserErrorCode.EXPECTED_TOKEN) {
+ _addFix_insertSemicolon();
+ }
+ if (errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS) {
+ _addFix_removeParameters_inGetterDeclaration();
+ }
+ if (errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER) {
+ _addFix_makeEnclosingClassAbstract();
+ }
+ if (errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) {
+ _addFix_createConstructor_insteadOfSyntheticDefault();
+ }
+ if (errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR) {
+ _addFix_createConstructor_named();
+ }
+ if (errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
+ errorCode ==
+ StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS) {
+ // make class abstract
+ _addFix_makeEnclosingClassAbstract();
+ // implement methods
+ AnalysisErrorWithProperties errorWithProperties =
+ error as AnalysisErrorWithProperties;
+ Object property =
+ errorWithProperties.getProperty(ErrorProperty.UNIMPLEMENTED_METHODS);
+ List<ExecutableElement> missingOverrides =
+ property as List<ExecutableElement>;
+ _addFix_createMissingOverrides(missingOverrides);
+ _addFix_createNoSuchMethod();
+ }
+ if (errorCode == StaticWarningCode.UNDEFINED_CLASS) {
+ _addFix_importLibrary_withType();
+ _addFix_createClass();
+ _addFix_undefinedClass_useSimilar();
+ }
+// if (identical(errorCode, StaticWarningCode.UNDEFINED_IDENTIFIER)) {
+// _addFix_createFunction_forFunctionType();
+// _addFix_importLibrary_withType();
+// _addFix_importLibrary_withTopLevelVariable();
+// }
+ if (errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER) {
+ _addFix_useStaticAccess_method();
+ _addFix_useStaticAccess_property();
+ }
+ if (errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) {
+ _addFix_removeParentheses_inGetterInvocation();
+ }
+// if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_FUNCTION)) {
+// _addFix_importLibrary_withFunction();
+// _addFix_undefinedFunction_useSimilar();
+// _addFix_undefinedFunction_create();
+// }
+// if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_GETTER)) {
+// _addFix_createFunction_forFunctionType();
+// }
+// if (identical(errorCode, HintCode.UNDEFINED_METHOD) ||
+// identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
+// _addFix_undefinedMethod_useSimilar();
+// _addFix_undefinedMethod_create();
+// _addFix_undefinedFunction_create();
+// }
+ // done
+ return fixes;
+ }
+
+ void _addFix(FixKind kind, List args, {String fixFile}) {
+ if (fixFile == null) {
+ fixFile = file;
+ }
+ FileEdit fileEdit = new FileEdit(file);
+ edits.forEach((edit) => fileEdit.add(edit));
+ // prepare Change
+ String message = JavaString.format(kind.message, args);
+ Change change = new Change(message);
+ change.add(fileEdit);
+ linkedPositionGroups.values.forEach(
+ (group) => change.addLinkedPositionGroup(group));
+ // add Fix
+ Fix fix = new Fix(kind, change);
+ fixes.add(fix);
+ }
+
+ void _addFix_addPackageDependency() {
+ // TODO(scheglov) implement
+// if (node is SimpleStringLiteral && node.parent is NamespaceDirective) {
+// SimpleStringLiteral uriLiteral = node as SimpleStringLiteral;
+// String uriString = uriLiteral.value;
+// // we need package: import
+// if (!uriString.startsWith("package:")) {
+// return;
+// }
+// // prepare package name
+// String packageName = StringUtils.removeStart(uriString, "package:");
+// packageName = StringUtils.substringBefore(packageName, "/");
+// // add proposal
+// _proposals.add(
+// new AddDependencyCorrectionProposal(
+// _unitFile,
+// packageName,
+// FixKind.ADD_PACKAGE_DEPENDENCY,
+// [packageName]));
+// }
+ }
+
+ void _addFix_boolInsteadOfBoolean() {
+ SourceRange range = rf.rangeError(error);
+ _addReplaceEdit(range, "bool");
+ _addFix(FixKind.REPLACE_BOOLEAN_WITH_BOOL, []);
+ }
+
+
+ void _addFix_createClass() {
+ if (_mayBeTypeIdentifier(node)) {
+ String name = (node as SimpleIdentifier).name;
+ // prepare environment
+ String eol = utils.endOfLine;
+ CompilationUnitMember enclosingMember =
+ node.getAncestor((node) => node is CompilationUnitMember);
+ int offset = enclosingMember.end;
+ String prefix = "";
+ // prepare source
+ SourceBuilder sb = new SourceBuilder(file, offset);
+ {
+ sb.append("${eol}${eol}");
+ sb.append(prefix);
+ // "class"
+ sb.append("class ");
+ // append name
+ {
+ sb.startPosition("NAME");
+ sb.append(name);
+ sb.endPosition();
+ }
+ // no members
+ sb.append(" {");
+ sb.append(eol);
+ sb.append("}");
+ }
+ // insert source
+ _insertBuilder(sb);
+ _addLinkedPosition("NAME", rf.rangeNode(node));
+ // add proposal
+ _addFix(FixKind.CREATE_CLASS, [name]);
+ }
+ }
+
+
+ void _addFix_createConstructorSuperExplicit() {
+ ConstructorDeclaration targetConstructor =
+ node.parent as ConstructorDeclaration;
+ ClassDeclaration targetClassNode =
+ targetConstructor.parent as ClassDeclaration;
+ ClassElement targetClassElement = targetClassNode.element;
+ ClassElement superClassElement = targetClassElement.supertype.element;
+ // add proposals for all super constructors
+ List<ConstructorElement> superConstructors = superClassElement.constructors;
+ for (ConstructorElement superConstructor in superConstructors) {
+ String constructorName = superConstructor.name;
+ // skip private
+ if (Identifier.isPrivateName(constructorName)) {
+ continue;
+ }
+ // prepare SourceBuilder
+ SourceBuilder sb;
+ {
+ List<ConstructorInitializer> initializers =
+ targetConstructor.initializers;
+ if (initializers.isEmpty) {
+ int insertOffset = targetConstructor.parameters.end;
+ sb = new SourceBuilder(file, insertOffset);
+ sb.append(" : ");
+ } else {
+ ConstructorInitializer lastInitializer =
+ initializers[initializers.length - 1];
+ int insertOffset = lastInitializer.end;
+ sb = new SourceBuilder(file, insertOffset);
+ sb.append(", ");
+ }
+ }
+ // add super constructor name
+ sb.append("super");
+ if (!StringUtils.isEmpty(constructorName)) {
+ sb.append(".");
+ sb.append(constructorName);
+ }
+ // add arguments
+ sb.append("(");
+ bool firstParameter = true;
+ for (ParameterElement parameter in superConstructor.parameters) {
+ // skip non-required parameters
+ if (parameter.parameterKind != ParameterKind.REQUIRED) {
+ break;
+ }
+ // comma
+ if (firstParameter) {
+ firstParameter = false;
+ } else {
+ sb.append(", ");
+ }
+ // default value
+ DartType parameterType = parameter.type;
+ sb.startPosition(parameter.name);
+ sb.append(getDefaultValueCode(parameterType));
+ sb.endPosition();
+ }
+ sb.append(")");
+ // insert proposal
+ _insertBuilder(sb);
+ // add proposal
+ String proposalName = _getConstructorProposalName(superConstructor);
+ _addFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, [proposalName]);
+ }
+ }
+
+ void _addFix_createConstructorSuperImplicit() {
+ // TODO(scheglov) implement
+// ClassDeclaration targetClassNode = node.parent as ClassDeclaration;
+// ClassElement targetClassElement = targetClassNode.element;
+// ClassElement superClassElement = targetClassElement.supertype.element;
+// String targetClassName = targetClassElement.name;
+// // add proposals for all super constructors
+// List<ConstructorElement> superConstructors = superClassElement.constructors;
+// for (ConstructorElement superConstructor in superConstructors) {
+// String constructorName = superConstructor.name;
+// // skip private
+// if (Identifier.isPrivateName(constructorName)) {
+// continue;
+// }
+// // prepare parameters and arguments
+// JavaStringBuilder parametersBuffer = new JavaStringBuilder();
+// JavaStringBuilder argumentsBuffer = new JavaStringBuilder();
+// bool firstParameter = true;
+// for (ParameterElement parameter in superConstructor.parameters) {
+// // skip non-required parameters
+// if (parameter.parameterKind != ParameterKind.REQUIRED) {
+// break;
+// }
+// // comma
+// if (firstParameter) {
+// firstParameter = false;
+// } else {
+// parametersBuffer.append(", ");
+// argumentsBuffer.append(", ");
+// }
+// // name
+// String parameterName = parameter.displayName;
+// if (parameterName.length > 1 && parameterName.startsWith("_")) {
+// parameterName = parameterName.substring(1);
+// }
+// // parameter & argument
+// _appendParameterSource(parametersBuffer, parameter.type, parameterName);
+// argumentsBuffer.append(parameterName);
+// }
+// // add proposal
+// String eol = utils.endOfLine;
+// QuickFixProcessorImpl_NewConstructorLocation targetLocation =
+// _prepareNewConstructorLocation(targetClassNode, eol);
+// SourceBuilder sb = new SourceBuilder.con1(targetLocation._offset);
+// {
+// String indent = utils.getIndent(1);
+// sb.append(targetLocation._prefix);
+// sb.append(indent);
+// sb.append(targetClassName);
+// if (!constructorName.isEmpty) {
+// sb.startPosition("NAME");
+// sb.append(".");
+// sb.append(constructorName);
+// sb.endPosition();
+// }
+// sb.append("(");
+// sb.append(parametersBuffer.toString());
+// sb.append(") : super");
+// if (!constructorName.isEmpty) {
+// sb.append(".");
+// sb.append(constructorName);
+// }
+// sb.append("(");
+// sb.append(argumentsBuffer.toString());
+// sb.append(");");
+// sb.append(targetLocation._suffix);
+// }
+// _addInsertEdit3(sb);
+// // add proposal
+// String proposalName = _getConstructorProposalName(superConstructor);
+// _addFix(
+// FixKind.CREATE_CONSTRUCTOR_SUPER,
+// [proposalName]);
+// }
+ }
+
+ void _addFix_createConstructor_insteadOfSyntheticDefault() {
+ TypeName typeName = null;
+ ConstructorName constructorName = null;
+ InstanceCreationExpression instanceCreation = null;
+ if (node is SimpleIdentifier) {
+ if (node.parent is TypeName) {
+ typeName = node.parent as TypeName;
+ if (typeName.name == node && typeName.parent is ConstructorName) {
+ constructorName = typeName.parent as ConstructorName;
+ // should be synthetic default constructor
+ {
+ ConstructorElement constructorElement =
+ constructorName.staticElement;
+ if (constructorElement == null ||
+ !constructorElement.isDefaultConstructor ||
+ !constructorElement.isSynthetic) {
+ return;
+ }
+ }
+ // prepare InstanceCreationExpression
+ if (constructorName.parent is InstanceCreationExpression) {
+ instanceCreation = constructorName.parent as
+ InstanceCreationExpression;
+ if (instanceCreation.constructorName != constructorName) {
+ return;
+ }
+ }
+ }
+ }
+ }
+ // do we have enough information?
+ if (instanceCreation == null) {
+ return;
+ }
+ // prepare environment
+ String eol = utils.endOfLine;
+ // prepare target
+ DartType targetType = typeName.type;
+ if (targetType is! InterfaceType) {
+ return;
+ }
+ ClassElement targetElement = targetType.element as ClassElement;
+ String targetFile = targetElement.source.fullName;
+ ClassDeclaration targetClass = targetElement.node;
+ QuickFixProcessorImpl_NewConstructorLocation targetLocation =
+ _prepareNewConstructorLocation(targetClass, eol);
+ // build method source
+ SourceBuilder sb = new SourceBuilder(targetFile, targetLocation._offset);
+ {
+ String indent = " ";
+ sb.append(targetLocation._prefix);
+ sb.append(indent);
+ sb.append(targetElement.name);
+ _addFix_undefinedMethod_create_parameters(
+ sb,
+ instanceCreation.argumentList);
+ sb.append(") {${eol}${indent}}");
+ sb.append(targetLocation._suffix);
+ }
+ // insert source
+ _insertBuilder(sb);
+ // add proposal
+ _addFix(FixKind.CREATE_CONSTRUCTOR, [constructorName], fixFile: targetFile);
+ }
+
+ void _addFix_createConstructor_named() {
+ SimpleIdentifier name = null;
+ ConstructorName constructorName = null;
+ InstanceCreationExpression instanceCreation = null;
+ if (node is SimpleIdentifier) {
+ // name
+ name = node as SimpleIdentifier;
+ if (name.parent is ConstructorName) {
+ constructorName = name.parent as ConstructorName;
+ if (constructorName.name == name) {
+ // Type.name
+ if (constructorName.parent is InstanceCreationExpression) {
+ instanceCreation = constructorName.parent as
+ InstanceCreationExpression;
+ // new Type.name()
+ if (instanceCreation.constructorName != constructorName) {
+ return;
+ }
+ }
+ }
+ }
+ }
+ // do we have enough information?
+ if (instanceCreation == null) {
+ return;
+ }
+ // prepare environment
+ String eol = utils.endOfLine;
+ // prepare target interface type
+ DartType targetType = constructorName.type.type;
+ if (targetType is! InterfaceType) {
+ return;
+ }
+ ClassElement targetElement = targetType.element as ClassElement;
+ String targetFile = targetElement.source.fullName;
+ ClassDeclaration targetClass = targetElement.node;
+ QuickFixProcessorImpl_NewConstructorLocation targetLocation =
+ _prepareNewConstructorLocation(targetClass, eol);
+ // build method source
+ SourceBuilder sb = new SourceBuilder(targetFile, targetLocation._offset);
+ {
+ String indent = " ";
+ sb.append(targetLocation._prefix);
+ sb.append(indent);
+ sb.append(targetElement.name);
+ sb.append(".");
+ // append name
+ {
+ sb.startPosition("NAME");
+ sb.append(name.name);
+ sb.endPosition();
+ }
+ _addFix_undefinedMethod_create_parameters(
+ sb,
+ instanceCreation.argumentList);
+ sb.append(") {${eol}${indent}}");
+ sb.append(targetLocation._suffix);
+ }
+ // insert source
+ _insertBuilder(sb);
+ if (targetFile == file) {
+ _addLinkedPosition("NAME", rf.rangeNode(name));
+ }
+ // add proposal
+ _addFix(FixKind.CREATE_CONSTRUCTOR, [constructorName], fixFile: targetFile);
+ }
+
+ void _addFix_createFunction_forFunctionType() {
+ // TODO(scheglov) implement
+// if (node is SimpleIdentifier) {
+// SimpleIdentifier nameNode = node as SimpleIdentifier;
+// // prepare argument expression (to get parameter)
+// ClassElement targetElement;
+// Expression argument;
+// {
+// Expression target = CorrectionUtils.getQualifiedPropertyTarget(node);
+// if (target != null) {
+// DartType targetType = target.bestType;
+// if (targetType != null && targetType.element is ClassElement) {
+// targetElement = targetType.element as ClassElement;
+// argument = target.parent as Expression;
+// } else {
+// return;
+// }
+// } else {
+// ClassDeclaration enclosingClass =
+// node.getAncestor((node) => node is ClassDeclaration);
+// targetElement = enclosingClass != null ?
+// enclosingClass.element :
+// null;
+// argument = nameNode;
+// }
+// }
+// // should be argument of some invocation
+// ParameterElement parameterElement = argument.bestParameterElement;
+// if (parameterElement == null) {
+// return;
+// }
+// // should be parameter of function type
+// DartType parameterType = parameterElement.type;
+// if (parameterType is! FunctionType) {
+// return;
+// }
+// FunctionType functionType = parameterType as FunctionType;
+// // add proposal
+// if (targetElement != null) {
+// _addProposal_createFunction_method(targetElement, functionType);
+// } else {
+// _addProposal_createFunction_function(functionType);
+// }
+// }
+ }
+
+ void
+ _addFix_createMissingOverrides(List<ExecutableElement> missingOverrides) {
+ // TODO(scheglov) implement
+// // sort by name
+// missingOverrides.sort(
+// (Element firstElement, Element secondElement) =>
+// ObjectUtils.compare(firstElement.displayName, secondElement.displayName));
+// // add elements
+// ClassDeclaration targetClass = node.parent as ClassDeclaration;
+// bool isFirst = true;
+// for (ExecutableElement missingOverride in missingOverrides) {
+// _addFix_createMissingOverrides_single(
+// targetClass,
+// missingOverride,
+// isFirst);
+// isFirst = false;
+// }
+// // add proposal
+// _addFix(
+// FixKind.CREATE_MISSING_OVERRIDES,
+// [missingOverrides.length]);
+ }
+
+ void _addFix_createMissingOverrides_single(ClassDeclaration targetClass,
+ ExecutableElement missingOverride, bool isFirst) {
+ // TODO(scheglov) implement
+// // prepare environment
+// String eol = utils.endOfLine;
+// String prefix = utils.getIndent(1);
+// String prefix2 = utils.getIndent(2);
+// int insertOffset = targetClass.end - 1;
+// // prepare source
+// JavaStringBuilder sb = new JavaStringBuilder();
+// // may be empty line
+// if (!isFirst || !targetClass.members.isEmpty) {
+// sb.append(eol);
+// }
+// // may be property
+// ElementKind elementKind = missingOverride.kind;
+// bool isGetter = elementKind == ElementKind.GETTER;
+// bool isSetter = elementKind == ElementKind.SETTER;
+// bool isMethod = elementKind == ElementKind.METHOD;
+// bool isOperator = isMethod && (missingOverride as MethodElement).isOperator;
+// sb.append(prefix);
+// if (isGetter) {
+// sb.append("// TODO: implement ${missingOverride.displayName}");
+// sb.append(eol);
+// sb.append(prefix);
+// }
+// // @override
+// {
+// sb.append("@override");
+// sb.append(eol);
+// sb.append(prefix);
+// }
+// // return type
+// _appendType(sb, missingOverride.type.returnType);
+// if (isGetter) {
+// sb.append("get ");
+// } else if (isSetter) {
+// sb.append("set ");
+// } else if (isOperator) {
+// sb.append("operator ");
+// }
+// // name
+// sb.append(missingOverride.displayName);
+// // parameters + body
+// if (isGetter) {
+// sb.append(" => null;");
+// } else if (isMethod || isSetter) {
+// List<ParameterElement> parameters = missingOverride.parameters;
+// _appendParameters(sb, parameters);
+// sb.append(" {");
+// // TO-DO
+// sb.append(eol);
+// sb.append(prefix2);
+// if (isMethod) {
+// sb.append("// TODO: implement ${missingOverride.displayName}");
+// } else {
+// sb.append("// TODO: implement ${missingOverride.displayName}");
+// }
+// sb.append(eol);
+// // close method
+// sb.append(prefix);
+// sb.append("}");
+// }
+// sb.append(eol);
+// // done
+// _addInsertEdit(insertOffset, sb.toString());
+// // maybe set end range
+// if (_endRange == null) {
+// _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0);
+// }
+ }
+
+ void _addFix_createNoSuchMethod() {
+ // TODO(scheglov) implement
+// ClassDeclaration targetClass = node.parent as ClassDeclaration;
+// // prepare environment
+// String eol = utils.endOfLine;
+// String prefix = utils.getIndent(1);
+// int insertOffset = targetClass.end - 1;
+// // prepare source
+// SourceBuilder sb = new SourceBuilder.con1(insertOffset);
+// {
+// // insert empty line before existing member
+// if (!targetClass.members.isEmpty) {
+// sb.append(eol);
+// }
+// // append method
+// sb.append(prefix);
+// sb.append(
+// "noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);");
+// sb.append(eol);
+// }
+// // done
+// _addInsertEdit3(sb);
+// _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0);
+// // add proposal
+// _addFix(FixKind.CREATE_NO_SUCH_METHOD, []);
+ }
+
+ void _addFix_createPart() {
+ // TODO(scheglov) implement
+// if (node is SimpleStringLiteral && node.parent is PartDirective) {
+// SimpleStringLiteral uriLiteral = node as SimpleStringLiteral;
+// String uriString = uriLiteral.value;
+// // prepare referenced File
+// JavaFile newFile;
+// {
+// Uri uri = parseUriWithException(uriString);
+// if (uri.isAbsolute) {
+// return;
+// }
+// newFile = new JavaFile.relative(_unitLibraryFolder, uriString);
+// }
+// if (!newFile.exists()) {
+// // prepare new source
+// String source;
+// {
+// String eol = utils.endOfLine;
+// String libraryName = _unitLibraryElement.displayName;
+// source = "part of ${libraryName};${eol}${eol}";
+// }
+// // add proposal
+// _proposals.add(
+// new CreateFileCorrectionProposal(
+// newFile,
+// source,
+// FixKind.CREATE_PART,
+// [uriString]));
+// }
+// }
+ }
+
+ void _addFix_importLibrary(FixKind kind, String importPath) {
+ // TODO(scheglov) implement
+// CompilationUnitElement libraryUnitElement =
+// _unitLibraryElement.definingCompilationUnit;
+// CompilationUnit libraryUnit = libraryUnitElement.node;
+// // prepare new import location
+// int offset = 0;
+// String prefix;
+// String suffix;
+// {
+// String eol = utils.endOfLine;
+// // if no directives
+// prefix = "";
+// suffix = eol;
+// CorrectionUtils libraryUtils = new CorrectionUtils(libraryUnit);
+// // after last directive in library
+// for (Directive directive in libraryUnit.directives) {
+// if (directive is LibraryDirective || directive is ImportDirective) {
+// offset = directive.end;
+// prefix = eol;
+// suffix = "";
+// }
+// }
+// // if still beginning of file, skip shebang and line comments
+// if (offset == 0) {
+// CorrectionUtils_InsertDesc desc = libraryUtils.insertDescTop;
+// offset = desc.offset;
+// prefix = desc.prefix;
+// suffix = "${desc.suffix}${eol}";
+// }
+// }
+// // insert new import
+// String importSource = "${prefix}import '${importPath}';${suffix}";
+// _addInsertEdit(offset, importSource);
+// // add proposal
+// _addUnitCorrectionProposal2(libraryUnitElement.source, kind, [importPath]);
+ }
+
+ void _addFix_importLibrary_withElement(String name, ElementKind kind) {
+ // TODO(scheglov) implement
+// // ignore if private
+// if (name.startsWith("_")) {
+// return;
+// }
+// // may be there is an existing import, but it is with prefix and we don't use this prefix
+// for (ImportElement imp in _unitLibraryElement.imports) {
+// // prepare element
+// LibraryElement libraryElement = imp.importedLibrary;
+// Element element =
+// CorrectionUtils.getExportedElement(libraryElement, name);
+// if (element == null) {
+// continue;
+// }
+// if (element is PropertyAccessorElement) {
+// element = (element as PropertyAccessorElement).variable;
+// }
+// if (element.kind != kind) {
+// continue;
+// }
+// // may be apply prefix
+// PrefixElement prefix = imp.prefix;
+// if (prefix != null) {
+// SourceRange range = SourceRangeFactory.rangeStartLength(node, 0);
+// _addReplaceEdit(range, "${prefix.displayName}.");
+// _addFix(
+// FixKind.IMPORT_LIBRARY_PREFIX,
+// [libraryElement.displayName, prefix.displayName]);
+// continue;
+// }
+// // may be update "show" directive
+// List<NamespaceCombinator> combinators = imp.combinators;
+// if (combinators.length == 1 && combinators[0] is ShowElementCombinator) {
+// ShowElementCombinator showCombinator =
+// combinators[0] as ShowElementCombinator;
+// // prepare new set of names to show
+// Set<String> showNames = new Set<String>();
+// showNames.addAll(showCombinator.shownNames);
+// showNames.add(name);
+// // prepare library name - unit name or 'dart:name' for SDK library
+// String libraryName = libraryElement.definingCompilationUnit.displayName;
+// if (libraryElement.isInSdk) {
+// libraryName = imp.uri;
+// }
+// // update library
+// String newShowCode = "show ${StringUtils.join(showNames, ", ")}";
+// // TODO(scheglov)
+// _addReplaceEdit(
+// SourceRangeFactory.rangeShowCombinator(showCombinator),
+// newShowCode);
+// _addUnitCorrectionProposal2(
+// _unitLibraryElement.source,
+// FixKind.IMPORT_LIBRARY_SHOW,
+// [libraryName]);
+// // we support only one import without prefix
+// return;
+// }
+// }
+// // check SDK libraries
+// AnalysisContext context = _unitLibraryElement.context;
+// {
+// DartSdk sdk = context.sourceFactory.dartSdk;
+// List<SdkLibrary> sdkLibraries = sdk.sdkLibraries;
+// for (SdkLibrary sdkLibrary in sdkLibraries) {
+// SourceFactory sdkSourceFactory = context.sourceFactory;
+// String libraryUri = sdkLibrary.shortName;
+// Source librarySource = sdkSourceFactory.resolveUri(null, libraryUri);
+// // prepare LibraryElement
+// LibraryElement libraryElement =
+// context.getLibraryElement(librarySource);
+// if (libraryElement == null) {
+// continue;
+// }
+// // prepare exported Element
+// Element element =
+// CorrectionUtils.getExportedElement(libraryElement, name);
+// if (element == null) {
+// continue;
+// }
+// if (element is PropertyAccessorElement) {
+// element = (element as PropertyAccessorElement).variable;
+// }
+// if (element.kind != kind) {
+// continue;
+// }
+// // add import
+// _addFix_importLibrary(FixKind.IMPORT_LIBRARY_SDK, libraryUri);
+// }
+// }
+// // check project libraries
+// {
+// List<Source> librarySources = context.librarySources;
+// for (Source librarySource in librarySources) {
+// // we don't need SDK libraries here
+// if (librarySource.isInSystemLibrary) {
+// continue;
+// }
+// // prepare LibraryElement
+// LibraryElement libraryElement =
+// context.getLibraryElement(librarySource);
+// if (libraryElement == null) {
+// continue;
+// }
+// // prepare exported Element
+// Element element =
+// CorrectionUtils.getExportedElement(libraryElement, name);
+// if (element == null) {
+// continue;
+// }
+// if (element.kind != kind) {
+// continue;
+// }
+// // prepare "library" file
+// JavaFile libraryFile = getSourceFile(librarySource);
+// if (libraryFile == null) {
+// continue;
+// }
+// // may be "package:" URI
+// {
+// Uri libraryPackageUri = _findPackageUri(context, libraryFile);
+// if (libraryPackageUri != null) {
+// _addFix_importLibrary(
+// FixKind.IMPORT_LIBRARY_PROJECT,
+// libraryPackageUri.toString());
+// continue;
+// }
+// }
+// // relative URI
+// String relative =
+// URIUtils.computeRelativePath(
+// _unitLibraryFolder.getAbsolutePath(),
+// libraryFile.getAbsolutePath());
+// _addFix_importLibrary(
+// FixKind.IMPORT_LIBRARY_PROJECT,
+// relative);
+// }
+// }
+ }
+
+ void _addFix_importLibrary_withFunction() {
+ // TODO(scheglov) implement
+// if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+// MethodInvocation invocation = node.parent as MethodInvocation;
+// if (invocation.realTarget == null &&
+// identical(invocation.methodName, node)) {
+// String name = (node as SimpleIdentifier).name;
+// _addFix_importLibrary_withElement(name, ElementKind.FUNCTION);
+// }
+// }
+ }
+
+ void _addFix_importLibrary_withTopLevelVariable() {
+ // TODO(scheglov) implement
+// if (node is SimpleIdentifier) {
+// String name = (node as SimpleIdentifier).name;
+// _addFix_importLibrary_withElement(name, ElementKind.TOP_LEVEL_VARIABLE);
+// }
+ }
+
+ void _addFix_importLibrary_withType() {
+ // TODO(scheglov) implement
+// if (_mayBeTypeIdentifier(node)) {
+// String typeName = (node as SimpleIdentifier).name;
+// _addFix_importLibrary_withElement(typeName, ElementKind.CLASS);
+// }
+ }
+
+ void _addFix_insertSemicolon() {
+ if (error.message.contains("';'")) {
+ int insertOffset = error.offset + error.length;
+ _addInsertEdit(insertOffset, ";");
+ _addFix(FixKind.INSERT_SEMICOLON, []);
+ }
+ }
+
+ void _addFix_isNotNull() {
+ if (coveredNode is IsExpression) {
+ IsExpression isExpression = coveredNode as IsExpression;
+ _addReplaceEdit(
+ rf.rangeEndEnd(isExpression.expression, isExpression),
+ " != null");
+ _addFix(FixKind.USE_NOT_EQ_NULL, []);
+ }
+ }
+
+ void _addFix_isNull() {
+ if (coveredNode is IsExpression) {
+ IsExpression isExpression = coveredNode as IsExpression;
+ _addReplaceEdit(
+ rf.rangeEndEnd(isExpression.expression, isExpression),
+ " == null");
+ _addFix(FixKind.USE_EQ_EQ_NULL, []);
+ }
+ }
+
+ void _addFix_makeEnclosingClassAbstract() {
+ ClassDeclaration enclosingClass =
+ node.getAncestor((node) => node is ClassDeclaration);
+ String className = enclosingClass.name.name;
+ _addInsertEdit(enclosingClass.classKeyword.offset, "abstract ");
+ _addFix(FixKind.MAKE_CLASS_ABSTRACT, [className]);
+ }
+
+ void _addFix_removeParameters_inGetterDeclaration() {
+ if (node is SimpleIdentifier && node.parent is MethodDeclaration) {
+ MethodDeclaration method = node.parent as MethodDeclaration;
+ FunctionBody body = method.body;
+ if (method.name == node && body != null) {
+ _addReplaceEdit(rf.rangeEndStart(node, body), " ");
+ _addFix(FixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, []);
+ }
+ }
+ }
+
+ void _addFix_removeParentheses_inGetterInvocation() {
+ if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+ MethodInvocation invocation = node.parent as MethodInvocation;
+ if (invocation.methodName == node && invocation.target != null) {
+ _addRemoveEdit(rf.rangeEndEnd(node, invocation));
+ _addFix(FixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION, []);
+ }
+ }
+ }
+
+ void _addFix_removeUnnecessaryCast() {
+ if (coveredNode is! AsExpression) {
+ return;
+ }
+ AsExpression asExpression = coveredNode as AsExpression;
+ Expression expression = asExpression.expression;
+ int expressionPrecedence = getExpressionPrecedence(expression);
+ // remove 'as T' from 'e as T'
+ _addRemoveEdit(rf.rangeEndEnd(expression, asExpression));
+ _removeEnclosingParentheses(asExpression, expressionPrecedence);
+ // done
+ _addFix(FixKind.REMOVE_UNNECASSARY_CAST, []);
+ }
+
+ void _addFix_removeUnusedImport() {
+ // prepare ImportDirective
+ ImportDirective importDirective =
+ node.getAncestor((node) => node is ImportDirective);
+ if (importDirective == null) {
+ return;
+ }
+ // remove the whole line with import
+ _addRemoveEdit(utils.getLinesRange(rf.rangeNode(importDirective)));
+ // done
+ _addFix(FixKind.REMOVE_UNUSED_IMPORT, []);
+ }
+
+ void _addFix_replaceWithConstInstanceCreation() {
+ if (coveredNode is InstanceCreationExpression) {
+ var instanceCreation = coveredNode as InstanceCreationExpression;
+ _addReplaceEdit(rf.rangeToken(instanceCreation.keyword), "const");
+ _addFix(FixKind.USE_CONST, []);
+ }
+ }
+
+ void _addFix_undefinedClass_useSimilar() {
+ // TODO(scheglov) implement
+// if (_mayBeTypeIdentifier(node)) {
+// String name = (node as SimpleIdentifier).name;
+// QuickFixProcessorImpl_ClosestElementFinder finder =
+// new QuickFixProcessorImpl_ClosestElementFinder(
+// name,
+// new Predicate_QuickFixProcessorImpl_addFix_undefinedClass_useSimilar());
+// // find closest element
+// {
+// // elements of this library
+// _unitLibraryElement.accept(
+// new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefinedClass_useSimilar(
+// finder));
+// // elements from imports
+// for (ImportElement importElement in _unitLibraryElement.imports) {
+// if (importElement.prefix == null) {
+// Map<String, Element> namespace =
+// CorrectionUtils.getImportNamespace(importElement);
+// finder._update2(namespace.values);
+// }
+// }
+// }
+// // if we have close enough element, suggest to use it
+// if (finder != null && finder._distance < 5) {
+// String closestName = finder._element.name;
+// _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
+// // add proposal
+// if (closestName != null) {
+// _addFix(
+// FixKind.CHANGE_TO,
+// [closestName]);
+// }
+// }
+// }
+ }
+
+ void _addFix_undefinedFunction_create() {
+ // TODO(scheglov) implement
+// // should be the name of the invocation
+// if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+// } else {
+// return;
+// }
+// String name = (node as SimpleIdentifier).name;
+// MethodInvocation invocation = node.parent as MethodInvocation;
+// // function invocation has no target
+// Expression target = invocation.realTarget;
+// if (target != null) {
+// return;
+// }
+// // prepare environment
+// String eol = utils.endOfLine;
+// int insertOffset;
+// String sourcePrefix;
+// AstNode enclosingMember =
+// node.getAncestor((node) => node is CompilationUnitMember);
+// insertOffset = enclosingMember.end;
+// sourcePrefix = "${eol}${eol}";
+// // build method source
+// SourceBuilder sb = new SourceBuilder.con1(insertOffset);
+// {
+// sb.append(sourcePrefix);
+// // may be return type
+// {
+// DartType type =
+// _addFix_undefinedMethod_create_getReturnType(invocation);
+// if (type != null) {
+// String typeSource = utils.getTypeSource2(type);
+// if (typeSource != "dynamic") {
+// sb.startPosition("RETURN_TYPE");
+// sb.append(typeSource);
+// sb.endPosition();
+// sb.append(" ");
+// }
+// }
+// }
+// // append name
+// {
+// sb.startPosition("NAME");
+// sb.append(name);
+// sb.endPosition();
+// }
+// _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList);
+// sb.append(") {${eol}}");
+// }
+// // insert source
+// _addInsertEdit(insertOffset, sb.toString());
+// // add linked positions
+// _addLinkedPosition("NAME", sb, SourceRangeFactory.rangeNode(node));
+// _addLinkedPositions(sb);
+// // add proposal
+// _addFix(FixKind.CREATE_FUNCTION, [name]);
+ }
+
+ void _addFix_undefinedFunction_useSimilar() {
+ // TODO(scheglov) implement
+// if (node is SimpleIdentifier) {
+// String name = (node as SimpleIdentifier).name;
+// QuickFixProcessorImpl_ClosestElementFinder finder =
+// new QuickFixProcessorImpl_ClosestElementFinder(
+// name,
+// new Predicate_QuickFixProcessorImpl_addFix_undefinedFunction_useSimilar());
+// // this library
+// _unitLibraryElement.accept(
+// new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefinedFunction_useSimilar(
+// finder));
+// // imports
+// for (ImportElement importElement in _unitLibraryElement.imports) {
+// if (importElement.prefix == null) {
+// Map<String, Element> namespace =
+// CorrectionUtils.getImportNamespace(importElement);
+// finder._update2(namespace.values);
+// }
+// }
+// // if we have close enough element, suggest to use it
+// String closestName = null;
+// if (finder != null && finder._distance < 5) {
+// closestName = finder._element.name;
+// _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
+// _addFix(FixKind.CHANGE_TO, [closestName]);
+// }
+// }
+ }
+
+ void _addFix_undefinedMethod_create() {
+ // TODO(scheglov) implement
+// if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+// String name = (node as SimpleIdentifier).name;
+// MethodInvocation invocation = node.parent as MethodInvocation;
+// // prepare environment
+// String eol = utils.endOfLine;
+// Source targetSource;
+// String prefix;
+// int insertOffset;
+// String sourcePrefix;
+// String sourceSuffix;
+// bool staticModifier = false;
+// Expression target = invocation.realTarget;
+// if (target == null) {
+// targetSource = _source;
+// ClassMember enclosingMember =
+// node.getAncestor((node) => node is ClassMember);
+// staticModifier = _inStaticMemberContext2(enclosingMember);
+// prefix = utils.getNodePrefix(enclosingMember);
+// insertOffset = enclosingMember.end;
+// sourcePrefix = "${eol}${prefix}${eol}";
+// sourceSuffix = "";
+// } else {
+// // prepare target interface type
+// DartType targetType = target.bestType;
+// if (targetType is! InterfaceType) {
+// return;
+// }
+// ClassElement targetElement = targetType.element as ClassElement;
+// targetSource = targetElement.source;
+// // may be static
+// if (target is Identifier) {
+// staticModifier = target.bestElement.kind == ElementKind.CLASS;
+// }
+// // prepare insert offset
+// ClassDeclaration targetClass = targetElement.node;
+// prefix = " ";
+// insertOffset = targetClass.end - 1;
+// if (targetClass.members.isEmpty) {
+// sourcePrefix = "";
+// } else {
+// sourcePrefix = "${prefix}${eol}";
+// }
+// sourceSuffix = eol;
+// }
+// // build method source
+// SourceBuilder sb = new SourceBuilder.con1(insertOffset);
+// {
+// sb.append(sourcePrefix);
+// sb.append(prefix);
+// // may be "static"
+// if (staticModifier) {
+// sb.append("static ");
+// }
+// // may be return type
+// {
+// DartType type =
+// _addFix_undefinedMethod_create_getReturnType(invocation);
+// if (type != null) {
+// String typeSource = utils.getTypeSource2(type);
+// if (typeSource != "dynamic") {
+// sb.startPosition("RETURN_TYPE");
+// sb.append(typeSource);
+// sb.endPosition();
+// sb.append(" ");
+// }
+// }
+// }
+// // append name
+// {
+// sb.startPosition("NAME");
+// sb.append(name);
+// sb.endPosition();
+// }
+// _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList);
+// sb.append(") {${eol}${prefix}}");
+// sb.append(sourceSuffix);
+// }
+// // insert source
+// _addInsertEdit(insertOffset, sb.toString());
+// // add linked positions
+// if (targetSource == _source) {
+// _addLinkedPosition("NAME", sb, SourceRangeFactory.rangeNode(node));
+// }
+// _addLinkedPositions(sb);
+// // add proposal
+// _addUnitCorrectionProposal2(
+// targetSource,
+// FixKind.CREATE_METHOD,
+// [name]);
+// }
+ }
+
+ /**
+ * @return the possible return [Type], may be <code>null</code> if can not be identified.
+ */
+ DartType
+ _addFix_undefinedMethod_create_getReturnType(MethodInvocation invocation) {
+ // TODO(scheglov) implement
+// AstNode parent = invocation.parent;
+// // myFunction();
+// if (parent is ExpressionStatement) {
+// return VoidTypeImpl.instance;
+// }
+// // return myFunction();
+// if (parent is ReturnStatement) {
+// ExecutableElement executable =
+// CorrectionUtils.getEnclosingExecutableElement(invocation);
+// return executable != null ? executable.returnType : null;
+// }
+// // int v = myFunction();
+// if (parent is VariableDeclaration) {
+// VariableDeclaration variableDeclaration = parent;
+// if (identical(variableDeclaration.initializer, invocation)) {
+// VariableElement variableElement = variableDeclaration.element;
+// if (variableElement != null) {
+// return variableElement.type;
+// }
+// }
+// }
+// // v = myFunction();
+// if (parent is AssignmentExpression) {
+// AssignmentExpression assignment = parent;
+// if (identical(assignment.rightHandSide, invocation)) {
+// if (assignment.operator.type == TokenType.EQ) {
+// // v = myFunction();
+// Expression lhs = assignment.leftHandSide;
+// if (lhs != null) {
+// return lhs.bestType;
+// }
+// } else {
+// // v += myFunction();
+// MethodElement method = assignment.bestElement;
+// if (method != null) {
+// List<ParameterElement> parameters = method.parameters;
+// if (parameters.length == 1) {
+// return parameters[0].type;
+// }
+// }
+// }
+// }
+// }
+// // v + myFunction();
+// if (parent is BinaryExpression) {
+// BinaryExpression binary = parent;
+// MethodElement method = binary.bestElement;
+// if (method != null) {
+// if (identical(binary.rightOperand, invocation)) {
+// List<ParameterElement> parameters = method.parameters;
+// return parameters.length == 1 ? parameters[0].type : null;
+// }
+// }
+// }
+// // foo( myFunction() );
+// if (parent is ArgumentList) {
+// ParameterElement parameter = invocation.bestParameterElement;
+// return parameter != null ? parameter.type : null;
+// }
+// // bool
+// {
+// // assert( myFunction() );
+// if (parent is AssertStatement) {
+// AssertStatement statement = parent;
+// if (identical(statement.condition, invocation)) {
+// return coreTypeBool;
+// }
+// }
+// // if ( myFunction() ) {}
+// if (parent is IfStatement) {
+// IfStatement statement = parent;
+// if (identical(statement.condition, invocation)) {
+// return coreTypeBool;
+// }
+// }
+// // while ( myFunction() ) {}
+// if (parent is WhileStatement) {
+// WhileStatement statement = parent;
+// if (identical(statement.condition, invocation)) {
+// return coreTypeBool;
+// }
+// }
+// // do {} while ( myFunction() );
+// if (parent is DoStatement) {
+// DoStatement statement = parent;
+// if (identical(statement.condition, invocation)) {
+// return coreTypeBool;
+// }
+// }
+// // !myFunction()
+// if (parent is PrefixExpression) {
+// PrefixExpression prefixExpression = parent;
+// if (prefixExpression.operator.type == TokenType.BANG) {
+// return coreTypeBool;
+// }
+// }
+// // binary expression '&&' or '||'
+// if (parent is BinaryExpression) {
+// BinaryExpression binaryExpression = parent;
+// TokenType operatorType = binaryExpression.operator.type;
+// if (operatorType == TokenType.AMPERSAND_AMPERSAND ||
+// operatorType == TokenType.BAR_BAR) {
+// return coreTypeBool;
+// }
+// }
+// }
+ // we don't know
+ return null;
+ }
+
+ void _addFix_undefinedMethod_create_parameters(SourceBuilder sb,
+ ArgumentList argumentList) {
+ // append parameters
+ sb.append("(");
+ Set<String> excluded = new Set();
+ List<Expression> arguments = argumentList.arguments;
+ for (int i = 0; i < arguments.length; i++) {
+ Expression argument = arguments[i];
+ // append separator
+ if (i != 0) {
+ sb.append(", ");
+ }
+ // append type name
+ DartType type = argument.bestType;
+ String typeSource = utils.getTypeSource(type);
+ {
+ sb.startPosition("TYPE${i}");
+ sb.append(typeSource);
+ _addSuperTypeProposals(sb, new Set(), type);
+ sb.endPosition();
+ }
+ sb.append(" ");
+ // append parameter name
+ {
+ List<String> suggestions =
+ _getArgumentNameSuggestions(excluded, type, argument, i);
+ String favorite = suggestions[0];
+ excluded.add(favorite);
+ sb.startPosition("ARG${i}");
+ sb.append(favorite);
+ sb.addProposals(suggestions);
+ sb.endPosition();
+ }
+ }
+ }
+
+ void _addFix_undefinedMethod_useSimilar() {
+ // TODO(scheglov) implement
+// if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+// MethodInvocation invocation = node.parent as MethodInvocation;
+// String name = (node as SimpleIdentifier).name;
+// QuickFixProcessorImpl_ClosestElementFinder finder =
+// new QuickFixProcessorImpl_ClosestElementFinder(
+// name,
+// new Predicate_QuickFixProcessorImpl_addFix_undefinedMethod_useSimilar());
+// // unqualified invocation
+// Expression target = invocation.realTarget;
+// if (target == null) {
+// ClassDeclaration clazz =
+// invocation.getAncestor((node) => node is ClassDeclaration);
+// if (clazz != null) {
+// ClassElement classElement = clazz.element;
+// _updateFinderWithClassMembers(finder, classElement);
+// }
+// } else {
+// DartType type = target.bestType;
+// if (type is InterfaceType) {
+// ClassElement classElement = type.element;
+// _updateFinderWithClassMembers(finder, classElement);
+// }
+// }
+// // if we have close enough element, suggest to use it
+// String closestName = null;
+// if (finder != null && finder._distance < 5) {
+// closestName = finder._element.name;
+// _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
+// _addFix(FixKind.CHANGE_TO, [closestName]);
+// }
+// }
+ }
+
+ void _addFix_useEffectiveIntegerDivision() {
+ for (AstNode n = node; n != null; n = n.parent) {
+ if (n is MethodInvocation &&
+ n.offset == errorOffset &&
+ n.length == errorLength) {
+ MethodInvocation invocation = n as MethodInvocation;
+ Expression target = invocation.target;
+ while (target is ParenthesizedExpression) {
+ target = (target as ParenthesizedExpression).expression;
+ }
+ // replace "/" with "~/"
+ BinaryExpression binary = target as BinaryExpression;
+ _addReplaceEdit(rf.rangeToken(binary.operator), "~/");
+ // remove everything before and after
+ _addRemoveEdit(rf.rangeStartStart(invocation, binary.leftOperand));
+ _addRemoveEdit(rf.rangeEndEnd(binary.rightOperand, invocation));
+ // add proposal
+ _addFix(FixKind.USE_EFFECTIVE_INTEGER_DIVISION, []);
+ // done
+ break;
+ }
+ }
+ }
+
+ void _addFix_useStaticAccess_method() {
+ if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+ MethodInvocation invocation = node.parent as MethodInvocation;
+ if (invocation.methodName == node) {
+ Expression target = invocation.target;
+ String targetType = utils.getExpressionTypeSource(target);
+ // replace "target" with class name
+ SourceRange range = rf.rangeNode(target);
+ _addReplaceEdit(range, targetType);
+ // add proposal
+ _addFix(FixKind.CHANGE_TO_STATIC_ACCESS, [targetType]);
+ }
+ }
+ }
+
+ void _addFix_useStaticAccess_property() {
+ if (node is SimpleIdentifier) {
+ if (node.parent is PrefixedIdentifier) {
+ PrefixedIdentifier prefixed = node.parent as PrefixedIdentifier;
+ if (prefixed.identifier == node) {
+ Expression target = prefixed.prefix;
+ String targetType = utils.getExpressionTypeSource(target);
+ // replace "target" with class name
+ SourceRange range = rf.rangeNode(target);
+ _addReplaceEdit(range, targetType);
+ // add proposal
+ _addFix(FixKind.CHANGE_TO_STATIC_ACCESS, [targetType]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a new [Edit] to [edits].
+ */
+ void _addInsertEdit(int offset, String text) {
+ Edit edit = new Edit(offset, 0, text);
+ edits.add(edit);
+ }
+
+ /**
+ * Adds a single linked position to [groupId].
+ */
+ void _addLinkedPosition(String groupId, SourceRange range) {
+ _addLinkedPosition2(
+ groupId,
+ new Position(file, range.offset, range.length));
+ }
+
+ /**
+ * Adds a single linked position to [groupId].
+ */
+ void _addLinkedPosition2(String groupId, Position position) {
+ LinkedPositionGroup group = linkedPositionGroups[groupId];
+ if (group == null) {
+ group = new LinkedPositionGroup(groupId);
+ linkedPositionGroups[groupId] = group;
+ }
+ group.add(position);
+ }
+
+ /**
+ * Adds a new [Edit] to [edits].
+ */
+ void _addRemoveEdit(SourceRange range) {
+ _addReplaceEdit(range, '');
+ }
+
+ /**
+ * Adds a new [Edit] to [edits].
+ */
+ void _addReplaceEdit(SourceRange range, String text) {
+ Edit edit = new Edit(range.offset, range.length, text);
+ edits.add(edit);
+ }
+
+ void _appendParameterSource(StringBuffer sb, DartType type, String name) {
+ String parameterSource = utils.getParameterSource(type, name);
+ sb.write(parameterSource);
+ }
+
+ void _appendParameters(StringBuffer sb, List<ParameterElement> parameters,
+ Map<ParameterElement, String> defaultValueMap) {
+ sb.write("(");
+ bool firstParameter = true;
+ bool sawNamed = false;
+ bool sawPositional = false;
+ for (ParameterElement parameter in parameters) {
+ if (!firstParameter) {
+ sb.write(", ");
+ } else {
+ firstParameter = false;
+ }
+ // may be optional
+ ParameterKind parameterKind = parameter.parameterKind;
+ if (parameterKind == ParameterKind.NAMED) {
+ if (!sawNamed) {
+ sb.write("{");
+ sawNamed = true;
+ }
+ }
+ if (parameterKind == ParameterKind.POSITIONAL) {
+ if (!sawPositional) {
+ sb.write("[");
+ sawPositional = true;
+ }
+ }
+ // parameter
+ _appendParameterSource(sb, parameter.type, parameter.name);
+ // default value
+ if (defaultValueMap != null) {
+ String defaultSource = defaultValueMap[parameter];
+ if (defaultSource != null) {
+ if (sawPositional) {
+ sb.write(" = ");
+ } else {
+ sb.write(": ");
+ }
+ sb.write(defaultSource);
+ }
+ }
+ }
+ // close parameters
+ if (sawNamed) {
+ sb.write("}");
+ }
+ if (sawPositional) {
+ sb.write("]");
+ }
+ sb.write(")");
+ }
+
+// void _addLinkedPositionProposal(String group,
+// LinkedPositionProposal proposal) {
+// List<LinkedPositionProposal> nodeProposals = linkedPositionProposals[group];
+// if (nodeProposals == null) {
+// nodeProposals = <LinkedPositionProposal>[];
+// linkedPositionProposals[group] = nodeProposals;
+// }
+// nodeProposals.add(proposal);
+// }
+
+ /**
+ * @return the string to display as the name of the given constructor in a proposal name.
+ */
+ String _getConstructorProposalName(ConstructorElement constructor) {
+ StringBuffer proposalNameBuffer = new StringBuffer();
+ proposalNameBuffer.write("super");
+ // may be named
+ String constructorName = constructor.displayName;
+ if (!constructorName.isEmpty) {
+ proposalNameBuffer.write(".");
+ proposalNameBuffer.write(constructorName);
+ }
+ // parameters
+ _appendParameters(proposalNameBuffer, constructor.parameters, null);
+ // done
+ return proposalNameBuffer.toString();
+ }
+
+ /**
+ * Inserts the given [SourceBuilder] at its offset.
+ */
+ void _insertBuilder(SourceBuilder builder) {
+ String text = builder.toString();
+ _addInsertEdit(builder.offset, text);
+ // add linked positions
+ builder.linkedPositionGroups.forEach((LinkedPositionGroup group) {
+ group.positions.forEach((Position position) {
+ _addLinkedPosition2(group.id, position);
+ });
+ });
+ }
+
+ QuickFixProcessorImpl_NewConstructorLocation
+ _prepareNewConstructorLocation(ClassDeclaration classDeclaration, String eol) {
+ List<ClassMember> members = classDeclaration.members;
+ // find the last field/constructor
+ ClassMember lastFieldOrConstructor = null;
+ for (ClassMember member in members) {
+ if (member is FieldDeclaration || member is ConstructorDeclaration) {
+ lastFieldOrConstructor = member;
+ } else {
+ break;
+ }
+ }
+ // after the field/constructor
+ if (lastFieldOrConstructor != null) {
+ return new QuickFixProcessorImpl_NewConstructorLocation(
+ "${eol}${eol}",
+ lastFieldOrConstructor.end,
+ "");
+ }
+ // at the beginning of the class
+ String suffix = members.isEmpty ? "" : eol;
+ return new QuickFixProcessorImpl_NewConstructorLocation(
+ eol,
+ classDeclaration.leftBracket.end,
+ suffix);
+ }
+
+ /**
+ * Removes any [ParenthesizedExpression] enclosing [expr].
+ *
+ * [exprPrecedence] - the effective precedence of [expr].
+ */
+ void _removeEnclosingParentheses(Expression expr, int exprPrecedence) {
+ while (expr.parent is ParenthesizedExpression) {
+ ParenthesizedExpression parenthesized =
+ expr.parent as ParenthesizedExpression;
+ if (getExpressionParentPrecedence(parenthesized) > exprPrecedence) {
+ break;
+ }
+ _addRemoveEdit(rf.rangeToken(parenthesized.leftParenthesis));
+ _addRemoveEdit(rf.rangeToken(parenthesized.rightParenthesis));
+ expr = parenthesized;
+ }
+ }
+
+ static void _addSuperTypeProposals(SourceBuilder sb,
+ Set<DartType> alreadyAdded, DartType type) {
+ if (type != null &&
+ !alreadyAdded.contains(type) &&
+ type.element is ClassElement) {
+ alreadyAdded.add(type);
+ ClassElement element = type.element as ClassElement;
+ sb.addProposal(element.name);
+ _addSuperTypeProposals(sb, alreadyAdded, element.supertype);
+ for (InterfaceType interfaceType in element.interfaces) {
+ _addSuperTypeProposals(sb, alreadyAdded, interfaceType);
+ }
+ }
+ }
+
+ /**
+ * @return the suggestions for given [Type] and [DartExpression], not empty.
+ */
+ static List<String> _getArgumentNameSuggestions(Set<String> excluded,
+ DartType type, Expression expression, int index) {
+ List<String> suggestions =
+ getVariableNameSuggestionsForExpression(type, expression, excluded);
+ if (suggestions.length != 0) {
+ return suggestions;
+ }
+ return <String>["arg${index}"];
+ }
+
+ /**
+ * Returns `true` if [node] is a type name.
+ */
+ static bool _mayBeTypeIdentifier(AstNode node) {
+ if (node is SimpleIdentifier) {
+ AstNode parent = node.parent;
+ if (parent is TypeName) {
+ return true;
+ }
+ if (parent is MethodInvocation) {
+ return parent.realTarget == node;
+ }
+ if (parent is PrefixedIdentifier) {
+ return parent.prefix == node;
+ }
+ }
+ return false;
+ }
+}
+
+
+/**
+ * Describes the location for a newly created [ConstructorDeclaration].
+ *
+ * TODO(scheglov) rename
+ */
+class QuickFixProcessorImpl_NewConstructorLocation {
+ final String _prefix;
+ final int _offset;
+ final String _suffix;
+
+ QuickFixProcessorImpl_NewConstructorLocation(this._prefix, this._offset,
+ this._suffix);
+}
diff --git a/pkg/analysis_services/lib/src/correction/name_suggestion.dart b/pkg/analysis_services/lib/src/correction/name_suggestion.dart
new file mode 100644
index 0000000..7440be1
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/name_suggestion.dart
@@ -0,0 +1,258 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.name_suggestion;
+
+import 'package:analysis_services/src/correction/strings.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+
+
+List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];
+
+/**
+ * Returns a list of words for the given camel case string.
+ *
+ * 'getCamelWords' => ['get', 'Camel', 'Words']
+ * 'getHTMLText' => ['get', 'HTML', 'Text']
+ */
+List<String> getCamelWords(String str) {
+ if (str == null || str.isEmpty) {
+ return <String>[];
+ }
+ List<String> parts = <String>[];
+ bool wasLowerCase = false;
+ bool wasUpperCase = false;
+ int wordStart = 0;
+ for (int i = 0; i < str.length; i++) {
+ int c = str.codeUnitAt(i);
+ var newLowerCase = isLowerCase(c);
+ var newUpperCase = isUpperCase(c);
+ // myWord
+ // | ^
+ if (wasLowerCase && newUpperCase) {
+ parts.add(str.substring(wordStart, i));
+ wordStart = i;
+ }
+ // myHTMLText
+ // | ^
+ if (wasUpperCase &&
+ newUpperCase &&
+ i + 1 < str.length &&
+ isLowerCase(str.codeUnitAt(i + 1))) {
+ parts.add(str.substring(wordStart, i));
+ wordStart = i;
+ }
+ wasLowerCase = newLowerCase;
+ wasUpperCase = newUpperCase;
+ }
+ parts.add(str.substring(wordStart));
+ return parts;
+}
+
+/**
+ * Returns possible names for a [String] variable with [text] value.
+ */
+List<String> getVariableNameSuggestionsForText(String text,
+ Set<String> excluded) {
+ // filter out everything except of letters and white spaces
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < text.length; i++) {
+ int c = text.codeUnitAt(i);
+ if (isLetter(c) || isWhitespace(c)) {
+ sb.writeCharCode(c);
+ }
+ }
+ text = sb.toString();
+ }
+ // make single camel-case text
+ {
+ List<String> words = text.split(' ');
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < words.length; i++) {
+ String word = words[i];
+ if (i > 0) {
+ word = capitalize(word);
+ }
+ sb.write(word);
+ }
+ text = sb.toString();
+ }
+ // split camel-case into separate suggested names
+ Set<String> res = new Set();
+ _addAll(excluded, res, _getCamelWordCombinations(text));
+ return new List.from(res);
+}
+
+/**
+ * Returns possible names for a variable with the given expected type and
+ * expression assigned.
+ */
+List<String> getVariableNameSuggestionsForExpression(DartType expectedType,
+ Expression assignedExpression, Set<String> excluded) {
+ Set<String> res = new Set();
+ // use expression
+ if (assignedExpression != null) {
+ String nameFromExpression = _getBaseNameFromExpression(assignedExpression);
+ if (nameFromExpression != null) {
+ nameFromExpression = removeStart(nameFromExpression, '_');
+ _addAll(excluded, res, _getCamelWordCombinations(nameFromExpression));
+ }
+ String nameFromParent =
+ _getBaseNameFromLocationInParent(assignedExpression);
+ if (nameFromParent != null) {
+ _addAll(excluded, res, _getCamelWordCombinations(nameFromParent));
+ }
+ }
+ // use type
+ if (expectedType != null && !expectedType.isDynamic) {
+ String typeName = expectedType.name;
+ if ('int' == typeName) {
+ _addSingleCharacterName(excluded, res, 0x69);
+ } else if ('double' == typeName) {
+ _addSingleCharacterName(excluded, res, 0x64);
+ } else if ('String' == typeName) {
+ _addSingleCharacterName(excluded, res, 0x73);
+ } else {
+ _addAll(excluded, res, _getCamelWordCombinations(typeName));
+ }
+ res.remove(typeName);
+ }
+ // done
+ return new List.from(res);
+}
+
+/**
+ * Adds [toAdd] items which are not excluded.
+ */
+void _addAll(Set<String> excluded, Set<String> result, Iterable<String> toAdd) {
+ for (String item in toAdd) {
+ // add name based on "item", but not "excluded"
+ for (int suffix = 1; ; suffix++) {
+ // prepare name, just "item" or "item2", "item3", etc
+ String name = item;
+ if (suffix > 1) {
+ name += suffix.toString();
+ }
+ // add once found not excluded
+ if (!excluded.contains(name)) {
+ result.add(name);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Adds to [result] either [c] or the first ASCII character after it.
+ */
+void _addSingleCharacterName(Set<String> excluded, Set<String> result, int c) {
+ while (c < 0x7A) {
+ String name = new String.fromCharCode(c);
+ // may be done
+ if (!excluded.contains(name)) {
+ result.add(name);
+ break;
+ }
+ // next character
+ c = c + 1;
+ }
+}
+
+String _getBaseNameFromExpression(Expression expression) {
+ String name = null;
+ // e as Type
+ if (expression is AsExpression) {
+ AsExpression asExpression = expression as AsExpression;
+ expression = asExpression.expression;
+ }
+ // analyze expressions
+ if (expression is SimpleIdentifier) {
+ SimpleIdentifier node = expression;
+ return node.name;
+ } else if (expression is PrefixedIdentifier) {
+ PrefixedIdentifier node = expression;
+ return node.identifier.name;
+ } else if (expression is MethodInvocation) {
+ name = expression.methodName.name;
+ } else if (expression is InstanceCreationExpression) {
+ InstanceCreationExpression creation = expression;
+ ConstructorName constructorName = creation.constructorName;
+ TypeName typeName = constructorName.type;
+ if (typeName != null) {
+ Identifier typeNameIdentifier = typeName.name;
+ // new ClassName()
+ if (typeNameIdentifier is SimpleIdentifier) {
+ return typeNameIdentifier.name;
+ }
+ // new prefix.name();
+ if (typeNameIdentifier is PrefixedIdentifier) {
+ PrefixedIdentifier prefixed = typeNameIdentifier;
+ // new prefix.ClassName()
+ if (prefixed.prefix.staticElement is PrefixElement) {
+ return prefixed.identifier.name;
+ }
+ // new ClassName.constructorName()
+ return prefixed.prefix.name;
+ }
+ }
+ }
+ // strip known prefixes
+ if (name != null) {
+ for (int i = 0; i < _KNOWN_METHOD_NAME_PREFIXES.length; i++) {
+ String curr = _KNOWN_METHOD_NAME_PREFIXES[i];
+ if (name.startsWith(curr)) {
+ if (name == curr) {
+ return null;
+ } else if (isUpperCase(name.codeUnitAt(curr.length))) {
+ return name.substring(curr.length);
+ }
+ }
+ }
+ }
+ // done
+ return name;
+}
+
+
+String _getBaseNameFromLocationInParent(Expression expression) {
+ // value in named expression
+ if (expression.parent is NamedExpression) {
+ NamedExpression namedExpression = expression.parent as NamedExpression;
+ if (identical(namedExpression.expression, expression)) {
+ return namedExpression.name.label.name;
+ }
+ }
+ // positional argument
+ {
+ ParameterElement parameter = expression.propagatedParameterElement;
+ if (parameter == null) {
+ parameter = expression.staticParameterElement;
+ }
+ if (parameter != null) {
+ return parameter.displayName;
+ }
+ }
+ // unknown
+ return null;
+}
+
+/**
+ * Returns all variants of names by removing leading words one by one.
+ */
+List<String> _getCamelWordCombinations(String name) {
+ List<String> result = [];
+ List<String> parts = getCamelWords(name);
+ for (int i = 0; i < parts.length; i++) {
+ var s1 = parts[i].toLowerCase();
+ var s2 = parts.skip(i + 1).join();
+ String suggestion = '$s1$s2';
+ result.add(suggestion);
+ }
+ return result;
+}
diff --git a/pkg/analysis_services/lib/src/correction/source_buffer.dart b/pkg/analysis_services/lib/src/correction/source_buffer.dart
new file mode 100644
index 0000000..fb9e204
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/source_buffer.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.source_buffer;
+
+import 'package:analysis_services/correction/change.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+
+/**
+ * Helper for building Dart source with linked positions.
+ */
+class SourceBuilder {
+ final String file;
+ final int offset;
+ final StringBuffer _buffer = new StringBuffer();
+
+ final List<LinkedPositionGroup> linkedPositionGroups = <LinkedPositionGroup>[
+ ];
+ LinkedPositionGroup _currentLinkedPositionGroup;
+ int _currentPositionStart;
+
+ SourceBuilder(this.file, this.offset);
+
+ void addProposal(String proposal) {
+ // TODO(scheglov) implement
+// _currentPositionGroup.addProposal();
+ }
+
+ void addProposals(List<String> proposals) {
+ proposals.forEach((proposal) => addProposal(proposal));
+ }
+
+ /**
+ * Appends [s] to the buffer.
+ */
+ SourceBuilder append(String s) {
+ _buffer.write(s);
+ return this;
+ }
+
+ /**
+ * Ends position started using [startPosition].
+ */
+ void endPosition() {
+ assert(_currentLinkedPositionGroup != null);
+ _addPosition();
+ _currentLinkedPositionGroup = null;
+ }
+
+ /**
+ * Marks start of a new linked position for the group with the given ID.
+ */
+ void startPosition(String groupId) {
+ assert(_currentLinkedPositionGroup == null);
+ for (LinkedPositionGroup position in linkedPositionGroups) {
+ if (position.id == groupId) {
+ _currentLinkedPositionGroup = position;
+ break;
+ }
+ }
+ if (_currentLinkedPositionGroup == null) {
+ _currentLinkedPositionGroup = new LinkedPositionGroup(groupId);
+ linkedPositionGroups.add(_currentLinkedPositionGroup);
+ }
+ _currentPositionStart = _buffer.length;
+ }
+
+ @override
+ String toString() => _buffer.toString();
+
+ /**
+ * Adds position location [SourceRange] using current fields.
+ */
+ void _addPosition() {
+ int start = offset + _currentPositionStart;
+ int end = offset + _buffer.length;
+ Position position = new Position(file, start, end - start);
+ _currentLinkedPositionGroup.add(position);
+ }
+}
diff --git a/pkg/analysis_services/lib/correction/source_range_factory.dart b/pkg/analysis_services/lib/src/correction/source_range.dart
similarity index 81%
rename from pkg/analysis_services/lib/correction/source_range_factory.dart
rename to pkg/analysis_services/lib/src/correction/source_range.dart
index 4637ed8..433d5e6 100644
--- a/pkg/analysis_services/lib/correction/source_range_factory.dart
+++ b/pkg/analysis_services/lib/src/correction/source_range.dart
@@ -5,7 +5,7 @@
// This code was auto-generated, is not intended to be edited, and is subject to
// significant change. Please see the README file for more information.
-library services.correction.source_range_factory;
+library services.src.correction.source_range_factory;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
@@ -24,10 +24,6 @@
return new SourceRange(offset, length);
}
-SourceRange rangeEndLength(a, int length) {
- return new SourceRange(a.nameOffset, length);
-}
-
SourceRange rangeEndStart(a, b) {
int offset = a.end;
var length = b.offset - offset;
@@ -52,22 +48,23 @@
}
SourceRange rangeStartEnd(a, b) {
- int offset = a.offset;
- var length = b.end - offset;
+ int offset = a is int ? a : a.offset;
+ int end = b is int ? b : b.end;
+ var length = end - offset;
return new SourceRange(offset, length);
}
SourceRange rangeStartLength(a, int length) {
- int offset = a.offset;
+ int offset = a is int ? a : a.offset;
return new SourceRange(offset, length);
}
SourceRange rangeStartStart(a, b) {
- int offset = a.offset;
- var length = b.offset - offset;
+ int offset = a is int ? a : a.offset;
+ var length = (b is int ? b : b.offset) - offset;
return new SourceRange(offset, length);
}
-SourceRange rangeToken(Token node) {
- return new SourceRange(node.offset, node.length);
+SourceRange rangeToken(Token token) {
+ return new SourceRange(token.offset, token.length);
}
diff --git a/pkg/analysis_services/lib/src/correction/strings.dart b/pkg/analysis_services/lib/src/correction/strings.dart
new file mode 100644
index 0000000..14887cc
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/strings.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.strings;
+
+
+String capitalize(String str) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ return str.substring(0, 1).toUpperCase() + str.substring(1);
+}
+
+bool isDigit(int c) {
+ return c >= 0x30 && c <= 0x39;
+}
+
+bool isEmpty(String str) {
+ return str == null || str.isEmpty;
+}
+
+bool isLetter(int c) {
+ return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A);
+}
+
+bool isLowerCase(int c) {
+ return c >= 0x61 && c <= 0x7A;
+}
+
+bool isSpace(int c) => c == 0x20 || c == 0x09;
+
+bool isUpperCase(int c) {
+ return c >= 0x41 && c <= 0x5A;
+}
+
+bool isWhitespace(int c) {
+ return isSpace(c) || c == 0x0D || c == 0x0A;
+}
+
+String remove(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ return str.replaceAll(remove, '');
+}
+
+String removeStart(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ if (str.startsWith(remove)) {
+ return str.substring(remove.length);
+ }
+ return str;
+}
+
+String repeat(String s, int n) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < n; i++) {
+ sb.write(s);
+ }
+ return sb.toString();
+}
diff --git a/pkg/analysis_services/lib/src/correction/util.dart b/pkg/analysis_services/lib/src/correction/util.dart
new file mode 100644
index 0000000..e868a0f
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/util.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.util;
+
+import 'package:analysis_services/src/correction/source_range.dart';
+import 'package:analysis_services/src/correction/strings.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+
+String getDefaultValueCode(DartType type) {
+ if (type != null) {
+ String typeName = type.displayName;
+ if (typeName == "bool") {
+ return "false";
+ }
+ if (typeName == "int") {
+ return "0";
+ }
+ if (typeName == "double") {
+ return "0.0";
+ }
+ if (typeName == "String") {
+ return "''";
+ }
+ }
+ // no better guess
+ return "null";
+}
+
+
+/**
+ * Returns [getExpressionPrecedence] for the parent of [node],
+ * or `0` if the parent node is [ParenthesizedExpression].
+ *
+ * The reason is that `(expr)` is always executed after `expr`.
+ */
+int getExpressionParentPrecedence(AstNode node) {
+ AstNode parent = node.parent;
+ if (parent is ParenthesizedExpression) {
+ return 0;
+ }
+ return getExpressionPrecedence(parent);
+}
+
+
+/**
+ * Returns the precedence of [node] it is an [Expression], negative otherwise.
+ */
+int getExpressionPrecedence(AstNode node) {
+ if (node is Expression) {
+ return node.precedence;
+ }
+ return -1000;
+}
+
+
+/**
+ * Returns the namespace of the given [ImportElement].
+ */
+Map<String, Element> getImportNamespace(ImportElement imp) {
+ NamespaceBuilder builder = new NamespaceBuilder();
+ Namespace namespace = builder.createImportNamespaceForDirective(imp);
+ return namespace.definedNames;
+}
+
+
+class CorrectionUtils {
+ final CompilationUnit unit;
+
+ LibraryElement _library;
+ String _buffer;
+ String _endOfLine;
+
+ CorrectionUtils(this.unit) {
+ CompilationUnitElement unitElement = unit.element;
+ this._library = unitElement.library;
+ this._buffer = unitElement.context.getContents(unitElement.source).data;
+ }
+
+ /**
+ * Returns the EOL to use for this [CompilationUnit].
+ */
+ String get endOfLine {
+ if (_endOfLine == null) {
+ if (_buffer.contains("\r\n")) {
+ _endOfLine = "\r\n";
+ } else {
+ _endOfLine = "\n";
+ }
+ }
+ return _endOfLine;
+ }
+
+ /**
+ * Skips whitespace characters and single EOL on the right from [index].
+ *
+ * If [index] the end of a statement or method, then in the most cases it is
+ * a start of the next line.
+ */
+ int getLineContentEnd(int index) {
+ int length = _buffer.length;
+ // skip whitespace characters
+ while (index < length) {
+ int c = _buffer.codeUnitAt(index);
+ if (!isWhitespace(c) || c == 0x0D || c == 0x0A) {
+ break;
+ }
+ index++;
+ }
+ // skip single \r
+ if (index < length && _buffer.codeUnitAt(index) == 0x0D) {
+ index++;
+ }
+ // skip single \n
+ if (index < length && _buffer.codeUnitAt(index) == 0x0A) {
+ index++;
+ }
+ // done
+ return index;
+ }
+
+ /**
+ * Skips spaces and tabs on the left from [index].
+ *
+ * If [index] is the start or a statement, then in the most cases it is a
+ * start on its line.
+ */
+ int getLineContentStart(int index) {
+ while (index > 0) {
+ int c = _buffer.codeUnitAt(index - 1);
+ if (!isSpace(c)) {
+ break;
+ }
+ index--;
+ }
+ return index;
+ }
+
+ /**
+ * Returns a [SourceRange] that covers [range] and extends (if possible) to
+ * cover whole lines.
+ */
+ SourceRange getLinesRange(SourceRange range) {
+ // start
+ int startOffset = range.offset;
+ int startLineOffset = getLineContentStart(startOffset);
+ // end
+ int endOffset = range.end;
+ int afterEndLineOffset = getLineContentEnd(endOffset);
+ // range
+ return rangeStartEnd(startLineOffset, afterEndLineOffset);
+ }
+
+ /**
+ * @return the source for the parameter with the given type and name.
+ */
+ String getParameterSource(DartType type, String name) {
+ // no type
+ if (type == null || type.isDynamic) {
+ return name;
+ }
+ // function type
+ if (type is FunctionType) {
+ FunctionType functionType = type;
+ StringBuffer sb = new StringBuffer();
+ // return type
+ DartType returnType = functionType.returnType;
+ if (returnType != null && !returnType.isDynamic) {
+ sb.write(getTypeSource(returnType));
+ sb.write(' ');
+ }
+ // parameter name
+ sb.write(name);
+ // parameters
+ sb.write('(');
+ List<ParameterElement> fParameters = functionType.parameters;
+ for (int i = 0; i < fParameters.length; i++) {
+ ParameterElement fParameter = fParameters[i];
+ if (i != 0) {
+ sb.write(", ");
+ }
+ sb.write(getParameterSource(fParameter.type, fParameter.name));
+ }
+ sb.write(')');
+ // done
+ return sb.toString();
+ }
+ // simple type
+ return "${getTypeSource(type)} ${name}";
+ }
+
+ /**
+ * Returns the actual type source of the given [Expression], may be `null`
+ * if can not be resolved, should be treated as the `dynamic` type.
+ */
+ String getExpressionTypeSource(Expression expression) {
+ if (expression == null) {
+ return null;
+ }
+ DartType type = expression.bestType;
+ String typeSource = getTypeSource(type);
+ if ("dynamic" == typeSource) {
+ return null;
+ }
+ return typeSource;
+ }
+
+ /**
+ * Returns the source to reference [type] in this [CompilationUnit].
+ */
+ String getTypeSource(DartType type) {
+ StringBuffer sb = new StringBuffer();
+ // prepare element
+ Element element = type.element;
+ if (element == null) {
+ String source = type.toString();
+ source = source.replaceAll('<dynamic>', '');
+ source = source.replaceAll('<dynamic, dynamic>', '');
+ return source;
+ }
+ // append prefix
+ {
+ ImportElement imp = _getImportElement(element);
+ if (imp != null && imp.prefix != null) {
+ sb.write(imp.prefix.displayName);
+ sb.write(".");
+ }
+ }
+ // append simple name
+ String name = element.displayName;
+ sb.write(name);
+ // may be type arguments
+ if (type is InterfaceType) {
+ InterfaceType interfaceType = type;
+ List<DartType> arguments = interfaceType.typeArguments;
+ // check if has arguments
+ bool hasArguments = false;
+ for (DartType argument in arguments) {
+ if (!argument.isDynamic) {
+ hasArguments = true;
+ break;
+ }
+ }
+ // append type arguments
+ if (hasArguments) {
+ sb.write("<");
+ for (int i = 0; i < arguments.length; i++) {
+ DartType argument = arguments[i];
+ if (i != 0) {
+ sb.write(", ");
+ }
+ sb.write(getTypeSource(argument));
+ }
+ sb.write(">");
+ }
+ }
+ // done
+ return sb.toString();
+ }
+
+ /**
+ * @return the [ImportElement] used to import given [Element] into [library].
+ * May be `null` if was not imported, i.e. declared in the same library.
+ */
+ ImportElement _getImportElement(Element element) {
+ for (ImportElement imp in _library.imports) {
+ Map<String, Element> definedNames = getImportNamespace(imp);
+ if (definedNames.containsValue(element)) {
+ return imp;
+ }
+ }
+ return null;
+ }
+}
diff --git a/pkg/analysis_services/lib/src/generated/completion.dart b/pkg/analysis_services/lib/src/generated/completion.dart
index a49b805..513fe14 100644
--- a/pkg/analysis_services/lib/src/generated/completion.dart
+++ b/pkg/analysis_services/lib/src/generated/completion.dart
@@ -23,6 +23,8 @@
import 'stubs.dart';
import 'util.dart';
+import '../../completion/completion_suggestion.dart';
+
class AstNodeClassifier_CompletionEngine_typeOf extends CompletionEngine_AstNodeClassifier {
final CompletionEngine CompletionEngine_this;
@@ -159,7 +161,7 @@
VariableDeclarationList varList = varDecl.parent as VariableDeclarationList;
TypeName type = varList.type;
if (identifier.length > 0) {
- _pName3(identifier.name, ProposalKind.VARIABLE);
+ _pName3(identifier.name, CompletionSuggestionKind.VARIABLE);
}
if (type == null) {
if (varList.keyword == null) {
@@ -189,7 +191,7 @@
ClassDeclaration classDecl = fieldName.getAncestor((node) => node is ClassDeclaration);
ClassElement classElement = classDecl.element;
for (FieldElement field in classElement.fields) {
- _pName3(field.displayName, ProposalKind.FIELD);
+ _pName3(field.displayName, CompletionSuggestionKind.FIELD);
}
}
@@ -269,7 +271,7 @@
continue;
}
// OK, add proposal
- CompletionProposal prop = _createProposal4(ProposalKind.NAMED_ARGUMENT);
+ CompletionProposal prop = _createProposal4(CompletionSuggestionKind.NAMED_ARGUMENT);
prop.setCompletion(parameterName);
prop.setParameterName(parameterName);
prop.setParameterType(parameterElement.type.displayName);
@@ -319,7 +321,7 @@
ParameterElement parameter = parameters[argIndex];
if (parameter.parameterKind != ParameterKind.NAMED) {
String parameterName = parameter.displayName;
- CompletionProposal prop = _createProposal4(ProposalKind.OPTIONAL_ARGUMENT);
+ CompletionProposal prop = _createProposal4(CompletionSuggestionKind.OPTIONAL_ARGUMENT);
prop.setCompletion(parameterName);
prop.setParameterName(parameterName);
prop.setParameterType(parameter.type.displayName);
@@ -587,7 +589,7 @@
if (_filterDisallows2(uri)) {
continue;
}
- CompletionProposal prop = _createProposal4(ProposalKind.IMPORT);
+ CompletionProposal prop = _createProposal4(CompletionSuggestionKind.IMPORT);
prop.setCompletion(uri);
// put "lib" before "lib/src"
if (!uri.contains("/src/")) {
@@ -668,7 +670,7 @@
continue;
}
// add with "dart:" prefix
- _pName3("dart:${name}", ProposalKind.IMPORT);
+ _pName3("dart:${name}", CompletionSuggestionKind.IMPORT);
}
}
@@ -770,7 +772,7 @@
}
CompletionProposal _createProposal3(Element element, String completion) {
- ProposalKind kind = _proposalKindOf(element);
+ CompletionSuggestionKind kind = _proposalKindOf(element);
CompletionProposal prop = _createProposal4(kind);
prop.setElement(element);
prop.setCompletion(completion);
@@ -784,7 +786,7 @@
return prop;
}
- CompletionProposal _createProposal4(ProposalKind kind) => _factory.createCompletionProposal(kind, _completionTokenOffset());
+ CompletionProposal _createProposal4(CompletionSuggestionKind kind) => _factory.createCompletionProposal(kind, _completionTokenOffset());
List<LibraryElement> _currentLibraryList() {
Set<LibraryElement> libraries = new Set<LibraryElement>();
@@ -1007,7 +1009,7 @@
return;
}
// fill arguments proposal
- CompletionProposal prop = _createProposal4(ProposalKind.ARGUMENT_LIST);
+ CompletionProposal prop = _createProposal4(CompletionSuggestionKind.ARGUMENT_LIST);
prop.setElement(proposal.element);
prop.setCompletion(proposal.completion).setReturnType(proposal.returnType);
prop.setParameterNames(parameterNames);
@@ -1019,7 +1021,7 @@
}
void _pDynamic() {
- _pWord(_C_DYNAMIC, ProposalKind.VARIABLE);
+ _pWord(_C_DYNAMIC, CompletionSuggestionKind.VARIABLE);
}
void _pExecutable(Element element, FunctionType functionType, SimpleIdentifier identifier, bool isPotentialMatch) {
@@ -1039,7 +1041,7 @@
DartType parameterType = _state._targetParameter.type;
if (parameterType is FunctionType) {
if (functionType.isAssignableTo(parameterType)) {
- _pName2(name, element, CompletionProposal.RELEVANCE_HIGH, ProposalKind.METHOD_NAME);
+ _pName2(name, element, CompletionProposal.RELEVANCE_HIGH, CompletionSuggestionKind.METHOD_NAME);
}
}
}
@@ -1052,7 +1054,7 @@
prop.setCompletion(name).setReturnType(functionType.returnType.displayName);
// If there is already argument list, then update only method name.
if (identifier.parent is MethodInvocation && (identifier.parent as MethodInvocation).argumentList != null) {
- prop.setKind(ProposalKind.METHOD_NAME);
+ prop.setKind(CompletionSuggestionKind.METHOD_NAME);
}
Element container = element.enclosingElement;
if (container != null) {
@@ -1086,7 +1088,7 @@
}
void _pFalse() {
- _pWord(_C_FALSE, ProposalKind.VARIABLE);
+ _pWord(_C_FALSE, CompletionSuggestionKind.VARIABLE);
}
void _pField(FieldElement element, SimpleIdentifier identifier, ClassElement classElement) {
@@ -1114,7 +1116,7 @@
if (_context.selectionOffset == node.keyword.end) {
newUri = " ${newUri}";
}
- _pName3(newUri, ProposalKind.IMPORT);
+ _pName3(newUri, CompletionSuggestionKind.IMPORT);
}
void _pKeyword(Token keyword) {
@@ -1122,7 +1124,7 @@
// This isn't as useful as it might seem. It only works in the case that completion
// is requested on an existing recognizable keyword.
// TODO: Add keyword proposal kind
- CompletionProposal prop = _createProposal4(ProposalKind.LIBRARY_PREFIX);
+ CompletionProposal prop = _createProposal4(CompletionSuggestionKind.LIBRARY_PREFIX);
prop.setCompletion(keyword.lexeme);
_requestor.accept(prop);
}
@@ -1134,7 +1136,7 @@
}
}
- void _pName2(String name, Element element, int relevance, ProposalKind kind) {
+ void _pName2(String name, Element element, int relevance, CompletionSuggestionKind kind) {
if (_filterDisallows2(name)) {
return;
}
@@ -1145,7 +1147,7 @@
_requestor.accept(prop);
}
- void _pName3(String name, ProposalKind kind) {
+ void _pName3(String name, CompletionSuggestionKind kind) {
if (_filterDisallows2(name)) {
return;
}
@@ -1175,47 +1177,47 @@
}
void _pNull() {
- _pWord(_C_NULL, ProposalKind.VARIABLE);
+ _pWord(_C_NULL, CompletionSuggestionKind.VARIABLE);
}
void _pParamName(String name) {
if (_filterDisallows2(name)) {
return;
}
- CompletionProposal prop = _createProposal4(ProposalKind.PARAMETER);
+ CompletionProposal prop = _createProposal4(CompletionSuggestionKind.PARAMETER);
prop.setCompletion(name);
_requestor.accept(prop);
}
- ProposalKind _proposalKindOf(Element element) {
- ProposalKind kind;
+ CompletionSuggestionKind _proposalKindOf(Element element) {
+ CompletionSuggestionKind kind;
while (true) {
if (element.kind == ElementKind.CONSTRUCTOR) {
- kind = ProposalKind.CONSTRUCTOR;
+ kind = CompletionSuggestionKind.CONSTRUCTOR;
} else if (element.kind == ElementKind.FUNCTION) {
- kind = ProposalKind.FUNCTION;
+ kind = CompletionSuggestionKind.FUNCTION;
} else if (element.kind == ElementKind.METHOD) {
- kind = ProposalKind.METHOD;
+ kind = CompletionSuggestionKind.METHOD;
} else if (element.kind == ElementKind.GETTER) {
- kind = ProposalKind.GETTER;
+ kind = CompletionSuggestionKind.GETTER;
} else if (element.kind == ElementKind.SETTER) {
- kind = ProposalKind.SETTER;
+ kind = CompletionSuggestionKind.SETTER;
} else if (element.kind == ElementKind.CLASS) {
- kind = ProposalKind.CLASS;
+ kind = CompletionSuggestionKind.CLASS;
} else if (element.kind == ElementKind.FIELD) {
- kind = ProposalKind.FIELD;
+ kind = CompletionSuggestionKind.FIELD;
} else if (element.kind == ElementKind.IMPORT) {
- kind = ProposalKind.IMPORT;
+ kind = CompletionSuggestionKind.IMPORT;
} else if (element.kind == ElementKind.PARAMETER) {
- kind = ProposalKind.PARAMETER;
+ kind = CompletionSuggestionKind.PARAMETER;
} else if (element.kind == ElementKind.PREFIX) {
- kind = ProposalKind.LIBRARY_PREFIX;
+ kind = CompletionSuggestionKind.LIBRARY_PREFIX;
} else if (element.kind == ElementKind.FUNCTION_TYPE_ALIAS) {
- kind = ProposalKind.CLASS_ALIAS;
+ kind = CompletionSuggestionKind.CLASS_ALIAS;
} else if (element.kind == ElementKind.TYPE_PARAMETER) {
- kind = ProposalKind.TYPE_PARAMETER;
+ kind = CompletionSuggestionKind.TYPE_PARAMETER;
} else if (element.kind == ElementKind.LOCAL_VARIABLE || element.kind == ElementKind.TOP_LEVEL_VARIABLE) {
- kind = ProposalKind.VARIABLE;
+ kind = CompletionSuggestionKind.VARIABLE;
} else {
throw new IllegalArgumentException();
}
@@ -1241,8 +1243,8 @@
// propose each Element
for (Element element in nameCollector.uniqueElements) {
CompletionProposal proposal = _createProposal(element);
- if (proposal.kind == ProposalKind.FUNCTION) {
- proposal.setKind(ProposalKind.METHOD_NAME);
+ if (proposal.kind == CompletionSuggestionKind.FUNCTION) {
+ proposal.setKind(CompletionSuggestionKind.METHOD_NAME);
}
_requestor.accept(proposal);
}
@@ -1277,18 +1279,18 @@
}
void _pTrue() {
- _pWord(_C_TRUE, ProposalKind.VARIABLE);
+ _pWord(_C_TRUE, CompletionSuggestionKind.VARIABLE);
}
void _pVar() {
- _pWord(_C_VAR, ProposalKind.VARIABLE);
+ _pWord(_C_VAR, CompletionSuggestionKind.VARIABLE);
}
void _pVoid() {
- _pWord(_C_VOID, ProposalKind.VARIABLE);
+ _pWord(_C_VOID, CompletionSuggestionKind.VARIABLE);
}
- void _pWord(String word, ProposalKind kind) {
+ void _pWord(String word, CompletionSuggestionKind kind) {
if (_filterDisallows2(word)) {
return;
}
@@ -1473,7 +1475,7 @@
if (proposal != null) {
// we don't want to add arguments, just names
if (element is MethodElement || element is FunctionElement) {
- proposal.setKind(ProposalKind.METHOD_NAME);
+ proposal.setKind(CompletionSuggestionKind.METHOD_NAME);
}
// elevate priority for local elements
if (_enclosingElements.contains(element.enclosingElement)) {
@@ -1590,7 +1592,7 @@
Object visitConstructorDeclaration(ConstructorDeclaration node) {
if (identical(node.returnType, _completionNode)) {
CompletionEngine_this._filter = CompletionEngine_this._createFilter(_completionNode);
- CompletionEngine_this._pName3(_completionNode.name, ProposalKind.CONSTRUCTOR);
+ CompletionEngine_this._pName3(_completionNode.name, CompletionSuggestionKind.CONSTRUCTOR);
}
return null;
}
@@ -2849,7 +2851,7 @@
/**
* Create a completion proposal of the given kind.
*/
- CompletionProposal createCompletionProposal(ProposalKind kind, int insertionPoint) {
+ CompletionProposal createCompletionProposal(CompletionSuggestionKind kind, int insertionPoint) {
CompletionProposalImpl prop = new CompletionProposalImpl();
prop.setKind(kind);
prop.setLocation(insertionPoint);
@@ -2877,7 +2879,7 @@
Element get element;
- ProposalKind get kind;
+ CompletionSuggestionKind get kind;
int get location;
@@ -2917,7 +2919,7 @@
CompletionProposal setElement(Element element);
- CompletionProposal setKind(ProposalKind x);
+ CompletionProposal setKind(CompletionSuggestionKind x);
CompletionProposal setLocation(int x);
@@ -2959,7 +2961,7 @@
String _parameterType;
- ProposalKind _kind = ProposalKind.NONE;
+ CompletionSuggestionKind _kind = null;
int _location = 0;
@@ -2994,7 +2996,7 @@
Element get element => _element;
@override
- ProposalKind get kind => _kind;
+ CompletionSuggestionKind get kind => _kind;
@override
int get location => _location;
@@ -3072,7 +3074,7 @@
}
@override
- CompletionProposal setKind(ProposalKind x) {
+ CompletionProposal setKind(CompletionSuggestionKind x) {
_kind = x;
return this;
}
@@ -3667,73 +3669,6 @@
List<CompletionProposal> get proposals => _proposals;
}
-/**
- * The various kinds of completion proposals. Each specifies the kind of completion to be created,
- * corresponding to different syntactical elements.
- */
-class ProposalKind extends Enum<ProposalKind> {
- static const ProposalKind NONE = const ProposalKind('NONE', 0);
-
- static const ProposalKind CLASS = const ProposalKind('CLASS', 1);
-
- static const ProposalKind CLASS_ALIAS = const ProposalKind('CLASS_ALIAS', 2);
-
- static const ProposalKind CONSTRUCTOR = const ProposalKind('CONSTRUCTOR', 3);
-
- static const ProposalKind FIELD = const ProposalKind('FIELD', 4);
-
- static const ProposalKind FUNCTION = const ProposalKind('FUNCTION', 5);
-
- static const ProposalKind FUNCTION_ALIAS = const ProposalKind('FUNCTION_ALIAS', 6);
-
- static const ProposalKind GETTER = const ProposalKind('GETTER', 7);
-
- static const ProposalKind IMPORT = const ProposalKind('IMPORT', 8);
-
- static const ProposalKind LIBRARY_PREFIX = const ProposalKind('LIBRARY_PREFIX', 9);
-
- static const ProposalKind METHOD = const ProposalKind('METHOD', 10);
-
- static const ProposalKind METHOD_NAME = const ProposalKind('METHOD_NAME', 11);
-
- static const ProposalKind PARAMETER = const ProposalKind('PARAMETER', 12);
-
- static const ProposalKind SETTER = const ProposalKind('SETTER', 13);
-
- static const ProposalKind VARIABLE = const ProposalKind('VARIABLE', 14);
-
- static const ProposalKind TYPE_PARAMETER = const ProposalKind('TYPE_PARAMETER', 15);
-
- static const ProposalKind ARGUMENT_LIST = const ProposalKind('ARGUMENT_LIST', 16);
-
- static const ProposalKind OPTIONAL_ARGUMENT = const ProposalKind('OPTIONAL_ARGUMENT', 17);
-
- static const ProposalKind NAMED_ARGUMENT = const ProposalKind('NAMED_ARGUMENT', 18);
-
- static const List<ProposalKind> values = const [
- NONE,
- CLASS,
- CLASS_ALIAS,
- CONSTRUCTOR,
- FIELD,
- FUNCTION,
- FUNCTION_ALIAS,
- GETTER,
- IMPORT,
- LIBRARY_PREFIX,
- METHOD,
- METHOD_NAME,
- PARAMETER,
- SETTER,
- VARIABLE,
- TYPE_PARAMETER,
- ARGUMENT_LIST,
- OPTIONAL_ARGUMENT,
- NAMED_ARGUMENT];
-
- const ProposalKind(String name, int ordinal) : super(name, ordinal);
-}
-
class SearchFilter_CompletionEngine_allSubtypes implements SearchFilter {
ClassElement classElement;
diff --git a/pkg/analysis_services/test/correction/change_test.dart b/pkg/analysis_services/test/correction/change_test.dart
new file mode 100644
index 0000000..d0fd91e
--- /dev/null
+++ b/pkg/analysis_services/test/correction/change_test.dart
@@ -0,0 +1,447 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.change;
+
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart';
+
+
+main() {
+ groupSep = ' | ';
+ group('ChangeTest', () {
+ runReflectiveTests(ChangeTest);
+ });
+ group('EditTest', () {
+ runReflectiveTests(EditTest);
+ });
+ group('FileEditTest', () {
+ runReflectiveTests(FileEditTest);
+ });
+ group('LinkedPositionGroupTest', () {
+ runReflectiveTests(LinkedPositionGroupTest);
+ });
+ group('PositionTest', () {
+ runReflectiveTests(PositionTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class ChangeTest {
+// void test_fromJson() {
+// var json = {
+// OFFSET: 1,
+// LENGTH: 2,
+// REPLACEMENT: 'foo'
+// };
+// Edit edit = Edit.fromJson(json);
+// expect(edit.offset, 1);
+// expect(edit.length, 2);
+// expect(edit.replacement, 'foo');
+// }
+
+ void test_fromJson() {
+ var json = {
+ MESSAGE: 'msg',
+ EDITS: [{
+ FILE: '/a.dart',
+ EDITS: [{
+ OFFSET: 1,
+ LENGTH: 2,
+ REPLACEMENT: 'aaa'
+ }, {
+ OFFSET: 10,
+ LENGTH: 20,
+ REPLACEMENT: 'bbb'
+ }]
+ }, {
+ FILE: '/b.dart',
+ EDITS: [{
+ OFFSET: 21,
+ LENGTH: 22,
+ REPLACEMENT: 'xxx'
+ }, {
+ OFFSET: 210,
+ LENGTH: 220,
+ REPLACEMENT: 'yyy'
+ }]
+ }],
+ LINKED_POSITION_GROUPS: [{
+ ID: 'id-a',
+ POSITIONS: [{
+ FILE: '/ga.dart',
+ OFFSET: 1,
+ LENGTH: 2
+ }, {
+ FILE: '/ga.dart',
+ OFFSET: 10,
+ LENGTH: 2
+ }]
+ }, {
+ ID: 'id-b',
+ POSITIONS: [{
+ FILE: '/gb.dart',
+ OFFSET: 10,
+ LENGTH: 5
+ }, {
+ FILE: '/gb.dart',
+ OFFSET: 100,
+ LENGTH: 5
+ }]
+ }]
+ };
+ Change change = Change.fromJson(json);
+ expect(change.message, 'msg');
+ // edits
+ expect(change.edits, hasLength(2));
+ {
+ FileEdit fileEdit = change.edits[0];
+ expect(fileEdit.file, '/a.dart');
+ expect(fileEdit.edits, hasLength(2));
+ expect(fileEdit.edits[0], new Edit(1, 2, 'aaa'));
+ expect(fileEdit.edits[1], new Edit(10, 20, 'bbb'));
+ }
+ {
+ FileEdit fileEdit = change.edits[1];
+ expect(fileEdit.file, '/b.dart');
+ expect(fileEdit.edits, hasLength(2));
+ expect(fileEdit.edits[0], new Edit(21, 22, 'xxx'));
+ expect(fileEdit.edits[1], new Edit(210, 220, 'yyy'));
+ }
+ // linked position groups
+ expect(change.linkedPositionGroups, hasLength(2));
+ {
+ LinkedPositionGroup group = change.linkedPositionGroups[0];
+ expect(group.id, 'id-a');
+ expect(group.positions, hasLength(2));
+ expect(group.positions[0], new Position('/ga.dart', 1, 2));
+ expect(group.positions[1], new Position('/ga.dart', 10, 2));
+ }
+ {
+ LinkedPositionGroup group = change.linkedPositionGroups[1];
+ expect(group.id, 'id-b');
+ expect(group.positions, hasLength(2));
+ expect(group.positions[0], new Position('/gb.dart', 10, 5));
+ expect(group.positions[1], new Position('/gb.dart', 100, 5));
+ }
+ }
+
+ void test_new() {
+ Change change = new Change('msg');
+ change.add(new FileEdit('/a.dart')
+ ..add(new Edit(1, 2, 'aaa'))
+ ..add(new Edit(10, 20, 'bbb')));
+ change.add(new FileEdit('/b.dart')
+ ..add(new Edit(21, 22, 'xxx'))
+ ..add(new Edit(210, 220, 'yyy')));
+ change.addLinkedPositionGroup(new LinkedPositionGroup('id-a')
+ ..add(new Position('/ga.dart', 1, 2))
+ ..add(new Position('/ga.dart', 10, 2)));
+ change.addLinkedPositionGroup(new LinkedPositionGroup('id-b')
+ ..add(new Position('/gb.dart', 10, 5))
+ ..add(new Position('/gb.dart', 100, 5)));
+ expect(
+ change.toString(),
+ 'Change(message=msg, edits=[FileEdit(file=/a.dart, edits=['
+ 'Edit(offset=1, length=2, replacement=:>aaa<:), '
+ 'Edit(offset=10, length=20, replacement=:>bbb<:)]), '
+ 'FileEdit(file=/b.dart, edits=['
+ 'Edit(offset=21, length=22, replacement=:>xxx<:), '
+ 'Edit(offset=210, length=220, replacement=:>yyy<:)])], '
+ 'linkedPositionGroups=[' 'LinkedPositionGroup(id=id-a, positions=['
+ 'Position(file=/ga.dart, offset=1, length=2), '
+ 'Position(file=/ga.dart, offset=10, length=2)]), '
+ 'LinkedPositionGroup(id=id-b, positions=['
+ 'Position(file=/gb.dart, offset=10, length=5), '
+ 'Position(file=/gb.dart, offset=100, length=5)])])');
+ }
+
+ void test_toJson() {
+ Change change = new Change('msg');
+ change.add(new FileEdit('/a.dart')
+ ..add(new Edit(1, 2, 'aaa'))
+ ..add(new Edit(10, 20, 'bbb')));
+ change.add(new FileEdit('/b.dart')
+ ..add(new Edit(21, 22, 'xxx'))
+ ..add(new Edit(210, 220, 'yyy')));
+ change.addLinkedPositionGroup(new LinkedPositionGroup('id-a')
+ ..add(new Position('/ga.dart', 1, 2))
+ ..add(new Position('/ga.dart', 10, 2)));
+ change.addLinkedPositionGroup(new LinkedPositionGroup('id-b')
+ ..add(new Position('/gb.dart', 10, 5))
+ ..add(new Position('/gb.dart', 100, 5)));
+ var expectedJson = {
+ MESSAGE: 'msg',
+ EDITS: [{
+ FILE: '/a.dart',
+ EDITS: [{
+ OFFSET: 1,
+ LENGTH: 2,
+ REPLACEMENT: 'aaa'
+ }, {
+ OFFSET: 10,
+ LENGTH: 20,
+ REPLACEMENT: 'bbb'
+ }]
+ }, {
+ FILE: '/b.dart',
+ EDITS: [{
+ OFFSET: 21,
+ LENGTH: 22,
+ REPLACEMENT: 'xxx'
+ }, {
+ OFFSET: 210,
+ LENGTH: 220,
+ REPLACEMENT: 'yyy'
+ }]
+ }],
+ LINKED_POSITION_GROUPS: [{
+ ID: 'id-a',
+ POSITIONS: [{
+ FILE: '/ga.dart',
+ OFFSET: 1,
+ LENGTH: 2
+ }, {
+ FILE: '/ga.dart',
+ OFFSET: 10,
+ LENGTH: 2
+ }]
+ }, {
+ ID: 'id-b',
+ POSITIONS: [{
+ FILE: '/gb.dart',
+ OFFSET: 10,
+ LENGTH: 5
+ }, {
+ FILE: '/gb.dart',
+ OFFSET: 100,
+ LENGTH: 5
+ }]
+ }]
+ };
+ expect(change.toJson(), expectedJson);
+ }
+}
+
+
+@ReflectiveTestCase()
+class EditTest {
+ void test_end() {
+ Edit edit = new Edit(1, 2, 'foo');
+ expect(edit.end, 3);
+ }
+
+ void test_fromJson() {
+ var json = {
+ OFFSET: 1,
+ LENGTH: 2,
+ REPLACEMENT: 'foo'
+ };
+ Edit edit = Edit.fromJson(json);
+ expect(edit.offset, 1);
+ expect(edit.length, 2);
+ expect(edit.replacement, 'foo');
+ }
+
+ void test_new() {
+ Edit edit = new Edit(1, 2, 'foo');
+ expect(edit.offset, 1);
+ expect(edit.length, 2);
+ expect(edit.replacement, 'foo');
+ expect(edit.toString(), 'Edit(offset=1, length=2, replacement=:>foo<:)');
+ }
+
+ void test_toJson() {
+ Edit edit = new Edit(1, 2, 'foo');
+ var expectedJson = {
+ OFFSET: 1,
+ LENGTH: 2,
+ REPLACEMENT: 'foo'
+ };
+ expect(edit.toJson(), expectedJson);
+ }
+ void test_eqEq() {
+ Edit a = new Edit(1, 2, 'aaa');
+ Edit a2 = new Edit(1, 2, 'aaa');
+ Edit b = new Edit(1, 2, 'aaa');
+ expect(a == a, isTrue);
+ expect(a == new Edit(1, 2, 'aaa'), isTrue);
+ expect(a == this, isFalse);
+ expect(a == new Edit(1, 2, 'bbb'), isFalse);
+ expect(a == new Edit(10, 2, 'aaa'), isFalse);
+ }
+
+}
+
+
+@ReflectiveTestCase()
+class FileEditTest {
+ void test_fromJson() {
+ var json = {
+ FILE: '/test.dart',
+ EDITS: [{
+ OFFSET: 1,
+ LENGTH: 2,
+ REPLACEMENT: 'aaa'
+ }, {
+ OFFSET: 10,
+ LENGTH: 20,
+ REPLACEMENT: 'bbb'
+ },]
+ };
+ var fileEdit = FileEdit.fromJson(json);
+ expect(fileEdit.file, '/test.dart');
+ expect(fileEdit.edits, hasLength(2));
+ expect(fileEdit.edits[0], new Edit(1, 2, 'aaa'));
+ expect(fileEdit.edits[1], new Edit(10, 20, 'bbb'));
+ }
+
+ void test_new() {
+ FileEdit fileEdit = new FileEdit('/test.dart');
+ fileEdit.add(new Edit(1, 2, 'aaa'));
+ fileEdit.add(new Edit(10, 20, 'bbb'));
+ expect(
+ fileEdit.toString(),
+ 'FileEdit(file=/test.dart, edits=['
+ 'Edit(offset=1, length=2, replacement=:>aaa<:), '
+ 'Edit(offset=10, length=20, replacement=:>bbb<:)])');
+ }
+
+ void test_toJson() {
+ FileEdit fileEdit = new FileEdit('/test.dart');
+ fileEdit.add(new Edit(1, 2, 'aaa'));
+ fileEdit.add(new Edit(10, 20, 'bbb'));
+ expect(fileEdit.toJson(), {
+ FILE: '/test.dart',
+ EDITS: [{
+ OFFSET: 1,
+ LENGTH: 2,
+ REPLACEMENT: 'aaa'
+ }, {
+ OFFSET: 10,
+ LENGTH: 20,
+ REPLACEMENT: 'bbb'
+ },]
+ });
+ }
+}
+
+
+@ReflectiveTestCase()
+class LinkedPositionGroupTest {
+ void test_addWrongLength() {
+ LinkedPositionGroup group = new LinkedPositionGroup('my-id');
+ group.add(new Position('/a.dart', 1, 2));
+ expect(() {
+ group.add(new Position('/b.dart', 10, 20));
+ }, throws);
+ }
+
+ void test_fromJson() {
+ var json = {
+ ID: 'my-id',
+ POSITIONS: [{
+ FILE: '/a.dart',
+ OFFSET: 1,
+ LENGTH: 2
+ }, {
+ FILE: '/b.dart',
+ OFFSET: 10,
+ LENGTH: 2
+ }]
+ };
+ LinkedPositionGroup group = LinkedPositionGroup.fromJson(json);
+ expect(group.id, 'my-id');
+ expect(group.positions, hasLength(2));
+ expect(group.positions[0], new Position('/a.dart', 1, 2));
+ expect(group.positions[1], new Position('/b.dart', 10, 2));
+ }
+
+ void test_new() {
+ LinkedPositionGroup group = new LinkedPositionGroup('my-id');
+ group.add(new Position('/a.dart', 1, 2));
+ group.add(new Position('/b.dart', 10, 2));
+ expect(
+ group.toString(),
+ 'LinkedPositionGroup(id=my-id, positions=['
+ 'Position(file=/a.dart, offset=1, length=2), '
+ 'Position(file=/b.dart, offset=10, length=2)])');
+ }
+
+ void test_toJson() {
+ LinkedPositionGroup group = new LinkedPositionGroup('my-id');
+ group.add(new Position('/a.dart', 1, 2));
+ group.add(new Position('/b.dart', 10, 2));
+ var expectedJson = {
+ ID: 'my-id',
+ POSITIONS: [{
+ FILE: '/a.dart',
+ OFFSET: 1,
+ LENGTH: 2
+ }, {
+ FILE: '/b.dart',
+ OFFSET: 10,
+ LENGTH: 2
+ }]
+ };
+ expect(group.toJson(), expectedJson);
+ }
+}
+
+
+@ReflectiveTestCase()
+class PositionTest {
+ void test_eqEq() {
+ Position a = new Position('/a.dart', 1, 2);
+ Position a2 = new Position('/a.dart', 1, 2);
+ Position b = new Position('/b.dart', 1, 2);
+ expect(a == a, isTrue);
+ expect(a == a2, isTrue);
+ expect(a == b, isFalse);
+ expect(a == this, isFalse);
+ }
+
+ void test_fromJson() {
+ var json = {
+ FILE: '/test.dart',
+ OFFSET: 1,
+ LENGTH: 2
+ };
+ Position position = Position.fromJson(json);
+ expect(position.file, '/test.dart');
+ expect(position.offset, 1);
+ expect(position.length, 2);
+ }
+
+ void test_hashCode() {
+ Position position = new Position('/test.dart', 1, 2);
+ position.hashCode;
+ }
+
+ void test_new() {
+ Position position = new Position('/test.dart', 1, 2);
+ expect(position.file, '/test.dart');
+ expect(position.offset, 1);
+ expect(position.length, 2);
+ expect(
+ position.toString(),
+ 'Position(file=/test.dart, offset=1, length=2)');
+ }
+
+ void test_toJson() {
+ Position position = new Position('/test.dart', 1, 2);
+ var expectedJson = {
+ FILE: '/test.dart',
+ OFFSET: 1,
+ LENGTH: 2
+ };
+ expect(position.toJson(), expectedJson);
+ }
+}
diff --git a/pkg/analysis_services/test/correction/fix_test.dart b/pkg/analysis_services/test/correction/fix_test.dart
index f7f6005..31f926a 100644
--- a/pkg/analysis_services/test/correction/fix_test.dart
+++ b/pkg/analysis_services/test/correction/fix_test.dart
@@ -12,12 +12,11 @@
import 'package:analysis_services/index/index.dart';
import 'package:analysis_services/index/local_memory_index.dart';
import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:unittest/unittest.dart';
-import '../index/abstract_single_unit.dart';
-
main() {
groupSep = ' | ';
@@ -32,15 +31,56 @@
Index index;
SearchEngineImpl searchEngine;
+ Fix fix;
+ Change change;
+ String resultCode;
+
void assertHasFix(FixKind kind, String expected) {
AnalysisError error = _findErrorToFix();
- Fix fix = _computeFix(kind, error);
+ fix = _assertHasFix(kind, error);
+ change = fix.change;
// apply to "file"
- List<FileEdit> fileEdits = fix.change.edits;
+ List<FileEdit> fileEdits = change.edits;
expect(fileEdits, hasLength(1));
- String actualCode = _applyEdits(testCode, fix.change.edits[0].edits);
+ resultCode = _applyEdits(testCode, change.edits[0].edits);
// verify
- expect(expected, actualCode);
+ expect(resultCode, expected);
+ }
+
+ void assertHasPositionGroup(String id, List<Position> expectedPositions) {
+ List<LinkedPositionGroup> linkedPositionGroups =
+ change.linkedPositionGroups;
+ for (LinkedPositionGroup group in linkedPositionGroups) {
+ if (group.id == id) {
+ expect(group.positions, unorderedEquals(expectedPositions));
+ return;
+ }
+ }
+ fail('No PositionGroup with id=$id found in $linkedPositionGroups');
+ }
+
+ void assertNoFix(FixKind kind) {
+ AnalysisError error = _findErrorToFix();
+ List<Fix> fixes = computeFixes(searchEngine, testFile, testUnit, error);
+ for (Fix fix in fixes) {
+ if (fix.kind == kind) {
+ throw fail('Unexpected fix $kind in\n${fixes.join('\n')}');
+ }
+ }
+ }
+
+ Position expectedPosition(String search) {
+ int offset = resultCode.indexOf(search);
+ int length = getLeadingIdentifierLength(search);
+ return new Position(testFile, offset, length);
+ }
+
+ List<Position> expectedPositions(List<String> patterns) {
+ List<Position> positions = <Position>[];
+ patterns.forEach((String search) {
+ positions.add(expectedPosition(search));
+ });
+ return positions;
}
void setUp() {
@@ -63,6 +103,387 @@
''');
}
+ void test_changeToStaticAccess_method() {
+ _indexTestUnit('''
+class A {
+ static foo() {}
+}
+main(A a) {
+ a.foo();
+}
+''');
+ assertHasFix(FixKind.CHANGE_TO_STATIC_ACCESS, '''
+class A {
+ static foo() {}
+}
+main(A a) {
+ A.foo();
+}
+''');
+ }
+
+ void test_changeToStaticAccess_method_prefixLibrary() {
+ _indexTestUnit('''
+import 'dart:async' as pref;
+main(pref.Future f) {
+ f.wait([]);
+}
+''');
+ assertHasFix(FixKind.CHANGE_TO_STATIC_ACCESS, '''
+import 'dart:async' as pref;
+main(pref.Future f) {
+ pref.Future.wait([]);
+}
+''');
+ }
+
+ void test_changeToStaticAccess_property() {
+ _indexTestUnit('''
+class A {
+ static get foo => 42;
+}
+main(A a) {
+ a.foo;
+}
+''');
+ assertHasFix(FixKind.CHANGE_TO_STATIC_ACCESS, '''
+class A {
+ static get foo => 42;
+}
+main(A a) {
+ A.foo;
+}
+''');
+ }
+
+ void test_createClass() {
+ _indexTestUnit('''
+main() {
+ Test v = null;
+}
+''');
+ assertHasFix(FixKind.CREATE_CLASS, '''
+main() {
+ Test v = null;
+}
+
+class Test {
+}
+''');
+ assertHasPositionGroup('NAME', expectedPositions(['Test v =', 'Test {']));
+ }
+
+ void test_createConstructorSuperExplicit() {
+ _indexTestUnit('''
+class A {
+ A(bool p1, int p2, double p3, String p4, {p5});
+}
+class B extends A {
+ B() {}
+}
+''');
+ assertHasFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+class A {
+ A(bool p1, int p2, double p3, String p4, {p5});
+}
+class B extends A {
+ B() : super(false, 0, 0.0, '') {}
+}
+''');
+ }
+
+ void test_createConstructorSuperExplicit_hasInitializers() {
+ _indexTestUnit('''
+class A {
+ A(int p);
+}
+class B extends A {
+ int field;
+ B() : field = 42 {}
+}
+''');
+ assertHasFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+class A {
+ A(int p);
+}
+class B extends A {
+ int field;
+ B() : field = 42, super(0) {}
+}
+''');
+ }
+
+ void test_createConstructorSuperExplicit_named() {
+ _indexTestUnit('''
+class A {
+ A.named(int p);
+}
+class B extends A {
+ B() {}
+}
+''');
+ assertHasFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+class A {
+ A.named(int p);
+}
+class B extends A {
+ B() : super.named(0) {}
+}
+''');
+ }
+
+ void test_createConstructorSuperExplicit_named_private() {
+ _indexTestUnit('''
+class A {
+ A._named(int p);
+}
+class B extends A {
+ B() {}
+}
+''');
+ assertNoFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION);
+ }
+
+ void test_createConstructor_insteadOfSyntheticDefault() {
+ _indexTestUnit('''
+class A {
+ int field;
+
+ method() {}
+}
+main() {
+ new A(1, 2.0);
+}
+''');
+ assertHasFix(FixKind.CREATE_CONSTRUCTOR, '''
+class A {
+ int field;
+
+ A(int i, double d) {
+ }
+
+ method() {}
+}
+main() {
+ new A(1, 2.0);
+}
+''');
+ }
+
+ void test_createConstructor_named() {
+ _indexTestUnit('''
+class A {
+ method() {}
+}
+main() {
+ new A.named(1, 2.0);
+}
+''');
+ assertHasFix(FixKind.CREATE_CONSTRUCTOR, '''
+class A {
+ A.named(int i, double d) {
+ }
+
+ method() {}
+}
+main() {
+ new A.named(1, 2.0);
+}
+''');
+ }
+
+ void test_expectedToken_semicolon() {
+ _indexTestUnit('''
+main() {
+ print(0)
+}
+''');
+ assertHasFix(FixKind.INSERT_SEMICOLON, '''
+main() {
+ print(0);
+}
+''');
+ }
+
+ void test_isNotNull() {
+ _indexTestUnit('''
+main(p) {
+ p is! Null;
+}
+''');
+ assertHasFix(FixKind.USE_NOT_EQ_NULL, '''
+main(p) {
+ p != null;
+}
+''');
+ }
+
+ void test_isNull() {
+ _indexTestUnit('''
+main(p) {
+ p is Null;
+}
+''');
+ assertHasFix(FixKind.USE_EQ_EQ_NULL, '''
+main(p) {
+ p == null;
+}
+''');
+ }
+
+ void test_makeEnclosingClassAbstract_declaresAbstractMethod() {
+ _indexTestUnit('''
+class A {
+ m();
+}
+''');
+ assertHasFix(FixKind.MAKE_CLASS_ABSTRACT, '''
+abstract class A {
+ m();
+}
+''');
+ }
+
+ void test_makeEnclosingClassAbstract_inheritsAbstractMethod() {
+ _indexTestUnit('''
+abstract class A {
+ m();
+}
+class B extends A {
+}
+''');
+ assertHasFix(FixKind.MAKE_CLASS_ABSTRACT, '''
+abstract class A {
+ m();
+}
+abstract class B extends A {
+}
+''');
+ }
+
+ void test_removeParentheses_inGetterDeclaration() {
+ _indexTestUnit('''
+class A {
+ int get foo() => 0;
+}
+''');
+ assertHasFix(FixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, '''
+class A {
+ int get foo => 0;
+}
+''');
+ }
+
+ void test_removeParentheses_inGetterInvocation() {
+ _indexTestUnit('''
+class A {
+ int get foo => 0;
+}
+main(A a) {
+ a.foo();
+}
+''');
+ assertHasFix(FixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION, '''
+class A {
+ int get foo => 0;
+}
+main(A a) {
+ a.foo;
+}
+''');
+ }
+
+ void test_removeUnnecessaryCast_assignment() {
+ _indexTestUnit('''
+main(Object p) {
+ if (p is String) {
+ String v = ((p as String));
+ }
+}
+''');
+ assertHasFix(FixKind.REMOVE_UNNECASSARY_CAST, '''
+main(Object p) {
+ if (p is String) {
+ String v = p;
+ }
+}
+''');
+ }
+
+ void test_removeUnusedImport() {
+ _indexTestUnit('''
+import 'dart:math';
+main() {
+}
+''');
+ assertHasFix(FixKind.REMOVE_UNUSED_IMPORT, '''
+main() {
+}
+''');
+ }
+
+ void test_removeUnusedImport_anotherImportOnLine() {
+ _indexTestUnit('''
+import 'dart:math'; import 'dart:async';
+
+main() {
+ Future f;
+}
+''');
+ assertHasFix(FixKind.REMOVE_UNUSED_IMPORT, '''
+import 'dart:async';
+
+main() {
+ Future f;
+}
+''');
+ }
+
+ void test_removeUnusedImport_severalLines() {
+ _indexTestUnit('''
+import
+ 'dart:math';
+main() {
+}
+''');
+ assertHasFix(FixKind.REMOVE_UNUSED_IMPORT, '''
+main() {
+}
+''');
+ }
+
+ void test_replaceWithConstInstanceCreation() {
+ _indexTestUnit('''
+class A {
+ const A();
+}
+const a = new A();
+''');
+ assertHasFix(FixKind.USE_CONST, '''
+class A {
+ const A();
+}
+const a = const A();
+''');
+ }
+
+ void test_useEffectiveIntegerDivision() {
+ _indexTestUnit('''
+main() {
+ var a = 5;
+ var b = 2;
+ print((a / b).toInt());
+}
+''');
+ assertHasFix(FixKind.USE_EFFECTIVE_INTEGER_DIVISION, '''
+main() {
+ var a = 5;
+ var b = 2;
+ print(a ~/ b);
+}
+''');
+ }
+
String _applyEdits(String code, List<Edit> edits) {
edits.sort((a, b) => b.offset - a.offset);
edits.forEach((Edit edit) {
@@ -73,7 +494,10 @@
return code;
}
- Fix _computeFix(FixKind kind, AnalysisError error) {
+ /**
+ * Computes fixes and verifies that there is a fix of the given kind.
+ */
+ Fix _assertHasFix(FixKind kind, AnalysisError error) {
List<Fix> fixes = computeFixes(searchEngine, testFile, testUnit, error);
for (Fix fix in fixes) {
if (fix.kind == kind) {
@@ -84,7 +508,7 @@
}
AnalysisError _findErrorToFix() {
- List<AnalysisError> errors = context.getErrors(testSource).errors;
+ List<AnalysisError> errors = context.computeErrors(testSource);
expect(
errors,
hasLength(1),
diff --git a/pkg/analysis_services/test/correction/name_suggestion_test.dart b/pkg/analysis_services/test/correction/name_suggestion_test.dart
new file mode 100644
index 0000000..c3fb487
--- /dev/null
+++ b/pkg/analysis_services/test/correction/name_suggestion_test.dart
@@ -0,0 +1,381 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.name_suggestion;
+
+import 'package:analysis_services/src/correction/name_suggestion.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:unittest/unittest.dart' hide isEmpty;
+
+
+main() {
+ groupSep = ' | ';
+ group('source_range', () {
+ runReflectiveTests(VariableNameSuggestionTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class VariableNameSuggestionTest extends AbstractSingleUnitTest {
+ void test_forExpression_cast() {
+ resolveTestUnit('''
+main() {
+ var sortedNodes;
+ var res = sortedNodes as String;
+}
+''');
+ var excluded = new Set.from([]);
+ var expr = findNodeAtString('as String', (node) => node is AsExpression);
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['sortedNodes', 'nodes']));
+ }
+
+ void test_forExpression_expectedType() {
+ resolveTestUnit('''
+class TreeNode {}
+main() {
+ TreeNode node = null;
+}
+''');
+ Set excluded = new Set.from([]);
+ DartType expectedType = (findElement('node') as LocalVariableElement).type;
+ Expression assignedExpression =
+ findNodeAtString('null;', (node) => node is NullLiteral);
+ List<String> suggestions =
+ getVariableNameSuggestionsForExpression(
+ expectedType,
+ assignedExpression,
+ excluded);
+ expect(suggestions, unorderedEquals(['treeNode', 'node']));
+ }
+
+ void test_forExpression_expectedType_String() {
+ resolveTestUnit('''
+main() {
+ String res = 'abc';
+}
+''');
+ DartType expectedType = (findElement('res') as LocalVariableElement).type;
+ Expression assignedExpression = findNodeAtString("'abc';");
+ // first choice for "String" is "s"
+ expect(
+ getVariableNameSuggestionsForExpression(
+ expectedType,
+ assignedExpression,
+ new Set.from([])),
+ unorderedEquals(['s']));
+ }
+
+ void test_forExpression_expectedType_double() {
+ resolveTestUnit('''
+main() {
+ double res = 0.0;
+}
+''');
+ DartType expectedType = (findElement('res') as LocalVariableElement).type;
+ Expression assignedExpression = findNodeAtString('0.0;');
+ // first choice for "double" is "d"
+ expect(
+ getVariableNameSuggestionsForExpression(
+ expectedType,
+ assignedExpression,
+ new Set.from([])),
+ unorderedEquals(['d']));
+ // if "d" is used, try "e", "f", etc
+ expect(
+ getVariableNameSuggestionsForExpression(
+ expectedType,
+ assignedExpression,
+ new Set.from(['d', 'e'])),
+ unorderedEquals(['f']));
+ }
+
+ void test_forExpression_expectedType_int() {
+ resolveTestUnit('''
+main() {
+ int res = 0;
+}
+''');
+ DartType expectedType = (findElement('res') as LocalVariableElement).type;
+ Expression assignedExpression = findNodeAtString('0;');
+ // first choice for "int" is "i"
+ expect(
+ getVariableNameSuggestionsForExpression(
+ expectedType,
+ assignedExpression,
+ new Set.from([])),
+ unorderedEquals(['i']));
+ // if "i" is used, try "j", "k", etc
+ expect(
+ getVariableNameSuggestionsForExpression(
+ expectedType,
+ assignedExpression,
+ new Set.from(['i', 'j'])),
+ unorderedEquals(['k']));
+ }
+
+ void test_forExpression_instanceCreation() {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+import 'dart:math' as p;
+main(p) {
+ new NoSuchClass();
+ new p.NoSuchClass();
+ new NoSuchClass.named();
+}
+''');
+ var excluded = new Set.from([]);
+ expect(
+ getVariableNameSuggestionsForExpression(
+ null,
+ findNodeAtString('new NoSuchClass()'),
+ excluded),
+ unorderedEquals(['noSuchClass', 'suchClass', 'class']));
+ expect(
+ getVariableNameSuggestionsForExpression(
+ null,
+ findNodeAtString('new NoSuchClass.named()'),
+ excluded),
+ unorderedEquals(['noSuchClass', 'suchClass', 'class']));
+ // TODO(scheglov) This test does not work.
+ // In "p.NoSuchClass" the identifier "p" is not resolved to a PrefixElement.
+// expect(
+// getVariableNameSuggestionsForExpression(
+// null,
+// findNodeAtString('new p.NoSuchClass()'),
+// excluded),
+// unorderedEquals(['noSuchClass', 'suchClass', 'class']));
+ }
+
+ void test_forExpression_invocationArgument_named() {
+ resolveTestUnit('''
+foo({a, b, c}) {}
+main() {
+ foo(a: 111, c: 333, b: 222);
+}
+''');
+ var excluded = new Set.from([]);
+ {
+ var expr = findNodeAtString('111');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['a']));
+ }
+ {
+ var expr = findNodeAtString('222');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['b']));
+ }
+ {
+ var expr = findNodeAtString('333');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['c']));
+ }
+ }
+
+ void test_forExpression_invocationArgument_optional() {
+ resolveTestUnit('''
+foo(a, [b = 2, c = 3]) {}
+main() {
+ foo(111, 222, 333);
+}
+''');
+ var excluded = new Set.from([]);
+ {
+ var expr = findNodeAtString('111');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['a']));
+ }
+ {
+ var expr = findNodeAtString('222');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['b']));
+ }
+ {
+ var expr = findNodeAtString('333');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['c']));
+ }
+ }
+
+ void test_forExpression_invocationArgument_positional() {
+ resolveTestUnit('''
+foo(a, b) {}
+main() {
+ foo(111, 222);
+}
+''');
+ var excluded = new Set.from([]);
+ {
+ var expr = findNodeAtString('111');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['a']));
+ }
+ {
+ var expr = findNodeAtString('222');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['b']));
+ }
+ }
+
+ void test_forExpression_methodInvocation() {
+ resolveTestUnit('''
+main(p) {
+ var res = p.getSortedNodes();
+}
+''');
+ var excluded = new Set.from([]);
+ var expr = findNodeAtString('p.get', (node) => node is MethodInvocation);
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['sortedNodes', 'nodes']));
+ }
+
+ void test_forExpression_methodInvocation_noPrefix() {
+ resolveTestUnit('''
+main(p) {
+ var res = p.sortedNodes();
+}
+''');
+ var excluded = new Set.from([]);
+ var expr = findNodeAtString('p.sorted', (node) => node is MethodInvocation);
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['sortedNodes', 'nodes']));
+ }
+
+ void test_forExpression_name_get() {
+ resolveTestUnit('''
+main(p) {
+ var res = p.get();
+}
+''');
+ var excluded = new Set.from([]);
+ var expr = findNodeAtString('p.get', (node) => node is MethodInvocation);
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals([]));
+ }
+
+ void test_forExpression_privateName() {
+ resolveTestUnit('''
+main(p) {
+ p._name;
+ p._computeSuffix();
+}
+''');
+ var excluded = new Set.from([]);
+ expect(
+ getVariableNameSuggestionsForExpression(
+ null,
+ findNodeAtString('p._name', (node) => node is PrefixedIdentifier),
+ excluded),
+ unorderedEquals(['name']));
+ expect(
+ getVariableNameSuggestionsForExpression(
+ null,
+ findNodeAtString('p._compute', (node) => node is MethodInvocation),
+ excluded),
+ unorderedEquals(['computeSuffix', 'suffix']));
+ }
+
+ void test_forExpression_propertyAccess() {
+ resolveTestUnit('''
+main(p) {
+ var res = p.sortedNodes;
+}
+''');
+ var excluded = new Set.from([]);
+ expect(
+ getVariableNameSuggestionsForExpression(
+ null,
+ findNodeAtString('p.sorted', (node) => node is PrefixedIdentifier),
+ excluded),
+ unorderedEquals(['sortedNodes', 'nodes']));
+ }
+
+ void test_forExpression_simpleName() {
+ resolveTestUnit('''
+main(p) {
+ var sortedNodes = null;
+ var res = sortedNodes;
+}
+''');
+ var excluded = new Set.from([]);
+ var expr = findNodeAtString('sortedNodes;');
+ expect(
+ getVariableNameSuggestionsForExpression(null, expr, excluded),
+ unorderedEquals(['sortedNodes', 'nodes']));
+ }
+
+ void test_forExpression_unqualifiedInvocation() {
+ resolveTestUnit('''
+getSortedNodes() => [];
+main(p) {
+ var res = getSortedNodes();
+}
+''');
+ var excluded = new Set.from([]);
+ expect(
+ getVariableNameSuggestionsForExpression(
+ null,
+ findNodeAtString('getSortedNodes();', (node) => node is MethodInvocation),
+ excluded),
+ unorderedEquals(['sortedNodes', 'nodes']));
+ }
+
+ void test_forText() {
+ {
+ Set excluded = new Set.from([]);
+ List<String> suggestions =
+ getVariableNameSuggestionsForText('Goodbye, cruel world!', excluded);
+ expect(
+ suggestions,
+ unorderedEquals(['goodbyeCruelWorld', 'cruelWorld', 'world']));
+ }
+ {
+ Set excluded = new Set.from(['world']);
+ List<String> suggestions =
+ getVariableNameSuggestionsForText('Goodbye, cruel world!', excluded);
+ expect(
+ suggestions,
+ unorderedEquals(['goodbyeCruelWorld', 'cruelWorld', 'world2']));
+ }
+ }
+
+ void test_getCamelWords_empty() {
+ expect(getCamelWords(''), unorderedEquals([]));
+ }
+
+ void test_getCamelWords_multipleUpper() {
+ expect(
+ getCamelWords('sortedHTMLNodes'),
+ unorderedEquals(['sorted', 'HTML', 'Nodes']));
+ }
+
+ void test_getCamelWords_simpleCamel() {
+ expect(
+ getCamelWords('mySimpleText'),
+ unorderedEquals(['my', 'Simple', 'Text']));
+ }
+
+ void test_getCamelWords_simpleName() {
+ expect(getCamelWords('name'), unorderedEquals(['name']));
+ }
+}
diff --git a/pkg/analysis_services/test/correction/source_range_test.dart b/pkg/analysis_services/test/correction/source_range_test.dart
new file mode 100644
index 0000000..419d523
--- /dev/null
+++ b/pkg/analysis_services/test/correction/source_range_test.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.source_range;
+
+import 'package:analysis_services/src/correction/source_range.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart' hide isEmpty;
+
+
+main() {
+ groupSep = ' | ';
+ group('source_range', () {
+ runReflectiveTests(SourceRangesTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class SourceRangesTest extends AbstractSingleUnitTest {
+ void test_rangeElementName() {
+ resolveTestUnit('class ABC {}');
+ Element element = findElement('ABC');
+ expect(rangeElementName(element), new SourceRange(6, 3));
+ }
+
+ void test_rangeEndEnd_nodeNode() {
+ resolveTestUnit('main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ FunctionBody mainBody = mainFunction.functionExpression.body;
+ expect(rangeEndEnd(mainName, mainBody), new SourceRange(4, 5));
+ }
+
+ void test_rangeEndStart_nodeNode() {
+ resolveTestUnit('main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ FunctionBody mainBody = mainFunction.functionExpression.body;
+ expect(rangeEndStart(mainName, mainBody), new SourceRange(4, 3));
+ }
+
+ void test_rangeError() {
+ AnalysisError error =
+ new AnalysisError.con2(null, 10, 5, ParserErrorCode.CONST_CLASS, []);
+ expect(rangeError(error), new SourceRange(10, 5));
+ }
+
+ void test_rangeNode() {
+ resolveTestUnit('main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ expect(rangeNode(mainName), new SourceRange(0, 4));
+ }
+
+ void test_rangeNodes() {
+ resolveTestUnit(' main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ FunctionBody mainBody = mainFunction.functionExpression.body;
+ expect(rangeNodes([mainName, mainBody]), new SourceRange(1, 9));
+ }
+
+ void test_rangeNodes_empty() {
+ resolveTestUnit('main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ FunctionBody mainBody = mainFunction.functionExpression.body;
+ expect(rangeNodes([]), new SourceRange(0, 0));
+ }
+
+ void test_rangeStartEnd_intInt() {
+ expect(rangeStartEnd(10, 25), new SourceRange(10, 15));
+ }
+
+ void test_rangeStartEnd_nodeNode() {
+ resolveTestUnit(' main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ FunctionBody mainBody = mainFunction.functionExpression.body;
+ expect(rangeStartEnd(mainName, mainBody), new SourceRange(1, 9));
+ }
+
+ void test_rangeStartLength_int() {
+ expect(rangeStartLength(5, 10), new SourceRange(5, 10));
+ }
+
+ void test_rangeStartLength_node() {
+ resolveTestUnit(' main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ expect(rangeStartLength(mainName, 10), new SourceRange(1, 10));
+ }
+
+ void test_rangeStartStart_intInt() {
+ expect(rangeStartStart(10, 25), new SourceRange(10, 15));
+ }
+
+ void test_rangeStartStart_nodeNode() {
+ resolveTestUnit('main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ FunctionBody mainBody = mainFunction.functionExpression.body;
+ expect(rangeStartStart(mainName, mainBody), new SourceRange(0, 7));
+ }
+
+ void test_rangeToken() {
+ resolveTestUnit(' main() {}');
+ FunctionDeclaration mainFunction = testUnit.declarations[0];
+ SimpleIdentifier mainName = mainFunction.name;
+ expect(rangeToken(mainName.beginToken), new SourceRange(1, 4));
+ }
+}
diff --git a/pkg/analysis_services/test/correction/strings_test.dart b/pkg/analysis_services/test/correction/strings_test.dart
new file mode 100644
index 0000000..a02f164
--- /dev/null
+++ b/pkg/analysis_services/test/correction/strings_test.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.strings;
+
+import 'package:analysis_services/src/correction/strings.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart' hide isEmpty;
+
+
+
+main() {
+ groupSep = ' | ';
+ group('strings', () {
+ runReflectiveTests(StringsTest);
+ });
+}
+
+
+@ReflectiveTestCase()
+class StringsTest {
+ void test_capitalize() {
+ expect(capitalize(null), null);
+ expect(capitalize(''), '');
+ expect(capitalize('a'), 'A');
+ expect(capitalize('abc'), 'Abc');
+ expect(capitalize('abc def'), 'Abc def');
+ expect(capitalize('ABC'), 'ABC');
+ }
+
+ void test_isDigit() {
+ for (int c in '0123456789'.codeUnits) {
+ expect(isDigit(c), isTrue);
+ }
+ expect(isDigit(' '.codeUnitAt(0)), isFalse);
+ expect(isDigit('A'.codeUnitAt(0)), isFalse);
+ }
+
+ void test_isEmpty() {
+ expect(isEmpty(null), isTrue);
+ expect(isEmpty(''), isTrue);
+ expect(isEmpty('X'), isFalse);
+ expect(isEmpty(' '), isFalse);
+ }
+
+ void test_isLetter() {
+ for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
+ expect(isLetter(c), isTrue);
+ }
+ for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
+ expect(isLetter(c), isTrue);
+ }
+ expect(isLetter(' '.codeUnitAt(0)), isFalse);
+ expect(isLetter('0'.codeUnitAt(0)), isFalse);
+ }
+
+ void test_isSpace() {
+ expect(isSpace(' '.codeUnitAt(0)), isTrue);
+ expect(isSpace('\t'.codeUnitAt(0)), isTrue);
+ expect(isSpace('\r'.codeUnitAt(0)), isFalse);
+ expect(isSpace('\n'.codeUnitAt(0)), isFalse);
+ expect(isSpace('0'.codeUnitAt(0)), isFalse);
+ expect(isSpace('A'.codeUnitAt(0)), isFalse);
+ }
+
+ void test_isUpperCase() {
+ for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
+ expect(isUpperCase(c), isFalse);
+ }
+ for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
+ expect(isUpperCase(c), isTrue);
+ }
+ expect(isUpperCase(' '.codeUnitAt(0)), isFalse);
+ expect(isUpperCase('0'.codeUnitAt(0)), isFalse);
+ }
+
+ void test_isWhitespace() {
+ expect(isWhitespace(' '.codeUnitAt(0)), isTrue);
+ expect(isWhitespace('\t'.codeUnitAt(0)), isTrue);
+ expect(isWhitespace('\r'.codeUnitAt(0)), isTrue);
+ expect(isWhitespace('\n'.codeUnitAt(0)), isTrue);
+ expect(isWhitespace('0'.codeUnitAt(0)), isFalse);
+ expect(isWhitespace('A'.codeUnitAt(0)), isFalse);
+ }
+
+ void test_remove() {
+ expect(remove(null, 'x'), null);
+ expect(remove('abc', null), 'abc');
+ expect(remove('abc abbc abbbc', 'b'), 'ac ac ac');
+ expect(remove('abc abbc abbbc', 'bc'), 'a ab abb');
+ }
+
+ void test_removeStart() {
+ expect(removeStart(null, 'x'), null);
+ expect(removeStart('abc', null), 'abc');
+ expect(removeStart('abcTest', 'abc'), 'Test');
+ expect(removeStart('my abcTest', 'abc'), 'my abcTest');
+ }
+
+ void test_repeat() {
+ expect(repeat('x', 0), '');
+ expect(repeat('x', 5), 'xxxxx');
+ expect(repeat('abc', 3), 'abcabcabc');
+ }
+}
diff --git a/pkg/analysis_services/test/correction/test_all.dart b/pkg/analysis_services/test/correction/test_all.dart
index 169f143..a092de11 100644
--- a/pkg/analysis_services/test/correction/test_all.dart
+++ b/pkg/analysis_services/test/correction/test_all.dart
@@ -6,12 +6,20 @@
import 'package:unittest/unittest.dart';
-import 'fix_test.dart' as fix_processor_test;
+import 'change_test.dart' as change_test;
+import 'fix_test.dart' as fix_test;
+import 'name_suggestion_test.dart' as name_suggestion_test;
+import 'source_range_test.dart' as source_range_test;
+import 'strings_test.dart' as strings_test;
/// Utility for manually running all tests.
main() {
groupSep = ' | ';
group('correction', () {
- fix_processor_test.main();
+ change_test.main();
+ fix_test.main();
+ name_suggestion_test.main();
+ source_range_test.main();
+ strings_test.main();
});
}
\ No newline at end of file
diff --git a/pkg/analysis_services/test/index/dart_index_contributor_test.dart b/pkg/analysis_services/test/index/dart_index_contributor_test.dart
index 9912459..f6d7e20 100644
--- a/pkg/analysis_services/test/index/dart_index_contributor_test.dart
+++ b/pkg/analysis_services/test/index/dart_index_contributor_test.dart
@@ -7,6 +7,7 @@
import 'package:analysis_services/index/index.dart';
import 'package:analysis_services/index/index_store.dart';
import 'package:analysis_services/src/index/index_contributor.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
@@ -14,8 +15,6 @@
import 'package:typed_mock/typed_mock.dart';
import 'package:unittest/unittest.dart';
-import 'abstract_single_unit.dart';
-
main() {
groupSep = ' | ';
@@ -123,6 +122,26 @@
_expectedLocation(mainElement, 'field); // not a member'));
}
+ void test_NameElement_isDefinedBy_localVariable_inForEach() {
+ _indexTestUnit('''
+class A {
+ main() {
+ for (int test in []) {
+ }
+ }
+}
+''');
+ // prepare elements
+ Element mainElement = findElement('main');
+ LocalVariableElement testElement = findElement('test');
+ Element nameElement = new NameElement('test');
+ // verify
+ _assertRecordedRelation(
+ nameElement,
+ IndexConstants.NAME_IS_DEFINED_BY,
+ _expectedLocation(testElement, 'test in []'));
+ }
+
void test_NameElement_method() {
_indexTestUnit('''
class A {
@@ -152,26 +171,6 @@
_expectedLocationQU(mainElement, 'method(); // ur'));
}
- void test_NameElement_isDefinedBy_localVariable_inForEach() {
- _indexTestUnit('''
-class A {
- main() {
- for (int test in []) {
- }
- }
-}
-''');
- // prepare elements
- Element mainElement = findElement('main');
- LocalVariableElement testElement = findElement('test');
- Element nameElement = new NameElement('test');
- // verify
- _assertRecordedRelation(
- nameElement,
- IndexConstants.NAME_IS_DEFINED_BY,
- _expectedLocation(testElement, 'test in []'));
- }
-
void test_NameElement_operator_resolved() {
_indexTestUnit('''
class A {
diff --git a/pkg/analysis_services/test/index/store/codec_test.dart b/pkg/analysis_services/test/index/store/codec_test.dart
index 6664b90..141c1cb 100644
--- a/pkg/analysis_services/test/index/store/codec_test.dart
+++ b/pkg/analysis_services/test/index/store/codec_test.dart
@@ -6,14 +6,13 @@
import 'package:analysis_services/index/index.dart';
import 'package:analysis_services/src/index/store/codec.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
import 'package:analysis_testing/mocks.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:unittest/unittest.dart';
-import '../abstract_single_unit.dart';
-
main() {
groupSep = ' | ';
@@ -82,29 +81,6 @@
codec = new ElementCodec(stringCodec);
}
- void test_field() {
- resolveTestUnit('''
-class A {
- int field;
-}
-''');
- FieldElement field = findElement('field', ElementKind.FIELD);
- PropertyAccessorElement getter = field.getter;
- PropertyAccessorElement setter = field.setter;
- {
- int id = codec.encode(getter);
- expect(codec.decode(context, id), getter);
- }
- {
- int id = codec.encode(setter);
- expect(codec.decode(context, id), setter);
- }
- {
- int id = codec.encode(field);
- expect(codec.decode(context, id), field);
- }
- }
-
void test_encodeHash_notLocal() {
resolveTestUnit('''
class A {
@@ -129,6 +105,29 @@
expect(id_fooA == id_bar, isFalse);
}
+ void test_field() {
+ resolveTestUnit('''
+class A {
+ int field;
+}
+''');
+ FieldElement field = findElement('field', ElementKind.FIELD);
+ PropertyAccessorElement getter = field.getter;
+ PropertyAccessorElement setter = field.setter;
+ {
+ int id = codec.encode(getter);
+ expect(codec.decode(context, id), getter);
+ }
+ {
+ int id = codec.encode(setter);
+ expect(codec.decode(context, id), setter);
+ }
+ {
+ int id = codec.encode(field);
+ expect(codec.decode(context, id), field);
+ }
+ }
+
void test_localLocalVariable() {
resolveTestUnit('''
main() {
diff --git a/pkg/analysis_services/test/search/hierarchy_test.dart b/pkg/analysis_services/test/search/hierarchy_test.dart
index a83312c..c9a0c1d 100644
--- a/pkg/analysis_services/test/search/hierarchy_test.dart
+++ b/pkg/analysis_services/test/search/hierarchy_test.dart
@@ -13,12 +13,11 @@
import 'package:analysis_services/index/local_memory_index.dart';
import 'package:analysis_services/search/hierarchy.dart';
import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:unittest/unittest.dart';
-import '../index/abstract_single_unit.dart';
-
main() {
groupSep = ' | ';
diff --git a/pkg/analysis_services/test/search/search_engine_test.dart b/pkg/analysis_services/test/search/search_engine_test.dart
index df96e48..0445c24 100644
--- a/pkg/analysis_services/test/search/search_engine_test.dart
+++ b/pkg/analysis_services/test/search/search_engine_test.dart
@@ -13,6 +13,7 @@
import 'package:analysis_services/index/local_memory_index.dart';
import 'package:analysis_services/search/search_engine.dart';
import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
import 'package:analysis_testing/mocks.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/element.dart';
@@ -20,8 +21,6 @@
import 'package:typed_mock/typed_mock.dart';
import 'package:unittest/unittest.dart';
-import '../index/abstract_single_unit.dart';
-
main() {
groupSep = ' | ';
diff --git a/pkg/analysis_services/test/index/abstract_single_unit.dart b/pkg/analysis_testing/lib/abstract_single_unit.dart
similarity index 100%
rename from pkg/analysis_services/test/index/abstract_single_unit.dart
rename to pkg/analysis_testing/lib/abstract_single_unit.dart
diff --git a/pkg/analysis_testing/lib/mock_sdk.dart b/pkg/analysis_testing/lib/mock_sdk.dart
index 89de9b6..99cf23c 100644
--- a/pkg/analysis_testing/lib/mock_sdk.dart
+++ b/pkg/analysis_testing/lib/mock_sdk.dart
@@ -33,6 +33,7 @@
num operator -(num other);
num operator *(num other);
num operator /(num other);
+ int toInt();
}
abstract class int extends num {
int operator -();
@@ -62,6 +63,13 @@
class HtmlElement {}
''',
+ "/lib/async/async.dart": '''
+ library dart.async;
+ class Future {
+ static Future wait(List<Future> futures) => null;
+ }
+ ''',
+
"/lib/math/math.dart": '''
library dart.math;
const double E = 2.718281828459045;
@@ -114,6 +122,7 @@
const Map<String, String> uriToPath = const {
"dart:core": "/lib/core/core.dart",
"dart:html": "/lib/html/dartium/html_dartium.dart",
+ "dart:async": "/lib/async/async.dart",
"dart:math": "/lib/math/math.dart"
};
diff --git a/pkg/docgen/lib/src/generator.dart b/pkg/docgen/lib/src/generator.dart
index 42c2e3b..1258d20 100644
--- a/pkg/docgen/lib/src/generator.dart
+++ b/pkg/docgen/lib/src/generator.dart
@@ -423,18 +423,20 @@
/// from a snapshot and using --parse-sdk or --include-sdk, then use this
/// hard-coded version. This should be updated to be consistent with the text
/// in docgen/doc/sdk-introduction.md
+// TODO(alanknight): It would be better if we could resolve the references to
+// dart:core etc. at load-time in the viewer. dartbug.com/20112
const _DEFAULT_SDK_INTRODUCTION =
"""
Welcome to the Dart API reference documentation,
covering the official Dart API libraries.
Some of the most fundamental Dart libraries include:
-* [dart:core](#dart:core):
+* [dart:core](./dart:core):
Core functionality such as strings, numbers, collections, errors,
dates, and URIs.
-* [dart:html](#dart:html):
+* [dart:html](./dart:html):
DOM manipulation for web apps.
-* [dart:io](#dart:io):
+* [dart:io](./dart:io):
I/O for command-line apps.
Except for dart:core, you must import a library before you can use it.
diff --git a/pkg/intl/README.md b/pkg/intl/README.md
index 74594b9..18951c7 100644
--- a/pkg/intl/README.md
+++ b/pkg/intl/README.md
@@ -45,10 +45,7 @@
to make
sure the data is available. This reduces the size of the application by only
loading the
-data that is actually required. However, deferred loading does not yet work for
-multiple
-libraries, so currently all the code will be included anyay, increasing the code
-size in the short term.
+data that is actually required.
Each different area of internationalization (messages, dates, numbers) requires
a separate initialization process. That way, if the application only needs to
@@ -153,36 +150,33 @@
examples: {{'userGender': 'male', 'userName': 'Fred'},
{'userGender': 'female', 'userName' : 'Alice'}});
+It's recommended to use complete sentences in the sub-messages to keep
+the structure as simple as possible for the translators.
+
## Extracting And Using Translated Messages
When your program contains messages that need translation, these must
be extracted from the program source, sent to human translators, and the
-results need to be incorporated. This is still work in progress, and
-the extraction is done to a custom JSON format that is not supported
-by translation tools. We intend to support one or more actual
-translation file formats.
+results need to be incorporated.
-To extract messages, run the `pkg/intl/test/extract_to_json.dart` program.
+To extract messages, run the `extract_to_arb.dart` program.
- dart extract_to_json.dart --output-dir=target/directory
+ pub run intl:extract_to_arb --output-dir=target/directory
my_program.dart more_of_my_program.dart
-This will produce a file `intl_messages.json` with the messages from
-all of these programs. This is in a simple JSON format with a map from
-message names to message strings.
+This will produce a file `intl_messages.arb` with the messages from
+all of these programs. an [ARB]
+(https://code.google.com/p/arb/wiki/ApplicationResourceBundleSpecification)
+format file which can be used for input to translation tools like
+[Google Translator Toolkit](https://translate.google.com/toolkit/)
+The resulting translations can be used to generate a set of libraries
+using the `generate_from_arb.dart` program.
-The reverse step expects to receive a series of files, one per
-locale. These consist of a map with the entry for "_locale" indicating
-the locale, and with the function name mapped to the translated
-string. However, plurals and genders are currently represented in an
-opaque form, by serializing the internal objects that represent
-them. You can see the generation of this code in the
-`make_hardcoded_translation.dart` test file.
+This expects to receive a series of files, one per
+locale.
-If you manage to create such a set of input files, then you can run
-
- dart generate_from_json.dart --generated_file_prefix=<prefix>
- <my dart files> <translated json files>
+ pub run intl:generate_from_arb --generated_file_prefix=<prefix>
+ <my_dart_files> <translated_ARB_files>
This will generate Dart libraries, one per locale, which contain the
translated versions. Your Dart libraries can import the primary file,
@@ -291,16 +285,16 @@
new BidiFormatter.RTL().wrapWithUnicode('xyz');
new BidiFormatter.RTL().wrapWithSpan('xyz');
-[intl_lib]: https://api.dartlang.org/docs/channels/stable/latest/intl.html
-[Intl]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html
-[DateFormat]: https://api.dartlang.org/docs/channels/stable/latest/intl/DateFormat.html
-[NumberFormat]: https://api.dartlang.org/docs/channels/stable/latest/intl/NumberFormat.html
-[withLocale]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#withLocale
-[defaultLocale]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#defaultLocale
-[Intl.message]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#message
-[Intl.plural]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#plural
-[Intl.gender]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#gender
-[DateTime]: https://api.dartlang.org/docs/channels/stable/latest/dart_core/DateTime.html
-[BidiFormatter]: https://api.dartlang.org/docs/channels/stable/latest/intl/BidiFormatter.html
-[BidiFormatter.RTL]: https://api.dartlang.org/docs/channels/stable/latest/intl/BidiFormatter.html#RTL
-[BidiFormatter.LTR]: https://api.dartlang.org/docs/channels/stable/latest/intl/BidiFormatter.html#LTR
+[intl_lib]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl
+[Intl]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl
+[DateFormat]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.DateFormat
+[NumberFormat]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.NumberFormat
+[withLocale]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_withLocale
+[defaultLocale]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_defaultLocale
+[Intl.message]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_message
+[Intl.plural]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_plural
+[Intl.gender]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_gender
+[DateTime]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:core.DateTime
+[BidiFormatter]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.BidiFormatter
+[BidiFormatter.RTL]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.BidiFormatter#id_BidiFormatter-RTL
+[BidiFormatter.LTR]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.BidiFormatter#id_BidiFormatter-LTR
diff --git a/pkg/intl/lib/date_format.dart b/pkg/intl/lib/date_format.dart
index d2889ec..4b29df9 100644
--- a/pkg/intl/lib/date_format.dart
+++ b/pkg/intl/lib/date_format.dart
@@ -233,6 +233,8 @@
}
/**
+ * NOT YET IMPLEMENTED.
+ *
* Returns a date string indicating how long ago (3 hours, 2 minutes)
* something has happened or how long in the future something will happen
* given a [reference] DateTime relative to the current time.
@@ -240,6 +242,8 @@
String formatDuration(DateTime reference) => '';
/**
+ * NOT YET IMPLEMENTED.
+ *
* Formats a string indicating how long ago (negative [duration]) or how far
* in the future (positive [duration]) some time is with respect to a
* reference [date].
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index a7213d0..0ce6c44 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -8,7 +8,7 @@
* and utilities for working with Bidirectional text.
*
* This is part of the [intl package]
- * (http://pub.dartlang.org/packages/intl).
+ * (https://pub.dartlang.org/packages/intl).
*
* For things that require locale or other data, there are multiple different
* ways of making that data available, which may require importing different
@@ -43,13 +43,7 @@
* and used to create a date format via `anIntl.date()`. Static methods
* on this class are also used in message formatting.
*
- * Message example:
- * '''I see ${Intl.plural(num_people,
- * {'0': 'no one at all',
- * '1': 'one other person',
- * 'other': '$num_people other people'})} in $place.''''
- *
- * Usage examples:
+ * Examples:
* today(date) => Intl.message(
* "Today's date is $date",
* name: 'today',
@@ -58,18 +52,22 @@
* examples: {'date' : 'June 8, 2012'});
* print(today(new DateTime.now().toString());
*
- * msg(num_people, place) => Intl.message(
- * '''I see ${Intl.plural(num_people,
- * {'0': 'no one at all',
- * '1': 'one other person',
- * 'other': '$num_people other people'})} in $place.''',
+ * howManyPeople(numberOfPeople, place) => Intl.plural(
+ * zero: 'I see no one at all',
+ * one: 'I see one other person',
+ * other: 'I see $numberOfPeople other people')} in $place.''',
* name: 'msg',
- * args: [num_people, place],
- * desc: 'Description of how many people are seen as program start.',
- * examples: {'num_people': 3, 'place': 'London'});
+ * args: [numberOfPeople, place],
+ * desc: 'Description of how many people are seen in a place.',
+ * examples: {'numberOfPeople': 3, 'place': 'London'});
*
- * Calling `msg(2, 'Athens');` would
+ * Calling `howManyPeople(2, 'Athens');` would
* produce "I see 2 other people in Athens." as output in the default locale.
+ * If run in a different locale it would produce appropriately translated
+ * output.
+ *
+ * For more detailed information on messages and localizing them see
+ * the main [package documentation](https://pub.dartlang.org/packages/intl)
*
* You can set the default locale.
* Intl.defaultLocale = "pt_BR";
@@ -148,8 +146,10 @@
* be a valid const literal map. Similarly, the [desc] argument must
* be a single, simple string. These two arguments will not be used at runtime
* but will be extracted from
- * the source code and used as additional data for translators.
- *
+ * the source code and used as additional data for translators. For more
+ * information see the "Messages" section of the main [package documentation]
+ * (https://pub.dartlang.org/packages/intl).
+ *
* The [name] and [args] arguments are required, and are used at runtime
* to look up the localized version and pass the appropriate arguments to it.
* We may in the future modify the code during compilation to make manually
diff --git a/pkg/intl/pubspec.yaml b/pkg/intl/pubspec.yaml
index fdd984f..a38f52c 100644
--- a/pkg/intl/pubspec.yaml
+++ b/pkg/intl/pubspec.yaml
@@ -5,7 +5,6 @@
homepage: http://www.dartlang.org
environment:
sdk: '>=1.4.0 <2.0.0'
-documentation: http://api.dartlang.org/docs/pkg/intl
dependencies:
analyzer: '>=0.13.2 <0.16.0'
path: '>=0.9.0 <2.0.0'
diff --git a/pkg/matcher/CHANGELOG.md b/pkg/matcher/CHANGELOG.md
index af9ce95..e175d94 100644
--- a/pkg/matcher/CHANGELOG.md
+++ b/pkg/matcher/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.11.0
+
+* Removed deprecated matchers.
+
## 0.10.1+1
* Get the tests passing when run on dart2js in minified mode.
diff --git a/pkg/matcher/lib/src/error_matchers.dart b/pkg/matcher/lib/src/error_matchers.dart
index cb716f5..dca1759 100644
--- a/pkg/matcher/lib/src/error_matchers.dart
+++ b/pkg/matcher/lib/src/error_matchers.dart
@@ -7,28 +7,6 @@
import 'core_matchers.dart';
import 'interfaces.dart';
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher isAbstractClassInstantiationError =
- const _AbstractClassInstantiationError();
-
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher throwsAbstractClassInstantiationError =
- const Throws(isAbstractClassInstantiationError);
-
-class _AbstractClassInstantiationError extends TypeMatcher {
- const _AbstractClassInstantiationError() :
- super("AbstractClassInstantiationError");
- bool matches(item, Map matchState) => item is AbstractClassInstantiationError;
-}
-
/// A matcher for ArgumentErrors.
const Matcher isArgumentError = const _ArgumentError();
@@ -76,20 +54,6 @@
bool matches(item, Map matchState) => item is Exception;
}
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher isFallThroughError = const _FallThroughError();
-
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher throwsFallThroughError = const Throws(isFallThroughError);
-
class _FallThroughError extends TypeMatcher {
const _FallThroughError(): super("FallThroughError");
bool matches(item, Map matchState) => item is FallThroughError;
diff --git a/pkg/matcher/pubspec.yaml b/pkg/matcher/pubspec.yaml
index 6f6f277..4612c58 100644
--- a/pkg/matcher/pubspec.yaml
+++ b/pkg/matcher/pubspec.yaml
@@ -1,10 +1,9 @@
name: matcher
-version: 0.10.1+1
+version: 0.11.0
author: Dart Team <misc@dartlang.org>
description: Support for specifying test expectations
-homepage: http://www.dartlang.org
+homepage: https://pub.dartlang.org/packages/matcher
environment:
sdk: '>=1.0.0 <2.0.0'
-documentation: http://api.dartlang.org/docs/pkg/matcher
dev_dependencies:
unittest: '>=0.10.0 <0.12.0'
diff --git a/pkg/matcher/test/deprecated_matchers_test.dart b/pkg/matcher/test/deprecated_matchers_test.dart
deleted file mode 100644
index b6acc1c..0000000
--- a/pkg/matcher/test/deprecated_matchers_test.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library matcher.deprecated_matchers_test;
-
-import 'package:matcher/matcher.dart';
-import 'package:unittest/unittest.dart' show test, group;
-
-import 'test_utils.dart';
-
-void main() {
- initUtils();
-
- test('throwsAbstractClassInstantiationError', () {
- expect(() => new _AbstractClass(), throwsAbstractClassInstantiationError);
- });
-
- test('throwsFallThroughError', () {
- expect(() {
- var a = 0;
- switch (a) {
- case 0:
- a += 1;
- case 1:
- return;
- }
- }, throwsFallThroughError);
- });
-}
-
-abstract class _AbstractClass {
-}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 76bf1a2..fff2bfb 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -249,6 +249,11 @@
third_party/angular_tests/browser_test: StaticWarning # Issue 15890
+[ $compiler == dartanalyzer ]
+# This test uses third_party/pkg/perf_api/lib/perf_api.dart, which
+# contains illegal constant constructors.
+third_party/angular_tests/browser_test: CompileTimeError
+
[ $compiler == dart2js && $runtime == none]
polymer/e2e_test/canonicalization: Skip
polymer/e2e_test/experimental_boot: Skip
diff --git a/pkg/polymer/lib/src/build/import_inliner.dart b/pkg/polymer/lib/src/build/import_inliner.dart
index dc181c3..675db29 100644
--- a/pkg/polymer/lib/src/build/import_inliner.dart
+++ b/pkg/polymer/lib/src/build/import_inliner.dart
@@ -144,7 +144,12 @@
/// Loads an asset identified by [id], visits its imports and collects its
/// html imports. Then inlines it into the main document.
Future _inlineImport(AssetId id, Element link) {
- return readAsHtml(id, transform).then((doc) {
+ return readAsHtml(id, transform).catchError((error) {
+ transform.logger.error(
+ "Failed to inline html import: $error", asset: id,
+ span: link.sourceSpan);
+ }).then((doc) {
+ if (doc == null) return false;
new _UrlNormalizer(transform, id).visit(doc);
return _visitImports(doc).then((_) {
// _UrlNormalizer already ensures there is a library name.
@@ -160,7 +165,15 @@
}
Future _inlineStylesheet(AssetId id, Element link) {
- return transform.readInputAsString(id).then((css) {
+ return transform.readInputAsString(id).catchError((error) {
+ // TODO(jakemac): Move this warning to the linter once we can make it run
+ // always (see http://dartbug.com/17199). Then hide this error and replace
+ // with a comment pointing to the linter error (so we don't double warn).
+ transform.logger.warning(
+ "Failed to inline stylesheet: $error", asset: id,
+ span: link.sourceSpan);
+ }).then((css) {
+ if (css == null) return;
css = new _UrlNormalizer(transform, id).visitCss(css);
var styleElement = new Element.tag('style')..text = css;
// Copy over the extra attributes from the link tag to the style tag.
@@ -324,7 +337,7 @@
if (!isCustomTagName(node.localName)) {
node.attributes.forEach((name, value) {
if (_urlAttributes.contains(name)) {
- if (value != '' && !value.trim().startsWith('{{')) {
+ if (value != '' && !value.trim().startsWith(_BINDINGS)) {
node.attributes[name] = _newUrl(value, node.sourceSpan);
changed = changed || value != node.attributes[name];
}
@@ -347,6 +360,7 @@
static final _URL = new RegExp(r'url\(([^)]*)\)', multiLine: true);
static final _QUOTE = new RegExp('["\']', multiLine: true);
+ static final _BINDINGS = new RegExp(r'({{)|(\[\[)');
/// Visit the CSS text and replace any relative URLs so we can inline it.
// Ported from:
@@ -403,7 +417,10 @@
}
String _newUrl(String href, Span span) {
- var uri = Uri.parse(href);
+ // Uri.parse blows up on invalid characters (like {{). Encoding the uri
+ // allows it to be parsed, which does the correct thing in the general case.
+ // This uri not used to build the new uri, so it never needs to be decoded.
+ var uri = Uri.parse(Uri.encodeFull(href));
if (uri.isAbsolute) return href;
if (!uri.scheme.isEmpty) return href;
if (!uri.host.isEmpty) return href;
diff --git a/pkg/polymer/test/build/import_inliner_test.dart b/pkg/polymer/test/build/import_inliner_test.dart
index 023bf4d..f6daa40 100644
--- a/pkg/polymer/test/build/import_inliner_test.dart
+++ b/pkg/polymer/test/build/import_inliner_test.dart
@@ -612,6 +612,31 @@
'</head><body>'
'<polymer-element>3</polymer-element></body></html>',
});
+
+ testPhases("missing styles don't throw errors and are not inlined", phases, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="stylesheet" href="foo.css">'
+ '</head></html>',
+ }, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head></head><body>'
+ '<link rel="stylesheet" href="foo.css">'
+ '</body></html>',
+ }, [
+ 'warning: Failed to inline stylesheet: '
+ 'Could not find asset a|web/foo.css. (web/test.html 0 27)',
+ ]);
+
+ testPhases("missing html imports throw errors", phases, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="foo.html">'
+ '</head></html>',
+ }, {}, [
+ 'error: Failed to inline html import: '
+ 'Could not find asset a|web/foo.html. (web/test.html 0 27)',
+ ]);
}
void stylesheetTests() {
@@ -823,6 +848,41 @@
'a|web/foo/test_2.html':
'<foo-element src="baz.jpg"></foo-element>',
});
+
+ testPhases('paths with a binding prefix are not normalized', phases, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="foo/test.html">'
+ '</head></html>',
+ 'a|web/foo/test.html':
+ '<img src="{{bar}}">'
+ '<img src="[[bar]]">',
+ }, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head></head><body>'
+ '<img src="{{bar}}">'
+ '<img src="[[bar]]">'
+ '</body></html>',
+ 'a|web/foo/test.html':
+ '<img src="{{bar}}">'
+ '<img src="[[bar]]">',
+ });
+
+ testPhases('relative paths followed by bindings are normalized', phases, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="foo/test.html">'
+ '</head></html>',
+ 'a|web/foo/test.html':
+ '<img src="baz/{{bar}}">'
+ '<img src="./{{bar}}">',
+ }, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head></head><body>'
+ '<img src="foo/baz/{{bar}}">'
+ '<img src="foo/{{bar}}">'
+ '</body></html>',
+ });
}
void entryPointTests() {
diff --git a/pkg/serialization/README.md b/pkg/serialization/README.md
index d35ebc8..aaa7165 100644
--- a/pkg/serialization/README.md
+++ b/pkg/serialization/README.md
@@ -1,6 +1,3 @@
-Serialization
-=============
-
A general-purpose serialization facility for Dart Objects.
This provides the ability to save and restore objects to pluggable
@@ -13,8 +10,3 @@
APIs using JSON to pass acyclic structures without class information,
and is fairly heavweight and expensive for doing that compared to simpler
approaches.
-
-For more detailed descriptions and examples of use, see the comment on
-the [serialization][serialization] library.
-
-[serialization]: https://api.dartlang.org/docs/channels/stable/latest/serialization.html
diff --git a/pkg/serialization/pubspec.yaml b/pkg/serialization/pubspec.yaml
index 2a8d9b2..3e11f26 100644
--- a/pkg/serialization/pubspec.yaml
+++ b/pkg/serialization/pubspec.yaml
@@ -1,11 +1,9 @@
name: serialization
-version: 0.9.1
-author: "Dart Team <misc@dartlang.org>"
-homepage: http://www.dartlang.org
-documentation: http://api.dartlang.org/docs/pkg/serialization
-description: >
- Provide a serialization facility for Dart objects.
-dev_dependencies:
- unittest: ">=0.9.0 <0.10.0"
+version: 0.9.1+1
+author: Dart Team <misc@dartlang.org>
+description: Provide a serialization facility for Dart objects.
+homepage: https://pub.dartlang.org/packages/serialization
environment:
- sdk: ">=1.0.0 <2.0.0"
+ sdk: '>=1.0.0 <2.0.0'
+dev_dependencies:
+ unittest: '>=0.9.0 <0.12.0'
diff --git a/pkg/source_maps/CHANGELOG.md b/pkg/source_maps/CHANGELOG.md
index 7767fc1..c52d585 100644
--- a/pkg/source_maps/CHANGELOG.md
+++ b/pkg/source_maps/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.9.4
+
+* Update `SpanFormatException` with `source` and `offset`.
+
## 0.9.3
* Support writing SingleMapping objects to source map version 3 format.
diff --git a/pkg/source_maps/lib/span.dart b/pkg/source_maps/lib/span.dart
index 771e9e0..b546a97 100644
--- a/pkg/source_maps/lib/span.dart
+++ b/pkg/source_maps/lib/span.dart
@@ -385,9 +385,10 @@
/// A [SpanException] that's also a [FormatException].
class SpanFormatException extends SpanException implements FormatException {
- SpanFormatException(String message, Span span)
+ final source;
+
+ SpanFormatException(String message, Span span, [this.source])
: super(message, span);
- get source => null;
- int get position => null;
+ int get offset => span == null ? null : span.start.offset;
}
diff --git a/pkg/source_maps/pubspec.yaml b/pkg/source_maps/pubspec.yaml
index ae0323d..c5029e2 100644
--- a/pkg/source_maps/pubspec.yaml
+++ b/pkg/source_maps/pubspec.yaml
@@ -7,7 +7,7 @@
#
# When the minor version is upgraded, you *must* update that version constraint
# in pub to stay in sync with this.
-version: 0.9.3
+version: 0.9.4
author: Dart Team <misc@dartlang.org>
description: Library to programmatically manipulate source map files.
homepage: http://www.dartlang.org
diff --git a/pkg/source_span/lib/src/span_exception.dart b/pkg/source_span/lib/src/span_exception.dart
index af64241..36f2488 100644
--- a/pkg/source_span/lib/src/span_exception.dart
+++ b/pkg/source_span/lib/src/span_exception.dart
@@ -36,7 +36,7 @@
implements FormatException {
final source;
- int get position => span == null ? null : span.start.offset;
+ int get offset => span == null ? null : span.start.offset;
SourceSpanFormatException(String message, SourceSpan span, [this.source])
: super(message, span);
diff --git a/pkg/unittest/CHANGELOG.md b/pkg/unittest/CHANGELOG.md
index d8171f9..b913589 100644
--- a/pkg/unittest/CHANGELOG.md
+++ b/pkg/unittest/CHANGELOG.md
@@ -1,3 +1,7 @@
+##0.11.0+3
+
+* Updated maximum `matcher` version.
+
##0.11.0+2
* Removed unused files from tests and standardized remaining test file names.
diff --git a/pkg/unittest/pubspec.yaml b/pkg/unittest/pubspec.yaml
index c5b04ca..6d9e4a6 100644
--- a/pkg/unittest/pubspec.yaml
+++ b/pkg/unittest/pubspec.yaml
@@ -1,11 +1,10 @@
name: unittest
-version: 0.11.0+2
+version: 0.11.0+3
author: Dart Team <misc@dartlang.org>
description: A library for writing dart unit tests.
-homepage: http://www.dartlang.org
+homepage: https://pub.dartlang.org/packages/unittest
environment:
sdk: '>=1.0.0 <2.0.0'
-documentation: http://api.dartlang.org/docs/pkg/unittest
dependencies:
- matcher: '>=0.10.0 <0.11.0'
+ matcher: '>=0.10.0 <0.12.0'
stack_trace: '>=0.9.0 <2.0.0'
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index c8cf522..5582f35 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -744,7 +744,7 @@
// Callback function that gets called from dartutils when there are
// no more outstanding load requests.
void FUNCTION_NAME(Builtin_DoneLoading)(Dart_NativeArguments args) {
- Dart_Handle res = Dart_FinalizeLoading();
+ Dart_Handle res = Dart_FinalizeLoading(true);
if (Dart_IsError(res)) {
Dart_PropagateError(res);
}
@@ -799,6 +799,12 @@
Dart_Handle async_lib = Dart_LookupLibrary(url);
DART_CHECK_VALID(async_lib);
Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
+
+ // We need to ensure that all the scripts loaded so far are finalized
+ // as we are about to invoke some Dart code below to setup closures.
+ result = Dart_FinalizeLoading(false);
+ DART_CHECK_VALID(result);
+
Dart_Handle timer_closure =
Dart_Invoke(io_lib, NewString("_getTimerFactoryClosure"), 0, NULL);
Dart_Handle args[1];
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 06f3884..8284c67 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -468,6 +468,14 @@
Dart_Handle library = LoadGenericSnapshotCreationScript(Builtin::kIOLibrary);
VerifyLoaded(library);
+ Dart_Handle result = Dart_FinalizeLoading(false);
+ if (Dart_IsError(result)) {
+ const char* err_msg = Dart_GetError(library);
+ Log::PrintErr("Errors encountered while loading: %s\n", err_msg);
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ exit(255);
+ }
}
@@ -532,6 +540,10 @@
Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
CHECK_RESULT(builtin_lib);
+ // Ensure that we mark all libraries as loaded.
+ result = Dart_FinalizeLoading(false);
+ CHECK_RESULT(result);
+
// Prepare for script loading by setting up the 'print' and 'timer'
// closures and setting up 'package root' for URI resolution.
result = DartUtils::PrepareForScriptLoading(package_root, builtin_lib);
@@ -556,6 +568,9 @@
// Load the specified script.
library = LoadSnapshotCreationScript(app_script_name);
VerifyLoaded(library);
+ // Ensure that we mark all libraries as loaded.
+ result = Dart_FinalizeLoading(false);
+ CHECK_RESULT(result);
CreateAndWriteSnapshot();
Dart_EnterIsolate(UriResolverIsolateScope::isolate);
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 32edb0c..ff95402 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -115,6 +115,8 @@
// Expect a library.
ASSERT(library != Dart_Null());
SHUTDOWN_ON_ERROR(library);
+ result = Dart_FinalizeLoading(false);
+ ASSERT(!Dart_IsError(result));
Dart_ExitScope();
Dart_ExitIsolate();
bool retval = Dart_IsolateMakeRunnable(isolate);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 4788997..471d2cd 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2670,15 +2670,19 @@
/**
- * Indicates that all outstanding load requests have been satisfied,
- * finalizing classes and completing deferred library futures.
+ * Indicates that all outstanding load requests have been satisfied.
+ * This finalizes all the new classes loaded and optionally completes
+ * deferred library futures.
*
* Requires there to be a current isolate.
*
- * \return Success if all deferred library futures are completed.
- * Otherwise, returns an error.
+ * \param complete_futures Specify true if all deferred library
+ * futures should be completed, false otherwise.
+ *
+ * \return Success if all classes have been finalized and deferred library
+ * futures are completed. Otherwise, returns an error.
*/
-DART_EXPORT Dart_Handle Dart_FinalizeLoading();
+DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures);
/*
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 60c2b6a..78d30f7 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -53,7 +53,7 @@
}
Iterable<E> getRange(int start, [int end]) {
- return IterableMixinWorkaround.getRangeList(this, start, end);
+ return new IterableMixinWorkaround<E>().getRangeList(this, start, end);
}
// List interface.
@@ -136,7 +136,7 @@
}
Iterable<E> where(bool f(E element)) {
- return IterableMixinWorkaround.where(this, f);
+ return new IterableMixinWorkaround<E>().where(this, f);
}
Iterable expand(Iterable f(E element)) {
@@ -144,19 +144,19 @@
}
Iterable<E> take(int n) {
- return IterableMixinWorkaround.takeList(this, n);
+ return new IterableMixinWorkaround<E>().takeList(this, n);
}
Iterable<E> takeWhile(bool test(E value)) {
- return IterableMixinWorkaround.takeWhile(this, test);
+ return new IterableMixinWorkaround<E>().takeWhile(this, test);
}
Iterable<E> skip(int n) {
- return IterableMixinWorkaround.skipList(this, n);
+ return new IterableMixinWorkaround<E>().skipList(this, n);
}
Iterable<E> skipWhile(bool test(E value)) {
- return IterableMixinWorkaround.skipWhile(this, test);
+ return new IterableMixinWorkaround<E>().skipWhile(this, test);
}
bool every(bool f(E element)) {
@@ -189,7 +189,8 @@
bool get isNotEmpty => !isEmpty;
- Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
+ Iterable<E> get reversed =>
+ new IterableMixinWorkaround<E>().reversedList(this);
void sort([int compare(E a, E b)]) {
IterableMixinWorkaround.sortList(this, compare);
@@ -257,7 +258,7 @@
}
Map<int, E> asMap() {
- return IterableMixinWorkaround.asMapList(this);
+ return new IterableMixinWorkaround<E>().asMapList(this);
}
}
@@ -347,7 +348,7 @@
}
Iterable<E> getRange(int start, int end) {
- return IterableMixinWorkaround.getRangeList(this, start, end);
+ return new IterableMixinWorkaround<E>().getRangeList(this, start, end);
}
// Collection interface.
@@ -377,7 +378,7 @@
}
Iterable<E> where(bool f(E element)) {
- return IterableMixinWorkaround.where(this, f);
+ return new IterableMixinWorkaround<E>().where(this, f);
}
Iterable expand(Iterable f(E element)) {
@@ -385,19 +386,19 @@
}
Iterable<E> take(int n) {
- return IterableMixinWorkaround.takeList(this, n);
+ return new IterableMixinWorkaround<E>().takeList(this, n);
}
Iterable<E> takeWhile(bool test(E value)) {
- return IterableMixinWorkaround.takeWhile(this, test);
+ return new IterableMixinWorkaround<E>().takeWhile(this, test);
}
Iterable<E> skip(int n) {
- return IterableMixinWorkaround.skipList(this, n);
+ return new IterableMixinWorkaround<E>().skipList(this, n);
}
Iterable<E> skipWhile(bool test(E value)) {
- return IterableMixinWorkaround.skipWhile(this, test);
+ return new IterableMixinWorkaround<E>().skipWhile(this, test);
}
bool every(bool f(E element)) {
@@ -430,7 +431,8 @@
bool get isNotEmpty => !isEmpty;
- Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
+ Iterable<E> get reversed =>
+ new IterableMixinWorkaround<E>().reversedList(this);
void sort([int compare(E a, E b)]) {
throw UnmodifiableListError.change();
@@ -502,7 +504,7 @@
}
Map<int, E> asMap() {
- return IterableMixinWorkaround.asMapList(this);
+ return new IterableMixinWorkaround<E>().asMapList(this);
}
}
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index aae3197..1a7b882 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -77,7 +77,7 @@
}
Iterable<T> getRange(int start, int end) {
- return IterableMixinWorkaround.getRangeList(this, start, end);
+ return new IterableMixinWorkaround<T>().getRangeList(this, start, end);
}
void setRange(int start, int end, Iterable<T> iterable, [int skipCount = 0]) {
@@ -216,7 +216,7 @@
_setData(new_data);
}
- // Collection interface.
+ // Iterable interface.
bool contains(Object element) {
return IterableMixinWorkaround.contains(this, element);
@@ -261,7 +261,7 @@
}
Iterable<T> where(bool f(T element)) {
- return IterableMixinWorkaround.where(this, f);
+ return new IterableMixinWorkaround<T>().where(this, f);
}
Iterable expand(Iterable f(T element)) {
@@ -269,19 +269,19 @@
}
Iterable<T> take(int n) {
- return IterableMixinWorkaround.takeList(this, n);
+ return new IterableMixinWorkaround<T>().takeList(this, n);
}
Iterable<T> takeWhile(bool test(T value)) {
- return IterableMixinWorkaround.takeWhile(this, test);
+ return new IterableMixinWorkaround<T>().takeWhile(this, test);
}
Iterable<T> skip(int n) {
- return IterableMixinWorkaround.skipList(this, n);
+ return new IterableMixinWorkaround<T>().skipList(this, n);
}
Iterable<T> skipWhile(bool test(T value)) {
- return IterableMixinWorkaround.skipWhile(this, test);
+ return new IterableMixinWorkaround<T>().skipWhile(this, test);
}
bool every(bool f(T element)) {
@@ -318,7 +318,8 @@
this.length = 0;
}
- Iterable<T> get reversed => IterableMixinWorkaround.reversedList(this);
+ Iterable<T> get reversed =>
+ new IterableMixinWorkaround<T>().reversedList(this);
void sort([int compare(T a, T b)]) {
IterableMixinWorkaround.sortList(this, compare);
@@ -343,6 +344,6 @@
}
Map<int, T> asMap() {
- return IterableMixinWorkaround.asMapList(this);
+ return new IterableMixinWorkaround<T>().asMapList(this);
}
}
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 370b5ca..51a9d80 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -241,7 +241,7 @@
// Based class for _TypedList that provides common methods for implementing
// the collection and list interfaces.
-
+// TODO(13647): Make this extends ListBase<T>
abstract class _TypedListBase {
// Method(s) implementing the Collection interface.
@@ -254,10 +254,6 @@
}
}
- Iterable map(f(element)) {
- return IterableMixinWorkaround.mapList(this, f);
- }
-
String join([String separator = ""]) {
return IterableMixinWorkaround.join(this, separator);
}
@@ -271,30 +267,48 @@
return IterableMixinWorkaround.fold(this, initialValue, combine);
}
- Iterable where(bool f(element)) {
- return IterableMixinWorkaround.where(this, f);
+ Iterable map(f(element)) {
+ return IterableMixinWorkaround.mapList(this, f);
}
Iterable expand(Iterable f(element)) {
return IterableMixinWorkaround.expand(this, f);
}
+ // The following methods need to know the element type (int or double).
+ Iterable where(bool f(element)) {
+ return new IterableMixinWorkaround().where(this, f);
+ }
+
Iterable take(int n) {
- return IterableMixinWorkaround.takeList(this, n);
+ return new IterableMixinWorkaround().takeList(this, n);
}
Iterable takeWhile(bool test(element)) {
- return IterableMixinWorkaround.takeWhile(this, test);
+ return new IterableMixinWorkaround().takeWhile(this, test);
}
Iterable skip(int n) {
- return IterableMixinWorkaround.skipList(this, n);
+ return new IterableMixinWorkaround().skipList(this, n);
}
Iterable skipWhile(bool test(element)) {
- return IterableMixinWorkaround.skipWhile(this, test);
+ return new IterableMixinWorkaround().skipWhile(this, test);
}
+ Iterable<dynamic> get reversed {
+ return new IterableMixinWorkaround().reversedList(this);
+ }
+
+ Map<int, dynamic> asMap() {
+ return new IterableMixinWorkaround().asMapList(this);
+ }
+
+ Iterable getRange(int start, [int end]) {
+ return new IterableMixinWorkaround().getRangeList(this, start, end);
+ }
+ // End of methods returning incorrectly parameterized types.
+
bool every(bool f(element)) {
return IterableMixinWorkaround.every(this, f);
}
@@ -315,10 +329,6 @@
return IterableMixinWorkaround.singleWhere(this, test);
}
- Iterable<dynamic> get reversed {
- return IterableMixinWorkaround.reversedList(this);
- }
-
dynamic elementAt(int index) {
return this[index];
}
@@ -436,10 +446,6 @@
return new Set.from(this);
}
- Map<int, dynamic> asMap() {
- return IterableMixinWorkaround.asMapList(this);
- }
-
List sublist(int start, [int end]) {
if (end == null) end = this.length;
int length = end - start;
@@ -449,10 +455,6 @@
return result;
}
- Iterable getRange(int start, [int end]) {
- return IterableMixinWorkaround.getRangeList(this, start, end);
- }
-
void setRange(int start, int end, Iterable from, [int skipCount = 0]) {
// Check ranges.
if ((start < 0) || (start > length)) {
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index c8e859d..2ddf07c 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -2183,6 +2183,17 @@
}
+bool Address::CanHoldImmediateOffset(
+ bool is_load, intptr_t cid, int64_t offset) {
+ int32_t offset_mask = 0;
+ if (is_load) {
+ return CanHoldLoadOffset(OperandSizeFor(cid), offset, &offset_mask);
+ } else {
+ return CanHoldStoreOffset(OperandSizeFor(cid), offset, &offset_mask);
+ }
+}
+
+
void Assembler::Push(Register rd, Condition cond) {
str(rd, Address(SP, -kWordSize, Address::PreIndex), cond);
}
@@ -3224,6 +3235,73 @@
}
+Address Assembler::ElementAddressForIntIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index,
+ Register temp) {
+ const int64_t offset_base =
+ (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+ const int64_t offset = offset_base +
+ static_cast<int64_t>(index) * index_scale;
+ ASSERT(Utils::IsInt(32, offset));
+
+ if (Address::CanHoldImmediateOffset(is_load, cid, offset)) {
+ return Address(array, static_cast<int32_t>(offset));
+ } else {
+ ASSERT(Address::CanHoldImmediateOffset(is_load, cid, offset - offset_base));
+ AddImmediate(temp, array, static_cast<int32_t>(offset_base));
+ return Address(temp, static_cast<int32_t>(offset - offset_base));
+ }
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
+ // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+ const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+ int32_t offset =
+ is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+ const OperandSize size = Address::OperandSizeFor(cid);
+ ASSERT(array != IP);
+ ASSERT(index != IP);
+ const Register base = is_load ? IP : index;
+ if ((offset != 0) ||
+ (size == kSWord) || (size == kDWord) || (size == kRegList)) {
+ if (shift < 0) {
+ ASSERT(shift == -1);
+ add(base, array, Operand(index, ASR, 1));
+ } else {
+ add(base, array, Operand(index, LSL, shift));
+ }
+ } else {
+ if (shift < 0) {
+ ASSERT(shift == -1);
+ return Address(array, index, ASR, 1);
+ } else {
+ return Address(array, index, LSL, shift);
+ }
+ }
+ int32_t offset_mask = 0;
+ if ((is_load && !Address::CanHoldLoadOffset(size,
+ offset,
+ &offset_mask)) ||
+ (!is_load && !Address::CanHoldStoreOffset(size,
+ offset,
+ &offset_mask))) {
+ AddImmediate(base, offset & ~offset_mask);
+ offset = offset & offset_mask;
+ }
+ return Address(base, offset);
+}
+
+
static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 5af7c66..a09145a 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -250,6 +250,9 @@
static bool CanHoldStoreOffset(OperandSize size,
int32_t offset,
int32_t* offset_mask);
+ static bool CanHoldImmediateOffset(bool is_load,
+ intptr_t cid,
+ int64_t offset);
private:
uint32_t encoding() const { return encoding_; }
@@ -781,6 +784,21 @@
Register temp_reg,
Heap::Space space = Heap::kNew);
+ Address ElementAddressForIntIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index,
+ Register temp);
+
+ Address ElementAddressForRegIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index);
+
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
// Allocated instance is returned in 'instance_reg'.
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 4766040..6da9770 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -1413,6 +1413,47 @@
}
}
+
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) const {
+ const int64_t offset = index * index_scale +
+ (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+ ASSERT(Utils::IsInt(32, offset));
+ const OperandSize size = Address::OperandSizeFor(cid);
+ ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
+ return Address(array, static_cast<int32_t>(offset), Address::Offset, size);
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
+ // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+ const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+ const int32_t offset =
+ is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+ ASSERT(array != TMP);
+ ASSERT(index != TMP);
+ const Register base = is_load ? TMP : index;
+ if ((offset == 0) && (shift == 0)) {
+ return Address(array, index, UXTX, Address::Unscaled);
+ } else if (shift < 0) {
+ ASSERT(shift == -1);
+ add(base, array, Operand(index, ASR, 1));
+ } else {
+ add(base, array, Operand(index, LSL, shift));
+ }
+ const OperandSize size = Address::OperandSizeFor(cid);
+ ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
+ return Address(base, offset, Address::Offset, size);
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index fa76634..03224f6 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -1219,6 +1219,18 @@
Register instance_reg,
Register pp);
+ Address ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) const;
+ Address ElementAddressForRegIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index);
+
private:
AssemblerBuffer buffer_; // Contains position independent code.
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index f76403c..1491cf3 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -2741,6 +2741,56 @@
}
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) {
+ if (is_external) {
+ return Address(array, index * index_scale);
+ } else {
+ const int64_t disp = static_cast<int64_t>(index) * index_scale +
+ Instance::DataOffsetFor(cid);
+ ASSERT(Utils::IsInt(32, disp));
+ return FieldAddress(array, static_cast<int32_t>(disp));
+ }
+}
+
+
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+ // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+ // expected to be untagged before accessing.
+ ASSERT(kSmiTagShift == 1);
+ switch (index_scale) {
+ case 1: return TIMES_1;
+ case 2: return TIMES_1;
+ case 4: return TIMES_2;
+ case 8: return TIMES_4;
+ case 16: return TIMES_8;
+ default:
+ UNREACHABLE();
+ return TIMES_1;
+ }
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
+ if (is_external) {
+ return Address(array, index, ToScaleFactor(index_scale), 0);
+ } else {
+ return FieldAddress(array,
+ index,
+ ToScaleFactor(index_scale),
+ Instance::DataOffsetFor(cid));
+ }
+}
+
+
static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
};
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 4e3fefb..bd11704 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -697,6 +697,18 @@
void LoadTaggedClassIdMayBeSmi(Register result,
Register object);
+ static Address ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index);
+
+ static Address ElementAddressForRegIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index);
+
/*
* Misc. functionality
*/
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 647ec7f..3cfcdea 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -1095,6 +1095,47 @@
}
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) const {
+ const int64_t offset = index * index_scale +
+ (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+ ASSERT(Utils::IsInt(32, offset));
+ ASSERT(Address::CanHoldOffset(offset));
+ return Address(array, static_cast<int32_t>(offset));
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
+ // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+ const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+ const int32_t offset =
+ is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+ ASSERT(array != TMP);
+ ASSERT(index != TMP);
+ const Register base = is_load ? TMP : index;
+ if (shift < 0) {
+ ASSERT(shift == -1);
+ sra(TMP, index, 1);
+ addu(base, array, TMP);
+ } else if (shift == 0) {
+ addu(base, array, index);
+ } else {
+ sll(TMP, index, shift);
+ addu(base, array, TMP);
+ }
+ ASSERT(Address::CanHoldOffset(offset));
+ return Address(base, offset);
+}
+
+
static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
"zr", "tmp", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 2f7c38f..d5ee12e 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -1222,6 +1222,18 @@
// up on entry (it is the frame of the unoptimized code).
void EnterOsrFrame(intptr_t extra_size);
+ Address ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) const;
+ Address ElementAddressForRegIndex(bool is_load,
+ bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index);
+
// On some other platforms, we draw a distinction between safe and unsafe
// smis.
static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 3b08240..1a4a376 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -3411,6 +3411,56 @@
}
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) {
+ if (is_external) {
+ return Address(array, index * index_scale);
+ } else {
+ const int64_t disp = static_cast<int64_t>(index) * index_scale +
+ Instance::DataOffsetFor(cid);
+ ASSERT(Utils::IsInt(32, disp));
+ return FieldAddress(array, static_cast<int32_t>(disp));
+ }
+}
+
+
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+ // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+ // expected to be untagged before accessing.
+ ASSERT(kSmiTagShift == 1);
+ switch (index_scale) {
+ case 1: return TIMES_1;
+ case 2: return TIMES_1;
+ case 4: return TIMES_2;
+ case 8: return TIMES_4;
+ case 16: return TIMES_8;
+ default:
+ UNREACHABLE();
+ return TIMES_1;
+ }
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
+ if (is_external) {
+ return Address(array, index, ToScaleFactor(index_scale), 0);
+ } else {
+ return FieldAddress(array,
+ index,
+ ToScaleFactor(index_scale),
+ Instance::DataOffsetFor(cid));
+ }
+}
+
+
static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 3323b73..6644ae1 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -884,6 +884,17 @@
static const char* FpuRegisterName(FpuRegister reg);
+ static Address ElementAddressForIntIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index);
+ static Address ElementAddressForRegIndex(bool is_external,
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index);
+
// On some other platforms, we draw a distinction between safe and unsafe
// smis.
static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index cd8dc78..8e58da5 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -153,12 +153,16 @@
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars,
- reinterpret_cast<Dart_NativeEntryResolver>(bm_uda_lookup));
+ reinterpret_cast<Dart_NativeEntryResolver>(bm_uda_lookup),
+ USER_TEST_URI,
+ false);
// Create a native wrapper class with native fields.
Dart_Handle result = Dart_CreateNativeWrapperClass(
lib, NewString("NativeFieldsWrapper"), 1);
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
Dart_Handle args[1];
args[0] = Dart_NewInteger(kNumIterations);
@@ -411,7 +415,7 @@
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
- Api::CheckIsolateState(Isolate::Current());
+ Api::CheckAndFinalizePendingClasses(Isolate::Current());
// Write snapshot with object content.
FullSnapshotWriter writer(&buffer, &malloc_allocator);
@@ -442,7 +446,7 @@
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
- Api::CheckIsolateState(Isolate::Current());
+ Api::CheckAndFinalizePendingClasses(Isolate::Current());
// Write snapshot with object content.
FullSnapshotWriter writer(&buffer, &malloc_allocator);
@@ -478,7 +482,7 @@
"\n";
const intptr_t kLoopCount = 1000000;
TestCase::LoadTestScript(kScriptChars, NULL);
- Api::CheckIsolateState(Isolate::Current());
+ Api::CheckAndFinalizePendingClasses(Isolate::Current());
Dart_Isolate isolate = Dart_CurrentIsolate();
Timer timer(true, "Enter and Exit isolate");
timer.Start();
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 937286e..20cce5c 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -7,6 +7,7 @@
#include "include/dart_api.h"
#include "vm/bootstrap_natives.h"
+#include "vm/class_finalizer.h"
#include "vm/compiler.h"
#include "vm/dart_api_impl.h"
#include "vm/object.h"
@@ -311,6 +312,7 @@
}
if (error.IsNull()) {
SetupNativeResolver();
+ ClassFinalizer::ProcessPendingClasses();
}
// Restore the library tag handler for the isolate.
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 5d39333..283a260 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1458,8 +1458,14 @@
name.ToCString(),
super_class_name.ToCString());
}
- // The function may be a still unresolved redirecting factory. Do not yet
- // try to resolve it in order to avoid cycles in class finalization.
+ if (function.IsRedirectingFactory()) {
+ // The function may be a still unresolved redirecting factory. Do not
+ // yet try to resolve it in order to avoid cycles in class finalization.
+ // However, the redirection type should be finalized.
+ Type& type = Type::Handle(function.RedirectionType());
+ type ^= FinalizeType(cls, type, kCanonicalize);
+ function.SetRedirectionType(type);
+ }
} else if (function.IsGetterFunction() ||
function.IsImplicitGetterFunction()) {
super_class = FindSuperOwnerOfFunction(cls, name);
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 5592f67..7de90df 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -258,9 +258,8 @@
PcDescriptors::Handle(code.pc_descriptors());
int call_count = 0;
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kUnoptStaticCall);
- while (iter.HasNext()) {
- const uword pc = iter.NextPc();
- stackmap_table_builder->AddEntry(pc - code.EntryPoint(),
+ while (iter.MoveNext()) {
+ stackmap_table_builder->AddEntry(iter.Pc() - code.EntryPoint(),
stack_bitmap,
0);
++call_count;
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 60a66ab..557d61c 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -479,6 +479,10 @@
DeadCodeElimination::EliminateDeadPhis(flow_graph);
DEBUG_ASSERT(flow_graph->VerifyUseLists());
+ if (optimizer.Canonicalize()) {
+ optimizer.Canonicalize();
+ }
+
// Attempt to sink allocations of temporary non-escaping objects to
// the deoptimization path.
AllocationSinking* sinking = NULL;
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
index f4ee0fe..7344761 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -93,13 +93,11 @@
// Only IC based calls have counting.
PcDescriptors::Iterator iter(descriptors,
RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall);
- while (iter.HasNext()) {
+ while (iter.MoveNext()) {
HANDLESCOPE(isolate);
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- const ICData* ic_data = (*ic_data_array)[rec.deopt_id()];
+ const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
if (!ic_data->IsNull()) {
- const intptr_t token_pos = rec.token_pos();
+ const intptr_t token_pos = iter.TokenPos();
// Filter out descriptors that do not map to tokens in the source code.
if ((token_pos < begin_pos) || (token_pos > end_pos)) {
continue;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index d418d12..3570912 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -371,7 +371,7 @@
}
-Dart_Handle Api::CheckIsolateState(Isolate* isolate) {
+Dart_Handle Api::CheckAndFinalizePendingClasses(Isolate* isolate) {
if (!isolate->AllowClassFinalization()) {
// Class finalization is blocked for the isolate. Do nothing.
return Api::Success();
@@ -1400,7 +1400,8 @@
if (size == NULL) {
RETURN_NULL_ERROR(size);
}
- Dart_Handle state = Api::CheckIsolateState(isolate);
+ // Finalize all classes if needed.
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
if (::Dart_IsError(state)) {
return state;
}
@@ -1424,7 +1425,8 @@
if (size == NULL) {
RETURN_NULL_ERROR(size);
}
- Dart_Handle state = Api::CheckIsolateState(isolate);
+ // Finalize all classes if needed.
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
if (::Dart_IsError(state)) {
return state;
}
@@ -1715,6 +1717,11 @@
*value = false;
RETURN_TYPE_ERROR(isolate, type, Type);
}
+ if (!type_obj.IsFinalized()) {
+ return Api::NewError(
+ "%s expects argument 'type' to be a fully resolved type.",
+ CURRENT_FUNC);
+ }
if (object == Api::Null()) {
*value = false;
return Api::Success();
@@ -1724,12 +1731,6 @@
*value = false;
RETURN_TYPE_ERROR(isolate, object, Instance);
}
- // Finalize all classes.
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- *value = false;
- return state;
- }
CHECK_CALLBACK_STATE(isolate);
Error& malformed_type_error = Error::Handle(isolate);
*value = instance.IsInstanceOf(type_obj,
@@ -3506,6 +3507,11 @@
}
Type& type_obj = Type::Handle();
type_obj ^= unchecked_type.raw();
+ if (!type_obj.IsFinalized()) {
+ return Api::NewError(
+ "%s expects argument 'type' to be a fully resolved type.",
+ CURRENT_FUNC);
+ }
Class& cls = Class::Handle(isolate, type_obj.type_class());
TypeArguments& type_arguments =
TypeArguments::Handle(isolate, type_obj.arguments());
@@ -3522,10 +3528,6 @@
} else {
RETURN_TYPE_ERROR(isolate, constructor_name, String);
}
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
- }
// Resolve the constructor.
String& constr_name =
@@ -3753,9 +3755,8 @@
RETURN_TYPE_ERROR(isolate, object, Instance);
}
- // Since we have allocated an object it would mean that all classes
- // are finalized and hence it is not necessary to call
- // Api::CheckIsolateState.
+ // Since we have allocated an object it would mean that the type
+ // is finalized.
// TODO(asiva): How do we ensure that a constructor is not called more than
// once for the same object.
@@ -3841,10 +3842,10 @@
Dart_Handle result;
Array& args = Array::Handle(isolate);
if (obj.IsType()) {
- // Finalize all classes.
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
+ if (!Type::Cast(obj).IsFinalized()) {
+ return Api::NewError(
+ "%s expects argument 'target' to be a fully resolved type.",
+ CURRENT_FUNC);
}
const Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
@@ -3869,9 +3870,9 @@
}
return result;
} else if (obj.IsNull() || obj.IsInstance()) {
- // Since we have allocated an object it would mean that all classes
- // are finalized and hence it is not necessary to call
- // Api::CheckIsolateState.
+ // Since we have allocated an object it would mean that the type of the
+ // receiver is already resolved and finalized, hence it is not necessary
+ // to check here.
Instance& instance = Instance::Handle(isolate);
instance ^= obj.raw();
ArgumentsDescriptor args_desc(
@@ -3910,10 +3911,11 @@
// Check whether class finalization is needed.
const Library& lib = Library::Cast(obj);
- // Finalize all classes if needed.
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
+ // Check that the library is loaded.
+ if (!lib.Loaded()) {
+ return Api::NewError(
+ "%s expects library argument 'target' to be loaded.",
+ CURRENT_FUNC);
}
const Function& function =
@@ -3994,12 +3996,6 @@
RETURN_TYPE_ERROR(isolate, name, String);
}
- // Finalize all classes.
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
- }
-
Field& field = Field::Handle(isolate);
Function& getter = Function::Handle(isolate);
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
@@ -4007,6 +4003,11 @@
return Api::NewError("%s expects argument 'container' to be non-null.",
CURRENT_FUNC);
} else if (obj.IsType()) {
+ if (!Type::Cast(obj).IsFinalized()) {
+ return Api::NewError(
+ "%s expects argument 'container' to be a fully resolved type.",
+ CURRENT_FUNC);
+ }
// To access a static field we may need to use the Field or the
// getter Function.
Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
@@ -4065,6 +4066,12 @@
// getter Function. The getter function may either be in the
// library or in the field's owner class, depending.
const Library& lib = Library::Cast(obj);
+ // Check that the library is loaded.
+ if (!lib.Loaded()) {
+ return Api::NewError(
+ "%s expects library argument 'container' to be loaded.",
+ CURRENT_FUNC);
+ }
field = lib.LookupFieldAllowPrivate(field_name);
if (field.IsNull()) {
// No field found and no ambiguity error. Check for a getter in the lib.
@@ -4120,11 +4127,6 @@
Instance& value_instance = Instance::Handle(isolate);
value_instance ^= value_obj.raw();
- // Finalize all classes.
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
- }
Field& field = Field::Handle(isolate);
Function& setter = Function::Handle(isolate);
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
@@ -4132,6 +4134,12 @@
return Api::NewError("%s expects argument 'container' to be non-null.",
CURRENT_FUNC);
} else if (obj.IsType()) {
+ if (!Type::Cast(obj).IsFinalized()) {
+ return Api::NewError(
+ "%s expects argument 'container' to be a fully resolved type.",
+ CURRENT_FUNC);
+ }
+
// To access a static field we may need to use the Field or the
// setter Function.
Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
@@ -4210,6 +4218,12 @@
// setter Function. The setter function may either be in the
// library or in the field's owner class, depending.
const Library& lib = Library::Cast(obj);
+ // Check that the library is loaded.
+ if (!lib.Loaded()) {
+ return Api::NewError(
+ "%s expects library argument 'container' to be loaded.",
+ CURRENT_FUNC);
+ }
field = lib.LookupFieldAllowPrivate(field_name);
if (field.IsNull()) {
const String& setter_name =
@@ -4920,15 +4934,15 @@
if (lib.IsNull()) {
RETURN_TYPE_ERROR(isolate, library, Library);
}
+ if (!lib.Loaded()) {
+ return Api::NewError(
+ "%s expects library argument 'library' to be loaded.",
+ CURRENT_FUNC);
+ }
const String& name_str = Api::UnwrapStringHandle(isolate, class_name);
if (name_str.IsNull()) {
RETURN_TYPE_ERROR(isolate, class_name, String);
}
- // Ensure all classes are finalized.
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
- }
const Class& cls =
Class::Handle(isolate, lib.LookupClassAllowPrivate(name_str));
if (cls.IsNull()) {
@@ -5055,7 +5069,7 @@
// If this is the dart:_builtin library, register it with the VM.
if (url_str.Equals("dart:_builtin")) {
isolate->object_store()->set_builtin_library(library);
- Dart_Handle state = Api::CheckIsolateState(isolate);
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
if (::Dart_IsError(state)) {
return state;
}
@@ -5170,7 +5184,7 @@
// Finalizes classes and invokes Dart core library function that completes
// futures of loadLibrary calls (deferred library loading).
-DART_EXPORT Dart_Handle Dart_FinalizeLoading() {
+DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
CHECK_CALLBACK_STATE(isolate);
@@ -5181,24 +5195,26 @@
// invoing of _completeDeferredLoads) into Isolate::DoneLoading().
// Finalize all classes if needed.
- Dart_Handle state = Api::CheckIsolateState(isolate);
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
if (::Dart_IsError(state)) {
return state;
}
- const Library& corelib = Library::Handle(isolate, Library::CoreLibrary());
- const String& function_name =
- String::Handle(isolate, String::New("_completeDeferredLoads"));
- const Function& function =
- Function::Handle(isolate,
- corelib.LookupFunctionAllowPrivate(function_name));
- ASSERT(!function.IsNull());
- const Array& args = Array::empty_array();
+ if (complete_futures) {
+ const Library& corelib = Library::Handle(isolate, Library::CoreLibrary());
+ const String& function_name =
+ String::Handle(isolate, String::New("_completeDeferredLoads"));
+ const Function& function =
+ Function::Handle(isolate,
+ corelib.LookupFunctionAllowPrivate(function_name));
+ ASSERT(!function.IsNull());
+ const Array& args = Array::empty_array();
- const Object& res =
- Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
- if (res.IsError() || res.IsUnhandledException()) {
- return Api::NewHandle(isolate, res.raw());
+ const Object& res =
+ Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
+ if (res.IsError() || res.IsUnhandledException()) {
+ return Api::NewHandle(isolate, res.raw());
+ }
}
return Api::Success();
}
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 213590e..f659b8a 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -142,9 +142,10 @@
static const Instance& UnwrapInstanceHandle(
const ReusableObjectHandleScope& reused, Dart_Handle object);
- // Returns an Error handle if isolate is in an inconsistent state.
+ // Returns an Error handle if isolate is in an inconsistent state
+ // or there was an error while finalizing classes.
// Returns a Success handle when no error condition exists.
- static Dart_Handle CheckIsolateState(Isolate *isolate);
+ static Dart_Handle CheckAndFinalizePendingClasses(Isolate *isolate);
// Casts the internal Isolate* type to the external Dart_Isolate type.
static Dart_Isolate CastIsolate(Isolate* isolate);
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 90ac918..6032692 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3875,6 +3875,8 @@
EXPECT_VALID(imported_lib);
Dart_Handle result = Dart_LibraryImportLibrary(lib, imported_lib, prefix);
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
result = Dart_Invoke(imported_lib, NewString("test2"), 0, NULL);
EXPECT_VALID(result);
@@ -4091,14 +4093,17 @@
const int kNumNativeFields = 4;
// Create a test library.
- Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
- native_field_lookup);
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL,
+ USER_TEST_URI, false);
// Create a native wrapper class with native fields.
result = Dart_CreateNativeWrapperClass(
lib,
NewString("NativeFieldsWrapper"),
kNumNativeFields);
+ EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
// Load up a test script in the test library.
@@ -4138,7 +4143,8 @@
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
- Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL,
+ USER_TEST_URI, false);
// Invoke a function which returns an object of type NativeFields.
result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
@@ -4437,7 +4443,9 @@
// Create a test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
- native_field_lookup);
+ native_field_lookup,
+ USER_TEST_URI,
+ false);
// Create a native wrapper class with native fields.
Dart_Handle result = Dart_CreateNativeWrapperClass(
@@ -4445,6 +4453,8 @@
NewString("NativeFieldsWrapper"),
kNumNativeFields);
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
// Load up a test script in it.
@@ -5229,6 +5239,8 @@
// Import lib2 from lib1
Dart_Handle result = Dart_LibraryImportLibrary(lib1, lib2, Dart_Null());
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
// We can invoke both private and non-private local functions.
EXPECT_VALID(Dart_Invoke(lib1, NewString("local"), 0, NULL));
@@ -5772,6 +5784,7 @@
// Load a script successfully.
result = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(result);
+ Dart_FinalizeLoading(false);
result = Dart_Invoke(result, NewString("main"), 0, NULL);
EXPECT_VALID(result);
@@ -6039,6 +6052,8 @@
Dart_Handle source = NewString(kLibraryChars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
+ Dart_Handle result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
Dart_Handle list = Dart_LibraryGetClassNames(lib);
EXPECT_VALID(list);
@@ -6090,6 +6105,8 @@
Dart_Handle source = NewString(kLibraryChars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
+ Dart_Handle result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
Dart_Handle list = Dart_GetFunctionNames(lib);
EXPECT_VALID(list);
@@ -6205,6 +6222,8 @@
Dart_Handle prefix = NewString("foo");
Dart_Handle result = Dart_LibraryImportLibrary(lib2, lib1, prefix);
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
// Lib1 is imported under a library prefix and therefore 'foo' should
// not be found directly in lib2.
@@ -6387,12 +6406,14 @@
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
+ Dart_Handle result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
// Call a dynamic function on OldClass.
Dart_Handle type = Dart_GetType(lib, NewString("OldClass"), 0, NULL);
EXPECT_VALID(type);
Dart_Handle recv = Dart_New(type, Dart_Null(), 0, NULL);
- Dart_Handle result = Dart_Invoke(recv, NewString("foo"), 0, NULL);
+ result = Dart_Invoke(recv, NewString("foo"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
const char* result_cstr = "";
@@ -6403,6 +6424,8 @@
url = NewString("source_url");
source = NewString(kSourceChars);
EXPECT_VALID(Dart_LoadSource(lib, url, source));
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
// Call a dynamic function on NewClass in the updated library.
type = Dart_GetType(lib, NewString("NewClass"), 0, NULL);
@@ -6444,6 +6467,8 @@
result = Dart_LibraryLoadPatch(lib, url, source);
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
EXPECT_VALID(result);
@@ -6591,6 +6616,8 @@
source = NewString(kScriptChars);
Dart_Handle test_script = Dart_LoadScript(script_url, source, 0, 0);
EXPECT_VALID(test_script);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
// Make sure that we can compile all of the patched code.
result = Dart_CompileAll();
@@ -6693,6 +6720,8 @@
EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
EXPECT(Dart_IsLibrary(lib));
Dart_Handle type = Dart_GetType(lib, NewString("Test"), 0, NULL);
EXPECT_VALID(type);
@@ -6785,6 +6814,8 @@
source = NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source);
+ Dart_FinalizeLoading(false);
+
result = Dart_Invoke(result, NewString("main"), 0, NULL);
EXPECT_VALID(result);
}
@@ -6821,6 +6852,8 @@
url = NewString("library1_dart");
source = NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
result = Dart_Invoke(result, NewString("main"), 0, NULL);
EXPECT(Dart_IsError(result));
@@ -6858,6 +6891,7 @@
url = NewString("library1_dart");
source = NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
+ Dart_FinalizeLoading(false);
result = Dart_Invoke(result, NewString("main"), 0, NULL);
EXPECT_VALID(result);
@@ -6888,6 +6922,7 @@
url = NewString("lib.dart");
source = NewString(kLibraryChars);
Dart_LoadLibrary(url, source);
+ Dart_FinalizeLoading(false);
result = Dart_Invoke(result, NewString("main"), 0, NULL);
EXPECT_VALID(result);
@@ -7027,6 +7062,8 @@
EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
Dart_ExitScope();
Dart_ExitIsolate();
bool retval = Dart_IsolateMakeRunnable(isolate);
@@ -7168,6 +7205,8 @@
EXPECT_VALID(result);
lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
result =
Dart_SetNativeResolver(lib, &IsolateInterruptTestNativeLookup, NULL);
DART_CHECK_VALID(result);
@@ -7353,6 +7392,8 @@
EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
EXPECT_VALID(lib);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
result = Dart_Invoke(lib, NewString("main"), 0, NULL);
EXPECT_VALID(result);
Dart_ExitScope();
@@ -7533,6 +7574,8 @@
EXPECT(Dart_IsLibrary(lib));
result = Dart_SetNativeResolver(lib, &MyNativeClosureResolver, NULL);
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
@@ -7680,6 +7723,8 @@
EXPECT(Dart_IsLibrary(lib));
result = Dart_SetNativeResolver(lib, &MyStaticNativeClosureResolver, NULL);
EXPECT_VALID(result);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
@@ -8356,6 +8401,8 @@
Dart_Handle source = NewString(kLoadSecond);
Dart_Handle url = NewString(TestCase::url());
Dart_LoadSource(TestCase::lib(), url, source);
+ result = Dart_FinalizeLoading(false);
+ EXPECT_VALID(result);
dart_args[0] = Dart_NewInteger(1);
result = Dart_Invoke(lib1, NewString("start"), 1, dart_args);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 6fd0c2a..c1391a5 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -362,12 +362,10 @@
token_pos_ = Scanner::kNoSourcePos;
GetPcDescriptors();
PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if (rec.pc() == pc_) {
- try_index_ = rec.try_index();
- token_pos_ = rec.token_pos();
+ while (iter.MoveNext()) {
+ if (iter.Pc() == pc_) {
+ try_index_ = iter.TryIndex();
+ token_pos_ = iter.TokenPos();
break;
}
}
@@ -931,21 +929,18 @@
RawPcDescriptors::kRuntimeCall;
-static bool HasTokenPos(const RawPcDescriptors::PcDescriptorRec& rec) {
- return rec.token_pos() != Scanner::kNoSourcePos;
-}
-
-
CodeBreakpoint::CodeBreakpoint(const Code& code,
- const RawPcDescriptors::PcDescriptorRec& rec)
+ intptr_t token_pos,
+ uword pc,
+ RawPcDescriptors::Kind kind)
: code_(code.raw()),
- token_pos_(rec.token_pos()),
- pc_(rec.pc()),
+ token_pos_(token_pos),
+ pc_(pc),
line_number_(-1),
is_enabled_(false),
src_bpt_(NULL),
next_(NULL),
- breakpoint_kind_(rec.kind()),
+ breakpoint_kind_(kind),
saved_value_(0) {
ASSERT(!code.IsNull());
ASSERT(token_pos_ > 0);
@@ -1204,18 +1199,17 @@
ASSERT(!target_function.HasOptimizedCode());
PcDescriptors& desc = PcDescriptors::Handle(isolate, code.pc_descriptors());
PcDescriptors::Iterator iter(desc, kSafepointKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if (HasTokenPos(rec)) {
- CodeBreakpoint* bpt = GetCodeBreakpoint(rec.pc());
+ while (iter.MoveNext()) {
+ if (iter.TokenPos() != Scanner::kNoSourcePos) {
+ CodeBreakpoint* bpt = GetCodeBreakpoint(iter.Pc());
if (bpt != NULL) {
// There is already a breakpoint for this address. Make sure
// it is enabled.
bpt->Enable();
continue;
}
- bpt = new CodeBreakpoint(code, rec);
+ bpt = new CodeBreakpoint(code, iter.TokenPos(),
+ iter.Pc(), iter.Kind());
RegisterCodeBreakpoint(bpt);
bpt->Enable();
}
@@ -1256,9 +1250,8 @@
const PcDescriptors& pc_desc =
PcDescriptors::Handle(isolate, code.pc_descriptors());
PcDescriptors::Iterator iter(pc_desc, RawPcDescriptors::kClosureCall);
- while (iter.HasNext()) {
- const uword rec_pc = iter.NextPc();
- if (rec_pc == pc) {
+ while (iter.MoveNext()) {
+ if (iter.Pc() == pc) {
is_closure_call = true;
break;
}
@@ -1552,12 +1545,10 @@
uword lowest_pc = kUwordMax;
intptr_t lowest_pc_token_pos = INT_MAX;
PcDescriptors::Iterator iter(desc, kSafepointKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- intptr_t desc_token_pos = rec.token_pos();
+ while (iter.MoveNext()) {
+ const intptr_t desc_token_pos = iter.TokenPos();
ASSERT(desc_token_pos >= 0);
- if (HasTokenPos(rec)) {
+ if (desc_token_pos != Scanner::kNoSourcePos) {
if ((desc_token_pos < requested_token_pos) ||
(desc_token_pos > last_token_pos)) {
// This descriptor is outside the desired token range.
@@ -1568,9 +1559,9 @@
// the first acceptable token position.
best_fit_pos = desc_token_pos;
}
- if (rec.pc() < lowest_pc) {
+ if (iter.Pc() < lowest_pc) {
// This descriptor so far has the lowest code address.
- lowest_pc = rec.pc();
+ lowest_pc = iter.Pc();
lowest_pc_token_pos = desc_token_pos;
}
}
@@ -1596,34 +1587,33 @@
void Debugger::MakeCodeBreakpointAt(const Function& func,
SourceBreakpoint* bpt) {
+ ASSERT(bpt->token_pos_ != Scanner::kNoSourcePos);
ASSERT((bpt != NULL) && bpt->IsResolved());
ASSERT(!func.HasOptimizedCode());
Code& code = Code::Handle(func.unoptimized_code());
ASSERT(!code.IsNull());
PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
uword lowest_pc = kUwordMax;
+ RawPcDescriptors::Kind lowest_kind = RawPcDescriptors::kAnyKind;
// Find the safe point with the lowest compiled code address
// that maps to the token position of the source breakpoint.
PcDescriptors::Iterator iter(desc, kSafepointKind);
- RawPcDescriptors::PcDescriptorRec lowest_rec;
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- intptr_t desc_token_pos = rec.token_pos();
- if ((desc_token_pos == bpt->token_pos_) && HasTokenPos(rec)) {
- if (rec.pc() < lowest_pc) {
- lowest_pc = rec.pc();
- lowest_rec = rec;
+ while (iter.MoveNext()) {
+ if (iter.TokenPos() == bpt->token_pos_) {
+ if (iter.Pc() < lowest_pc) {
+ lowest_pc = iter.Pc();
+ lowest_kind = iter.Kind();
}
}
}
if (lowest_pc == kUwordMax) {
return;
}
- CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_rec.pc());
+ CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_pc);
if (code_bpt == NULL) {
// No code breakpoint for this code exists; create one.
- code_bpt = new CodeBreakpoint(code, lowest_rec);
+ code_bpt = new CodeBreakpoint(code, bpt->token_pos_,
+ lowest_pc, lowest_kind);
RegisterCodeBreakpoint(code_bpt);
}
code_bpt->set_src_bpt(bpt);
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index e193e48..51b1ddb 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -80,7 +80,9 @@
class CodeBreakpoint {
public:
CodeBreakpoint(const Code& code,
- const RawPcDescriptors::PcDescriptorRec& rec);
+ intptr_t token_pos,
+ uword pc,
+ RawPcDescriptors::Kind kind);
~CodeBreakpoint();
RawFunction* function() const;
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 05ee325..bba0434 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -314,11 +314,6 @@
DARTSCOPE(isolate);
UNWRAP_AND_CHECK_PARAM(Function, function, function_in);
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
- }
-
const Class& cls = Class::Handle(function.origin());
if (!cls.IsTopLevel()) {
return Dart_NewInteger(cls.id());
@@ -343,11 +338,6 @@
DARTSCOPE(isolate);
UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
- }
-
Debugger* debugger = isolate->debugger();
ASSERT(debugger != NULL);
SourceBreakpoint* bpt =
@@ -400,9 +390,11 @@
UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
+ // Ensure that the library is loaded.
+ if (!library.Loaded()) {
+ return Api::NewError(
+ "%s expects library argument 'library_in' to be loaded.",
+ CURRENT_FUNC);
}
// Resolve the breakpoint target function.
@@ -438,9 +430,11 @@
UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
+ // Ensure that the library is loaded.
+ if (!library.Loaded()) {
+ return Api::NewError(
+ "%s expects library argument 'library_in' to be loaded.",
+ CURRENT_FUNC);
}
// Resolve the breakpoint target function.
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 5868293..c79e586 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -2016,7 +2016,7 @@
" get r => sqrt(x*x + y*y); \n"
"} \n";
LoadScript(kScriptChars);
- Dart_FinalizeLoading();
+ Dart_FinalizeLoading(false);
Dart_SetExceptionThrownHandler(&EvaluateInActivationOfEvaluateHandler);
Dart_SetExceptionPauseInfo(kPauseOnAllExceptions);
@@ -2050,7 +2050,7 @@
"} \n";
LoadScript(kScriptChars);
- Dart_FinalizeLoading();
+ Dart_FinalizeLoading(false);
Dart_SetExceptionThrownHandler(&UnhandledExceptionHandler);
breakpoint_hit_counter = 0;
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index d0efc36..a275a5c 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -97,13 +97,17 @@
RawInstance* DeferredObject::object() {
if (object_ == NULL) {
- Materialize();
+ Create();
}
return object_->raw();
}
-void DeferredObject::Materialize() {
+void DeferredObject::Create() {
+ if (object_ != NULL) {
+ return;
+ }
+
Class& cls = Class::Handle();
cls ^= GetClass();
@@ -114,7 +118,17 @@
field_count_);
}
- const Instance& obj = Instance::ZoneHandle(Instance::New(cls));
+ object_ = &Instance::ZoneHandle(Instance::New(cls));
+}
+
+
+void DeferredObject::Fill() {
+ Create(); // Ensure instance is created.
+
+ Class& cls = Class::Handle();
+ cls ^= GetClass();
+
+ const Instance& obj = *object_;
Smi& offset = Smi::Handle();
Field& field = Field::Handle();
@@ -143,8 +157,6 @@
}
}
}
-
- object_ = &obj;
}
} // namespace dart
diff --git a/runtime/vm/deferred_objects.h b/runtime/vm/deferred_objects.h
index 9619d16..cfb8d94 100644
--- a/runtime/vm/deferred_objects.h
+++ b/runtime/vm/deferred_objects.h
@@ -157,6 +157,9 @@
RawInstance* object();
+ // Fill object with actual field values.
+ void Fill();
+
private:
enum {
kClassIndex = 0,
@@ -169,10 +172,11 @@
kFieldEntrySize,
};
- // Materializes the object. Returns amount of values that were consumed
- // and should be removed from the expression stack at the very end of
- // deoptimization.
- void Materialize();
+ // Allocate the object but keep its fields null-initialized. Actual field
+ // values will be filled later by the Fill method. This separation between
+ // allocation and filling is needed because dematerialized objects form
+ // a graph which can contain cycles.
+ void Create();
RawObject* GetClass() const {
return args_[kClassIndex];
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index ba12b63..99aac37 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -38,8 +38,7 @@
num_args_(0),
deopt_reason_(ICData::kDeoptUnknown),
isolate_(Isolate::Current()),
- deferred_boxes_(NULL),
- deferred_object_refs_(NULL),
+ deferred_slots_(NULL),
deferred_objects_count_(0),
deferred_objects_(NULL) {
object_table_ = code.object_table();
@@ -323,18 +322,16 @@
// Materializes all deferred objects. Returns the total number of
// artificial arguments used during deoptimization.
intptr_t DeoptContext::MaterializeDeferredObjects() {
- // First materialize all unboxed "primitive" values (doubles, mints, simd)
- // then materialize objects. The order is important: objects might be
- // referencing boxes allocated on the first step. At the same time
- // objects can't be referencing other deferred objects because storing
- // an object into a field is always conservatively treated as escaping by
- // allocation sinking and load forwarding.
- FillDeferredSlots(this, &deferred_boxes_);
- FillDeferredSlots(this, &deferred_object_refs_);
+ // Populate slots with references to all unboxed "primitive" values (doubles,
+ // mints, simd) and deferred objects. Deferred objects are only allocated
+ // but not filled with data. This is done later because deferred objects
+ // can references each other.
+ FillDeferredSlots(this, &deferred_slots_);
// Compute total number of artificial arguments used during deoptimization.
intptr_t deopt_arg_count = 0;
for (intptr_t i = 0; i < DeferredObjectsCount(); i++) {
+ GetDeferredObject(i)->Fill();
deopt_arg_count += GetDeferredObject(i)->ArgumentCount();
}
@@ -1633,6 +1630,14 @@
instructions_.Add(
new(isolate()) DeoptMaterializeObjectInstr(non_null_fields));
+
+ for (intptr_t i = 0; i < mat->InputCount(); i++) {
+ MaterializeObjectInstr* nested_mat = mat->InputAt(i)->definition()->
+ AsMaterializeObject();
+ if (nested_mat != NULL) {
+ AddMaterialization(nested_mat);
+ }
+ }
}
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 9fcda82..93def97 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -114,48 +114,48 @@
void VisitObjectPointers(ObjectPointerVisitor* visitor);
void DeferMaterializedObjectRef(intptr_t idx, intptr_t* slot) {
- deferred_object_refs_ = new DeferredObjectRef(
+ deferred_slots_ = new DeferredObjectRef(
idx,
reinterpret_cast<RawInstance**>(slot),
- deferred_object_refs_);
+ deferred_slots_);
}
void DeferDoubleMaterialization(double value, RawDouble** slot) {
- deferred_boxes_ = new DeferredDouble(
+ deferred_slots_ = new DeferredDouble(
value,
reinterpret_cast<RawInstance**>(slot),
- deferred_boxes_);
+ deferred_slots_);
}
void DeferMintMaterialization(int64_t value, RawMint** slot) {
- deferred_boxes_ = new DeferredMint(
+ deferred_slots_ = new DeferredMint(
value,
reinterpret_cast<RawInstance**>(slot),
- deferred_boxes_);
+ deferred_slots_);
}
void DeferFloat32x4Materialization(simd128_value_t value,
RawFloat32x4** slot) {
- deferred_boxes_ = new DeferredFloat32x4(
+ deferred_slots_ = new DeferredFloat32x4(
value,
reinterpret_cast<RawInstance**>(slot),
- deferred_boxes_);
+ deferred_slots_);
}
void DeferFloat64x2Materialization(simd128_value_t value,
RawFloat64x2** slot) {
- deferred_boxes_ = new DeferredFloat64x2(
+ deferred_slots_ = new DeferredFloat64x2(
value,
reinterpret_cast<RawInstance**>(slot),
- deferred_boxes_);
+ deferred_slots_);
}
void DeferInt32x4Materialization(simd128_value_t value,
RawInt32x4** slot) {
- deferred_boxes_ = new DeferredInt32x4(
+ deferred_slots_ = new DeferredInt32x4(
value,
reinterpret_cast<RawInstance**>(slot),
- deferred_boxes_);
+ deferred_slots_);
}
DeferredObject* GetDeferredObject(intptr_t idx) const {
@@ -203,8 +203,7 @@
intptr_t caller_fp_;
Isolate* isolate_;
- DeferredSlot* deferred_boxes_;
- DeferredSlot* deferred_object_refs_;
+ DeferredSlot* deferred_slots_;
intptr_t deferred_objects_count_;
DeferredObject** deferred_objects_;
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index d2d0d11..3c710e5 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -193,7 +193,9 @@
for (intptr_t i = 0; i < instr->InputCount(); ++i) {
Value* use = instr->InputAt(i);
ASSERT(use->definition() != NULL);
- ASSERT((use->definition() != instr) || use->definition()->IsPhi());
+ ASSERT((use->definition() != instr) ||
+ use->definition()->IsPhi() ||
+ use->definition()->IsMaterializeObject());
ASSERT(use->instruction() == instr);
ASSERT(use->use_index() == i);
ASSERT(!FLAG_verify_compiler ||
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index e5f0865..0971696 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -122,6 +122,27 @@
}
+static void DeepLiveness(MaterializeObjectInstr* mat, BitVector* live_in) {
+ if (mat->was_visited_for_liveness()) {
+ return;
+ }
+ mat->mark_visited_for_liveness();
+
+ for (intptr_t i = 0; i < mat->InputCount(); i++) {
+ if (!mat->InputAt(i)->BindsToConstant()) {
+ Definition* defn = mat->InputAt(i)->definition();
+ MaterializeObjectInstr* inner_mat = defn->AsMaterializeObject();
+ if (inner_mat != NULL) {
+ DeepLiveness(inner_mat, live_in);
+ } else {
+ intptr_t idx = defn->ssa_temp_index();
+ live_in->Add(idx);
+ }
+ }
+ }
+}
+
+
void SSALivenessAnalysis::ComputeInitialSets() {
const intptr_t block_count = postorder_.length();
for (intptr_t i = 0; i < block_count; i++) {
@@ -173,12 +194,7 @@
if (defn->IsMaterializeObject()) {
// MaterializeObject instruction is not in the graph.
// Treat its inputs as part of the environment.
- for (intptr_t i = 0; i < defn->InputCount(); i++) {
- if (!defn->InputAt(i)->BindsToConstant()) {
- intptr_t idx = defn->InputAt(i)->definition()->ssa_temp_index();
- live_in->Add(idx);
- }
- }
+ DeepLiveness(defn->AsMaterializeObject(), live_in);
} else if (!defn->IsPushArgument() && !defn->IsConstant()) {
live_in->Add(defn->ssa_temp_index());
if (defn->HasPairRepresentation()) {
@@ -889,6 +905,7 @@
// Initialize location for every input of the MaterializeObject instruction.
Location* locations =
Isolate::Current()->current_zone()->Alloc<Location>(mat->InputCount());
+ mat->set_locations(locations);
for (intptr_t i = 0; i < mat->InputCount(); ++i) {
Definition* def = mat->InputAt(i)->definition();
@@ -915,6 +932,10 @@
range->AddUseInterval(block_start_pos, use_pos);
range->AddUse(use_pos, location_pair->SlotAt(1));
}
+ } else if (def->IsMaterializeObject()) {
+ locations[i] = Location::NoLocation();
+ ProcessMaterializationUses(
+ block, block_start_pos, use_pos, def->AsMaterializeObject());
} else {
locations[i] = Location::Any();
LiveRange* range = GetLiveRange(def->ssa_temp_index());
@@ -922,8 +943,6 @@
range->AddUse(use_pos, &locations[i]);
}
}
-
- mat->set_locations(locations);
}
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 4eab3f0..0de5492 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -731,23 +731,28 @@
function.HasOptionalParameters() ? 0 : function.num_fixed_parameters();
DeoptInfoBuilder builder(isolate(), incoming_arg_count);
- const Array& array =
- Array::Handle(Array::New(DeoptTable::SizeFor(deopt_infos_.length()),
- Heap::kOld));
- Smi& offset = Smi::Handle();
- DeoptInfo& info = DeoptInfo::Handle();
- Smi& reason = Smi::Handle();
- for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
- offset = Smi::New(deopt_infos_[i]->pc_offset());
- info = deopt_infos_[i]->CreateDeoptInfo(this, &builder, array);
- reason = Smi::New(deopt_infos_[i]->reason());
- DeoptTable::SetEntry(array, i, offset, info, reason);
+ intptr_t deopt_info_table_size = DeoptTable::SizeFor(deopt_infos_.length());
+ if (deopt_info_table_size == 0) {
+ code.set_deopt_info_array(Object::empty_array());
+ code.set_object_table(Object::empty_array());
+ } else {
+ const Array& array =
+ Array::Handle(Array::New(deopt_info_table_size, Heap::kOld));
+ Smi& offset = Smi::Handle();
+ DeoptInfo& info = DeoptInfo::Handle();
+ Smi& reason = Smi::Handle();
+ for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
+ offset = Smi::New(deopt_infos_[i]->pc_offset());
+ info = deopt_infos_[i]->CreateDeoptInfo(this, &builder, array);
+ reason = Smi::New(deopt_infos_[i]->reason());
+ DeoptTable::SetEntry(array, i, offset, info, reason);
+ }
+ code.set_deopt_info_array(array);
+ const Array& object_array =
+ Array::Handle(Array::MakeArray(builder.object_table()));
+ ASSERT(code.object_table() == Array::null());
+ code.set_object_table(object_array);
}
- code.set_deopt_info_array(array);
- const Array& object_array =
- Array::Handle(Array::MakeArray(builder.object_table()));
- ASSERT(code.object_table() == Array::null());
- code.set_object_table(object_array);
}
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 215eee7..b7b0cb6 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -165,6 +165,16 @@
// Implementation is in architecture specific file.
virtual void GenerateCode(FlowGraphCompiler* compiler, intptr_t stub_ix);
+ const char* Name() const {
+ const char* kFormat = "Deopt stub for id %d, reason: %s";
+ const intptr_t len = OS::SNPrint(NULL, 0, kFormat,
+ deopt_id(), DeoptReasonToCString(reason())) + 1;
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ OS::SNPrint(chars, len, kFormat,
+ deopt_id(), DeoptReasonToCString(reason()));
+ return chars;
+ }
+
private:
Label entry_label_;
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 118093e..929485f 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -163,7 +163,7 @@
ASSERT(reason() != ICData::kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %" Pd "", deopt_id());
+ __ Comment("%s", Name());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) {
__ bkpt(0);
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 8162630..72c14bd 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -155,7 +155,7 @@
ASSERT(reason() != ICData::kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %" Pd "", deopt_id());
+ __ Comment("%s", Name());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) {
__ brk(0);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index bf43fde..419f293 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -159,7 +159,7 @@
ASSERT(reason() != ICData::kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %" Pd "", deopt_id());
+ __ Comment("%s", Name());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) {
__ int3();
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 319a8dd..537a0dd 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -159,7 +159,7 @@
ASSERT(reason() != ICData::kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %" Pd "", deopt_id());
+ __ Comment("%s", Name());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) {
__ break_(0);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 289414e..37e6aab 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -157,7 +157,7 @@
ASSERT(reason() != ICData::kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %" Pd "", deopt_id());
+ __ Comment("%s", Name());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) {
__ int3();
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index fa5db4d..10bbbad 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -2020,6 +2020,7 @@
switch (op_kind) {
case Token::kADD:
case Token::kSUB:
+ case Token::kMUL:
if (HasOnlyTwoOf(ic_data, kSmiCid)) {
// Don't generate smi code if the IC data is marked because
// of an overflow.
@@ -2037,6 +2038,7 @@
} else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
operands_type = kFloat32x4Cid;
} else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+ ASSERT(op_kind != Token::kMUL); // Int32x4 doesn't have a multiply op.
operands_type = kInt32x4Cid;
} else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
operands_type = kFloat64x2Cid;
@@ -2044,23 +2046,6 @@
return false;
}
break;
- case Token::kMUL:
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
- // Don't generate smi code if the IC data is marked because of an
- // overflow.
- // TODO(fschneider): Add unboxed mint multiplication.
- if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) return false;
- operands_type = kSmiCid;
- } else if (ShouldSpecializeForDouble(ic_data)) {
- operands_type = kDoubleCid;
- } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
- operands_type = kFloat32x4Cid;
- } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
- operands_type = kFloat64x2Cid;
- } else {
- return false;
- }
- break;
case Token::kDIV:
if (ShouldSpecializeForDouble(ic_data) ||
HasOnlyTwoOf(ic_data, kSmiCid)) {
@@ -4412,7 +4397,7 @@
bool result = !getter.IsNull()
&& !setter.IsNull()
&& (setter.usage_counter() > 0)
- && (FLAG_getter_setter_ratio * setter.usage_counter() >
+ && (FLAG_getter_setter_ratio * setter.usage_counter() >=
getter.usage_counter());
if (!result) {
if (FLAG_trace_optimization) {
@@ -5667,103 +5652,38 @@
}
-// Alias represents a family of locations. It is used to capture aliasing
-// between stores and loads. Store can alias another load or store if and only
-// if they have the same alias.
-class Alias : public ValueObject {
- public:
- Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { }
-
- // All indexed load/stores alias each other.
- // TODO(vegorov): incorporate type of array into alias to disambiguate
- // different typed data and normal arrays.
- static Alias UnknownIndex(intptr_t id) {
- return Alias(kUnknownIndexAlias, id);
- }
-
- static Alias ConstantIndex(intptr_t id) {
- ASSERT(id != 0);
- return Alias(kConstantIndex, id);
- }
-
- // Field load/stores alias each other only when they access the same field.
- // AliasedSet assigns ids to a combination of instance and field during
- // the optimization phase.
- static Alias Field(intptr_t id) {
- ASSERT(id != 0);
- return Alias(kFieldAlias, id);
- }
-
- // VMField load/stores alias each other when field offset matches.
- // TODO(vegorov) storing a context variable does not alias loading array
- // length.
- static Alias VMField(intptr_t id) {
- ASSERT(id != 0);
- return Alias(kVMFieldAlias, id);
- }
-
- // Current context load/stores alias each other.
- static Alias CurrentContext() {
- return Alias(kCurrentContextAlias, 0);
- }
-
- // Operation does not alias anything.
- static Alias None() {
- return Alias(kNoneAlias);
- }
-
- bool IsNone() const {
- return alias_ == kNoneAlias;
- }
-
- // Convert this alias to a positive array index.
- intptr_t ToIndex() const {
- ASSERT(!IsNone());
- return alias_;
- }
-
- private:
- enum {
- // Number of bits required to encode Kind value.
- // The payload occupies the rest of the bits, but leaves the MSB (sign bit)
- // empty so that the resulting encoded value is always a positive integer.
- kBitsForKind = 3,
- kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind - 1,
- };
-
- enum Kind {
- kNoneAlias = -1,
- kCurrentContextAlias = 0,
- kUnknownIndexAlias = 1,
- kFieldAlias = 2,
- kVMFieldAlias = 3,
- kConstantIndex = 4,
- kNumKinds = kConstantIndex + 1
- };
- COMPILE_ASSERT(kNumKinds < ((1 << kBitsForKind) - 1));
-
- explicit Alias(intptr_t alias) : alias_(alias) { }
-
- Alias(Kind kind, uword payload)
- : alias_(KindField::encode(kind) | PayloadField::encode(payload)) { }
-
- uword payload() const {
- return PayloadField::decode(alias_);
- }
-
- Kind kind() const {
- return IsNone() ? kNoneAlias : KindField::decode(alias_);
- }
-
- typedef BitField<Kind, 0, kBitsForKind> KindField;
- typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
-
- const intptr_t alias_;
-};
-
-
// Place describes an abstract location (e.g. field) that IR can load
// from or store to.
+//
+// Places are also used to describe wild-card locations also known as aliases,
+// that essentially represent sets of places that alias each other. Places A
+// and B are said to alias each other if store into A can affect load from B.
+//
+// We distinguish the following aliases:
+//
+// - for fields
+// - *.f, *.@offs - field inside some object;
+// - X.f, X.@offs - field inside an allocated object X;
+// - for indexed accesses
+// - *[*] - non-constant index inside some object;
+// - *[C] - constant index inside some object;
+// - X[*] - non-constant index inside an allocated object X;
+// - X[C] - constant index inside an allocated object X.
+//
+// Separating allocations from other objects improves precision of the
+// load forwarding pass because of the following two properties:
+//
+// - if X can be proven to have no aliases itself (i.e. there is no other SSA
+// variable that points to X) then no place inside X can be aliased with any
+// wildcard dependent place (*.f, *.@offs, *[*], *[C]);
+// - given allocations X and Y no place inside X can be aliased with any place
+// inside Y even if any of them or both escape.
+//
+// It important to realize that single place can belong to multiple aliases.
+// For example place X.f with aliased allocation X belongs both to X.f and *.f
+// aliases. Likewise X[C] with non-aliased allocation X belongs to X[C] and X[*]
+// aliases.
+//
class Place : public ValueObject {
public:
enum Kind {
@@ -5778,9 +5698,12 @@
// being accessed and offset to the field.
kVMField,
- // Indexed location.
+ // Indexed location with a non-constant index.
kIndexed,
+ // Indexed location with a constant index.
+ kConstantIndexed,
+
// Current context.
kContext
};
@@ -5852,21 +5775,19 @@
case Instruction::kLoadIndexed: {
LoadIndexedInstr* load_indexed = instr->AsLoadIndexed();
- kind_ = kIndexed;
representation_ = load_indexed->representation();
instance_ = load_indexed->array()->definition()->OriginalDefinition();
- index_ = load_indexed->index()->definition();
+ SetIndex(load_indexed->index()->definition());
*is_load = true;
break;
}
case Instruction::kStoreIndexed: {
StoreIndexedInstr* store_indexed = instr->AsStoreIndexed();
- kind_ = kIndexed;
representation_ = store_indexed->
RequiredInputRepresentation(StoreIndexedInstr::kValuePos);
instance_ = store_indexed->array()->definition()->OriginalDefinition();
- index_ = store_indexed->index()->definition();
+ SetIndex(store_indexed->index()->definition());
*is_store = true;
break;
}
@@ -5891,20 +5812,75 @@
}
}
+ // Create object representing *[*] alias.
+ static Place* CreateAnyInstanceAnyIndexAlias(Isolate* isolate,
+ intptr_t id) {
+ return Wrap(isolate, Place(kIndexed, NULL, 0), id);
+ }
+
+ // Return least generic alias for this place. Given that aliases are
+ // essentially sets of places we define least generic alias as a smallest
+ // alias that contains this place.
+ //
+ // We obtain such alias by a simple transformation:
+ //
+ // - for places that depend on an instance X.f, X.@offs, X[i], X[C]
+ // we drop X if X is not an allocation because in this case X does not
+ // posess an identity obtaining aliases *.f, *.@offs, *[i] and *[C]
+ // respectively;
+ // - for non-constant indexed places X[i] we drop information about the
+ // index obtaining alias X[*].
+ //
+ Place ToAlias() const {
+ return Place(
+ kind_,
+ (DependsOnInstance() && IsAllocation(instance())) ? instance() : NULL,
+ (kind() == kIndexed) ? 0 : raw_selector_);
+ }
+
+ bool DependsOnInstance() const {
+ switch (kind()) {
+ case kField:
+ case kVMField:
+ case kIndexed:
+ case kConstantIndexed:
+ return true;
+
+ case kContext:
+ case kNone:
+ return false;
+ }
+
+ UNREACHABLE();
+ return false;
+ }
+
+ // Given instance dependent alias X.f, X.@offs, X[C], X[*] return
+ // wild-card dependent alias *.f, *.@offs, *[C] or *[*] respectively.
+ Place CopyWithoutInstance() const {
+ ASSERT(DependsOnInstance());
+ return Place(kind_, NULL, raw_selector_);
+ }
+
+ // Given alias X[C] or *[C] return X[*] and *[*] respectively.
+ Place CopyWithoutIndex() const {
+ ASSERT(kind_ == kConstantIndexed);
+ return Place(kIndexed, instance_, 0);
+ }
+
intptr_t id() const { return id_; }
- void set_id(intptr_t id) { id_ = id; }
Kind kind() const { return kind_; }
Representation representation() const { return representation_; }
Definition* instance() const {
- ASSERT((kind_ == kField) || (kind_ == kVMField) || (kind_ == kIndexed));
+ ASSERT(DependsOnInstance());
return instance_;
}
void set_instance(Definition* def) {
- ASSERT((kind_ == kField) || (kind_ == kVMField) || (kind_ == kIndexed));
+ ASSERT(DependsOnInstance());
instance_ = def->OriginalDefinition();
}
@@ -5923,6 +5899,20 @@
return index_;
}
+ intptr_t index_constant() const {
+ ASSERT(kind_ == kConstantIndexed);
+ return index_constant_;
+ }
+
+ static const char* DefinitionName(Definition* def) {
+ if (def == NULL) {
+ return "*";
+ } else {
+ return Isolate::Current()->current_zone()->PrintToString(
+ "v%" Pd, def->ssa_temp_index());
+ }
+ }
+
const char* ToCString() const {
switch (kind_) {
case kNone:
@@ -5930,25 +5920,32 @@
case kField: {
const char* field_name = String::Handle(field().name()).ToCString();
- if (instance() == NULL) {
- return field_name;
+ if (field().is_static()) {
+ return Isolate::Current()->current_zone()->PrintToString(
+ "<%s>", field_name);
+ } else {
+ return Isolate::Current()->current_zone()->PrintToString(
+ "<%s.%s>", DefinitionName(instance()), field_name);
}
- return Isolate::Current()->current_zone()->PrintToString(
- "<v%" Pd ".%s>", instance()->ssa_temp_index(), field_name);
}
- case kVMField: {
+ case kVMField:
return Isolate::Current()->current_zone()->PrintToString(
- "<v%" Pd "@%" Pd ">",
- instance()->ssa_temp_index(), offset_in_bytes());
- }
+ "<%s.@%" Pd ">",
+ DefinitionName(instance()),
+ offset_in_bytes());
- case kIndexed: {
+ case kIndexed:
return Isolate::Current()->current_zone()->PrintToString(
- "<v%" Pd "[v%" Pd "]>",
- instance()->ssa_temp_index(),
- index()->ssa_temp_index());
- }
+ "<%s[%s]>",
+ DefinitionName(instance()),
+ DefinitionName(index()));
+
+ case kConstantIndexed:
+ return Isolate::Current()->current_zone()->PrintToString(
+ "<%s[%" Pd "]>",
+ DefinitionName(instance()),
+ index_constant());
case kContext:
return "<context>";
@@ -5966,18 +5963,35 @@
representation_ * 15 + FieldHashcode();
}
- bool Equals(Place* other) const {
+ bool Equals(const Place* other) const {
return (kind_ == other->kind_) &&
(representation_ == other->representation_) &&
(instance_ == other->instance_) &&
SameField(other);
}
- // Create a zone allocated copy of this place.
- static Place* Wrap(Isolate* isolate, const Place& place);
+ // Create a zone allocated copy of this place and assign given id to it.
+ static Place* Wrap(Isolate* isolate, const Place& place, intptr_t id);
+
+ static bool IsAllocation(Definition* defn) {
+ // TODO(vegorov): add CreateContext to this list.
+ return (defn != NULL) &&
+ (defn->IsAllocateObject() ||
+ defn->IsCreateArray() ||
+ (defn->IsStaticCall() &&
+ defn->AsStaticCall()->IsRecognizedFactory()));
+ }
private:
- bool SameField(Place* other) const {
+ Place(Kind kind, Definition* instance, intptr_t selector)
+ : kind_(kind),
+ representation_(kNoRepresentation),
+ instance_(instance),
+ raw_selector_(selector),
+ id_(0) {
+ }
+
+ bool SameField(const Place* other) const {
return (kind_ == kField) ? (field().raw() == other->field().raw())
: (offset_in_bytes_ == other->offset_in_bytes_);
}
@@ -5987,6 +6001,17 @@
: offset_in_bytes_;
}
+ void SetIndex(Definition* index) {
+ ConstantInstr* index_constant = index->AsConstant();
+ if ((index_constant != NULL) && index_constant->value().IsSmi()) {
+ kind_ = kConstantIndexed;
+ index_constant_ = Smi::Cast(index_constant->value()).Value();
+ } else {
+ kind_ = kIndexed;
+ index_ = index;
+ }
+ }
+
Kind kind_;
Representation representation_;
Definition* instance_;
@@ -5994,6 +6019,7 @@
intptr_t raw_selector_;
const Field* field_;
intptr_t offset_in_bytes_;
+ intptr_t index_constant_;
Definition* index_;
};
@@ -6012,8 +6038,10 @@
};
-Place* Place::Wrap(Isolate* isolate, const Place& place) {
- return (new(isolate) ZonePlace(place))->place();
+Place* Place::Wrap(Isolate* isolate, const Place& place, intptr_t id) {
+ Place* wrapped = (new(isolate) ZonePlace(place))->place();
+ wrapped->id_ = id;
+ return wrapped;
}
@@ -6073,141 +6101,38 @@
: isolate_(isolate),
places_(*places),
phi_moves_(phi_moves),
- sets_(),
- aliased_by_effects_(new(isolate) BitVector(places->length())),
- max_field_id_(0),
- field_ids_(),
- max_index_id_(0),
- index_ids_(),
- max_unknown_index_id_(0),
- unknown_index_ids_(),
- max_vm_field_id_(0),
- vm_field_ids_() { }
-
- Alias ComputeAlias(Place* place) {
- switch (place->kind()) {
- case Place::kIndexed:
- if (place->index()->IsConstant()) {
- const Object& index = place->index()->AsConstant()->value();
- if (index.IsSmi()) {
- return Alias::ConstantIndex(
- GetInstanceIndexId(place->instance(),
- Smi::Cast(index).Value()));
- }
- }
- return Alias::UnknownIndex(GetUnknownIndexId(place->instance()));
- case Place::kField:
- return Alias::Field(
- GetInstanceFieldId(place->instance(), place->field()));
- case Place::kVMField:
- return Alias::VMField(
- GetInstanceVMFieldId(place->instance(), place->offset_in_bytes()));
- case Place::kContext:
- return Alias::CurrentContext();
- case Place::kNone:
- UNREACHABLE();
+ aliases_(5),
+ aliases_map_(),
+ representatives_(),
+ killed_(),
+ aliased_by_effects_(new(isolate) BitVector(places->length())) {
+ InsertAlias(Place::CreateAnyInstanceAnyIndexAlias(isolate_,
+ kAnyInstanceAnyIndexAlias));
+ for (intptr_t i = 0; i < places_.length(); i++) {
+ AddRepresentative(places_[i]);
}
-
- UNREACHABLE();
- return Alias::None();
+ ComputeKillSets();
}
- Alias ComputeAliasForStore(Instruction* instr) {
- StoreIndexedInstr* store_indexed = instr->AsStoreIndexed();
- if (store_indexed != NULL) {
- Definition* instance = store_indexed->array()->definition();
- if (store_indexed->index()->definition()->IsConstant()) {
- const Object& index =
- store_indexed->index()->definition()->AsConstant()->value();
- if (index.IsSmi()) {
- return Alias::ConstantIndex(
- GetInstanceIndexId(instance, Smi::Cast(index).Value()));
- }
- }
- return Alias::UnknownIndex(GetUnknownIndexId(instance));
- }
-
- StoreInstanceFieldInstr* store_instance_field =
- instr->AsStoreInstanceField();
- if (store_instance_field != NULL) {
- Definition* instance = store_instance_field->instance()->definition();
- if (!store_instance_field->field().IsNull()) {
- return Alias::Field(
- GetInstanceFieldId(instance, store_instance_field->field()));
- }
- return Alias::VMField(
- GetInstanceVMFieldId(instance,
- store_instance_field->offset_in_bytes()));
- }
-
- if (instr->IsStoreContext()) {
- return Alias::CurrentContext();
- }
-
- StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
- if (store_static_field != NULL) {
- return Alias::Field(GetStaticFieldId(store_static_field->field()));
- }
-
- return Alias::None();
+ intptr_t LookupAliasId(const Place& alias) {
+ const Place* result = aliases_map_.Lookup(&alias);
+ return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias);
}
- BitVector* Get(const Alias alias) {
- const intptr_t idx = alias.ToIndex();
- BitVector* ret = (idx < sets_.length()) ? sets_[idx] : NULL;
- return ret;
+ bool IsStore(Instruction* instr, BitVector** killed) {
+ bool is_load = false, is_store = false;
+ Place place(instr, &is_load, &is_store);
+ if (is_store && (place.kind() != Place::kNone)) {
+ const intptr_t alias_id = LookupAliasId(place.ToAlias());
+ if (alias_id != kNoAlias) {
+ *killed = GetKilledSet(alias_id);
+ }
+ }
+ return is_store;
}
- void AddRepresentative(Place* place) {
- if (!place->IsFinalField()) {
- AddIdForAlias(ComputeAlias(place), place->id());
- if (!IsIndependentFromEffects(place)) {
- aliased_by_effects_->Add(place->id());
- }
- }
- }
-
- void EnsureAliasingForUnknownIndices() {
- // Ids start at 1 because the hash-map uses 0 for element not found.
- for (intptr_t unknown_index_id = 1;
- unknown_index_id <= max_unknown_index_id_;
- unknown_index_id++) {
- BitVector* unknown_index = Get(Alias::UnknownIndex(unknown_index_id));
- if (unknown_index == NULL) {
- return;
- }
-
- // Constant indexes alias all non-constant indexes.
- // Non-constant indexes alias all constant indexes.
- // First update alias set for const-indices, then
- // update set for all indices. Ids start at 1.
- for (intptr_t id = 1; id <= max_index_id_; id++) {
- BitVector* const_indexes = Get(Alias::ConstantIndex(id));
- if (const_indexes != NULL) {
- const_indexes->AddAll(unknown_index);
- }
- }
-
- for (intptr_t id = 1; id <= max_index_id_; id++) {
- BitVector* const_indexes = Get(Alias::ConstantIndex(id));
- if (const_indexes != NULL) {
- unknown_index->AddAll(const_indexes);
- }
- }
- }
- }
-
- void AddIdForAlias(const Alias alias, intptr_t place_id) {
- const intptr_t idx = alias.ToIndex();
- while (sets_.length() <= idx) {
- sets_.Add(NULL);
- }
-
- if (sets_[idx] == NULL) {
- sets_[idx] = new(isolate_) BitVector(max_place_id());
- }
-
- sets_[idx]->Add(place_id);
+ BitVector* GetKilledSet(intptr_t alias) {
+ return (alias < killed_.length()) ? killed_[alias] : NULL;
}
intptr_t max_place_id() const { return places().length(); }
@@ -6234,158 +6159,209 @@
const PhiPlaceMoves* phi_moves() const { return phi_moves_; }
- // Returns true if the result of an allocation instruction can be aliased by
- // some other SSA variable and false otherwise. Currently simply checks if
- // this value is stored in a field, escapes to another function or
- // participates in a phi.
- static bool CanBeAliased(Definition* alloc) {
- ASSERT(alloc->IsAllocateObject() ||
- alloc->IsCreateArray() ||
- (alloc->IsStaticCall() &&
- alloc->AsStaticCall()->IsRecognizedFactory()));
- if (alloc->Identity() == kIdentityUnknown) {
- bool escapes = false;
- for (Value* use = alloc->input_use_list();
- use != NULL;
- use = use->next_use()) {
- Instruction* instr = use->instruction();
- if (instr->IsPushArgument() ||
- (instr->IsStoreInstanceField()
- && (use->use_index() != StoreInstanceFieldInstr::kInstancePos)) ||
- (instr->IsStoreIndexed()
- && (use->use_index() == StoreIndexedInstr::kValuePos)) ||
- instr->IsStoreStaticField() ||
- instr->IsPhi() ||
- instr->IsAssertAssignable() ||
- instr->IsRedefinition()) {
- escapes = true;
- break;
- }
- }
+ void RollbackAliasedIdentites() {
+ for (intptr_t i = 0; i < identity_rollback_.length(); ++i) {
+ identity_rollback_[i]->SetIdentity(AliasIdentity::Unknown());
+ }
+ }
- alloc->SetIdentity(escapes ? kIdentityAliased : kIdentityNotAliased);
+ // Returns false if the result of an allocation instruction can't be aliased
+ // by another SSA variable and true otherwise.
+ bool CanBeAliased(Definition* alloc) {
+ if (!Place::IsAllocation(alloc)) {
+ return true;
}
- return alloc->Identity() != kIdentityNotAliased;
+ if (alloc->Identity().IsUnknown()) {
+ ComputeAliasing(alloc);
+ }
+
+ return !alloc->Identity().IsNotAliased();
}
private:
- // Get id assigned to the given field. Assign a new id if the field is seen
- // for the first time.
- intptr_t GetFieldId(intptr_t instance_id, const Field& field) {
- intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field));
- if (id == 0) {
- id = ++max_field_id_;
- field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id));
- }
- return id;
- }
-
- intptr_t GetIndexId(intptr_t instance_id, intptr_t index) {
- intptr_t id = index_ids_.Lookup(
- ConstantIndexIdPair::Key(instance_id, index));
- if (id == 0) {
- // Zero is used to indicate element not found. The first id is one.
- id = ++max_index_id_;
- index_ids_.Insert(ConstantIndexIdPair(
- ConstantIndexIdPair::Key(instance_id, index), id));
- }
- return id;
- }
-
enum {
- kAnyInstance = -1
+ kNoAlias = 0,
+
+ // Artificial alias that is used to collect all representatives of the
+ // *[C], X[C] aliases for arbitrary C.
+ kAnyConstantIndexedAlias = 1,
+
+ // Artificial alias that is used to collect all representatives of
+ // *[C] alias for arbitrary C.
+ kUnknownInstanceConstantIndexedAlias = 2,
+
+ // Artificial alias that is used to collect all representatives of
+ // X[*] alias for all X.
+ kAnyAllocationIndexedAlias = 3,
+
+ // *[*] alias.
+ kAnyInstanceAnyIndexAlias = 4
};
- // Get or create an identifier for an instance field belonging to the
- // given instance.
- // The space of identifiers assigned to instance fields is split into
- // parts based on the instance that contains the field.
- // If compiler can prove that instance has a single SSA name in the compiled
- // function then we use that SSA name to distinguish fields of this object
- // from the same fields in other objects.
- // If multiple SSA names can point to the same object then we use
- // kAnyInstance instead of a concrete SSA name.
- intptr_t GetInstanceFieldId(Definition* defn, const Field& field) {
- ASSERT(field.is_static() == (defn == NULL));
+ // Compute least generic alias for the place and assign alias id to it.
+ void AddRepresentative(Place* place) {
+ if (!place->IsFinalField()) {
+ const Place* alias = CanonicalizeAlias(place->ToAlias());
+ EnsureSet(&representatives_, alias->id())->Add(place->id());
- intptr_t instance_id = kAnyInstance;
+ // Update cumulative representative sets that are used during
+ // killed sets computation.
+ if (alias->kind() == Place::kConstantIndexed) {
+ if (CanBeAliased(alias->instance())) {
+ EnsureSet(&representatives_, kAnyConstantIndexedAlias)->
+ Add(place->id());
+ }
- if (defn != NULL) {
- AllocateObjectInstr* alloc = defn->AsAllocateObject();
- if ((alloc != NULL) && !CanBeAliased(alloc)) {
- instance_id = alloc->ssa_temp_index();
- ASSERT(instance_id != kAnyInstance);
+ if (alias->instance() == NULL) {
+ EnsureSet(&representatives_, kUnknownInstanceConstantIndexedAlias)->
+ Add(place->id());
+ }
+ } else if ((alias->kind() == Place::kIndexed) &&
+ CanBeAliased(place->instance())) {
+ EnsureSet(&representatives_, kAnyAllocationIndexedAlias)->
+ Add(place->id());
+ }
+
+ if (!IsIndependentFromEffects(place)) {
+ aliased_by_effects_->Add(place->id());
}
}
-
- return GetFieldId(instance_id, field);
}
- intptr_t GetInstanceVMFieldId(Definition* defn, intptr_t offset) {
- intptr_t instance_id = kAnyInstance;
-
- ASSERT(defn != NULL);
- if ((defn->IsAllocateObject() ||
- defn->IsCreateArray() ||
- (defn->IsStaticCall() &&
- defn->AsStaticCall()->IsRecognizedFactory())) &&
- !CanBeAliased(defn)) {
- instance_id = defn->ssa_temp_index();
- ASSERT(instance_id != kAnyInstance);
+ void ComputeKillSets() {
+ for (intptr_t i = 0; i < aliases_.length(); ++i) {
+ const Place* alias = aliases_[i];
+ // Add all representatives to the kill set.
+ AddAllRepresentatives(alias->id(), alias->id());
+ ComputeKillSet(alias);
}
- intptr_t id = vm_field_ids_.Lookup(VMFieldIdPair::Key(instance_id, offset));
- if (id == 0) {
- id = ++max_vm_field_id_;
- vm_field_ids_.Insert(
- VMFieldIdPair(VMFieldIdPair::Key(instance_id, offset), id));
+ if (FLAG_trace_load_optimization) {
+ OS::Print("Aliases KILL sets:\n");
+ for (intptr_t i = 0; i < aliases_.length(); ++i) {
+ const Place* alias = aliases_[i];
+ BitVector* kill = GetKilledSet(alias->id());
+
+ OS::Print("%s: ", alias->ToCString());
+ if (kill != NULL) {
+ PrintSet(kill);
+ }
+ OS::Print("\n");
+ }
}
- return id;
}
- intptr_t GetInstanceIndexId(Definition* defn, intptr_t index) {
- intptr_t instance_id = kAnyInstance;
-
- ASSERT(defn != NULL);
- if ((defn->IsCreateArray() ||
- (defn->IsStaticCall() &&
- defn->AsStaticCall()->IsRecognizedFactory())) &&
- !CanBeAliased(defn)) {
- instance_id = defn->ssa_temp_index();
- ASSERT(instance_id != kAnyInstance);
- }
-
- return GetIndexId(instance_id, index);
+ void InsertAlias(const Place* alias) {
+ aliases_map_.Insert(alias);
+ aliases_.Add(alias);
}
- intptr_t GetUnknownIndexId(Definition* defn) {
- intptr_t instance_id = kAnyInstance;
-
- ASSERT(defn != NULL);
- if ((defn->IsCreateArray() ||
- (defn->IsStaticCall() &&
- defn->AsStaticCall()->IsRecognizedFactory())) &&
- !CanBeAliased(defn)) {
- instance_id = defn->ssa_temp_index();
- ASSERT(instance_id != kAnyInstance);
+ const Place* CanonicalizeAlias(const Place& alias) {
+ const Place* canonical = aliases_map_.Lookup(&alias);
+ if (canonical == NULL) {
+ canonical = Place::Wrap(isolate_,
+ alias,
+ kAnyInstanceAnyIndexAlias + aliases_.length());
+ InsertAlias(canonical);
}
-
- intptr_t id = unknown_index_ids_.Lookup(
- UnknownIndexIdPair::Key(instance_id));
- if (id == 0) {
- // Zero is used to indicate element not found. The first id is one.
- id = ++max_unknown_index_id_;
- unknown_index_ids_.Insert(
- UnknownIndexIdPair(UnknownIndexIdPair::Key(instance_id), id));
- }
- return id;
+ return canonical;
}
- // Get or create an identifier for a static field.
- intptr_t GetStaticFieldId(const Field& field) {
- ASSERT(field.is_static());
- return GetFieldId(kAnyInstance, field);
+ BitVector* GetRepresentativesSet(intptr_t alias) {
+ return (alias < representatives_.length()) ? representatives_[alias] : NULL;
+ }
+
+ BitVector* EnsureSet(GrowableArray<BitVector*>* sets,
+ intptr_t alias) {
+ while (sets->length() <= alias) {
+ sets->Add(NULL);
+ }
+
+ BitVector* set = (*sets)[alias];
+ if (set == NULL) {
+ (*sets)[alias] = set = new(isolate_) BitVector(max_place_id());
+ }
+ return set;
+ }
+
+ void AddAllRepresentatives(const Place* to, intptr_t from) {
+ AddAllRepresentatives(to->id(), from);
+ }
+
+ void AddAllRepresentatives(intptr_t to, intptr_t from) {
+ BitVector* from_set = GetRepresentativesSet(from);
+ if (from_set != NULL) {
+ EnsureSet(&killed_, to)->AddAll(from_set);
+ }
+ }
+
+ void CrossAlias(const Place* to, const Place& from) {
+ const intptr_t from_id = LookupAliasId(from);
+ if (from_id == kNoAlias) {
+ return;
+ }
+ CrossAlias(to, from_id);
+ }
+
+ void CrossAlias(const Place* to, intptr_t from) {
+ AddAllRepresentatives(to->id(), from);
+ AddAllRepresentatives(from, to->id());
+ }
+
+ // When computing kill sets we let less generic alias insert its
+ // representatives into more generic alias'es kill set. For example
+ // when visiting alias X[*] instead of searching for all aliases X[C]
+ // and inserting their representatives into kill set for X[*] we update
+ // kill set for X[*] each time we visit new X[C] for some C.
+ // There is an exception however: if both aliases are parametric like *[C]
+ // and X[*] which cross alias when X is an aliased allocation then we use
+ // artificial aliases that contain all possible representatives for the given
+ // alias for any value of the parameter to compute resulting kill set.
+ void ComputeKillSet(const Place* alias) {
+ switch (alias->kind()) {
+ case Place::kIndexed: // Either *[*] or X[*] alias.
+ if (alias->instance() == NULL) {
+ // *[*] aliases with X[*], X[C], *[C].
+ AddAllRepresentatives(alias, kAnyConstantIndexedAlias);
+ AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
+ } else if (CanBeAliased(alias->instance())) {
+ // X[*] aliases with X[C].
+ // If X can be aliased then X[*] also aliases with *[C], *[*].
+ CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+ AddAllRepresentatives(alias, kUnknownInstanceConstantIndexedAlias);
+ }
+ break;
+
+ case Place::kConstantIndexed: // Either X[C] or *[C] alias.
+ if (alias->instance() == NULL) {
+ // *[C] aliases with X[C], X[*], *[*].
+ AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
+ CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+ } else {
+ // X[C] aliases with X[*].
+ // If X can be aliased then X[C] also aliases with *[C], *[*].
+ CrossAlias(alias, alias->CopyWithoutIndex());
+ if (CanBeAliased(alias->instance())) {
+ CrossAlias(alias, alias->CopyWithoutInstance());
+ CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+ }
+ }
+ break;
+
+ case Place::kField:
+ case Place::kVMField:
+ if (CanBeAliased(alias->instance())) {
+ // X.f or X.@offs alias with *.f and *.@offs respectively.
+ CrossAlias(alias, alias->CopyWithoutInstance());
+ }
+
+ case Place::kContext:
+ return;
+
+ case Place::kNone:
+ UNREACHABLE();
+ }
}
// Returns true if the given load is unaffected by external side-effects.
@@ -6408,154 +6384,127 @@
return true;
}
- if (((place->kind() == Place::kField) ||
+ return ((place->kind() == Place::kField) ||
(place->kind() == Place::kVMField)) &&
- (place->instance() != NULL)) {
- AllocateObjectInstr* alloc = place->instance()->AsAllocateObject();
- return (alloc != NULL) && !CanBeAliased(alloc);
+ !CanBeAliased(place->instance());
+ }
+
+ // Returns true if there are direct loads from the given place.
+ bool HasLoadsFromPlace(Definition* defn, const Place* place) {
+ ASSERT((place->kind() == Place::kField) ||
+ (place->kind() == Place::kVMField));
+ ASSERT(place->instance() == defn);
+
+ for (Value* use = defn->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ bool is_load = false, is_store;
+ Place load_place(use->instruction(), &is_load, &is_store);
+
+ if (is_load && load_place.Equals(place)) {
+ return true;
+ }
}
return false;
}
- class FieldIdPair {
- public:
- struct Key {
- Key(intptr_t instance_id, const Field* field)
- : instance_id_(instance_id), field_(field) { }
+ // Check if any use of the definition can create an alias.
+ // Can add more objects into aliasing_worklist_.
+ bool AnyUseCreatesAlias(Definition* defn) {
+ for (Value* use = defn->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ Instruction* instr = use->instruction();
+ if (instr->IsPushArgument() ||
+ (instr->IsStoreIndexed()
+ && (use->use_index() == StoreIndexedInstr::kValuePos)) ||
+ instr->IsStoreStaticField() ||
+ instr->IsPhi() ||
+ instr->IsAssertAssignable() ||
+ instr->IsRedefinition()) {
+ return true;
+ } else if ((instr->IsStoreInstanceField()
+ && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) {
+ ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos);
+ // If we store this value into an object that is not aliased itself
+ // and we never load again then the store does not create an alias.
+ StoreInstanceFieldInstr* store = instr->AsStoreInstanceField();
+ Definition* instance = store->instance()->definition();
+ if (instance->IsAllocateObject() && !instance->Identity().IsAliased()) {
+ bool is_load, is_store;
+ Place store_place(instr, &is_load, &is_store);
- intptr_t instance_id_;
- const Field* field_;
- };
+ if (!HasLoadsFromPlace(instance, &store_place)) {
+ // No loads found that match this store. If it is yet unknown if
+ // the object is not aliased then optimistically assume this but
+ // add it to the worklist to check its uses transitively.
+ if (instance->Identity().IsUnknown()) {
+ instance->SetIdentity(AliasIdentity::NotAliased());
+ aliasing_worklist_.Add(instance);
+ }
+ continue;
+ }
+ }
- typedef intptr_t Value;
- typedef FieldIdPair Pair;
+ return true;
+ }
+ }
+ return false;
+ }
- FieldIdPair(Key key, Value value) : key_(key), value_(value) { }
-
- static Key KeyOf(Pair kv) {
- return kv.key_;
+ // Mark any value stored into the given object as potentially aliased.
+ void MarkStoredValuesEscaping(Definition* defn) {
+ if (!defn->IsAllocateObject()) {
+ return;
}
- static Value ValueOf(Pair kv) {
- return kv.value_;
+ // Find all stores into this object.
+ for (Value* use = defn->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) &&
+ use->instruction()->IsStoreInstanceField()) {
+ StoreInstanceFieldInstr* store =
+ use->instruction()->AsStoreInstanceField();
+ Definition* value = store->value()->definition();
+ if (value->Identity().IsNotAliased()) {
+ value->SetIdentity(AliasIdentity::Aliased());
+ identity_rollback_.Add(value);
+
+ // Add to worklist to propagate the mark transitively.
+ aliasing_worklist_.Add(value);
+ }
+ }
}
+ }
- static intptr_t Hashcode(Key key) {
- return String::Handle(key.field_->name()).Hash();
+ // Determine if the given definition can't be aliased.
+ void ComputeAliasing(Definition* alloc) {
+ ASSERT(alloc->Identity().IsUnknown());
+ ASSERT(aliasing_worklist_.is_empty());
+
+ alloc->SetIdentity(AliasIdentity::NotAliased());
+ aliasing_worklist_.Add(alloc);
+
+ while (!aliasing_worklist_.is_empty()) {
+ Definition* defn = aliasing_worklist_.RemoveLast();
+
+ // If the definition in the worklist was optimistically marked as
+ // not-aliased check that optimistic assumption still holds: check if
+ // any of its uses can create an alias.
+ if (!defn->Identity().IsAliased() && AnyUseCreatesAlias(defn)) {
+ defn->SetIdentity(AliasIdentity::Aliased());
+ identity_rollback_.Add(defn);
+ }
+
+ // If the allocation site is marked as aliased conservatively mark
+ // any values stored into the object aliased too.
+ if (defn->Identity().IsAliased()) {
+ MarkStoredValuesEscaping(defn);
+ }
}
-
- static inline bool IsKeyEqual(Pair kv, Key key) {
- return (KeyOf(kv).field_->raw() == key.field_->raw()) &&
- (KeyOf(kv).instance_id_ == key.instance_id_);
- }
-
- private:
- Key key_;
- Value value_;
- };
-
- class ConstantIndexIdPair {
- public:
- struct Key {
- Key(intptr_t instance_id, intptr_t index)
- : instance_id_(instance_id), index_(index) { }
-
- intptr_t instance_id_;
- intptr_t index_;
- };
- typedef intptr_t Value;
- typedef ConstantIndexIdPair Pair;
-
- ConstantIndexIdPair(Key key, Value value) : key_(key), value_(value) { }
-
- static Key KeyOf(ConstantIndexIdPair kv) {
- return kv.key_;
- }
-
- static Value ValueOf(ConstantIndexIdPair kv) {
- return kv.value_;
- }
-
- static intptr_t Hashcode(Key key) {
- return (key.instance_id_ + 1) * 1024 + key.index_;
- }
-
- static inline bool IsKeyEqual(ConstantIndexIdPair kv, Key key) {
- return (KeyOf(kv).index_ == key.index_)
- && (KeyOf(kv).instance_id_ == key.instance_id_);
- }
-
- private:
- Key key_;
- Value value_;
- };
-
- class UnknownIndexIdPair {
- public:
- typedef intptr_t Key;
- typedef intptr_t Value;
- typedef UnknownIndexIdPair Pair;
-
- UnknownIndexIdPair(Key key, Value value) : key_(key), value_(value) { }
-
- static Key KeyOf(UnknownIndexIdPair kv) {
- return kv.key_;
- }
-
- static Value ValueOf(UnknownIndexIdPair kv) {
- return kv.value_;
- }
-
- static intptr_t Hashcode(Key key) {
- return key + 1;
- }
-
- static inline bool IsKeyEqual(UnknownIndexIdPair kv, Key key) {
- return KeyOf(kv) == key;
- }
-
- private:
- Key key_;
- Value value_;
- };
-
- class VMFieldIdPair {
- public:
- struct Key {
- Key(intptr_t instance_id, intptr_t offset)
- : instance_id_(instance_id), offset_(offset) { }
-
- intptr_t instance_id_;
- intptr_t offset_;
- };
-
- typedef intptr_t Value;
- typedef VMFieldIdPair Pair;
-
- VMFieldIdPair(Key key, Value value) : key_(key), value_(value) { }
-
- static Key KeyOf(Pair kv) {
- return kv.key_;
- }
-
- static Value ValueOf(Pair kv) {
- return kv.value_;
- }
-
- static intptr_t Hashcode(Key key) {
- return (key.instance_id_ + 1) * 1024 + key.offset_;
- }
-
- static inline bool IsKeyEqual(Pair kv, Key key) {
- return (KeyOf(kv).offset_ == key.offset_) &&
- (KeyOf(kv).instance_id_ == key.instance_id_);
- }
-
- private:
- Key key_;
- Value value_;
- };
+ }
Isolate* isolate_;
@@ -6563,24 +6512,33 @@
const PhiPlaceMoves* phi_moves_;
- // Maps alias index to a set of ssa indexes corresponding to loads with the
- // given alias.
- GrowableArray<BitVector*> sets_;
+ // A list of all seen aliases and a map that allows looking up canonical
+ // alias object.
+ GrowableArray<const Place*> aliases_;
+ DirectChainedHashMap<PointerKeyValueTrait<const Place> > aliases_map_;
+ // Maps alias id to set of ids of places representing the alias.
+ // Place represents an alias if this alias is least generic alias for
+ // the place.
+ // (see ToAlias for the definition of least generic alias).
+ GrowableArray<BitVector*> representatives_;
+
+ // Maps alias id to set of ids of places aliased.
+ GrowableArray<BitVector*> killed_;
+
+ // Set of ids of places that can be affected by side-effects other than
+ // explicit stores (i.e. through calls).
BitVector* aliased_by_effects_;
- // Table mapping static field to their id used during optimization pass.
- intptr_t max_field_id_;
- DirectChainedHashMap<FieldIdPair> field_ids_;
+ // Worklist used during alias analysis.
+ GrowableArray<Definition*> aliasing_worklist_;
- intptr_t max_index_id_;
- DirectChainedHashMap<ConstantIndexIdPair> index_ids_;
-
- intptr_t max_unknown_index_id_;
- DirectChainedHashMap<UnknownIndexIdPair> unknown_index_ids_;
-
- intptr_t max_vm_field_id_;
- DirectChainedHashMap<VMFieldIdPair> vm_field_ids_;
+ // List of definitions that had their identity set to Aliased. At the end
+ // of load optimization their identity will be rolled back to Unknown to
+ // avoid treating them as Aliased at later stages without checking first
+ // as optimizations can potentially eliminate instructions leading to
+ // aliasing.
+ GrowableArray<Definition*> identity_rollback_;
};
@@ -6643,8 +6601,7 @@
Place* result = map->Lookup(&input_place);
if (result == NULL) {
- input_place.set_id(places->length());
- result = Place::Wrap(isolate, input_place);
+ result = Place::Wrap(isolate, input_place, places->length());
map->Insert(result);
places->Add(result);
if (FLAG_trace_optimization) {
@@ -6698,8 +6655,7 @@
Place* result = map->Lookup(&place);
if (result == NULL) {
- place.set_id(places->length());
- result = Place::Wrap(isolate, place);
+ result = Place::Wrap(isolate, place, places->length());
map->Insert(result);
places->Add(result);
@@ -6724,15 +6680,7 @@
PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places);
// Build aliasing sets mapping aliases to loads.
- AliasedSet* aliased_set = new(isolate) AliasedSet(isolate, places, phi_moves);
- for (intptr_t i = 0; i < places->length(); i++) {
- Place* place = (*places)[i];
- aliased_set->AddRepresentative(place);
- }
-
- aliased_set->EnsureAliasingForUnknownIndices();
-
- return aliased_set;
+ return new(isolate) AliasedSet(isolate, places, phi_moves);
}
@@ -6766,6 +6714,10 @@
}
}
+ ~LoadOptimizer() {
+ aliased_set_->RollbackAliasedIdentites();
+ }
+
Isolate* isolate() const { return graph_->isolate(); }
static bool OptimizeGraph(FlowGraph* graph) {
@@ -6831,11 +6783,8 @@
instr_it.Advance()) {
Instruction* instr = instr_it.Current();
- const Alias alias = aliased_set_->ComputeAliasForStore(instr);
- if (!alias.IsNone()) {
- // Interfering stores kill only loads from the same offset.
- BitVector* killed = aliased_set_->Get(alias);
-
+ BitVector* killed = NULL;
+ if (aliased_set_->IsStore(instr, &killed)) {
if (killed != NULL) {
kill->AddAll(killed);
// There is no need to clear out_values when clearing GEN set
@@ -6899,7 +6848,7 @@
// TODO(vegorov): record null-values at least for not final fields of
// escaping object.
AllocateObjectInstr* alloc = instr->AsAllocateObject();
- if ((alloc != NULL) && !AliasedSet::CanBeAliased(alloc)) {
+ if ((alloc != NULL) && !aliased_set_->CanBeAliased(alloc)) {
for (Value* use = alloc->input_use_list();
use != NULL;
use = use->next_use()) {
@@ -7691,8 +7640,8 @@
// Handle loads.
Definition* defn = instr->AsDefinition();
if ((defn != NULL) && IsLoadEliminationCandidate(defn)) {
- const Alias alias = aliased_set_->ComputeAlias(&place);
- live_in->AddAll(aliased_set_->Get(alias));
+ const intptr_t alias = aliased_set_->LookupAliasId(place.ToAlias());
+ live_in->AddAll(aliased_set_->GetKilledSet(alias));
continue;
}
}
@@ -9883,16 +9832,63 @@
}
+enum SafeUseCheck { kOptimisticCheck, kStrictCheck };
+
+// Check if the use is safe for allocation sinking. Allocation sinking
+// candidates can only be used at store instructions:
+//
+// - any store into the allocation candidate itself is unconditionally safe
+// as it just changes the rematerialization state of this candidate;
+// - store into another object is only safe if another object is allocation
+// candidate.
+//
+// We use a simple fix-point algorithm to discover the set of valid candidates
+// (see CollectCandidates method), that's why this IsSafeUse can operate in two
+// modes:
+//
+// - optimistic, when every allocation is assumed to be an allocation
+// sinking candidate;
+// - strict, when only marked allocations are assumed to be allocation
+// sinking candidates.
+//
+// Fix-point algorithm in CollectCandiates first collects a set of allocations
+// optimistically and then checks each collected candidate strictly and unmarks
+// invalid candidates transitively until only strictly valid ones remain.
+static bool IsSafeUse(Value* use, SafeUseCheck check_type) {
+ if (use->instruction()->IsMaterializeObject()) {
+ return true;
+ }
+
+ StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
+ if (store != NULL) {
+ if (use == store->value()) {
+ Definition* instance = store->instance()->definition();
+ return instance->IsAllocateObject() &&
+ ((check_type == kOptimisticCheck) ||
+ instance->Identity().IsAllocationSinkingCandidate());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+
// Right now we are attempting to sink allocation only into
// deoptimization exit. So candidate should only be used in StoreInstanceField
// instructions that write into fields of the allocated object.
// We do not support materialization of the object that has type arguments.
-static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) {
+static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc,
+ SafeUseCheck check_type) {
for (Value* use = alloc->input_use_list();
use != NULL;
use = use->next_use()) {
- if (!(use->instruction()->IsStoreInstanceField() &&
- (use->use_index() == 0))) {
+ if (!IsSafeUse(use, check_type)) {
+ if (FLAG_trace_optimization) {
+ OS::Print("use of %s at %s is unsafe for allocation sinking\n",
+ alloc->ToCString(),
+ use->instruction()->ToCString());
+ }
return false;
}
}
@@ -9901,10 +9897,22 @@
}
+// If the given use is a store into an object then return an object we are
+// storing into.
+static Definition* StoreInto(Value* use) {
+ StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
+ if (store != NULL) {
+ return store->instance()->definition();
+ }
+
+ return NULL;
+}
+
+
// Remove the given allocation from the graph. It is not observable.
// If deoptimization occurs the object will be materialized.
-static void EliminateAllocation(AllocateObjectInstr* alloc) {
- ASSERT(IsAllocationSinkingCandidate(alloc));
+void AllocationSinking::EliminateAllocation(AllocateObjectInstr* alloc) {
+ ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck));
if (FLAG_trace_optimization) {
OS::Print("removing allocation from the graph: v%" Pd "\n",
@@ -9921,7 +9929,13 @@
// There should be no environment uses. The pass replaced them with
// MaterializeObject instructions.
- ASSERT(alloc->env_use_list() == NULL);
+#ifdef DEBUG
+ for (Value* use = alloc->env_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ ASSERT(use->instruction()->IsMaterializeObject());
+ }
+#endif
ASSERT(alloc->input_use_list() == NULL);
alloc->RemoveFromGraph();
if (alloc->ArgumentCount() > 0) {
@@ -9933,31 +9947,205 @@
}
-void AllocationSinking::Optimize() {
- GrowableArray<AllocateObjectInstr*> candidates(5);
-
- // Collect sinking candidates.
- const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder();
- for (BlockIterator block_it(postorder);
+// Find allocation instructions that can be potentially eliminated and
+// rematerialized at deoptimization exits if needed. See IsSafeUse
+// for the description of algorithm used below.
+void AllocationSinking::CollectCandidates() {
+ // Optimistically collect all potential candidates.
+ for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
!block_it.Done();
block_it.Advance()) {
BlockEntryInstr* block = block_it.Current();
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
AllocateObjectInstr* alloc = it.Current()->AsAllocateObject();
- if ((alloc != NULL) && IsAllocationSinkingCandidate(alloc)) {
- if (FLAG_trace_optimization) {
- OS::Print("discovered allocation sinking candidate: v%" Pd "\n",
- alloc->ssa_temp_index());
- }
-
- // All sinking candidate are known to be not aliased.
- alloc->SetIdentity(kIdentityNotAliased);
-
- candidates.Add(alloc);
+ if ((alloc != NULL) &&
+ IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) {
+ alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate());
+ candidates_.Add(alloc);
}
}
}
+ // Transitively unmark all candidates that are not strictly valid.
+ bool changed;
+ do {
+ changed = false;
+ for (intptr_t i = 0; i < candidates_.length(); i++) {
+ AllocateObjectInstr* alloc = candidates_[i];
+ if (alloc->Identity().IsAllocationSinkingCandidate()) {
+ if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
+ alloc->SetIdentity(AliasIdentity::Unknown());
+ changed = true;
+ }
+ }
+ }
+ } while (changed);
+
+ // Shrink the list of candidates removing all unmarked ones.
+ intptr_t j = 0;
+ for (intptr_t i = 0; i < candidates_.length(); i++) {
+ AllocateObjectInstr* alloc = candidates_[i];
+ if (alloc->Identity().IsAllocationSinkingCandidate()) {
+ if (FLAG_trace_optimization) {
+ OS::Print("discovered allocation sinking candidate: v%" Pd "\n",
+ alloc->ssa_temp_index());
+ }
+
+ if (j != i) {
+ candidates_[j] = alloc;
+ }
+ j++;
+ }
+ }
+ candidates_.TruncateTo(j);
+}
+
+
+// If materialization references an allocation sinking candidate then replace
+// this reference with a materialization which should have been computed for
+// this side-exit. CollectAllExits should have collected this exit.
+void AllocationSinking::NormalizeMaterializations() {
+ for (intptr_t i = 0; i < candidates_.length(); i++) {
+ Definition* alloc = candidates_[i];
+
+ Value* next_use;
+ for (Value* use = alloc->input_use_list();
+ use != NULL;
+ use = next_use) {
+ next_use = use->next_use();
+ if (use->instruction()->IsMaterializeObject()) {
+ use->BindTo(MaterializationFor(alloc, use->instruction()));
+ }
+ }
+ }
+}
+
+
+// We transitively insert materializations at each deoptimization exit that
+// might see the given allocation (see ExitsCollector). Some of this
+// materializations are not actually used and some fail to compute because
+// they are inserted in the block that is not dominated by the allocation.
+// Remove them unused materializations from the graph.
+void AllocationSinking::RemoveUnusedMaterializations() {
+ intptr_t j = 0;
+ for (intptr_t i = 0; i < materializations_.length(); i++) {
+ MaterializeObjectInstr* mat = materializations_[i];
+ if ((mat->input_use_list() == NULL) && (mat->env_use_list() == NULL)) {
+ // Check if this materialization failed to compute and remove any
+ // unforwarded loads. There were no loads from any allocation sinking
+ // candidate in the beggining so it is safe to assume that any encountered
+ // load was inserted by CreateMaterializationAt.
+ for (intptr_t i = 0; i < mat->InputCount(); i++) {
+ LoadFieldInstr* load = mat->InputAt(i)->definition()->AsLoadField();
+ if ((load != NULL) &&
+ (load->instance()->definition() == mat->allocation())) {
+ load->ReplaceUsesWith(flow_graph_->constant_null());
+ load->RemoveFromGraph();
+ }
+ }
+ mat->RemoveFromGraph();
+ } else {
+ if (j != i) {
+ materializations_[j] = mat;
+ }
+ j++;
+ }
+ }
+ materializations_.TruncateTo(j);
+}
+
+
+// Some candidates might stop being eligible for allocation sinking after
+// the load forwarding because they flow into phis that load forwarding
+// inserts. Discover such allocations and remove them from the list
+// of allocation sinking candidates undoing all changes that we did
+// in preparation for sinking these allocations.
+void AllocationSinking::DiscoverFailedCandidates() {
+ // Transitively unmark all candidates that are not strictly valid.
+ bool changed;
+ do {
+ changed = false;
+ for (intptr_t i = 0; i < candidates_.length(); i++) {
+ AllocateObjectInstr* alloc = candidates_[i];
+ if (alloc->Identity().IsAllocationSinkingCandidate()) {
+ if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
+ alloc->SetIdentity(AliasIdentity::Unknown());
+ changed = true;
+ }
+ }
+ }
+ } while (changed);
+
+ // Remove all failed candidates from the candidates list.
+ intptr_t j = 0;
+ for (intptr_t i = 0; i < candidates_.length(); i++) {
+ AllocateObjectInstr* alloc = candidates_[i];
+ if (!alloc->Identity().IsAllocationSinkingCandidate()) {
+ if (FLAG_trace_optimization) {
+ OS::Print("allocation v%" Pd " can't be eliminated\n",
+ alloc->ssa_temp_index());
+ }
+
+#ifdef DEBUG
+ for (Value* use = alloc->env_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ ASSERT(use->instruction()->IsMaterializeObject());
+ }
+#endif
+
+ // All materializations will be removed from the graph. Remove inserted
+ // loads first and detach materializations from allocation's environment
+ // use list: we will reconstruct it when we start removing
+ // materializations.
+ alloc->set_env_use_list(NULL);
+ for (Value* use = alloc->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ if (use->instruction()->IsLoadField()) {
+ LoadFieldInstr* load = use->instruction()->AsLoadField();
+ load->ReplaceUsesWith(flow_graph_->constant_null());
+ load->RemoveFromGraph();
+ } else {
+ ASSERT(use->instruction()->IsMaterializeObject() ||
+ use->instruction()->IsPhi() ||
+ use->instruction()->IsStoreInstanceField());
+ }
+ }
+ } else {
+ if (j != i) {
+ candidates_[j] = alloc;
+ }
+ j++;
+ }
+ }
+
+ if (j != candidates_.length()) { // Something was removed from candidates.
+ intptr_t k = 0;
+ for (intptr_t i = 0; i < materializations_.length(); i++) {
+ MaterializeObjectInstr* mat = materializations_[i];
+ if (!mat->allocation()->Identity().IsAllocationSinkingCandidate()) {
+ // Restore environment uses of the allocation that were replaced
+ // by this materialization and drop materialization.
+ mat->ReplaceUsesWith(mat->allocation());
+ mat->RemoveFromGraph();
+ } else {
+ if (k != i) {
+ materializations_[k] = mat;
+ }
+ k++;
+ }
+ }
+ materializations_.TruncateTo(k);
+ }
+
+ candidates_.TruncateTo(j);
+}
+
+
+void AllocationSinking::Optimize() {
+ CollectCandidates();
+
// Insert MaterializeObject instructions that will describe the state of the
// object at all deoptimization points. Each inserted materialization looks
// like this (where v_0 is allocation that we are going to eliminate):
@@ -9965,8 +10153,8 @@
// ...
// v_N <- LoadField(v_0, field_N)
// v_{N+1} <- MaterializeObject(field_1 = v_1, ..., field_N = v_{N})
- for (intptr_t i = 0; i < candidates.length(); i++) {
- InsertMaterializations(candidates[i]);
+ for (intptr_t i = 0; i < candidates_.length(); i++) {
+ InsertMaterializations(candidates_[i]);
}
// Run load forwarding to eliminate LoadField instructions inserted above.
@@ -9977,15 +10165,19 @@
// external effects from calls.
LoadOptimizer::OptimizeGraph(flow_graph_);
- if (FLAG_trace_optimization) {
- FlowGraphPrinter::PrintGraph("Sinking", flow_graph_);
- }
+ NormalizeMaterializations();
+
+ RemoveUnusedMaterializations();
+
+ // If any candidates are no longer eligible for allocation sinking abort
+ // the optimization for them and undo any changes we did in preparation.
+ DiscoverFailedCandidates();
// At this point we have computed the state of object at each deoptimization
// point and we can eliminate it. Loads inserted above were forwarded so there
// are no uses of the allocation just as in the begging of the pass.
- for (intptr_t i = 0; i < candidates.length(); i++) {
- EliminateAllocation(candidates[i]);
+ for (intptr_t i = 0; i < candidates_.length(); i++) {
+ EliminateAllocation(candidates_[i]);
}
// Process materializations and unbox their arguments: materializations
@@ -10010,35 +10202,62 @@
// as part of the environment not as a real instruction.
void AllocationSinking::DetachMaterializations() {
for (intptr_t i = 0; i < materializations_.length(); i++) {
- ASSERT(materializations_[i]->input_use_list() == NULL);
materializations_[i]->previous()->LinkTo(materializations_[i]->next());
}
}
// Add a field/offset to the list of fields if it is not yet present there.
-static void AddSlot(ZoneGrowableArray<const Object*>* slots,
+static bool AddSlot(ZoneGrowableArray<const Object*>* slots,
const Object& slot) {
for (intptr_t i = 0; i < slots->length(); i++) {
if ((*slots)[i]->raw() == slot.raw()) {
- return;
+ return false;
}
}
slots->Add(&slot);
+ return true;
}
-// Add given instruction to the list of the instructions if it is not yet
-// present there.
-static void AddInstruction(GrowableArray<Instruction*>* exits,
- Instruction* exit) {
- ASSERT(!exit->IsGraphEntry());
- for (intptr_t i = 0; i < exits->length(); i++) {
- if ((*exits)[i] == exit) {
- return;
+// Find deoptimization exit for the given materialization assuming that all
+// materializations are emitted right before the instruction which is a
+// deoptimization exit.
+static Instruction* ExitForMaterialization(MaterializeObjectInstr* mat) {
+ while (mat->next()->IsMaterializeObject()) {
+ mat = mat->next()->AsMaterializeObject();
+ }
+ return mat->next();
+}
+
+
+// Given the deoptimization exit find first materialization that was inserted
+// before it.
+static Instruction* FirstMaterializationAt(Instruction* exit) {
+ while (exit->previous()->IsMaterializeObject()) {
+ exit = exit->previous();
+ }
+ return exit;
+}
+
+
+// Given the allocation and deoptimization exit try to find MaterializeObject
+// instruction corresponding to this allocation at this exit.
+MaterializeObjectInstr* AllocationSinking::MaterializationFor(
+ Definition* alloc, Instruction* exit) {
+ if (exit->IsMaterializeObject()) {
+ exit = ExitForMaterialization(exit->AsMaterializeObject());
+ }
+
+ for (MaterializeObjectInstr* mat = exit->previous()->AsMaterializeObject();
+ mat != NULL;
+ mat = mat->previous()->AsMaterializeObject()) {
+ if (mat->allocation() == alloc) {
+ return mat;
}
}
- exits->Add(exit);
+
+ return NULL;
}
@@ -10052,6 +10271,11 @@
ZoneGrowableArray<Value*>* values =
new(I) ZoneGrowableArray<Value*>(slots.length());
+ // All loads should be inserted before the first materialization so that
+ // IR follows the following pattern: loads, materializations, deoptimizing
+ // instruction.
+ Instruction* load_point = FirstMaterializationAt(exit);
+
// Insert load instruction for every field.
for (intptr_t i = 0; i < slots.length(); i++) {
LoadFieldInstr* load = slots[i]->IsField()
@@ -10066,12 +10290,12 @@
AbstractType::ZoneHandle(I),
alloc->token_pos());
flow_graph_->InsertBefore(
- exit, load, NULL, FlowGraph::kValue);
+ load_point, load, NULL, FlowGraph::kValue);
values->Add(new(I) Value(load));
}
MaterializeObjectInstr* mat =
- new(I) MaterializeObjectInstr(cls, slots, values);
+ new(I) MaterializeObjectInstr(alloc, cls, slots, values);
flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue);
// Replace all mentions of this allocation with a newly inserted
@@ -10089,11 +10313,81 @@
}
}
+ // Mark MaterializeObject as an environment use of this allocation.
+ // This will allow us to discover it when we are looking for deoptimization
+ // exits for another allocation that potentially flows into this one.
+ Value* val = new(I) Value(alloc);
+ val->set_instruction(mat);
+ alloc->AddEnvUse(val);
+
// Record inserted materialization.
materializations_.Add(mat);
}
+// Add given instruction to the list of the instructions if it is not yet
+// present there.
+template<typename T>
+void AddInstruction(GrowableArray<T*>* list, T* value) {
+ ASSERT(!value->IsGraphEntry());
+ for (intptr_t i = 0; i < list->length(); i++) {
+ if ((*list)[i] == value) {
+ return;
+ }
+ }
+ list->Add(value);
+}
+
+
+// Transitively collect all deoptimization exits that might need this allocation
+// rematerialized. It is not enough to collect only environment uses of this
+// allocation because it can flow into other objects that will be
+// dematerialized and that are referenced by deopt environments that
+// don't contain this allocation explicitly.
+void AllocationSinking::ExitsCollector::Collect(Definition* alloc) {
+ for (Value* use = alloc->env_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ if (use->instruction()->IsMaterializeObject()) {
+ AddInstruction(&exits_, ExitForMaterialization(
+ use->instruction()->AsMaterializeObject()));
+ } else {
+ AddInstruction(&exits_, use->instruction());
+ }
+ }
+
+ // Check if this allocation is stored into any other allocation sinking
+ // candidate and put it on worklist so that we conservatively collect all
+ // exits for that candidate as well because they potentially might see
+ // this object.
+ for (Value* use = alloc->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ Definition* obj = StoreInto(use);
+ if ((obj != NULL) && (obj != alloc)) {
+ AddInstruction(&worklist_, obj);
+ }
+ }
+}
+
+
+void AllocationSinking::ExitsCollector::CollectTransitively(Definition* alloc) {
+ exits_.TruncateTo(0);
+ worklist_.TruncateTo(0);
+
+ worklist_.Add(alloc);
+
+ // Note: worklist potentially will grow while we are iterating over it.
+ // We are not removing allocations from the worklist not to waste space on
+ // the side maintaining BitVector of already processed allocations: worklist
+ // is expected to be very small thus linear search in it is just as effecient
+ // as a bitvector.
+ for (intptr_t i = 0; i < worklist_.length(); i++) {
+ Collect(worklist_[i]);
+ }
+}
+
+
void AllocationSinking::InsertMaterializations(AllocateObjectInstr* alloc) {
// Collect all fields that are written for this instance.
ZoneGrowableArray<const Object*>* slots =
@@ -10103,10 +10397,12 @@
use != NULL;
use = use->next_use()) {
StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
- if (!store->field().IsNull()) {
- AddSlot(slots, store->field());
- } else {
- AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes())));
+ if ((store != NULL) && (store->instance()->definition() == alloc)) {
+ if (!store->field().IsNull()) {
+ AddSlot(slots, store->field());
+ } else {
+ AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes())));
+ }
}
}
@@ -10117,16 +10413,12 @@
}
// Collect all instructions that mention this object in the environment.
- GrowableArray<Instruction*> exits(10);
- for (Value* use = alloc->env_use_list();
- use != NULL;
- use = use->next_use()) {
- AddInstruction(&exits, use->instruction());
- }
+ exits_collector_.CollectTransitively(alloc);
// Insert materializations at environment uses.
- for (intptr_t i = 0; i < exits.length(); i++) {
- CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots);
+ for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) {
+ CreateMaterializationAt(
+ exits_collector_.exits()[i], alloc, alloc->cls(), *slots);
}
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 3aecb91..e9a7482 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -429,13 +429,54 @@
public:
explicit AllocationSinking(FlowGraph* flow_graph)
: flow_graph_(flow_graph),
+ candidates_(5),
materializations_(5) { }
+ const GrowableArray<AllocateObjectInstr*>& candidates() const {
+ return candidates_;
+ }
+
+ // Find the materialization insterted for the given allocation
+ // at the given exit.
+ MaterializeObjectInstr* MaterializationFor(Definition* alloc,
+ Instruction* exit);
+
void Optimize();
void DetachMaterializations();
private:
+ // Helper class to collect deoptimization exits that might need to
+ // rematerialize an object: that is either instructions that reference
+ // this object explicitly in their deoptimization environment or
+ // reference some other allocation sinking candidate that points to
+ // this object.
+ class ExitsCollector : public ValueObject {
+ public:
+ ExitsCollector() : exits_(10), worklist_(3) { }
+
+ const GrowableArray<Instruction*>& exits() const { return exits_; }
+
+ void CollectTransitively(Definition* alloc);
+
+ private:
+ // Collect immediate uses of this object in the environments.
+ // If this object is stored into other allocation sinking candidates
+ // put them onto worklist so that CollectTransitively will process them.
+ void Collect(Definition* alloc);
+
+ GrowableArray<Instruction*> exits_;
+ GrowableArray<Definition*> worklist_;
+ };
+
+ void CollectCandidates();
+
+ void NormalizeMaterializations();
+
+ void RemoveUnusedMaterializations();
+
+ void DiscoverFailedCandidates();
+
void InsertMaterializations(AllocateObjectInstr* alloc);
void CreateMaterializationAt(
@@ -444,11 +485,16 @@
const Class& cls,
const ZoneGrowableArray<const Object*>& fields);
+ void EliminateAllocation(AllocateObjectInstr* alloc);
+
Isolate* isolate() const { return flow_graph_->isolate(); }
FlowGraph* flow_graph_;
+ GrowableArray<AllocateObjectInstr*> candidates_;
GrowableArray<MaterializeObjectInstr*> materializations_;
+
+ ExitsCollector exits_collector_;
};
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 01f345c..b8664dc 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -507,6 +507,10 @@
f->Print(", ");
PushArgumentAt(i)->value()->PrintTo(f);
}
+
+ if (Identity().IsNotAliased()) {
+ f->Print(" <not-aliased>");
+ }
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index e23603f..6bb00cf 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2281,6 +2281,11 @@
// FlowGraphCompiler::SlowPathEnvironmentFor().
void MaterializeObjectInstr::RemapRegisters(intptr_t* fpu_reg_slots,
intptr_t* cpu_reg_slots) {
+ if (registers_remapped_) {
+ return;
+ }
+ registers_remapped_ = true;
+
for (intptr_t i = 0; i < InputCount(); i++) {
Location loc = LocationAt(i);
if (loc.IsRegister()) {
@@ -2305,11 +2310,10 @@
}
} else if (loc.IsPairLocation()) {
UNREACHABLE();
- } else if (loc.IsInvalid()) {
- // We currently only perform one iteration of allocation
- // sinking, so we do not expect to find materialized objects
- // here.
- ASSERT(!InputAt(i)->definition()->IsMaterializeObject());
+ } else if (loc.IsInvalid() &&
+ InputAt(i)->definition()->IsMaterializeObject()) {
+ InputAt(i)->definition()->AsMaterializeObject()->RemapRegisters(
+ fpu_reg_slots, cpu_reg_slots);
}
}
}
@@ -2732,7 +2736,7 @@
((limit > 0) && (Utils::IsInt(limit, value)))) {
// Result stays in 64 bit range.
int64_t result = value << shift_count;
- return Smi::IsValid(result) ? RangeBoundary(result) : overflow;
+ return RangeBoundary(result);
}
return overflow;
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 1606207..1e59e79 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -1763,10 +1763,54 @@
// If the result of the allocation is not stored into any field, passed
// as an argument or used in a phi then it can't alias with any other
// SSA value.
-enum AliasIdentity {
- kIdentityUnknown,
- kIdentityAliased,
- kIdentityNotAliased
+class AliasIdentity : public ValueObject {
+ public:
+ // It is unknown if value has aliases.
+ static AliasIdentity Unknown() { return AliasIdentity(kUnknown); }
+
+ // It is known that value can have aliases.
+ static AliasIdentity Aliased() { return AliasIdentity(kAliased); }
+
+ // It is known that value has no aliases.
+ static AliasIdentity NotAliased() { return AliasIdentity(kNotAliased); }
+
+ // It is known that value has no aliases and it was selected by
+ // allocation sinking pass as a candidate.
+ static AliasIdentity AllocationSinkingCandidate() {
+ return AliasIdentity(kAllocationSinkingCandidate);
+ }
+
+ bool IsUnknown() const { return value_ == kUnknown; }
+ bool IsAliased() const { return value_ == kAliased; }
+ bool IsNotAliased() const { return (value_ & kNotAliased) != 0; }
+ bool IsAllocationSinkingCandidate() const {
+ return value_ == kAllocationSinkingCandidate;
+ }
+
+ AliasIdentity(const AliasIdentity& other)
+ : ValueObject(), value_(other.value_) {
+ }
+
+ AliasIdentity& operator=(const AliasIdentity& other) {
+ value_ = other.value_;
+ return *this;
+ }
+
+ private:
+ explicit AliasIdentity(intptr_t value) : value_(value) { }
+
+ enum {
+ kUnknown = 0,
+ kNotAliased = 1,
+ kAliased = 2,
+ kAllocationSinkingCandidate = 3,
+ };
+
+ COMPILE_ASSERT((kUnknown & kNotAliased) == 0);
+ COMPILE_ASSERT((kAliased & kNotAliased) == 0);
+ COMPILE_ASSERT((kAllocationSinkingCandidate & kNotAliased) != 0);
+
+ intptr_t value_;
};
@@ -1927,9 +1971,7 @@
}
virtual AliasIdentity Identity() const {
- // Only implemented for allocation instructions.
- UNREACHABLE();
- return kIdentityUnknown;
+ return AliasIdentity::Unknown();
}
virtual void SetIdentity(AliasIdentity identity) {
@@ -3629,7 +3671,7 @@
result_cid_(kDynamicCid),
is_known_list_constructor_(false),
is_native_list_factory_(false),
- identity_(kIdentityUnknown) {
+ identity_(AliasIdentity::Unknown()) {
ASSERT(function.IsZoneHandle());
ASSERT(argument_names.IsZoneHandle() || argument_names.InVMHeap());
}
@@ -4474,7 +4516,7 @@
: token_pos_(token_pos),
cls_(cls),
arguments_(arguments),
- identity_(kIdentityUnknown),
+ identity_(AliasIdentity::Unknown()),
closure_function_(Function::ZoneHandle()) {
// Either no arguments or one type-argument and one instantiator.
ASSERT(arguments->is_empty() || (arguments->length() == 1));
@@ -4523,10 +4565,17 @@
// It does not produce any real code only deoptimization information.
class MaterializeObjectInstr : public Definition {
public:
- MaterializeObjectInstr(const Class& cls,
+ MaterializeObjectInstr(AllocateObjectInstr* allocation,
+ const Class& cls,
const ZoneGrowableArray<const Object*>& slots,
ZoneGrowableArray<Value*>* values)
- : cls_(cls), slots_(slots), values_(values), locations_(NULL) {
+ : allocation_(allocation),
+ cls_(cls),
+ slots_(slots),
+ values_(values),
+ locations_(NULL),
+ visited_for_liveness_(false),
+ registers_remapped_(false) {
ASSERT(slots_.length() == values_->length());
for (intptr_t i = 0; i < InputCount(); i++) {
InputAt(i)->set_instruction(this);
@@ -4534,6 +4583,7 @@
}
}
+ AllocateObjectInstr* allocation() const { return allocation_; }
const Class& cls() const { return cls_; }
intptr_t FieldOffsetAt(intptr_t i) const {
return slots_[i]->IsField()
@@ -4576,16 +4626,25 @@
void RemapRegisters(intptr_t* fpu_reg_slots,
intptr_t* cpu_reg_slots);
+ bool was_visited_for_liveness() const { return visited_for_liveness_; }
+ void mark_visited_for_liveness() {
+ visited_for_liveness_ = true;
+ }
+
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
(*values_)[i] = value;
}
+ AllocateObjectInstr* allocation_;
const Class& cls_;
const ZoneGrowableArray<const Object*>& slots_;
ZoneGrowableArray<Value*>* values_;
Location* locations_;
+ bool visited_for_liveness_;
+ bool registers_remapped_;
+
DISALLOW_COPY_AND_ASSIGN(MaterializeObjectInstr);
};
@@ -4595,7 +4654,7 @@
CreateArrayInstr(intptr_t token_pos,
Value* element_type,
Value* num_elements)
- : token_pos_(token_pos), identity_(kIdentityUnknown) {
+ : token_pos_(token_pos), identity_(AliasIdentity::Unknown()) {
SetInputAt(kElementTypePos, element_type);
SetInputAt(kLengthPos, num_elements);
}
@@ -4698,8 +4757,6 @@
};
-
-
class LoadFieldInstr : public TemplateDefinition<1> {
public:
LoadFieldInstr(Value* instance,
@@ -7086,7 +7143,8 @@
virtual bool CanDeoptimize() const {
return FLAG_throw_on_javascript_int_overflow
|| (can_overflow() && ((op_kind() == Token::kADD) ||
- (op_kind() == Token::kSUB)));
+ (op_kind() == Token::kSUB)))
+ || (op_kind() == Token::kMUL); // Deopt if inputs are not int32.
}
virtual Representation representation() const {
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 643f692..81cbe5f 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1140,19 +1140,6 @@
}
-static bool CanHoldImmediateOffset(bool is_load, intptr_t cid, int64_t offset) {
- int32_t offset_mask = 0;
- if (is_load) {
- return Address::CanHoldLoadOffset(Address::OperandSizeFor(cid),
- offset,
- &offset_mask);
- } else {
- return Address::CanHoldStoreOffset(Address::OperandSizeFor(cid),
- offset,
- &offset_mask);
- }
-}
-
static bool CanBeImmediateIndex(Value* value,
intptr_t cid,
bool is_external,
@@ -1177,12 +1164,12 @@
if (!Utils::IsAbsoluteUint(12, offset)) {
return false;
}
- if (CanHoldImmediateOffset(is_load, cid, offset)) {
+ if (Address::CanHoldImmediateOffset(is_load, cid, offset)) {
*needs_base = false;
return true;
}
- if (CanHoldImmediateOffset(is_load, cid, offset - base_offset)) {
+ if (Address::CanHoldImmediateOffset(is_load, cid, offset - base_offset)) {
*needs_base = true;
return true;
}
@@ -1230,91 +1217,20 @@
}
-static Address ElementAddressForIntIndex(Assembler* assembler,
- bool is_load,
- bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- intptr_t index,
- Register temp) {
- const int64_t offset_base =
- (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
- const int64_t offset = offset_base +
- static_cast<int64_t>(index) * index_scale;
- ASSERT(Utils::IsInt(32, offset));
-
- if (CanHoldImmediateOffset(is_load, cid, offset)) {
- return Address(array, static_cast<int32_t>(offset));
- } else {
- ASSERT(CanHoldImmediateOffset(is_load, cid, offset - offset_base));
- assembler->AddImmediate(
- temp, array, static_cast<int32_t>(offset_base));
- return Address(temp, static_cast<int32_t>(offset - offset_base));
- }
-}
-
-
-static Address ElementAddressForRegIndex(Assembler* assembler,
- bool is_load,
- bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- Register index) {
- // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
- const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
- int32_t offset =
- is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
- const OperandSize size = Address::OperandSizeFor(cid);
- ASSERT(array != IP);
- ASSERT(index != IP);
- const Register base = is_load ? IP : index;
- if ((offset != 0) ||
- (size == kSWord) || (size == kDWord) || (size == kRegList)) {
- if (shift < 0) {
- ASSERT(shift == -1);
- assembler->add(base, array, Operand(index, ASR, 1));
- } else {
- assembler->add(base, array, Operand(index, LSL, shift));
- }
- } else {
- if (shift < 0) {
- ASSERT(shift == -1);
- return Address(array, index, ASR, 1);
- } else {
- return Address(array, index, LSL, shift);
- }
- }
- int32_t offset_mask = 0;
- if ((is_load && !Address::CanHoldLoadOffset(size,
- offset,
- &offset_mask)) ||
- (!is_load && !Address::CanHoldStoreOffset(size,
- offset,
- &offset_mask))) {
- assembler->AddImmediate(base, offset & ~offset_mask);
- offset = offset & offset_mask;
- }
- return Address(base, offset);
-}
-
-
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The array register points to the backing store for external arrays.
const Register array = locs()->in(0).reg();
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(compiler->assembler(),
- true, // Load.
- IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(compiler->assembler(),
- true, // Load.
- IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value(),
- IP); // Temp register.
+ ? __ ElementAddressForRegIndex(true, // Load.
+ IsExternal(), class_id(), index_scale(),
+ array,
+ index.reg())
+ : __ ElementAddressForIntIndex(true, // Load.
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value(),
+ IP); // Temp register.
// Warning: element_address may use register IP as base.
if ((representation() == kUnboxedDouble) ||
@@ -1542,15 +1458,14 @@
(locs()->temp_count() > 0) ? locs()->temp(0).reg() : kNoRegister;
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(compiler->assembler(),
- false, // Store.
- IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(compiler->assembler(),
- false, // Store.
- IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value(),
- temp);
+ ? __ ElementAddressForRegIndex(false, // Store.
+ IsExternal(), class_id(), index_scale(),
+ array,
+ index.reg())
+ : __ ElementAddressForIntIndex(false, // Store.
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value(),
+ temp);
switch (class_id()) {
case kArrayCid:
@@ -6102,18 +6017,18 @@
case Token::kBIT_AND: {
__ and_(out_lo, left_lo, Operand(right_lo));
__ and_(out_hi, left_hi, Operand(right_hi));
+ break;
}
- break;
case Token::kBIT_OR: {
__ orr(out_lo, left_lo, Operand(right_lo));
__ orr(out_hi, left_hi, Operand(right_hi));
+ break;
}
- break;
case Token::kBIT_XOR: {
__ eor(out_lo, left_lo, Operand(right_lo));
__ eor(out_hi, left_hi, Operand(right_hi));
+ break;
}
- break;
case Token::kADD:
case Token::kSUB: {
if (op_kind() == Token::kADD) {
@@ -6130,9 +6045,23 @@
}
break;
}
+ case Token::kMUL: {
+ // The product of two signed 32-bit integers fits in a signed 64-bit
+ // result without causing overflow.
+ // We deopt on larger inputs.
+ // TODO(regis): Range analysis may eliminate the deopt check.
+ if (TargetCPUFeatures::arm_version() == ARMv7) {
+ __ cmp(left_hi, Operand(left_lo, ASR, 31));
+ __ cmp(right_hi, Operand(right_lo, ASR, 31), EQ);
+ __ b(deopt, NE);
+ __ smull(out_lo, out_hi, left_lo, right_lo);
+ } else {
+ __ b(deopt);
+ }
+ break;
+ }
default:
UNREACHABLE();
- break;
}
if (FLAG_throw_on_javascript_int_overflow) {
EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
@@ -6375,19 +6304,22 @@
switch (op_kind()) {
case Token::kBIT_AND:
__ and_(out, left, Operand(right));
- break;
+ break;
case Token::kBIT_OR:
__ orr(out, left, Operand(right));
- break;
+ break;
case Token::kBIT_XOR:
__ eor(out, left, Operand(right));
- break;
+ break;
case Token::kADD:
__ add(out, left, Operand(right));
- break;
+ break;
case Token::kSUB:
__ sub(out, left, Operand(right));
- break;
+ break;
+ case Token::kMUL:
+ __ mul(out, left, right);
+ break;
default:
UNREACHABLE();
}
@@ -6441,10 +6373,10 @@
switch (op_kind()) {
case Token::kSHR:
__ Lsr(out, left, shift_value);
- break;
+ break;
case Token::kSHL:
__ Lsl(out, left, shift_value);
- break;
+ break;
default:
UNREACHABLE();
}
@@ -6468,10 +6400,10 @@
switch (op_kind()) {
case Token::kSHR:
__ Lsr(out, left, temp, LS);
- break;
+ break;
case Token::kSHL:
__ Lsl(out, left, temp, LS);
- break;
+ break;
default:
UNREACHABLE();
}
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 6bcc36d..16a4162 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -1027,60 +1027,18 @@
}
-static Address ElementAddressForIntIndex(bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- intptr_t index) {
- const int64_t offset = index * index_scale +
- (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
- ASSERT(Utils::IsInt(32, offset));
- const OperandSize size = Address::OperandSizeFor(cid);
- ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
- return Address(array, static_cast<int32_t>(offset), Address::Offset, size);
-}
-
-
-static Address ElementAddressForRegIndex(Assembler* assembler,
- bool is_load,
- bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- Register index) {
- // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
- const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
- const int32_t offset =
- is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
- ASSERT(array != TMP);
- ASSERT(index != TMP);
- const Register base = is_load ? TMP : index;
- if ((offset == 0) && (shift == 0)) {
- return Address(array, index, UXTX, Address::Unscaled);
- } else if (shift < 0) {
- ASSERT(shift == -1);
- assembler->add(base, array, Operand(index, ASR, 1));
- } else {
- assembler->add(base, array, Operand(index, LSL, shift));
- }
- const OperandSize size = Address::OperandSizeFor(cid);
- ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
- return Address(base, offset, Address::Offset, size);
-}
-
-
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The array register points to the backing store for external arrays.
const Register array = locs()->in(0).reg();
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(compiler->assembler(),
- true, // Load.
- IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? __ ElementAddressForRegIndex(true, // Load.
+ IsExternal(), class_id(), index_scale(),
+ array, index.reg())
+ : __ ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
// Warning: element_address may use register TMP as base.
if ((representation() == kUnboxedDouble) ||
@@ -1237,12 +1195,12 @@
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(compiler->assembler(),
- false, // Store.
- IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? __ ElementAddressForRegIndex(false, // Store.
+ IsExternal(), class_id(), index_scale(),
+ array, index.reg())
+ : __ ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
switch (class_id()) {
case kArrayCid:
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index b3069b3..03d75b2 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -651,7 +651,7 @@
Register cid_reg = locs()->temp(0).reg();
Label* deopt = CanDeoptimize() ?
- compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL;
+ compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL;
const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
const ZoneGrowableArray<intptr_t>& data = cid_results();
@@ -1077,66 +1077,17 @@
}
-static Address ElementAddressForIntIndex(bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- intptr_t index) {
- if (is_external) {
- return Address(array, index * index_scale);
- } else {
- const int64_t disp = static_cast<int64_t>(index) * index_scale +
- Instance::DataOffsetFor(cid);
- ASSERT(Utils::IsInt(32, disp));
- return FieldAddress(array, static_cast<int32_t>(disp));
- }
-}
-
-
-static ScaleFactor ToScaleFactor(intptr_t index_scale) {
- // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
- // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
- // expected to be untagged before accessing.
- ASSERT(kSmiTagShift == 1);
- switch (index_scale) {
- case 1: return TIMES_1;
- case 2: return TIMES_1;
- case 4: return TIMES_2;
- case 8: return TIMES_4;
- case 16: return TIMES_8;
- default:
- UNREACHABLE();
- return TIMES_1;
- }
-}
-
-
-static Address ElementAddressForRegIndex(bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- Register index) {
- if (is_external) {
- return Address(array, index, ToScaleFactor(index_scale), 0);
- } else {
- return FieldAddress(array,
- index,
- ToScaleFactor(index_scale),
- Instance::DataOffsetFor(cid));
- }
-}
-
-
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The array register points to the backing store for external arrays.
const Register array = locs()->in(0).reg();
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? Assembler::ElementAddressForRegIndex(
+ IsExternal(), class_id(), index_scale(), array, index.reg())
+ : Assembler::ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
if ((representation() == kUnboxedDouble) ||
(representation() == kUnboxedFloat32x4) ||
@@ -1358,10 +1309,11 @@
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? Assembler::ElementAddressForRegIndex(
+ IsExternal(), class_id(), index_scale(), array, index.reg())
+ : Assembler::ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
if ((index_scale() == 1) && index.IsRegister()) {
__ SmiUntag(index.reg());
@@ -5846,27 +5798,24 @@
switch (op_kind()) {
case Token::kBIT_AND:
case Token::kBIT_OR:
- case Token::kBIT_XOR: {
- const intptr_t kNumTemps = 0;
- LocationSummary* summary = new(isolate) LocationSummary(
- isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::Pair(Location::RequiresRegister(),
- Location::RequiresRegister()));
- summary->set_in(1, Location::Pair(Location::RequiresRegister(),
- Location::RequiresRegister()));
- summary->set_out(0, Location::SameAsFirstInput());
- return summary;
- }
+ case Token::kBIT_XOR:
case Token::kADD:
- case Token::kSUB: {
- const intptr_t kNumTemps = 0;
+ case Token::kSUB:
+ case Token::kMUL: {
+ const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0;
LocationSummary* summary = new(isolate) LocationSummary(
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::Pair(Location::RequiresRegister(),
- Location::RequiresRegister()));
+ summary->set_in(0, (op_kind() == Token::kMUL)
+ ? Location::Pair(Location::RegisterLocation(EAX),
+ Location::RegisterLocation(EDX))
+ : Location::Pair(Location::RequiresRegister(),
+ Location::RequiresRegister()));
summary->set_in(1, Location::Pair(Location::RequiresRegister(),
Location::RequiresRegister()));
summary->set_out(0, Location::SameAsFirstInput());
+ if (kNumTemps > 0) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
return summary;
}
default:
@@ -5920,7 +5869,28 @@
}
break;
}
- default: UNREACHABLE();
+ case Token::kMUL: {
+ // The product of two signed 32-bit integers fits in a signed 64-bit
+ // result without causing overflow.
+ // We deopt on larger inputs.
+ // TODO(regis): Range analysis may eliminate the deopt check.
+ Register temp = locs()->temp(0).reg();
+ __ movl(temp, left_lo);
+ __ sarl(temp, Immediate(31));
+ __ cmpl(temp, left_hi);
+ __ j(NOT_EQUAL, deopt);
+ __ movl(temp, right_lo);
+ __ sarl(temp, Immediate(31));
+ __ cmpl(temp, right_hi);
+ __ j(NOT_EQUAL, deopt);
+ ASSERT(left_lo == EAX);
+ __ imull(right_lo); // Result in EDX:EAX.
+ ASSERT(out_lo == EAX);
+ ASSERT(out_hi == EDX);
+ break;
+ }
+ default:
+ UNREACHABLE();
}
if (FLAG_throw_on_javascript_int_overflow) {
EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
@@ -6113,7 +6083,6 @@
}
default:
UNREACHABLE();
- break;
}
__ Bind(&done);
}
@@ -6192,10 +6161,15 @@
LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate,
bool opt) const {
const intptr_t kNumInputs = 2;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0;
LocationSummary* summary = new(isolate) LocationSummary(
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::RequiresRegister());
+ if (op_kind() == Token::kMUL) {
+ summary->set_in(0, Location::RegisterLocation(EAX));
+ summary->set_temp(0, Location::RegisterLocation(EDX));
+ } else {
+ summary->set_in(0, Location::RequiresRegister());
+ }
summary->set_in(1, Location::RequiresRegister());
summary->set_out(0, Location::SameAsFirstInput());
return summary;
@@ -6210,19 +6184,24 @@
switch (op_kind()) {
case Token::kBIT_AND:
__ andl(out, right);
- break;
+ break;
case Token::kBIT_OR:
__ orl(out, right);
- break;
+ break;
case Token::kBIT_XOR:
__ xorl(out, right);
- break;
+ break;
case Token::kADD:
__ addl(out, right);
- break;
+ break;
case Token::kSUB:
__ subl(out, right);
- break;
+ break;
+ case Token::kMUL:
+ __ mull(right); // Result in EDX:EAX.
+ ASSERT(out == EAX);
+ ASSERT(locs()->temp(0).reg() == EDX);
+ break;
default:
UNREACHABLE();
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 668a1fd..ebf3a54 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1141,48 +1141,6 @@
}
-static Address ElementAddressForIntIndex(bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- intptr_t index) {
- const int64_t offset = index * index_scale +
- (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
- ASSERT(Utils::IsInt(32, offset));
- ASSERT(Address::CanHoldOffset(offset));
- return Address(array, static_cast<int32_t>(offset));
-}
-
-
-static Address ElementAddressForRegIndex(Assembler* assembler,
- bool is_load,
- bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- Register index) {
- // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
- const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
- const int32_t offset =
- is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
- ASSERT(array != TMP);
- ASSERT(index != TMP);
- const Register base = is_load ? TMP : index;
- if (shift < 0) {
- ASSERT(shift == -1);
- assembler->sra(TMP, index, 1);
- assembler->addu(base, array, TMP);
- } else if (shift == 0) {
- assembler->addu(base, array, index);
- } else {
- assembler->sll(TMP, index, shift);
- assembler->addu(base, array, TMP);
- }
- ASSERT(Address::CanHoldOffset(offset));
- return Address(base, offset);
-}
-
-
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ TraceSimMsg("LoadIndexedInstr");
// The array register points to the backing store for external arrays.
@@ -1190,12 +1148,12 @@
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(compiler->assembler(),
- true, // Load.
- IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? __ ElementAddressForRegIndex(true, // Load.
+ IsExternal(), class_id(), index_scale(),
+ array, index.reg())
+ : __ ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
// Warning: element_address may use register TMP as base.
if ((representation() == kUnboxedDouble) ||
@@ -1364,12 +1322,12 @@
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(compiler->assembler(),
- false, // Store.
- IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? __ ElementAddressForRegIndex(false, // Store.
+ IsExternal(), class_id(), index_scale(),
+ array, index.reg())
+ : __ ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
switch (class_id()) {
case kArrayCid:
diff --git a/runtime/vm/intermediate_language_test.cc b/runtime/vm/intermediate_language_test.cc
index 918849b..67f304e 100644
--- a/runtime/vm/intermediate_language_test.cc
+++ b/runtime/vm/intermediate_language_test.cc
@@ -62,7 +62,7 @@
EXPECT(!range_x->IsWithin(-15, 99));
EXPECT(!range_x->IsWithin(-14, 100));
-#define TEST_RANGE_OP(Op, l_min, l_max, r_min, r_max, result_min, result_max) \
+#define TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, Clamp, res_min, res_max)\
{ \
RangeBoundary min, max; \
Range* left_range = new Range( \
@@ -72,12 +72,24 @@
RangeBoundary::FromConstant(r_min), \
RangeBoundary::FromConstant(r_max)); \
Op(left_range, shift_range, &min, &max); \
- EXPECT(min.Equals(result_min)); \
- if (!min.Equals(result_min)) OS::Print("%s\n", min.ToCString()); \
- EXPECT(max.Equals(result_max)); \
- if (!max.Equals(result_max)) OS::Print("%s\n", max.ToCString()); \
+ min = Clamp(min); \
+ max = Clamp(max); \
+ EXPECT(min.Equals(res_min)); \
+ if (!min.Equals(res_min)) OS::Print("%s\n", min.ToCString()); \
+ EXPECT(max.Equals(res_max)); \
+ if (!max.Equals(res_max)) OS::Print("%s\n", max.ToCString()); \
}
+#define NO_CLAMP(b) (b)
+#define TEST_RANGE_OP(Op, l_min, l_max, r_min, r_max, result_min, result_max) \
+ TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, \
+ NO_CLAMP, result_min, result_max)
+
+#define CLAMP_TO_SMI(b) (b.Clamp(RangeBoundary::kRangeBoundarySmi))
+#define TEST_RANGE_OP_SMI(Op, l_min, l_max, r_min, r_max, res_min, res_max) \
+ TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, \
+ CLAMP_TO_SMI, res_min, res_max)
+
TEST_RANGE_OP(Range::Shl, -15, 100, 0, 2,
RangeBoundary(-60), RangeBoundary(400));
TEST_RANGE_OP(Range::Shl, -15, 100, -2, 2,
@@ -90,22 +102,22 @@
RangeBoundary::NegativeInfinity(),
RangeBoundary::PositiveInfinity());
TEST_RANGE_OP(Range::Shl, -1, 1, 63, 63,
- RangeBoundary::NegativeInfinity(),
+ RangeBoundary(kMinInt64),
RangeBoundary::PositiveInfinity());
if (kBitsPerWord == 64) {
- TEST_RANGE_OP(Range::Shl, -1, 1, 62, 62,
+ TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62,
RangeBoundary(kSmiMin),
- RangeBoundary::PositiveInfinity());
- TEST_RANGE_OP(Range::Shl, -1, 1, 30, 30,
+ RangeBoundary(kSmiMax));
+ TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
RangeBoundary(-1 << 30),
RangeBoundary(1 << 30));
} else {
- TEST_RANGE_OP(Range::Shl, -1, 1, 30, 30,
+ TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
RangeBoundary(kSmiMin),
- RangeBoundary::PositiveInfinity());
- TEST_RANGE_OP(Range::Shl, -1, 1, 62, 62,
- RangeBoundary::NegativeInfinity(),
- RangeBoundary::PositiveInfinity());
+ RangeBoundary(kSmiMax));
+ TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62,
+ RangeBoundary(kSmiMin),
+ RangeBoundary(kSmiMax));
}
TEST_RANGE_OP(Range::Shl, 0, 100, 0, 64,
RangeBoundary(0), RangeBoundary::PositiveInfinity());
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 3ec1f4d..19bf864 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -990,66 +990,17 @@
}
-static Address ElementAddressForIntIndex(bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- intptr_t index) {
- if (is_external) {
- return Address(array, index * index_scale);
- } else {
- const int64_t disp = static_cast<int64_t>(index) * index_scale +
- Instance::DataOffsetFor(cid);
- ASSERT(Utils::IsInt(32, disp));
- return FieldAddress(array, static_cast<int32_t>(disp));
- }
-}
-
-
-static ScaleFactor ToScaleFactor(intptr_t index_scale) {
- // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
- // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
- // expected to be untagged before accessing.
- ASSERT(kSmiTagShift == 1);
- switch (index_scale) {
- case 1: return TIMES_1;
- case 2: return TIMES_1;
- case 4: return TIMES_2;
- case 8: return TIMES_4;
- case 16: return TIMES_8;
- default:
- UNREACHABLE();
- return TIMES_1;
- }
-}
-
-
-static Address ElementAddressForRegIndex(bool is_external,
- intptr_t cid,
- intptr_t index_scale,
- Register array,
- Register index) {
- if (is_external) {
- return Address(array, index, ToScaleFactor(index_scale), 0);
- } else {
- return FieldAddress(array,
- index,
- ToScaleFactor(index_scale),
- Instance::DataOffsetFor(cid));
- }
-}
-
-
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The array register points to the backing store for external arrays.
const Register array = locs()->in(0).reg();
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? Assembler::ElementAddressForRegIndex(
+ IsExternal(), class_id(), index_scale(), array, index.reg())
+ : Assembler::ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
if ((representation() == kUnboxedDouble) ||
(representation() == kUnboxedFloat32x4) ||
@@ -1217,10 +1168,11 @@
const Location index = locs()->in(1);
Address element_address = index.IsRegister()
- ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
- array, index.reg())
- : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
- array, Smi::Cast(index.constant()).Value());
+ ? Assembler::ElementAddressForRegIndex(
+ IsExternal(), class_id(), index_scale(), array, index.reg())
+ : Assembler::ElementAddressForIntIndex(
+ IsExternal(), class_id(), index_scale(),
+ array, Smi::Cast(index.constant()).Value());
if ((index_scale() == 1) && index.IsRegister()) {
__ SmiUntag(index.reg());
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 183540b..fe0aa2a 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -133,6 +133,8 @@
V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 611308575) \
V(_Uint8Array, [], Uint8Array_getIndexed, 16125140) \
V(_ExternalUint8Array, [], ExternalUint8Array_getIndexed, 1678777951) \
+ V(_Float64Array, [], Float64Array_getIndexed, 1779054297) \
+ V(_Float64Array, []=, Float64Array_setIndexed, 243929230) \
#define PROFILER_LIB_INTRINSIC_LIST(V) \
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 11ac497..c026751 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -475,6 +475,76 @@
}
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index.
+ __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array.
+ __ tst(R0, Operand(kSmiTagMask));
+ __ b(&fall_through, NE); // Index is not a smi, fall through.
+
+ // Range check.
+ __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+ __ cmp(R0, Operand(R6));
+ __ b(&fall_through, CS);
+
+
+ Address element_address =
+ __ ElementAddressForRegIndex(true, // Load.
+ false, // Not external.
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ R1, // Array.
+ R0); // Index.
+
+ __ vldrd(D0, element_address);
+
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class,
+ &fall_through,
+ R0, // Result register.
+ R1);
+ __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
+ __ Ret();
+ __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index.
+ __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array.
+ __ tst(R0, Operand(kSmiTagMask));
+ __ b(&fall_through, NE); // Index is not a smi, fall through.
+
+ // Range check.
+ __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+ __ cmp(R0, Operand(R6));
+ __ b(&fall_through, CS);
+
+ __ ldr(R2, Address(SP, + 0 * kWordSize)); // Value.
+ __ tst(R2, Operand(kSmiTagMask));
+ __ b(&fall_through, EQ); // Value is Smi, fall through.
+
+ __ LoadClassId(R3, R2);
+ __ CompareImmediate(R3, kDoubleCid);
+ __ b(&fall_through, NE); // Not a Double, fall through.
+
+ __ LoadDFromOffset(D0, R2, Double::value_offset() - kHeapObjectTag);
+
+ Address element_address =
+ __ ElementAddressForRegIndex(false, // Store.
+ false, // Not external.
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ R1, // Array.
+ R0); // Index.
+ __ vstrd(D0, element_address);
+ __ Ret();
+ __ Bind(&fall_through);
+}
+
+
static int GetScaleFactor(intptr_t size) {
switch (size) {
case 1: return 0;
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index e8a5ee4..6e26b2e 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -400,6 +400,75 @@
}
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index.
+ __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array.
+ __ tsti(R0, kSmiTagMask);
+ __ b(&fall_through, NE); // Index is not a smi, fall through.
+
+ // Range check.
+ __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+ __ cmp(R0, Operand(R6));
+ __ b(&fall_through, CS);
+
+ Address element_address =
+ __ ElementAddressForRegIndex(true, // Load.
+ false, // Not external.
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ R1, // Array.
+ R0); // Index.
+
+ __ fldrd(V0, element_address);
+
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class,
+ &fall_through,
+ R0, // Result register.
+ kNoPP);
+ __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ ret();
+ __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index.
+ __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array.
+ __ tsti(R0, kSmiTagMask);
+ __ b(&fall_through, NE); // Index is not a smi, fall through.
+
+ // Range check.
+ __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+ __ cmp(R0, Operand(R6));
+ __ b(&fall_through, CS);
+
+ __ ldr(R2, Address(SP, + 0 * kWordSize)); // Value.
+ __ tsti(R2, kSmiTagMask);
+ __ b(&fall_through, EQ); // Value is Smi, fall through.
+
+ __ LoadClassId(R3, R2, kNoPP);
+ __ CompareImmediate(R3, kDoubleCid, kNoPP);
+ __ b(&fall_through, NE); // Not a Double, fall through.
+
+ __ LoadDFieldFromOffset(V0, R2, Double::value_offset(), kNoPP);
+
+ Address element_address =
+ __ ElementAddressForRegIndex(false, // Store.
+ false, // Not external.
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ R1, // Array.
+ R0); // Index.
+ __ fstrd(V0, element_address);
+ __ ret();
+ __ Bind(&fall_through);
+}
+
+
static int GetScaleFactor(intptr_t size) {
switch (size) {
case 1: return 0;
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index ab3948d..288373a 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -481,6 +481,73 @@
}
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index.
+ __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array.
+ __ testl(EBX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index.
+ // Range check.
+ __ cmpl(EBX, FieldAddress(EAX, TypedData::length_offset()));
+ // Runtime throws exception.
+ __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+ Address element_address =
+ Assembler::ElementAddressForRegIndex(false, // Not external
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ EAX, // Array.
+ EBX); // Index.
+
+ __ movsd(XMM0, element_address);
+
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class,
+ &fall_through,
+ Assembler::kNearJump,
+ EAX, // Result register.
+ EBX);
+ __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0);
+ __ ret();
+ __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index.
+ __ movl(EAX, Address(ESP, + 3 * kWordSize)); // Array.
+ __ testl(EBX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index.
+ // Range check.
+ __ cmpl(EBX, FieldAddress(EAX, TypedData::length_offset()));
+ // Runtime throws exception.
+ __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+ __ movl(ECX, Address(ESP, + 1 * kWordSize)); // Value.
+ __ testl(ECX, Immediate(kSmiTagMask));
+ __ j(ZERO, &fall_through, Assembler::kNearJump); // Value is Smi.
+ __ LoadClassId(EDI, ECX);
+
+ __ cmpl(EDI, Immediate(kDoubleCid));
+ __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); // Not a Double.
+
+ __ movsd(XMM0, FieldAddress(ECX, Double::value_offset()));
+
+ Address element_address =
+ Assembler::ElementAddressForRegIndex(false, // Not external
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ EAX, // Array.
+ EBX); // Index.
+
+ __ movsd(element_address, XMM0);
+ __ ret();
+ __ Bind(&fall_through);
+}
+
+
static ScaleFactor GetScaleFactor(intptr_t size) {
switch (size) {
case 1: return TIMES_1;
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index d1f7e35..de67175 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -484,6 +484,76 @@
}
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+
+ __ lw(T0, Address(SP, + 0 * kWordSize)); // Index.
+
+ __ andi(CMPRES1, T0, Immediate(kSmiTagMask));
+ __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through.
+ __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array.
+
+ // Range check.
+ __ lw(T2, FieldAddress(T1, TypedData::length_offset()));
+ __ BranchUnsignedGreaterEqual(T0, T2, &fall_through);
+
+ Address element_address =
+ __ ElementAddressForRegIndex(true, // Load.
+ false, // Not external.
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ T1, // Array.
+ T0); // Index.
+
+ __ LoadDFromOffset(D0, element_address.base(), element_address.offset());
+
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class,
+ &fall_through,
+ V0, // Result register.
+ T1);
+ __ StoreDToOffset(D0, V0, Double::value_offset() - kHeapObjectTag);
+ __ Ret();
+ __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+ Label fall_through;
+
+ __ lw(T0, Address(SP, + 1 * kWordSize)); // Index.
+
+ __ andi(CMPRES1, T0, Immediate(kSmiTagMask));
+ __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through.
+ __ delay_slot()->lw(T1, Address(SP, + 2 * kWordSize)); // Array.
+
+ // Range check.
+ __ lw(T2, FieldAddress(T1, TypedData::length_offset()));
+ __ BranchUnsignedGreaterEqual(T0, T2, &fall_through);
+
+ __ lw(T2, Address(SP, + 0 * kWordSize)); // Value.
+ __ andi(CMPRES1, T2, Immediate(kSmiTagMask));
+ __ beq(CMPRES1, ZR, &fall_through); // Value is a Smi. Fall through.
+
+ __ LoadClassId(T3, T2);
+ __ BranchNotEqual(T3, kDoubleCid, &fall_through); // Not a Double.
+
+ __ LoadDFromOffset(D0, T2, Double::value_offset() - kHeapObjectTag);
+
+ Address element_address =
+ __ ElementAddressForRegIndex(false, // Store.
+ false, // Not external.
+ kTypedDataFloat64ArrayCid, // Cid.
+ 8, // Index scale.
+ T1, // Array.
+ T0); // Index.
+ __ StoreDToOffset(D0, element_address.base(), element_address.offset());
+ __ Ret();
+ __ Bind(&fall_through);
+}
+
+
static int GetScaleFactor(intptr_t size) {
switch (size) {
case 1: return 0;
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index eb7ae29..b83522d 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -436,6 +436,73 @@
}
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index.
+ __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array.
+ __ testq(RCX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index.
+ // Range check.
+ __ cmpq(RCX, FieldAddress(RAX, TypedData::length_offset()));
+ // Runtime throws exception.
+ __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+ Address element_address =
+ Assembler::ElementAddressForRegIndex(false, // Not external.
+ kTypedDataFloat64ArrayCid,
+ 8, // Index scale.
+ RAX, // Array.
+ RCX); // Index.
+
+ __ movsd(XMM0, element_address);
+
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class,
+ &fall_through,
+ Assembler::kNearJump,
+ RAX, // Result register.
+ kNoRegister);
+ __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
+ __ ret();
+ __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+ Label fall_through;
+ __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index.
+ __ movq(RAX, Address(RSP, + 3 * kWordSize)); // Array.
+ __ testq(RCX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index.
+ // Range check.
+ __ cmpq(RCX, FieldAddress(RAX, TypedData::length_offset()));
+ // Runtime throws exception.
+ __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+ __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value
+ __ testq(RDX, Immediate(kSmiTagMask));
+ __ j(ZERO, &fall_through, Assembler::kNearJump); // Value is Smi.
+
+ __ LoadClassId(RDI, RDX);
+ __ cmpq(RDI, Immediate(kTypedDataFloat64ArrayCid));
+ __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+
+ __ movsd(XMM0, FieldAddress(RDX, Double::value_offset()));
+
+ Address element_address =
+ Assembler::ElementAddressForRegIndex(false, // Not external.
+ kTypedDataFloat64ArrayCid,
+ 8, // Index scale.
+ RAX, // Array.
+ RCX); // Index.
+
+ __ movsd(element_address, XMM0);
+ __ ret();
+ __ Bind(&fall_through);
+}
+
+
static ScaleFactor GetScaleFactor(intptr_t size) {
switch (size) {
case 1: return TIMES_1;
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 60d2ba5..f7ff985 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -83,7 +83,7 @@
DART_EXPORT Dart_Handle Dart_CompileAll() {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- Dart_Handle result = Api::CheckIsolateState(isolate);
+ Dart_Handle result = Api::CheckAndFinalizePendingClasses(isolate);
if (::Dart_IsError(result)) {
return result;
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index eec536b..1d4d290 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6511,15 +6511,18 @@
count++;
}
}
-
- const Array& a = Array::Handle(Array::New(count, Heap::kOld));
- count = 0;
- for (intptr_t i = 0; i < deopt_id_to_ic_data.length(); i++) {
- if (deopt_id_to_ic_data[i] != NULL) {
- a.SetAt(count++, *deopt_id_to_ic_data[i]);
+ if (count == 0) {
+ set_ic_data_array(Object::empty_array());
+ } else {
+ const Array& a = Array::Handle(Array::New(count, Heap::kOld));
+ count = 0;
+ for (intptr_t i = 0; i < deopt_id_to_ic_data.length(); i++) {
+ if (deopt_id_to_ic_data[i] != NULL) {
+ a.SetAt(count++, *deopt_id_to_ic_data[i]);
+ }
}
+ set_ic_data_array(a);
}
- set_ic_data_array(a);
}
@@ -10358,30 +10361,26 @@
// First compute the buffer size required.
intptr_t len = 1; // Trailing '\0'.
Iterator iter(*this, RawPcDescriptors::kAnyKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
+ while (iter.MoveNext()) {
len += OS::SNPrint(NULL, 0, kFormat, addr_width,
- rec.pc(),
- KindAsStr(rec.kind()),
- rec.deopt_id(),
- rec.token_pos(),
- rec.try_index());
+ iter.Pc(),
+ KindAsStr(iter.Kind()),
+ iter.DeoptId(),
+ iter.TokenPos(),
+ iter.TryIndex());
}
// Allocate the buffer.
char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len);
// Layout the fields in the buffer.
intptr_t index = 0;
Iterator iter2(*this, RawPcDescriptors::kAnyKind);
- while (iter2.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter2.NextRec(&rec);
+ while (iter2.MoveNext()) {
index += OS::SNPrint((buffer + index), (len - index), kFormat, addr_width,
- rec.pc(),
- KindAsStr(rec.kind()),
- rec.deopt_id(),
- rec.token_pos(),
- rec.try_index());
+ iter.Pc(),
+ KindAsStr(iter.Kind()),
+ iter.DeoptId(),
+ iter.TokenPos(),
+ iter.TryIndex());
}
return buffer;
}
@@ -10395,15 +10394,13 @@
jsobj->AddProperty("id", "");
JSONArray members(jsobj, "members");
Iterator iter(*this, RawPcDescriptors::kAnyKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
+ while (iter.MoveNext()) {
JSONObject descriptor(&members);
- descriptor.AddPropertyF("pc", "%" Px "", rec.pc());
- descriptor.AddProperty("kind", KindAsStr(rec.kind()));
- descriptor.AddProperty("deoptId", static_cast<intptr_t>(rec.deopt_id()));
- descriptor.AddProperty("tokenPos", static_cast<intptr_t>(rec.token_pos()));
- descriptor.AddProperty("tryIndex", static_cast<intptr_t>(rec.try_index()));
+ descriptor.AddPropertyF("pc", "%" Px "", iter.Pc());
+ descriptor.AddProperty("kind", KindAsStr(iter.Kind()));
+ descriptor.AddProperty("deoptId", iter.DeoptId());
+ descriptor.AddProperty("tokenPos", iter.TokenPos());
+ descriptor.AddProperty("tryIndex", iter.TryIndex());
}
}
@@ -10434,12 +10431,9 @@
return;
}
Iterator iter(*this, RawPcDescriptors::kDeopt | RawPcDescriptors::kIcCall);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
+ while (iter.MoveNext()) {
// 'deopt_id' is set for kDeopt and kIcCall and must be unique for one kind.
-
- if (Isolate::IsDeoptAfter(rec.deopt_id())) {
+ if (Isolate::IsDeoptAfter(iter.DeoptId())) {
// TODO(vegorov): some instructions contain multiple calls and have
// multiple "after" targets recorded. Right now it is benign but might
// lead to issues in the future. Fix that and enable verification.
@@ -10447,11 +10441,9 @@
}
Iterator nested(iter);
- while (nested.HasNext()) {
- RawPcDescriptors::PcDescriptorRec nested_rec;
- nested.NextRec(&nested_rec);
- if (rec.kind() == nested_rec.kind()) {
- ASSERT(nested_rec.deopt_id() != rec.deopt_id());
+ while (nested.MoveNext()) {
+ if (iter.Kind() == nested.Kind()) {
+ ASSERT(nested.DeoptId() != iter.DeoptId());
}
}
}
@@ -10461,8 +10453,8 @@
uword PcDescriptors::GetPcForKind(RawPcDescriptors::Kind kind) const {
Iterator iter(*this, kind);
- if (iter.HasNext()) {
- return iter.NextPc();
+ if (iter.MoveNext()) {
+ return iter.Pc();
}
return 0;
}
@@ -10710,7 +10702,8 @@
result ^= raw;
result.raw_ptr()->length_ = num_variables;
}
- const Array& names = Array::Handle(Array::New(num_variables, Heap::kOld));
+ const Array& names = (num_variables == 0) ? Object::empty_array() :
+ Array::Handle(Array::New(num_variables, Heap::kOld));
result.raw_ptr()->names_ = names.raw();
return result.raw();
}
@@ -10811,7 +10804,9 @@
result ^= raw;
result.raw_ptr()->length_ = num_handlers;
}
- const Array& handled_types_data = Array::Handle(Array::New(num_handlers));
+ const Array& handled_types_data = (num_handlers == 0) ?
+ Object::empty_array() :
+ Array::Handle(Array::New(num_handlers));
result.set_handled_types_data(handled_types_data);
return result.raw();
}
@@ -11960,11 +11955,9 @@
intptr_t Code::GetTokenIndexOfPC(uword pc) const {
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if (rec.pc() == pc) {
- return rec.token_pos();
+ while (iter.MoveNext()) {
+ if (iter.Pc() == pc) {
+ return iter.TokenPos();
}
}
return -1;
@@ -11975,11 +11968,9 @@
RawPcDescriptors::Kind kind) const {
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
PcDescriptors::Iterator iter(descriptors, kind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if (rec.deopt_id() == deopt_id) {
- uword pc = rec.pc();
+ while (iter.MoveNext()) {
+ if (iter.DeoptId() == deopt_id) {
+ uword pc = iter.Pc();
ASSERT(ContainsInstructionAt(pc));
return pc;
}
@@ -11991,11 +11982,9 @@
intptr_t Code::GetDeoptIdForOsr(uword pc) const {
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kOsrEntry);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if (rec.pc() == pc) {
- return rec.deopt_id();
+ while (iter.MoveNext()) {
+ if (iter.Pc() == pc) {
+ return iter.DeoptId();
}
}
return Isolate::kNoDeoptId;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index d499f92..7dd070e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3047,59 +3047,66 @@
class Iterator : ValueObject {
public:
Iterator(const PcDescriptors& descriptors, intptr_t kind_mask)
- : descriptors_(descriptors), kind_mask_(kind_mask), current_ix_(0) {
+ : descriptors_(descriptors),
+ kind_mask_(kind_mask),
+ next_ix_(0),
+ current_ix_(-1) {
MoveToMatching();
}
- bool HasNext() const { return current_ix_ < descriptors_.Length(); }
-
- intptr_t NextDeoptId() {
- ASSERT(HasNext());
- const intptr_t res = descriptors_.recAt(current_ix_++)->deopt_id();
- MoveToMatching();
- return res;
+ bool MoveNext() {
+ if (HasNext()) {
+ current_ix_ = next_ix_++;
+ MoveToMatching();
+ return true;
+ } else {
+ return false;
+ }
}
- uword NextPc() {
- ASSERT(HasNext());
- const uword res = descriptors_.recAt(current_ix_++)->pc();
- MoveToMatching();
- return res;
+ uword Pc() const { return descriptors_.recAt(current_ix_)->pc(); }
+ intptr_t DeoptId() const {
+ return descriptors_.recAt(current_ix_)->deopt_id();
}
-
- void NextRec(RawPcDescriptors::PcDescriptorRec* result) {
- ASSERT(HasNext());
- const RawPcDescriptors::PcDescriptorRec* r =
- descriptors_.recAt(current_ix_++);
- r->CopyTo(result);
- MoveToMatching();
+ intptr_t TokenPos() const {
+ return descriptors_.recAt(current_ix_)->token_pos();
+ }
+ intptr_t TryIndex() const {
+ return descriptors_.recAt(current_ix_)->try_index();
+ }
+ RawPcDescriptors::Kind Kind() const {
+ return descriptors_.recAt(current_ix_)->kind();
}
private:
friend class PcDescriptors;
+ bool HasNext() const { return next_ix_ < descriptors_.Length(); }
+
// For nested iterations, starting at element after.
explicit Iterator(const Iterator& iter)
: ValueObject(),
descriptors_(iter.descriptors_),
kind_mask_(iter.kind_mask_),
+ next_ix_(iter.next_ix_),
current_ix_(iter.current_ix_) {}
// Moves to record that matches kind_mask_.
void MoveToMatching() {
- while (current_ix_ < descriptors_.Length()) {
+ while (next_ix_ < descriptors_.Length()) {
const RawPcDescriptors::PcDescriptorRec& rec =
- *descriptors_.recAt(current_ix_);
+ *descriptors_.recAt(next_ix_);
if ((rec.kind() & kind_mask_) != 0) {
return; // Current is valid.
} else {
- ++current_ix_;
+ ++next_ix_;
}
}
}
const PcDescriptors& descriptors_;
const intptr_t kind_mask_;
+ intptr_t next_ix_;
intptr_t current_ix_;
};
@@ -3113,7 +3120,7 @@
intptr_t RecordSizeInBytes() const;
RawPcDescriptors::PcDescriptorRec* recAt(intptr_t ix) const {
- ASSERT(ix < Length());
+ ASSERT((0 <= ix) && (ix < Length()));
uint8_t* d = raw_ptr()->data() + (ix * RecordSizeInBytes());
return reinterpret_cast<RawPcDescriptors::PcDescriptorRec*>(d);
}
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 5a0f3f7..c8508cd 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2746,35 +2746,36 @@
// Verify the PcDescriptor entries by accessing them.
const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
- RawPcDescriptors::PcDescriptorRec rec0;
- RawPcDescriptors::PcDescriptorRec rec1;
- RawPcDescriptors::PcDescriptorRec rec2;
- RawPcDescriptors::PcDescriptorRec rec3;
- RawPcDescriptors::PcDescriptorRec rec4;
- RawPcDescriptors::PcDescriptorRec rec5;
- iter.NextRec(&rec0);
- iter.NextRec(&rec1);
- iter.NextRec(&rec2);
- iter.NextRec(&rec3);
- iter.NextRec(&rec4);
- iter.NextRec(&rec5);
- ASSERT(!iter.HasNext());
- EXPECT_EQ(1, rec0.try_index());
- EXPECT_EQ(static_cast<uword>(10), rec0.pc());
- EXPECT_EQ(1, rec0.deopt_id());
- EXPECT_EQ(20, rec0.token_pos());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(20, iter.TokenPos());
+ EXPECT_EQ(1, iter.TryIndex());
+ EXPECT_EQ(static_cast<uword>(10), iter.Pc());
+ EXPECT_EQ(1, iter.DeoptId());
+ EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
- EXPECT_EQ(3, rec5.try_index());
- EXPECT_EQ(static_cast<uword>(80), rec5.pc());
- EXPECT_EQ(150, rec5.token_pos());
- EXPECT_EQ(RawPcDescriptors::kOther, rec0.kind());
- EXPECT_EQ(RawPcDescriptors::kDeopt, rec1.kind());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(30, iter.TokenPos());
+ EXPECT_EQ(RawPcDescriptors::kDeopt, iter.Kind());
- EXPECT_EQ(30, rec1.token_pos());
- EXPECT_EQ(40, rec2.token_pos());
- EXPECT_EQ(40, rec3.token_pos());
- EXPECT_EQ(80, rec4.token_pos());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(40, iter.TokenPos());
+
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(40, iter.TokenPos());
+
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(80, iter.TokenPos());
+
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(150, iter.TokenPos());
+
+ EXPECT_EQ(3, iter.TryIndex());
+ EXPECT_EQ(static_cast<uword>(80), iter.Pc());
+ EXPECT_EQ(150, iter.TokenPos());
+ EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
+
+ EXPECT_EQ(false, iter.MoveNext());
}
@@ -2801,35 +2802,24 @@
// Verify the PcDescriptor entries by accessing them.
const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
- RawPcDescriptors::PcDescriptorRec rec0;
- RawPcDescriptors::PcDescriptorRec rec1;
- RawPcDescriptors::PcDescriptorRec rec2;
- RawPcDescriptors::PcDescriptorRec rec3;
- RawPcDescriptors::PcDescriptorRec rec4;
- RawPcDescriptors::PcDescriptorRec rec5;
- iter.NextRec(&rec0);
- iter.NextRec(&rec1);
- iter.NextRec(&rec2);
- iter.NextRec(&rec3);
- iter.NextRec(&rec4);
- iter.NextRec(&rec5);
- ASSERT(!iter.HasNext());
- EXPECT_EQ(-1, rec0.try_index());
- EXPECT_EQ(static_cast<uword>(10), rec0.pc());
- EXPECT_EQ(1, rec0.deopt_id());
- EXPECT_EQ(20, rec0.token_pos());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(static_cast<uword>(10), iter.Pc());
+ EXPECT_EQ(-1, iter.TryIndex());
+ EXPECT_EQ(1, iter.DeoptId());
+ EXPECT_EQ(20, iter.TokenPos());
- EXPECT_EQ(-1, rec5.try_index());
- EXPECT_EQ(static_cast<uword>(80), rec5.pc());
- EXPECT_EQ(150, rec5.token_pos());
- EXPECT_EQ(RawPcDescriptors::kOther, rec0.kind());
- EXPECT_EQ(RawPcDescriptors::kDeopt, rec1.kind());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(true, iter.MoveNext());
+ EXPECT_EQ(true, iter.MoveNext());
- EXPECT_EQ(30, rec1.token_pos());
- EXPECT_EQ(40, rec2.token_pos());
- EXPECT_EQ(40, rec3.token_pos());
- EXPECT_EQ(80, rec4.token_pos());
+ EXPECT_EQ(-1, iter.TryIndex());
+ EXPECT_EQ(static_cast<uword>(80), iter.Pc());
+ EXPECT_EQ(150, iter.TokenPos());
+
+ EXPECT_EQ(false, iter.MoveNext());
}
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 1018cf4..a2dec35 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -34,8 +34,6 @@
"Time between profiler samples in microseconds. Minimum 50.");
DEFINE_FLAG(int, profile_depth, 8,
"Maximum number stack frames walked. Minimum 1. Maximum 255.");
-DEFINE_FLAG(bool, profile_verify_stack_walk, false,
- "Verify instruction addresses while walking the stack.");
DEFINE_FLAG(bool, profile_vm, false,
"Always collect native stack traces.");
@@ -1663,21 +1661,39 @@
}
-class ProfilerDartStackWalker : public ValueObject {
+static void SetPCMarkerIfSafe(Sample* sample) {
+ ASSERT(sample != NULL);
+
+ uword* fp = reinterpret_cast<uword*>(sample->fp());
+ uword* sp = reinterpret_cast<uword*>(sample->sp());
+
+ // If FP == SP, the pc marker hasn't been pushed.
+ if (fp > sp) {
+#if defined(TARGET_OS_WINDOWS)
+ // If the fp is at the beginning of a page, it may be unsafe to access
+ // the pc marker, because we are reading it from a different thread on
+ // Windows. The next page may be a guard page.
+ const intptr_t kPageMask = VirtualMemory::PageSize() - 1;
+ if ((sample->fp() & kPageMask) == 0) {
+ return;
+ }
+#endif
+ const uword pc_marker = *(fp + kPcMarkerSlotFromFp);
+ sample->set_pc_marker(pc_marker);
+ }
+}
+
+
+// Given an exit frame, walk the Dart stack.
+class ProfilerDartExitStackWalker : public ValueObject {
public:
- ProfilerDartStackWalker(Isolate* isolate, Sample* sample)
+ ProfilerDartExitStackWalker(Isolate* isolate, Sample* sample)
: sample_(sample),
frame_iterator_(isolate) {
ASSERT(sample_ != NULL);
}
- ProfilerDartStackWalker(Isolate* isolate, Sample* sample, uword fp)
- : sample_(sample),
- frame_iterator_(fp, isolate) {
- ASSERT(sample_ != NULL);
- }
-
- int walk() {
+ void walk() {
intptr_t frame_index = 0;
StackFrame* frame = frame_iterator_.NextFrame();
while (frame != NULL) {
@@ -1688,7 +1704,6 @@
}
frame = frame_iterator_.NextFrame();
}
- return frame_index;
}
private:
@@ -1697,13 +1712,148 @@
};
-// Notes on stack frame walking:
-//
-// The sampling profiler will collect up to Sample::kNumStackFrames stack frames
-// The stack frame walking code uses the frame pointer to traverse the stack.
+// Executing Dart code, walk the stack.
+class ProfilerDartStackWalker : public ValueObject {
+ public:
+ ProfilerDartStackWalker(Isolate* isolate,
+ Sample* sample,
+ uword stack_lower,
+ uword stack_upper,
+ uword pc,
+ uword fp,
+ uword sp)
+ : isolate_(isolate),
+ sample_(sample),
+ stack_upper_(stack_upper),
+ stack_lower_(stack_lower) {
+ ASSERT(sample_ != NULL);
+ pc_ = reinterpret_cast<uword*>(pc);
+ fp_ = reinterpret_cast<uword*>(fp);
+ sp_ = reinterpret_cast<uword*>(sp);
+ }
+
+ void walk() {
+ if (!ValidFramePointer()) {
+ sample_->set_ignore_sample(true);
+ return;
+ }
+ ASSERT(ValidFramePointer());
+ uword return_pc = InitialReturnAddress();
+ if (StubCode::InInvocationStubForIsolate(isolate_, return_pc)) {
+ // Edge case- we have called out from the Invocation Stub but have not
+ // created the stack frame of the callee. Attempt to locate the exit
+ // frame before walking the stack.
+ if (!NextExit() || !ValidFramePointer()) {
+ // Nothing to sample.
+ sample_->set_ignore_sample(true);
+ return;
+ }
+ }
+ for (int i = 0; i < FLAG_profile_depth; i++) {
+ sample_->SetAt(i, reinterpret_cast<uword>(pc_));
+ if (!Next()) {
+ return;
+ }
+ }
+ }
+
+ private:
+ bool Next() {
+ if (!ValidFramePointer()) {
+ return false;
+ }
+ if (StubCode::InInvocationStubForIsolate(isolate_,
+ reinterpret_cast<uword>(pc_))) {
+ // In invocation stub.
+ return NextExit();
+ }
+ // In regular Dart frame.
+ uword* new_pc = CallerPC();
+ // Check if we've moved into the invocation stub.
+ if (StubCode::InInvocationStubForIsolate(isolate_,
+ reinterpret_cast<uword>(new_pc))) {
+ // New PC is inside invocation stub, skip.
+ return NextExit();
+ }
+ uword* new_fp = CallerFP();
+ if (new_fp <= fp_) {
+ // FP didn't move to a higher address.
+ return false;
+ }
+ // Success, update fp and pc.
+ fp_ = new_fp;
+ pc_ = new_pc;
+ return true;
+ }
+
+ bool NextExit() {
+ if (!ValidFramePointer()) {
+ return false;
+ }
+ uword* new_fp = ExitLink();
+ if (new_fp == NULL) {
+ // No exit link.
+ return false;
+ }
+ if (new_fp <= fp_) {
+ // FP didn't move to a higher address.
+ return false;
+ }
+ if (!ValidFramePointer(new_fp)) {
+ return false;
+ }
+ // Success, update fp and pc.
+ fp_ = new_fp;
+ pc_ = CallerPC();
+ return true;
+ }
+
+ uword InitialReturnAddress() const {
+ ASSERT(sp_ != NULL);
+ return *(sp_);
+ }
+
+ uword* CallerPC() const {
+ ASSERT(fp_ != NULL);
+ return reinterpret_cast<uword*>(*(fp_ + kSavedCallerPcSlotFromFp));
+ }
+
+ uword* CallerFP() const {
+ ASSERT(fp_ != NULL);
+ return reinterpret_cast<uword*>(*(fp_ + kSavedCallerFpSlotFromFp));
+ }
+
+ uword* ExitLink() const {
+ ASSERT(fp_ != NULL);
+ return reinterpret_cast<uword*>(*(fp_ + kExitLinkSlotFromEntryFp));
+ }
+
+ bool ValidFramePointer() const {
+ return ValidFramePointer(fp_);
+ }
+
+ bool ValidFramePointer(uword* fp) const {
+ if (fp == NULL) {
+ return false;
+ }
+ uword cursor = reinterpret_cast<uword>(fp);
+ cursor += sizeof(fp);
+ return (cursor >= stack_lower_) && (cursor < stack_upper_);
+ }
+
+ uword* pc_;
+ uword* fp_;
+ uword* sp_;
+ Isolate* isolate_;
+ Sample* sample_;
+ const uword stack_upper_;
+ uword stack_lower_;
+};
+
+
// If the VM is compiled without frame pointers (which is the default on
// recent GCC versions with optimizing enabled) the stack walking code may
-// fail (sometimes leading to a crash).
+// fail.
//
class ProfilerNativeStackWalker : public ValueObject {
public:
@@ -1722,98 +1872,59 @@
ASSERT(sample_ != NULL);
}
- int walk(Heap* heap) {
- const intptr_t kMaxStep = 0x1000; // 4K.
- const bool kWalkStack = true; // Walk the stack.
- // Always store the exclusive PC.
+ void walk() {
+ const uword kMaxStep = VirtualMemory::PageSize();
+
sample_->SetAt(0, original_pc_);
- if (!kWalkStack) {
- // Not walking the stack, only took exclusive sample.
- return 1;
- }
+
uword* pc = reinterpret_cast<uword*>(original_pc_);
uword* fp = reinterpret_cast<uword*>(original_fp_);
uword* previous_fp = fp;
- if (original_sp_ > original_fp_) {
- // Stack pointer should not be above frame pointer.
- return 1;
- }
- const intptr_t gap = original_fp_ - original_sp_;
+
+ uword gap = original_fp_ - original_sp_;
if (gap >= kMaxStep) {
// Gap between frame pointer and stack pointer is
// too large.
- return 1;
+ return;
}
- if (original_sp_ < lower_bound_) {
- // The stack pointer gives us a better lower bound than
- // the isolates stack limit.
- lower_bound_ = original_sp_;
+
+ if (!ValidFramePointer(fp)) {
+ return;
}
-#if defined(TARGET_OS_WINDOWS)
- // If the original_fp_ is at the beginning of a page, it may be unsafe
- // to access the pc marker, because we are reading it from a different
- // thread on Windows. The next page may be a guard page.
- const intptr_t kPageMask = kMaxStep - 1;
- bool safe_to_read_pc_marker = (original_fp_ & kPageMask) != 0;
-#else
- bool safe_to_read_pc_marker = true;
-#endif
- if (safe_to_read_pc_marker && (gap > 0)) {
- // Store the PC marker for the top frame.
- sample_->set_pc_marker(GetCurrentFramePcMarker(fp));
- }
- int i = 0;
- for (; i < FLAG_profile_depth; i++) {
- if (FLAG_profile_verify_stack_walk) {
- VerifyCodeAddress(heap, i, reinterpret_cast<uword>(pc));
- }
+
+ for (int i = 0; i < FLAG_profile_depth; i++) {
sample_->SetAt(i, reinterpret_cast<uword>(pc));
- if (fp == NULL) {
- return i + 1;
- }
- if (!ValidFramePointer(fp)) {
- return i + 1;
- }
+
pc = CallerPC(fp);
previous_fp = fp;
fp = CallerFP(fp);
- intptr_t step = fp - previous_fp;
+
if (fp == NULL) {
- return i + 1;
+ return;
}
- if ((step >= kMaxStep)) {
- // Frame pointer step is too large.
- return i + 1;
- }
- if ((fp <= previous_fp)) {
+
+ if (fp <= previous_fp) {
// Frame pointer did not move to a higher address.
- return i + 1;
+ return;
}
+
+ gap = fp - previous_fp;
+ if (gap >= kMaxStep) {
+ // Frame pointer step is too large.
+ return;
+ }
+
if (!ValidFramePointer(fp)) {
- // Frame pointer is outside of isolate stack bounds.
- return i + 1;
+ // Frame pointer is outside of isolate stack boundary.
+ return;
}
+
// Move the lower bound up.
lower_bound_ = reinterpret_cast<uword>(fp);
}
- return i;
}
private:
- void VerifyCodeAddress(Heap* heap, int i, uword pc) {
- if (heap != NULL) {
- if (heap->Contains(pc) && !heap->CodeContains(pc)) {
- for (int j = 0; j < i; j++) {
- OS::Print("%d %" Px "\n", j, sample_->At(j));
- }
- OS::Print("%d %" Px " <--\n", i, pc);
- OS::Print("---ASSERT-FAILED---\n");
- OS::Print("%" Px " %" Px "\n", original_pc_, original_fp_);
- UNREACHABLE();
- }
- }
- }
-
uword* CallerPC(uword* fp) const {
ASSERT(fp != NULL);
return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp));
@@ -1824,20 +1935,13 @@
return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp));
}
- uword GetCurrentFramePcMarker(uword* fp) const {
- if (!ValidFramePointer(fp)) {
- return 0;
- }
- return *(fp + kPcMarkerSlotFromFp);
- }
-
bool ValidFramePointer(uword* fp) const {
if (fp == NULL) {
return false;
}
uword cursor = reinterpret_cast<uword>(fp);
cursor += sizeof(fp);
- bool r = cursor >= lower_bound_ && cursor < stack_upper_;
+ bool r = (cursor >= lower_bound_) && (cursor < stack_upper_);
return r;
}
@@ -1855,57 +1959,127 @@
void* data) {
Isolate* isolate = reinterpret_cast<Isolate*>(data);
if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
+ // No isolate.
return;
}
+
ASSERT(isolate != Dart::vm_isolate());
+
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ // Profiler not initialized.
+ return;
+ }
+
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ // Profiler not initialized.
+ return;
+ }
+
+ if ((state.sp == 0) || (state.fp == 0) || (state.pc == 0)) {
+ // None of these registers should be zero.
+ return;
+ }
+
+ if (state.sp > state.fp) {
+ // Assuming the stack grows down, we should never have a stack pointer above
+ // the frame pointer.
+ return;
+ }
+
if (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.
return;
}
+
+ uword stack_lower = 0;
+ uword stack_upper = 0;
+ isolate->GetStackBounds(&stack_lower, &stack_upper);
+ if ((stack_lower == 0) || (stack_upper == 0)) {
+ // Could not get stack boundary.
+ return;
+ }
+
+ if (state.sp > stack_lower) {
+ // The stack pointer gives us a tighter lower bound.
+ stack_lower = state.sp;
+ }
+
+ if (stack_lower >= stack_upper) {
+ // Stack boundary is invalid.
+ return;
+ }
+
+ if ((state.sp < stack_lower) || (state.sp >= stack_upper)) {
+ // Stack pointer is outside isolate stack boundary.
+ return;
+ }
+
+ if ((state.fp < stack_lower) || (state.fp >= stack_upper)) {
+ // Frame pointer is outside isolate stack boundary.
+ return;
+ }
+
+ // At this point we have a valid stack boundary for this isolate and
+ // know that our initial stack and frame pointers are within the boundary.
+
+ // Increment counter for vm tag.
VMTagCounters* counters = isolate->vm_tag_counters();
ASSERT(counters != NULL);
counters->Increment(isolate->vm_tag());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- return;
- }
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- if (sample_buffer == NULL) {
- return;
- }
+
+ // Setup sample.
Sample* sample = sample_buffer->ReserveSample();
sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid);
sample->set_vm_tag(isolate->vm_tag());
sample->set_user_tag(isolate->user_tag());
sample->set_sp(state.sp);
sample->set_fp(state.fp);
+ SetPCMarkerIfSafe(sample);
- uword stack_lower = 0;
- uword stack_upper = 0;
- isolate->GetStackBounds(&stack_lower, &stack_upper);
- if ((stack_lower == 0) || (stack_upper == 0)) {
- stack_lower = 0;
- stack_upper = 0;
- }
+ // Walk the call stack.
if (FLAG_profile_vm) {
- // Collect native and Dart frames.
- ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper,
- state.pc, state.fp, state.sp);
- stackWalker.walk(isolate->heap());
+ // Always walk the native stack collecting both native and Dart frames.
+ ProfilerNativeStackWalker stackWalker(sample,
+ stack_lower,
+ stack_upper,
+ state.pc,
+ state.fp,
+ state.sp);
+ stackWalker.walk();
} else {
+ // Attempt to walk only the Dart call stack, falling back to walking
+ // the native stack.
if ((isolate->stub_code() != NULL) &&
(isolate->top_exit_frame_info() != 0) &&
(isolate->vm_tag() != VMTag::kScriptTagId)) {
// We have a valid exit frame info, use the Dart stack walker.
- ProfilerDartStackWalker stackWalker(isolate, sample);
+ ProfilerDartExitStackWalker stackWalker(isolate, sample);
+ stackWalker.walk();
+ } else if ((isolate->stub_code() != NULL) &&
+ (isolate->top_exit_frame_info() == 0) &&
+ (isolate->vm_tag() == VMTag::kScriptTagId)) {
+ // We are executing Dart code. We have frame pointers.
+ ProfilerDartStackWalker stackWalker(isolate,
+ sample,
+ stack_lower,
+ stack_upper,
+ state.pc,
+ state.fp,
+ state.sp);
stackWalker.walk();
} else {
- // Collect native and Dart frames.
- ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper,
- state.pc, state.fp, state.sp);
- stackWalker.walk(isolate->heap());
+ // Fall back to an extremely conservative stack walker.
+ ProfilerNativeStackWalker stackWalker(sample,
+ stack_lower,
+ stack_upper,
+ state.pc,
+ state.fp,
+ state.sp);
+ stackWalker.walk();
}
}
}
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index 871d9ec..0f629c6 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -233,6 +233,14 @@
state_ = LeafFrameIsDart::update(leaf_frame_is_dart, state_);
}
+ bool ignore_sample() const {
+ return IgnoreBit::decode(state_);
+ }
+
+ void set_ignore_sample(bool ignore_sample) {
+ state_ = IgnoreBit::update(ignore_sample, state_);
+ }
+
static void InitOnce();
static intptr_t instance_size() {
@@ -247,9 +255,11 @@
enum StateBits {
kProcessedBit = 0,
kLeafFrameIsDartBit = 1,
+ kIgnoreBit = 2,
};
class ProcessedBit : public BitField<bool, kProcessedBit, 1> {};
class LeafFrameIsDart : public BitField<bool, kLeafFrameIsDartBit, 1> {};
+ class IgnoreBit : public BitField<bool, kIgnoreBit, 1> {};
int64_t timestamp_;
ThreadId tid_;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 5d55742..5529293 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -921,11 +921,7 @@
};
// Compressed version assumes try_index is always -1 and does not store it.
- class PcDescriptorRec {
- public:
- PcDescriptorRec()
- : pc_(0), deopt_id_and_kind_(0), token_pos_(0), try_index_(0) {}
-
+ struct PcDescriptorRec {
uword pc() const { return pc_; }
void set_pc(uword value) { pc_ = value; }
@@ -957,14 +953,6 @@
deopt_id_and_kind_ = (deopt_id_and_kind_ & 0xFF) | (value << 8);
}
- void CopyTo(PcDescriptorRec* other) const {
- other->set_pc(pc());
- other->set_deopt_id(deopt_id());
- other->set_kind(kind());
- other->set_token_pos(token_pos(), false);
- other->set_try_index(try_index());
- }
-
private:
bool is_compressed() const {
return (token_pos_ & 0x1) == 1;
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 87ce4bc..5b7aee5f 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -442,8 +442,10 @@
const Error& error = Error::Handle(isolate,
Compiler::Compile(library, script));
ASSERT(error.IsNull());
+ Dart_Handle result = Dart_FinalizeLoading(false);
+ ASSERT(!Dart_IsError(result));
Dart_ExitScope();
- library.SetLoaded();
+
// Install embedder default library tag handler again.
isolate->set_library_tag_handler(embedder_provided_handler_);
embedder_provided_handler_ = NULL;
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index f0e3af3..619fee2 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -270,13 +270,11 @@
const PcDescriptors& descriptors =
PcDescriptors::Handle(code.pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if (rec.pc() == pc) {
- return rec.token_pos();
- } else if ((token_pos <= 0) && (rec.pc() > pc)) {
- token_pos = rec.token_pos();
+ while (iter.MoveNext()) {
+ if (iter.Pc() == pc) {
+ return iter.TokenPos();
+ } else if ((token_pos <= 0) && (iter.Pc() > pc)) {
+ token_pos = iter.TokenPos();
}
}
return token_pos;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 15086f4..666a853 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1039,7 +1039,7 @@
// Create a test library and Load up a test script in it.
TestCase::LoadTestScript(kScriptChars, NULL);
- EXPECT_VALID(Api::CheckIsolateState(isolate));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(isolate));
timer1.Stop();
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
@@ -1093,7 +1093,7 @@
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
- EXPECT_VALID(Api::CheckIsolateState(isolate));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(isolate));
timer1.Stop();
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
@@ -1214,7 +1214,7 @@
EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
import_lib,
Dart_Null()));
- EXPECT_VALID(Api::CheckIsolateState(Isolate::Current()));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
// Get list of library URLs loaded and save the count.
Dart_Handle libs = Dart_GetLibraryIds();
@@ -1384,7 +1384,7 @@
EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
import_lib,
Dart_Null()));
- EXPECT_VALID(Api::CheckIsolateState(Isolate::Current()));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
// Write out the script snapshot.
result = Dart_CreateScriptSnapshot(&buffer, &size);
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 9a44f6d..f33e0b4 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -225,12 +225,11 @@
PcDescriptors& descriptors = reused_pc_descriptors_handle.Handle();
descriptors = code.pc_descriptors();
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if ((rec.pc() == pc()) && (rec.try_index() != -1)) {
+ while (iter.MoveNext()) {
+ const intptr_t current_try_index = iter.TryIndex();
+ if ((iter.Pc() == pc()) && (current_try_index != -1)) {
RawExceptionHandlers::HandlerInfo handler_info;
- handlers.GetHandlerInfo(rec.try_index(), &handler_info);
+ handlers.GetHandlerInfo(current_try_index, &handler_info);
*handler_pc = handler_info.handler_pc;
*needs_stacktrace = handler_info.needs_stacktrace;
*has_catch_all = handler_info.has_catch_all;
@@ -250,11 +249,9 @@
PcDescriptors::Handle(code.pc_descriptors());
ASSERT(!descriptors.IsNull());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
- while (iter.HasNext()) {
- RawPcDescriptors::PcDescriptorRec rec;
- iter.NextRec(&rec);
- if (rec.pc() == pc()) {
- return rec.token_pos();
+ while (iter.MoveNext()) {
+ if (iter.Pc() == pc()) {
+ return iter.TokenPos();
}
}
return -1;
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 12f36ea..5c0a2c8 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -112,16 +112,20 @@
Dart_Handle TestCase::LoadTestScript(const char* script,
Dart_NativeEntryResolver resolver,
- const char* lib_url) {
+ const char* lib_url,
+ bool finalize_classes) {
Dart_Handle url = NewString(lib_url);
Dart_Handle source = NewString(script);
Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler);
EXPECT_VALID(result);
- EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
DART_CHECK_VALID(lib);
result = Dart_SetNativeResolver(lib, resolver, NULL);
DART_CHECK_VALID(result);
+ if (finalize_classes) {
+ result = Dart_FinalizeLoading(false);
+ DART_CHECK_VALID(result);
+ }
return lib;
}
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index cfab41b..f73617a 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -245,7 +245,8 @@
static Dart_Handle LoadTestScript(const char* script,
Dart_NativeEntryResolver resolver,
- const char* lib_uri = USER_TEST_URI);
+ const char* lib_uri = USER_TEST_URI,
+ bool finalize = true);
static Dart_Handle LoadCoreTestScript(const char* script,
Dart_NativeEntryResolver resolver);
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index 16713f1..54ad643 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -99,6 +99,8 @@
ClosureClassElement get closureClass => super.enclosingElement;
+ MemberElement get memberContext => closureClass.methodElement.memberContext;
+
bool get hasNode => false;
Node get node {
@@ -123,8 +125,8 @@
DartType computeType(Compiler compiler) => type;
DartType get type {
- if (local is TypedElement) {
- TypedElement element = local;
+ if (local is LocalElement) {
+ LocalElement element = local;
return element.type;
}
return const DynamicType();
@@ -146,15 +148,20 @@
/// Node that corresponds to this closure, used for source position.
final FunctionExpression node;
+ /**
+ * The element for the declaration of the function expression.
+ */
+ final LocalFunctionElement methodElement;
+
final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[];
ClosureClassElement(this.node,
String name,
Compiler compiler,
- this.methodElement,
- Element enclosingElement)
- : super(name,
- enclosingElement,
+ LocalFunctionElement closure)
+ : this.methodElement = closure,
+ super(name,
+ closure.compilationUnit,
// By assigning a fresh class-id we make sure that the hashcode
// is unique, but also emit closure classes after all other
// classes (since the emitter sorts classes by their id).
@@ -188,11 +195,6 @@
Node parseNode(DiagnosticListener listener) => node;
- /**
- * The element for the declaration of the function expression.
- */
- final TypedElement methodElement;
-
// A [ClosureClassElement] is nested inside a function or initializer in terms
// of [enclosingElement], but still has to be treated as a top-level
// element.
@@ -207,9 +209,9 @@
/// fields.
class BoxLocal extends Local {
final String name;
- final Element enclosingElement;
+ final ExecutableElement executableContext;
- BoxLocal(String this.name, Element this.enclosingElement);
+ BoxLocal(this.name, this.executableContext);
}
// TODO(ngeoffray, ahe): These classes continuously cause problems. We need to
@@ -220,7 +222,7 @@
BoxFieldElement(String name, this.variableElement, BoxLocal box)
: this.box = box,
- super(name, ElementKind.FIELD, box.enclosingElement);
+ super(name, ElementKind.FIELD, box.executableContext);
DartType computeType(Compiler compiler) => type;
@@ -233,22 +235,21 @@
/// A local variable used encode the direct (uncaptured) references to [this].
class ThisLocal extends Local {
- final Element enclosingElement;
+ final ExecutableElement executableContext;
- ThisLocal(Element enclosingElement)
- : this.enclosingElement = enclosingElement;
+ ThisLocal(this.executableContext);
String get name => 'this';
- ClassElement get enclosingClass => enclosingElement.enclosingClass;
+ ClassElement get enclosingClass => executableContext.enclosingClass;
}
/// Call method of a closure class.
class SynthesizedCallMethodElementX extends BaseFunctionElementX {
- final FunctionElement expression;
+ final LocalFunctionElement expression;
SynthesizedCallMethodElementX(String name,
- BaseFunctionElementX other,
+ LocalFunctionElementX other,
ClosureClassElement enclosing)
: expression = other,
super(name, other.kind, other.modifiers, enclosing, false) {
@@ -261,6 +262,10 @@
ClosureClassElement get closureClass => super.enclosingElement;
+ MemberElement get memberContext {
+ return closureClass.methodElement.memberContext;
+ }
+
bool get hasNode => expression.hasNode;
FunctionExpression get node => expression.node;
@@ -293,7 +298,7 @@
return _capturedVariableMapping.containsKey(variable);
}
- void forEachCapturedVariable(f(VariableElement variable,
+ void forEachCapturedVariable(f(LocalVariableElement variable,
BoxFieldElement boxField)) {
_capturedVariableMapping.forEach(f);
}
@@ -301,7 +306,7 @@
class ClosureClassMap {
// The closure's element before any translation. Will be null for methods.
- final FunctionElement closureElement;
+ final LocalFunctionElement closureElement;
// The closureClassElement will be null for methods that are not local
// closures.
final ClosureClassElement closureClassElement;
@@ -406,7 +411,7 @@
});
}
- void forEachBoxedVariable(void f(VariableElement local,
+ void forEachBoxedVariable(void f(LocalVariableElement local,
BoxFieldElement field)) {
_freeVariableMapping.forEach((variable, copy) {
if (!isVariableBoxed(variable)) return;
@@ -442,8 +447,8 @@
// non-mutated variables.
Set<VariableElement> mutatedVariables = new Set<VariableElement>();
- Element outermostElement;
- Element currentElement;
+ MemberElement outermostElement;
+ ExecutableElement executableContext;
// The closureData of the currentFunctionElement.
ClosureClassMap closureData;
@@ -573,9 +578,9 @@
// optimization: factories have type parameters as function
// parameters, and type parameters are declared in the class, not
// the factory.
- bool inCurrentContext(var variable) {
- return variable == currentElement ||
- variable.enclosingElement == currentElement;
+ bool inCurrentContext(Local variable) {
+ return variable == executableContext ||
+ variable.executableContext == executableContext;
}
if (insideClosure && !inCurrentContext(variable)) {
@@ -592,6 +597,10 @@
}
}
+ void useTypeVariableAsLocal(TypeVariableType typeVariable) {
+ useLocal(new TypeVariableLocal(typeVariable, outermostElement));
+ }
+
void declareLocal(Local element) {
scopeVariables.add(element);
}
@@ -614,9 +623,9 @@
!link.isEmpty;
link = link.tail) {
Node definition = link.head;
- VariableElement element = elements[definition];
+ LocalElement element = elements[definition];
assert(element != null);
- if (!element.isFieldParameter) {
+ if (!element.isInitializingFormal) {
declareLocal(element);
}
// We still need to visit the right-hand sides of the init-assignments.
@@ -635,7 +644,7 @@
}
visitTypeAnnotation(TypeAnnotation node) {
- Element member = currentElement.enclosingMember;
+ Element member = executableContext.enclosingMember;
DartType type = elements.getType(node);
// TODO(karlklose,johnniwinther): if the type is null, the annotation is
// from a parameter which has been analyzed before the method has been
@@ -646,7 +655,9 @@
// This is a closure in a factory constructor. Since there is no
// [:this:], we have to mark the type arguments as free variables to
// capture them in the closure.
- type.forEachTypeVariable((variable) => useLocal(variable.element));
+ type.forEachTypeVariable((TypeVariableType variable) {
+ useTypeVariableAsLocal(variable);
+ });
}
if (member.isInstanceMember && !member.isField) {
// In checked mode, using a type variable in a type annotation may lead
@@ -667,7 +678,7 @@
if (element != null && element.isTypeVariable) {
if (outermostElement.isConstructor) {
TypeVariableElement typeVariable = element;
- useLocal(typeVariable);
+ useTypeVariableAsLocal(typeVariable.type);
} else {
registerNeedsThis();
}
@@ -679,7 +690,7 @@
visitSend(Send node) {
Element element = elements[node];
if (Elements.isLocal(element)) {
- TypedElement localElement = element;
+ LocalElement localElement = element;
useLocal(localElement);
} else if (element != null && element.isTypeVariable) {
TypeVariableElement variable = element;
@@ -731,7 +742,7 @@
!outermostElement.isConstructor) {
registerNeedsThis();
} else {
- useLocal(typeVariable.element);
+ useTypeVariableAsLocal(typeVariable);
}
});
}
@@ -739,7 +750,7 @@
void analyzeType(DartType type) {
// TODO(johnniwinther): Find out why this can be null.
if (type == null) return;
- if (outermostElement.isMember &&
+ if (outermostElement.isClassMember &&
compiler.backend.classNeedsRti(outermostElement.enclosingClass)) {
if (outermostElement.isConstructor ||
outermostElement.isField) {
@@ -758,16 +769,16 @@
// The boxed variables are updated in the [capturedVariableMapping].
void attachCapturedScopeVariables(Node node) {
BoxLocal box = null;
- Map<VariableElement, BoxFieldElement> scopeMapping =
- new Map<VariableElement, BoxFieldElement>();
+ Map<LocalVariableElement, BoxFieldElement> scopeMapping =
+ new Map<LocalVariableElement, BoxFieldElement>();
- void boxCapturedVariable(VariableElement variable) {
+ void boxCapturedVariable(LocalVariableElement variable) {
if (isCapturedVariable(variable)) {
if (box == null) {
// TODO(floitsch): construct better box names.
String boxName =
namer.getClosureVariableName('box', closureFieldCounter++);
- box = new BoxLocal(boxName, currentElement);
+ box = new BoxLocal(boxName, executableContext);
}
String elementName = variable.name;
String boxedName =
@@ -821,12 +832,12 @@
if (definitions == null) return;
ClosureScope scopeData = closureData.capturingScopes[node];
if (scopeData == null) return;
- List<VariableElement> result = <VariableElement>[];
+ List<LocalVariableElement> result = <LocalVariableElement>[];
for (Link<Node> link = definitions.definitions.nodes;
!link.isEmpty;
link = link.tail) {
Node definition = link.head;
- VariableElement element = elements[definition];
+ LocalVariableElement element = elements[definition];
if (isCapturedVariable(element)) {
result.add(element);
}
@@ -873,15 +884,15 @@
}
ClosureClassMap globalizeClosure(FunctionExpression node,
- FunctionElement element) {
+ LocalFunctionElement element) {
String closureName = computeClosureName(element);
ClosureClassElement globalizedElement = new ClosureClassElement(
- node, closureName, compiler, element, element.compilationUnit);
+ node, closureName, compiler, element);
FunctionElement callElement =
new SynthesizedCallMethodElementX(Compiler.CALL_OPERATOR_NAME,
element,
globalizedElement);
- ClosureContainer enclosing = element.enclosingElement;
+ MemberElement enclosing = element.memberContext;
enclosing.nestedClosures.add(callElement);
globalizedElement.addMember(callElement, compiler);
globalizedElement.computeAllClassMembers(compiler);
@@ -893,14 +904,16 @@
callElement, thisElement);
}
- void visitInvokable(TypedElement element, Node node, void visitChildren()) {
+ void visitInvokable(ExecutableElement element,
+ Node node,
+ void visitChildren()) {
bool oldInsideClosure = insideClosure;
- Element oldFunctionElement = currentElement;
+ Element oldFunctionElement = executableContext;
ClosureClassMap oldClosureData = closureData;
insideClosure = outermostElement != null;
- FunctionElement closure;
- currentElement = element;
+ LocalFunctionElement closure;
+ executableContext = element;
if (insideClosure) {
closure = element;
closures.add(node);
@@ -928,13 +941,13 @@
declareLocal(closure);
}
- if (currentElement.isFactoryConstructor &&
- compiler.backend.classNeedsRti(currentElement.enclosingElement)) {
+ if (executableContext.isFactoryConstructor &&
+ compiler.backend.classNeedsRti(executableContext.enclosingElement)) {
// Declare the type parameters in the scope. Generative
// constructors just use 'this'.
- ClassElement cls = currentElement.enclosingElement;
+ ClassElement cls = executableContext.enclosingClass;
cls.typeVariables.forEach((TypeVariableType typeVariable) {
- declareLocal(typeVariable.element);
+ declareLocal(new TypeVariableLocal(typeVariable, executableContext));
});
}
@@ -957,7 +970,7 @@
// Restore old values.
insideClosure = oldInsideClosure;
closureData = oldClosureData;
- currentElement = oldFunctionElement;
+ executableContext = oldFunctionElement;
// Mark all free variables as captured and use them in the outer function.
Iterable<Local> freeVariables = savedClosureData.freeVariables;
@@ -989,7 +1002,7 @@
visitFunctionDeclaration(FunctionDeclaration node) {
node.visitChildren(this);
- FunctionElement localFunction = elements[node];
+ LocalFunctionElement localFunction = elements[node];
declareLocal(localFunction);
}
@@ -1001,3 +1014,20 @@
inTryStatement = oldInTryStatement;
}
}
+
+/// A type variable as a local variable.
+class TypeVariableLocal implements Local {
+ final TypeVariableType typeVariable;
+ final ExecutableElement executableContext;
+
+ TypeVariableLocal(this.typeVariable, this.executableContext);
+
+ String get name => typeVariable.name;
+
+ int get hashCode => typeVariable.hashCode;
+
+ bool operator ==(other) {
+ if (other is! TypeVariableLocal) return false;
+ return typeVariable == other.typeVariable;
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index 8a21068..52e988e 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -816,9 +816,9 @@
Node node = parameter.node;
potentiallyCheckType(node, parameter, argument);
definitions[parameter] = argument;
- if (parameter.kind == ElementKind.FIELD_PARAMETER) {
- FieldParameterElement fieldParameterElement = parameter;
- updateFieldValue(node, fieldParameterElement.fieldElement, argument);
+ if (parameter.isInitializingFormal) {
+ InitializingFormalElement initializingFormal = parameter;
+ updateFieldValue(node, initializingFormal.fieldElement, argument);
}
});
}
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index a08b609..3b3cdcd 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -391,6 +391,13 @@
return compiler.patchParser.patchLibrary(loader, patchUri, library);
}
}
+ if (library.canUseNative) {
+ library.forEachLocalMember((Element element) {
+ if (element.isClass) {
+ checkNativeAnnotation(compiler, element);
+ }
+ });
+ }
return new Future.value();
}
@@ -730,6 +737,9 @@
/// The constant for the [patch] variable defined in dart:_js_helper.
Constant patchConstant;
+ // TODO(johnniwinther): Move this to the JavaScriptBackend.
+ ClassElement nativeAnnotationClass;
+
// Initialized after symbolClass has been resolved.
FunctionElement symbolConstructor;
@@ -1021,6 +1031,9 @@
} else if (node is MetadataAnnotation) {
Uri uri = node.annotatedElement.compilationUnit.script.readableUri;
return spanFromTokens(node.beginToken, node.endToken, uri);
+ } else if (node is Local) {
+ Local local = node;
+ return spanFromElement(local.executableContext);
} else {
throw 'No error location.';
}
@@ -1126,6 +1139,8 @@
deferredLibraryClass = findRequiredElement(library, 'DeferredLibrary');
} else if (uri == DART_NATIVE_TYPED_DATA) {
typedDataClass = findRequiredElement(library, 'NativeTypedData');
+ } else if (uri == js_backend.JavaScriptBackend.DART_JS_HELPER) {
+ nativeAnnotationClass = findRequiredElement(library, 'Native');
}
return backend.onLibraryScanned(library, loader);
}
diff --git a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart
index af8e95e..0d92855 100644
--- a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart
@@ -133,7 +133,7 @@
/// Invoke a static function or static field getter/setter.
class InvokeStatic extends Expression implements Invoke {
/// [FunctionElement] or [FieldElement].
- final Element target;
+ final Entity target;
/**
* The selector encodes how the function is invoked: number of positional
@@ -149,7 +149,7 @@
List<Definition> args)
: continuation = new Reference(cont),
arguments = _referenceList(args) {
- assert(target.isErroneous || selector.name == target.name);
+ assert(target is ErroneousElement || selector.name == target.name);
}
accept(Visitor visitor) => visitor.visitInvokeStatic(this);
@@ -546,165 +546,6 @@
T visitIsTrue(IsTrue node) => visitCondition(node);
}
-/// Generate a Lisp-like S-expression representation of an IR node as a string.
-/// The representation is not pretty-printed, but it can easily be quoted and
-/// dropped into the REPL of one's favorite Lisp or Scheme implementation to be
-/// pretty-printed.
-class SExpressionStringifier extends Visitor<String> {
- final Map<Definition, String> names = <Definition, String>{};
-
- int _valueCounter = 0;
- int _continuationCounter = 0;
-
- String newValueName() => 'v${_valueCounter++}';
- String newContinuationName() => 'k${_continuationCounter++}';
-
- String visitFunctionDefinition(FunctionDefinition node) {
- names[node.returnContinuation] = 'return';
- String parameters = node.parameters
- .map((Parameter p) {
- String name = p.hint.name;
- names[p] = name;
- return name;
- })
- .join(' ');
- return '(FunctionDefinition ($parameters return) ${visit(node.body)})';
- }
-
- String visitLetPrim(LetPrim node) {
- String name = newValueName();
- names[node.primitive] = name;
- String value = visit(node.primitive);
- String body = visit(node.body);
- return '(LetPrim $name $value) $body';
- }
-
- String visitLetCont(LetCont node) {
- String cont = newContinuationName();
- names[node.continuation] = cont;
- String parameters = node.continuation.parameters
- .map((Parameter p) {
- String name = newValueName();
- names[p] = name;
- return ' $name';
- })
- .join('');
- String contBody = visit(node.continuation.body);
- String body = visit(node.body);
- String op = node.continuation.isRecursive ? 'LetCont*' : 'LetCont';
- return '($op ($cont$parameters) $contBody) $body';
- }
-
- String formatArguments(Invoke node) {
- int positionalArgumentCount = node.selector.positionalArgumentCount;
- List<String> args = new List<String>();
- args.addAll(node.arguments.getRange(0, positionalArgumentCount)
- .map((v) => names[v.definition]));
- for (int i = 0; i < node.selector.namedArgumentCount; ++i) {
- String name = node.selector.namedArguments[i];
- Definition arg = node.arguments[positionalArgumentCount + i].definition;
- args.add("($name: $arg)");
- }
- return args.join(' ');
- }
-
- String visitInvokeStatic(InvokeStatic node) {
- String name = node.target.name;
- String cont = names[node.continuation.definition];
- String args = formatArguments(node);
- return '(InvokeStatic $name $args $cont)';
- }
-
- String visitInvokeMethod(InvokeMethod node) {
- String name = node.selector.name;
- String rcv = names[node.receiver.definition];
- String cont = names[node.continuation.definition];
- String args = formatArguments(node);
- return '(InvokeMethod $rcv $name $args $cont)';
- }
-
- String visitInvokeConstructor(InvokeConstructor node) {
- String callName;
- if (node.target.name.isEmpty) {
- callName = '${node.type}';
- } else {
- callName = '${node.type}.${node.target.name}';
- }
- String cont = names[node.continuation.definition];
- String args = formatArguments(node);
- return '(InvokeConstructor $callName $args $cont)';
- }
-
- String visitConcatenateStrings(ConcatenateStrings node) {
- String cont = names[node.continuation.definition];
- String args = node.arguments.map((v) => names[v.definition]).join(' ');
- return '(ConcatenateStrings $args $cont)';
- }
-
- String visitInvokeContinuation(InvokeContinuation node) {
- String cont = names[node.continuation.definition];
- String args = node.arguments.map((v) => names[v.definition]).join(' ');
- String op =
- node.isRecursive ? 'InvokeContinuation*' : 'InvokeContinuation';
- return '($op $cont $args)';
- }
-
- String visitBranch(Branch node) {
- String condition = visit(node.condition);
- String trueCont = names[node.trueContinuation.definition];
- String falseCont = names[node.falseContinuation.definition];
- return '(Branch $condition $trueCont $falseCont)';
- }
-
- String visitConstant(Constant node) {
- return '(Constant ${node.value})';
- }
-
- String visitThis(This node) {
- return '(This)';
- }
-
- String visitReifyTypeVar(ReifyTypeVar node) {
- return '(ReifyTypeVar ${node.typeVariable.name})';
- }
-
- String visitCreateFunction(CreateFunction node) {
- String function = visit(node.definition);
- return '(CreateFunction ${node.definition.element} $function)';
- }
-
- String visitParameter(Parameter node) {
- // Parameters are visited directly in visitLetCont.
- return '(Unexpected Parameter)';
- }
-
- String visitContinuation(Continuation node) {
- // Continuations are visited directly in visitLetCont.
- return '(Unexpected Continuation)';
- }
-
- String visitGetClosureVariable(GetClosureVariable node) {
- return '(GetClosureVariable ${node.variable.name})';
- }
-
- String visitSetClosureVariable(SetClosureVariable node) {
- String value = names[node.value.definition];
- String body = visit(node.body);
- return '(SetClosureVariable ${node.variable.name} $value $body)';
- }
-
- String visitDeclareFunction(DeclareFunction node) {
- String function = visit(node.definition);
- String body = visit(node.body);
- return '(DeclareFunction ${node.variable} = $function in $body)';
- }
-
- String visitIsTrue(IsTrue node) {
- String value = names[node.value.definition];
- return '(IsTrue $value)';
- }
-}
-
/// Keeps track of currently unused register indices.
class RegisterArray {
int nextIndex = 0;
diff --git a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart
new file mode 100644
index 0000000..c0af4ae
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.ir_nodes_sexpr;
+
+import 'cps_ir_nodes.dart';
+
+/// Generate a Lisp-like S-expression representation of an IR node as a string.
+/// The representation is not pretty-printed, but it can easily be quoted and
+/// dropped into the REPL of one's favorite Lisp or Scheme implementation to be
+/// pretty-printed.
+class SExpressionStringifier extends Visitor<String> {
+ final Map<Definition, String> names = <Definition, String>{};
+
+ int _valueCounter = 0;
+ int _continuationCounter = 0;
+
+ String newValueName() => 'v${_valueCounter++}';
+ String newContinuationName() => 'k${_continuationCounter++}';
+
+ String visitFunctionDefinition(FunctionDefinition node) {
+ names[node.returnContinuation] = 'return';
+ String parameters = node.parameters
+ .map((Parameter p) {
+ String name = p.hint.name;
+ names[p] = name;
+ return name;
+ })
+ .join(' ');
+ return '(FunctionDefinition ($parameters return) ${visit(node.body)})';
+ }
+
+ String visitLetPrim(LetPrim node) {
+ String name = newValueName();
+ names[node.primitive] = name;
+ String value = visit(node.primitive);
+ String body = visit(node.body);
+ return '(LetPrim $name $value) $body';
+ }
+
+ String visitLetCont(LetCont node) {
+ String cont = newContinuationName();
+ names[node.continuation] = cont;
+ String parameters = node.continuation.parameters
+ .map((Parameter p) {
+ String name = newValueName();
+ names[p] = name;
+ return ' $name';
+ })
+ .join('');
+ String contBody = visit(node.continuation.body);
+ String body = visit(node.body);
+ String op = node.continuation.isRecursive ? 'LetCont*' : 'LetCont';
+ return '($op ($cont$parameters) $contBody) $body';
+ }
+
+ String formatArguments(Invoke node) {
+ int positionalArgumentCount = node.selector.positionalArgumentCount;
+ List<String> args = new List<String>();
+ args.addAll(node.arguments.getRange(0, positionalArgumentCount)
+ .map((v) => names[v.definition]));
+ for (int i = 0; i < node.selector.namedArgumentCount; ++i) {
+ String name = node.selector.namedArguments[i];
+ Definition arg = node.arguments[positionalArgumentCount + i].definition;
+ args.add("($name: $arg)");
+ }
+ return args.join(' ');
+ }
+
+ String visitInvokeStatic(InvokeStatic node) {
+ String name = node.target.name;
+ String cont = names[node.continuation.definition];
+ String args = formatArguments(node);
+ return '(InvokeStatic $name $args $cont)';
+ }
+
+ String visitInvokeMethod(InvokeMethod node) {
+ String name = node.selector.name;
+ String rcv = names[node.receiver.definition];
+ String cont = names[node.continuation.definition];
+ String args = formatArguments(node);
+ return '(InvokeMethod $rcv $name $args $cont)';
+ }
+
+ String visitInvokeSuperMethod(InvokeSuperMethod node) {
+ String name = node.selector.name;
+ String cont = names[node.continuation.definition];
+ String args = formatArguments(node);
+ return '(InvokeSuperMethod $name $args $cont)';
+ }
+
+ String visitInvokeConstructor(InvokeConstructor node) {
+ String callName;
+ if (node.target.name.isEmpty) {
+ callName = '${node.type}';
+ } else {
+ callName = '${node.type}.${node.target.name}';
+ }
+ String cont = names[node.continuation.definition];
+ String args = formatArguments(node);
+ return '(InvokeConstructor $callName $args $cont)';
+ }
+
+ String visitConcatenateStrings(ConcatenateStrings node) {
+ String cont = names[node.continuation.definition];
+ String args = node.arguments.map((v) => names[v.definition]).join(' ');
+ return '(ConcatenateStrings $args $cont)';
+ }
+
+ String visitInvokeContinuation(InvokeContinuation node) {
+ String cont = names[node.continuation.definition];
+ String args = node.arguments.map((v) => names[v.definition]).join(' ');
+ String op =
+ node.isRecursive ? 'InvokeContinuation*' : 'InvokeContinuation';
+ return '($op $cont $args)';
+ }
+
+ String visitBranch(Branch node) {
+ String condition = visit(node.condition);
+ String trueCont = names[node.trueContinuation.definition];
+ String falseCont = names[node.falseContinuation.definition];
+ return '(Branch $condition $trueCont $falseCont)';
+ }
+
+ String visitConstant(Constant node) {
+ return '(Constant ${node.value})';
+ }
+
+ String visitThis(This node) {
+ return '(This)';
+ }
+
+ String visitReifyTypeVar(ReifyTypeVar node) {
+ return '(ReifyTypeVar ${node.typeVariable.name})';
+ }
+
+ String visitCreateFunction(CreateFunction node) {
+ String function = visit(node.definition);
+ return '(CreateFunction ${node.definition.element} $function)';
+ }
+
+ String visitParameter(Parameter node) {
+ // Parameters are visited directly in visitLetCont.
+ return '(Unexpected Parameter)';
+ }
+
+ String visitContinuation(Continuation node) {
+ // Continuations are visited directly in visitLetCont.
+ return '(Unexpected Continuation)';
+ }
+
+ String visitGetClosureVariable(GetClosureVariable node) {
+ return '(GetClosureVariable ${node.variable.name})';
+ }
+
+ String visitSetClosureVariable(SetClosureVariable node) {
+ String value = names[node.value.definition];
+ String body = visit(node.body);
+ return '(SetClosureVariable ${node.variable.name} $value $body)';
+ }
+
+ String visitTypeOperator(TypeOperator node) {
+ String receiver = names[node.receiver.definition];
+ String cont = names[node.continuation.definition];
+ return '(TypeOperator ${node.operator} $receiver ${node.type} $cont)';
+ }
+
+ String visitLiteralList(LiteralList node) {
+ String values = node.values.map((v) => names[v.definition]).join(' ');
+ return '(LiteralList ($values))';
+ }
+
+ String visitLiteralMap(LiteralMap node) {
+ String keys = node.keys.map((v) => names[v.definition]).join(' ');
+ String values = node.values.map((v) => names[v.definition]).join(' ');
+ return '(LiteralMap ($keys) ($values))';
+ }
+
+ String visitDeclareFunction(DeclareFunction node) {
+ String function = visit(node.definition);
+ String body = visit(node.body);
+ return '(DeclareFunction ${node.variable} = $function in $body)';
+ }
+
+ String visitIsTrue(IsTrue node) {
+ String value = names[node.value.definition];
+ return '(IsTrue $value)';
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 9c3c58b..e71cb71 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -205,7 +205,7 @@
Link<Element> optionalParameters =
element.functionSignature.optionalParameters;
for (final optional in optionalParameters) {
- if (optional.kind != ElementKind.FIELD_PARAMETER) continue;
+ if (!optional.isInitializingFormal) continue;
fixedMemberNames.add(optional.name);
}
}
@@ -303,7 +303,7 @@
}
ElementAst elementAst = parse(element);
- if (element.isMember) {
+ if (element.isClassMember) {
ClassElement enclosingClass = element.enclosingClass;
assert(enclosingClass.isClass);
assert(enclosingClass.isTopLevel);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart
index 8c18384..c2d2a33 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart
@@ -284,9 +284,9 @@
// Synthesize an element for the variable
if (variable.element == null || name != variable.element.name) {
- variable.element = new modelx.VariableElementX(
+ // TODO(johnniwinther): Replace by synthetic [Entity].
+ variable.element = new modelx.LocalVariableElementX(
name,
- ElementKind.VARIABLE,
functionElement,
variableList,
null);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index 9b62291..d7279d5 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -210,7 +210,7 @@
// just to escape conflicts and that should be enough as we shouldn't
// be able to resolve private identifiers for other libraries.
makeElementPlaceholder(node.name, element);
- } else if (element.isMember) {
+ } else if (element.isClassMember) {
if (node.name is Identifier) {
tryMakeMemberPlaceholder(node.name);
} else {
@@ -407,7 +407,7 @@
Identifier name = named.name;
String nameAsString = name.source;
for (final parameter in optionalParameters) {
- if (identical(parameter.kind, ElementKind.FIELD_PARAMETER)) {
+ if (parameter.isInitializingFormal) {
if (parameter.name == nameAsString) {
tryMakeMemberPlaceholder(name);
break;
@@ -501,14 +501,14 @@
// May get FunctionExpression here in definition.selector
// in case of A(int this.f());
if (send.selector is Identifier) {
- if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
+ if (definitionElement.isInitializingFormal) {
tryMakeMemberPlaceholder(send.selector);
} else {
tryMakeLocalPlaceholder(definitionElement, send.selector);
}
} else {
assert(send.selector is FunctionExpression);
- if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
+ if (definitionElement.isInitializingFormal) {
tryMakeMemberPlaceholder(
send.selector.asFunctionExpression().name);
}
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart
index 6096966..27acff6 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart
@@ -122,7 +122,7 @@
* In contrast to the CPS-based IR, the arguments can be arbitrary expressions.
*/
class InvokeStatic extends Expression implements Invoke {
- final Element target;
+ final Entity target;
final List<Expression> arguments;
final Selector selector;
diff --git a/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
index 688ff66..87cd4ed 100644
--- a/sdk/lib/_internal/compiler/implementation/deferred_load.dart
+++ b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
@@ -31,7 +31,6 @@
MetadataAnnotation,
ScopeContainerElement,
PrefixElement,
- ClosureContainer,
VoidElement,
TypedefElement,
AstElement;
@@ -281,7 +280,7 @@
/// Returns a [Link] of every [Import] that imports [element] into [library].
Link<Import> _getImports(Element element, LibraryElement library) {
- if (element.isMember) {
+ if (element.isClassMember) {
element = element.enclosingClass;
}
if (element.isAccessor) {
diff --git a/sdk/lib/_internal/compiler/implementation/dump_info.dart b/sdk/lib/_internal/compiler/implementation/dump_info.dart
index 7360feb..6efb119 100644
--- a/sdk/lib/_internal/compiler/implementation/dump_info.dart
+++ b/sdk/lib/_internal/compiler/implementation/dump_info.dart
@@ -24,20 +24,6 @@
import 'js/js.dart' as jsAst;
import 'compilation_info.dart' show CompilationInformation;
-class CodeSizeCounter {
- final Map<Element, int> generatedSize = new Map<Element, int>();
-
- int getGeneratedSizeOf(Element element) {
- int result = generatedSize[element];
- return result == null ? 0: result;
- }
-
- void countCode(Element element, int added) {
- int before = generatedSize.putIfAbsent(element, () => 0);
- generatedSize[element] = before + added;
- }
-}
-
/// Maps elements to an id. Supports lookups in
/// both directions.
class ElementMapper {
@@ -150,8 +136,7 @@
String libname = element.getLibraryName();
libname = libname == "" ? "<unnamed>" : libname;
- int size =
- compiler.dumpInfoTask.codeSizeCounter.getGeneratedSizeOf(element);
+ int size = compiler.dumpInfoTask.sizeOf(element);
LibraryElement contentsOfLibrary = element.isPatched
? element.patch : element;
@@ -189,7 +174,7 @@
Map<String, dynamic> visitFieldElement(FieldElement element) {
String id = mapper._field.add(element);
List<String> children = [];
- CodeBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
+ StringBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
// If a field has an empty inferred type it is never used.
TypeMask inferredType =
@@ -203,7 +188,7 @@
if (emittedCode != null) {
size += emittedCode.length;
- code = emittedCode.getText();
+ code = emittedCode.toString();
}
for (Element closure in element.nestedClosures) {
@@ -232,7 +217,7 @@
String id = mapper._class.add(element);
List<String> children = [];
- int size = compiler.dumpInfoTask.codeSizeCounter.getGeneratedSizeOf(element);
+ int size = compiler.dumpInfoTask.sizeOf(element);
// Omit element if it is not needed.
JavaScriptBackend backend = compiler.backend;
@@ -267,8 +252,8 @@
String sideEffects = null;
String code = "";
- CodeBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
- int size = 0;
+ StringBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
+ int size = compiler.dumpInfoTask.sizeOf(element);
Map<String, dynamic> modifiers = {
'static': element.isStatic,
@@ -308,15 +293,15 @@
inferredReturnType = compiler.typesTask
.getGuaranteedReturnTypeOfElement(element).toString();
sideEffects = compiler.world.getSideEffectsOfElement(element).toString();
- code = emittedCode.getText();
- size += code.length;
+ code = emittedCode.toString();
}
-
- for (Element closure in element.nestedClosures) {
- Map<String, dynamic> child = this.process(closure);
- if (child != null) {
- children.add(child['id']);
- size += child['size'];
+ if (element is MethodElement) {
+ for (Element closure in element.nestedClosures) {
+ Map<String, dynamic> child = this.process(closure);
+ if (child != null) {
+ children.add(child['id']);
+ size += child['size'];
+ }
}
}
@@ -348,18 +333,104 @@
String name = "Dump Info";
- final CodeSizeCounter codeSizeCounter = new CodeSizeCounter();
-
ElementToJsonVisitor infoCollector;
- final Map<Element, jsAst.Expression> _generatedCode = {};
+ // A set of javascript AST nodes that we care about the size of.
+ // This set is automatically populated when registerElementAst()
+ // is called.
+ final Set<jsAst.Node> _tracking = new Set<jsAst.Node>();
+ // A mapping from Dart Elements to Javascript AST Nodes.
+ final Map<Element, List<jsAst.Node>> _elementToNodes =
+ <Element, List<jsAst.Node>>{};
+ // A mapping from Javascript AST Nodes to the size of their
+ // pretty-printed contents.
+ final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{};
+ final Map<jsAst.Node, int> _nodeBeforeSize = <jsAst.Node, int>{};
- void registerGeneratedCode(Element element, jsAst.Expression code) {
- if (compiler.dumpInfo) {
- _generatedCode[element] = code;
+ /**
+ * A callback that can be called before a jsAst [node] is
+ * pretty-printed. The size of the code buffer ([aftersize])
+ * is also passed.
+ */
+ void enteringAst(jsAst.Node node, int beforeSize) {
+ if (isTracking(node)) {
+ _nodeBeforeSize[node] = beforeSize;
}
}
+ /**
+ * A callback that can be called after a jsAst [node] is
+ * pretty-printed. The size of the code buffer ([aftersize])
+ * is also passed.
+ */
+ void exitingAst(jsAst.Node node, int afterSize) {
+ if (isTracking(node)) {
+ int diff = afterSize - _nodeBeforeSize[node];
+ recordAstSize(node, diff);
+ }
+ }
+
+ // Returns true if we care about tracking the size of
+ // this node.
+ bool isTracking(jsAst.Node code) {
+ if (compiler.dumpInfo) {
+ return _tracking.contains(code);
+ } else {
+ return false;
+ }
+ }
+
+ // Registers that a javascript AST node `code` was produced by the
+ // dart Element `element`.
+ void registerElementAst(Element element, jsAst.Node code) {
+ if (compiler.dumpInfo) {
+ _elementToNodes
+ .putIfAbsent(element, () => new List<jsAst.Node>())
+ .add(code);
+ _tracking.add(code);
+ }
+ }
+
+ // Records the size of a dart AST node after it has been
+ // pretty-printed into the output buffer.
+ void recordAstSize(jsAst.Node code, int size) {
+ if (compiler.dumpInfo) {
+ //TODO: should I be incrementing here instead?
+ _nodeToSize[code] = size;
+ }
+ }
+
+ // Returns the size of the source code that
+ // was generated for an element. If no source
+ // code was produced, return 0.
+ int sizeOf(Element element) {
+ if (_elementToNodes.containsKey(element)) {
+ return _elementToNodes[element]
+ .map(sizeOfNode)
+ .fold(0, (a, b) => a + b);
+ } else {
+ return 0;
+ }
+ }
+
+ int sizeOfNode(jsAst.Node node) {
+ if (_nodeToSize.containsKey(node)) {
+ return _nodeToSize[node];
+ } else {
+ return 0;
+ }
+ }
+
+ StringBuffer codeOf(Element element) {
+ List<jsAst.Node> code = _elementToNodes[element];
+ if (code == null) return null;
+ // Concatenate rendered ASTs.
+ StringBuffer sb = new StringBuffer();
+ for (jsAst.Node ast in code) {
+ sb.writeln(jsAst.prettyPrint(ast, compiler).getText());
+ }
+ return sb;
+ }
void collectInfo() {
infoCollector = new ElementToJsonVisitor(compiler);
@@ -379,12 +450,6 @@
});
}
- CodeBuffer codeOf(Element element) {
- jsAst.Expression code = _generatedCode[element];
- return code != null
- ? jsAst.prettyPrint(code, compiler)
- : compiler.backend.codeOf(element);
- }
void dumpInfoJson(StringSink buffer) {
JsonEncoder encoder = const JsonEncoder();
@@ -418,20 +483,22 @@
}
});
- Map<String, dynamic> outJson = {};
- outJson['elements'] = infoCollector.toJson();
- outJson['holding'] = holding;
- outJson['dump_version'] = 1;
+ Map<String, dynamic> outJson = {
+ 'elements': infoCollector.toJson(),
+ 'holding': holding,
+ 'dump_version': 1,
+ };
Duration toJsonDuration = new DateTime.now().difference(startToJsonTime);
- Map<String, dynamic> generalProgramInfo = <String, dynamic>{};
- generalProgramInfo['size'] = infoCollector.programSize;
- generalProgramInfo['dart2jsVersion'] = infoCollector.dart2jsVersion;
- generalProgramInfo['compilationMoment'] = infoCollector.compilationMoment.toString();
- generalProgramInfo['compilationDuration'] = infoCollector.compilationDuration.toString();
- generalProgramInfo['toJsonDuration'] = toJsonDuration.toString();
- generalProgramInfo['dumpInfoDuration'] = infoCollector.dumpInfoDuration.toString();
+ Map<String, dynamic> generalProgramInfo = <String, dynamic> {
+ 'size': infoCollector.programSize,
+ 'dart2jsVersion': infoCollector.dart2jsVersion,
+ 'compilationMoment': infoCollector.compilationMoment.toString(),
+ 'compilationDuration': infoCollector.compilationDuration.toString(),
+ 'toJsonDuration': toJsonDuration.toString(),
+ 'dumpInfoDuration': infoCollector.dumpInfoDuration.toString()
+ };
outJson['program'] = generalProgramInfo;
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 9d416c9..8246b93 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -81,8 +81,8 @@
const ElementKind('parameter', ElementCategory.VARIABLE);
// Parameters in constructors that directly initialize fields. For example:
// [:A(this.field):].
- static const ElementKind FIELD_PARAMETER =
- const ElementKind('field_parameter', ElementCategory.VARIABLE);
+ static const ElementKind INITIALIZING_FORMAL =
+ const ElementKind('initializing_formal', ElementCategory.VARIABLE);
static const ElementKind FUNCTION =
const ElementKind('function', ElementCategory.FUNCTION);
static const ElementKind CLASS =
@@ -91,8 +91,6 @@
const ElementKind('generative_constructor', ElementCategory.FACTORY);
static const ElementKind FIELD =
const ElementKind('field', ElementCategory.VARIABLE);
- static const ElementKind VARIABLE_LIST =
- const ElementKind('variable_list', ElementCategory.NONE);
static const ElementKind FIELD_LIST =
const ElementKind('field_list', ElementCategory.NONE);
static const ElementKind GENERATIVE_CONSTRUCTOR_BODY =
@@ -142,17 +140,6 @@
String get name;
}
-// TODO(johnniwinther): Should [Local] have `enclosingFunction`, `isAssignable`
-// or `type`?
-/// An entity that defines a local variable (memory slot) in generated code.
-///
-/// Several [Element] can define local variable, for instance parameter, local
-/// variables and local functions and thus implement [Local]. For non-element
-/// locals, like `this` and boxes, specialized [Local] class are created.
-abstract class Local extends Entity {
-
-}
-
/**
* A declared element of a program.
*
@@ -289,12 +276,12 @@
/// parameter.
///
/// This property is `false` if this element is an initializing formal.
- /// See [isFieldParameter].
+ /// See [isInitializingFormal].
bool get isParameter => kind == ElementKind.PARAMETER;
/// `true` if this element is an initializing formal of constructor, that
/// is a formal of the form `this.foo`.
- bool get isFieldParameter => kind == ElementKind.FIELD_PARAMETER;
+ bool get isInitializingFormal => kind == ElementKind.INITIALIZING_FORMAL;
bool get isStatement;
@@ -303,7 +290,13 @@
bool get isWarnOnUse;
bool get isClosure;
- bool get isMember;
+
+ /// `true` if the element is a (static or instance) member of a class.
+ /// Members are constructors, methods and fields.
+ bool get isClassMember;
+
+ /// `true` if the element is a nonstatic member of a class.
+ /// Instance members are methods and fields but not constructors.
bool get isInstanceMember;
/// Returns true if this [Element] is a top level element.
@@ -773,6 +766,7 @@
}
}
+/// An element representing an erroneous resolution.
abstract class ErroneousElement extends Element implements ConstructorElement {
MessageKind get messageKind;
Map get messageArguments;
@@ -790,6 +784,7 @@
Element unwrap(DiagnosticListener listener, Spannable usageSpannable);
}
+/// An element representing the ambiguous resolution of a name.
abstract class AmbiguousElement extends Element {
MessageKind get messageKind;
Map get messageArguments;
@@ -805,10 +800,6 @@
void forEachLocalMember(f(Element element));
}
-abstract class ClosureContainer implements Element {
- List<FunctionElement> get nestedClosures;
-}
-
abstract class CompilationUnitElement extends Element {
Script get script;
PartOf get partTag;
@@ -896,6 +887,7 @@
int compareTo(LibraryElement other);
}
+/// The implicit scope defined by a import declaration with a prefix clause.
abstract class PrefixElement extends Element {
void addImport(Element element, Import import, DiagnosticListener listener);
Element lookupLocalMember(String memberName);
@@ -905,25 +897,104 @@
Import get deferredImport;
}
+/// A type alias definition.
abstract class TypedefElement extends Element
implements AstElement, TypeDeclarationElement, FunctionTypedElement {
+
+ /// The type defined by this typedef with the type variables as its type
+ /// arguments.
+ ///
+ /// For instance `F<T>` for `typedef void F<T>(T t)`.
TypedefType get thisType;
+
+ /// The type defined by this typedef with `dynamic` as its type arguments.
+ ///
+ /// For instance `F<dynamic>` for `typedef void F<T>(T t)`.
TypedefType get rawType;
+
+ /// The type, function type if well-defined, for which this typedef is an
+ /// alias.
+ ///
+ /// For instance `(int)->void` for `typedef void F(int)`.
DartType get alias;
void checkCyclicReference(Compiler compiler);
}
-abstract class VariableElement extends Element
+/// An executable element is an element that can hold code.
+///
+/// These elements variables (fields, parameters and locals), which can hold
+/// code in their initializer, and functions (including methods and
+/// constructors), which can hold code in their body.
+abstract class ExecutableElement extends Element
implements TypedElement, AstElement {
+ /// The outermost member that contains this element.
+ ///
+ /// For top level, static or instance members, the member context is the
+ /// element itself. For parameters, local variables and nested closures, the
+ /// member context is the top level, static or instance member in which it is
+ /// defined.
+ MemberElement get memberContext;
+}
+
+/// A top-level or static field or method, or a constructor.
+///
+/// A [MemberElement] is the outermost executable element for any executable
+/// context.
+abstract class MemberElement extends Element implements ExecutableElement {
+ /// The local functions defined within this member.
+ List<FunctionElement> get nestedClosures;
+}
+
+/// A function, variable or parameter defined in an executable context.
+abstract class LocalElement extends Element implements TypedElement, Local {
+}
+
+/// A top level, static or instance field, a formal parameter or local variable.
+abstract class VariableElement extends ExecutableElement {
Expression get initializer;
}
-abstract class FieldElement extends VariableElement
- implements ClosureContainer {}
+/// An entity that defines a local entity (memory slot) in generated code.
+///
+/// Parameters, local variables and local functions (can) define local entity
+/// and thus implement [Local] through [LocalElement]. For
+/// non-element locals, like `this` and boxes, specialized [Local] class are
+/// created.
+///
+/// Type variables can introduce locals in factories and constructors
+/// but since one type variable can introduce different locals in different
+/// factories and constructors it is not itself a [Local] but instead
+/// a non-element [Local] is created through a specialized class.
+// TODO(johnniwinther): Should [Local] have `isAssignable` or `type`?
+abstract class Local extends Entity {
+ /// The context in which this local is defined.
+ ExecutableElement get executableContext;
+}
-abstract class ParameterElement extends VariableElement
- implements FunctionTypedElement {
+/// A variable or parameter that is local to an executable context.
+///
+/// The executable context is the [ExecutableElement] in which this variable
+/// is defined.
+abstract class LocalVariableElement extends VariableElement
+ implements LocalElement {
+}
+
+/// A top-level, static or instance field.
+abstract class FieldElement extends VariableElement implements MemberElement {
+}
+
+/// A parameter-like element of a function signature.
+///
+/// If the function signature comes from a typedef or an inline function-typed
+/// parameter (e.g. the parameter 'f' in `method(void f())`), then its
+/// parameters are not real parameters in that they can take no argument and
+/// hold no value. Such parameter-like elements are modeled by [FormalElement].
+///
+/// If the function signature comes from a function or constructor, its
+/// parameters are real parameters and are modeled by [ParameterElement].
+abstract class FormalElement extends Element
+ implements FunctionTypedElement, TypedElement, AstElement {
/// Use [functionDeclaration] instead.
@deprecated
get enclosingElement;
@@ -935,8 +1006,32 @@
VariableDefinitions get node;
}
-abstract class FieldParameterElement extends ParameterElement {
- VariableElement get fieldElement;
+/// A formal parameter of a function or constructor.
+///
+/// Normal parameter that introduce a local variable are modeled by
+/// [LocalParameterElement] whereas initializing formals, that is parameter of
+/// the form `this.x`, are modeled by [InitializingFormalParameter].
+abstract class ParameterElement extends Element
+ implements VariableElement, FormalElement, LocalElement {
+ /// The function on which this parameter is declared.
+ FunctionElement get functionDeclaration;
+}
+
+/// A formal parameter on a function or constructor that introduces a local
+/// variable in the scope of the function or constructor.
+abstract class LocalParameterElement extends ParameterElement
+ implements LocalVariableElement {
+}
+
+/// A formal parameter in a constructor that directly initializes a field.
+///
+/// For example: `A(this.field)`.
+abstract class InitializingFormalElement extends ParameterElement {
+ /// The field initialized by this initializing formal.
+ FieldElement get fieldElement;
+
+ /// The function on which this parameter is declared.
+ ConstructorElement get functionDeclaration;
}
/**
@@ -953,31 +1048,33 @@
abstract class FunctionSignature {
FunctionType get type;
- Link<Element> get requiredParameters;
- Link<Element> get optionalParameters;
+ Link<FormalElement> get requiredParameters;
+ Link<FormalElement> get optionalParameters;
int get requiredParameterCount;
int get optionalParameterCount;
bool get optionalParametersAreNamed;
- Element get firstOptionalParameter;
+ FormalElement get firstOptionalParameter;
int get parameterCount;
- List<Element> get orderedOptionalParameters;
+ List<FormalElement> get orderedOptionalParameters;
- void forEachParameter(void function(Element parameter));
- void forEachRequiredParameter(void function(Element parameter));
- void forEachOptionalParameter(void function(Element parameter));
+ void forEachParameter(void function(FormalElement parameter));
+ void forEachRequiredParameter(void function(FormalElement parameter));
+ void forEachOptionalParameter(void function(FormalElement parameter));
- void orderedForEachParameter(void function(Element parameter));
+ void orderedForEachParameter(void function(FormalElement parameter));
bool isCompatibleWith(FunctionSignature constructorSignature);
}
+/// A top level, static or instance method, constructor, local function, or
+/// closure (anonymous local function).
abstract class FunctionElement extends Element
implements AstElement,
TypedElement,
FunctionTypedElement,
- ClosureContainer {
+ ExecutableElement {
FunctionExpression get node;
FunctionElement get patch;
@@ -995,7 +1092,19 @@
@deprecated FunctionSignature computeSignature(Compiler compiler);
}
-abstract class ConstructorElement extends FunctionElement {
+/// A top level, static or instance function.
+abstract class MethodElement extends FunctionElement
+ implements MemberElement {
+}
+
+/// A local function or closure (anonymous local function).
+abstract class LocalFunctionElement extends FunctionElement
+ implements LocalElement {
+}
+
+/// A constructor.
+abstract class ConstructorElement extends FunctionElement
+ implements MemberElement {
/// The effective target of this constructor, that is the non-redirecting
/// constructor that is called on invocation of this constructor.
///
@@ -1049,14 +1158,14 @@
get enclosingElement;
}
+/// JavaScript backend specific element for the body of constructor.
+// TODO(johnniwinther): Remove this class for the element model.
abstract class ConstructorBodyElement extends FunctionElement {
FunctionElement get constructor;
}
-/**
- * [TypeDeclarationElement] defines the common interface for class/interface
- * declarations and typedefs.
- */
+/// [TypeDeclarationElement] defines the common interface for class/interface
+/// declarations and typedefs.
abstract class TypeDeclarationElement extends Element implements AstElement {
/**
* The `this type` for this type declaration.
@@ -1286,7 +1395,7 @@
}
/// An [Element] that has a type.
-abstract class TypedElement extends Element implements Local {
+abstract class TypedElement extends Element {
DartType get type;
}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index e388d9d..c4e0708 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -75,7 +75,7 @@
}
bool get isClosure => false;
- bool get isMember {
+ bool get isClassMember {
// Check that this element is defined in the scope of a Class.
return enclosingElement != null && enclosingElement.isClass;
}
@@ -200,7 +200,7 @@
*/
Element get enclosingMember {
for (Element e = this; e != null; e = e.enclosingElement) {
- if (e.isMember) return e;
+ if (e.isClassMember) return e;
}
return null;
}
@@ -211,7 +211,7 @@
// the outermost for elements in closure classses, but some call-sites rely
// on that behavior.
for (Element e = this; e != null; e = e.enclosingElement) {
- if (e.isMember || e.isTopLevel) {
+ if (e.isClassMember || e.isTopLevel) {
return e;
}
}
@@ -328,6 +328,8 @@
get origin => this;
get immediateRedirectionTarget => unsupported();
get nestedClosures => unsupported();
+ get memberContext => unsupported();
+ get executableContext => unsupported();
bool get isRedirectingFactory => unsupported();
@@ -1142,7 +1144,7 @@
DartType computeType(Element element, Compiler compiler) => type;
}
-class VariableElementX extends ElementX with AstElementMixin
+abstract class VariableElementX extends ElementX with AstElementMixin
implements VariableElement {
final Token token;
final VariableList variables;
@@ -1243,7 +1245,7 @@
return variables.type;
}
- bool get isInstanceMember => isMember && !isStatic;
+ bool get isInstanceMember => isClassMember && !isStatic;
// Note: cachedNode.beginToken will not be correct in all
// cases, for example, for function typed parameters.
@@ -1252,14 +1254,19 @@
accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
}
-class LocalVariableElementX extends VariableElementX {
+class LocalVariableElementX extends VariableElementX
+ implements LocalVariableElement {
LocalVariableElementX(String name,
- Element enclosingElement,
+ ExecutableElement enclosingElement,
VariableList variables,
Token token)
: super(name, ElementKind.VARIABLE, enclosingElement, variables, token) {
createDefinitions(variables.definitions);
}
+
+ ExecutableElement get executableContext => enclosingElement;
+
+ ExecutableElement get memberContext => executableContext.memberContext;
}
class FieldElementX extends VariableElementX
@@ -1273,39 +1280,16 @@
variables, name.token);
accept(ElementVisitor visitor) => visitor.visitFieldElement(this);
+
+ MemberElement get memberContext => this;
}
-/**
- * Parameters in constructors that directly initialize fields. For example:
- * [:A(this.field):].
- */
-class FieldParameterElementX extends ParameterElementX
- implements FieldParameterElement {
- VariableElement fieldElement;
-
- FieldParameterElementX(Element enclosingElement,
- VariableDefinitions variables,
- Identifier identifier,
- Expression initializer,
- this.fieldElement)
- : super(ElementKind.FIELD_PARAMETER, enclosingElement,
- variables, identifier, initializer);
-
- accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);
-}
-
-/// [Element] for a formal parameter.
-///
-/// A [ParameterElementX] can be patched. A parameter of an external method is
-/// patched with the corresponding parameter of the patch method. This is done
-/// to ensure that default values on parameters are computed once (on the
-/// origin parameter) but can be found through both the origin and the patch.
-class ParameterElementX extends ElementX
- with PatchMixin<ParameterElement>, AstElementMixin
- implements ParameterElement {
+/// [Element] for a parameter-like element.
+class FormalElementX extends ElementX
+ with AstElementMixin
+ implements FormalElement {
final VariableDefinitions definitions;
final Identifier identifier;
- final Expression initializer;
DartType typeCache;
/**
@@ -1315,11 +1299,10 @@
*/
FunctionSignature functionSignatureCache;
- ParameterElementX(ElementKind elementKind,
- FunctionTypedElement enclosingElement,
- this.definitions,
- Identifier identifier,
- this.initializer)
+ FormalElementX(ElementKind elementKind,
+ FunctionTypedElement enclosingElement,
+ this.definitions,
+ Identifier identifier)
: this.identifier = identifier,
super(identifier.source, elementKind, enclosingElement);
@@ -1355,12 +1338,68 @@
FunctionType get functionType => type;
- accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
+ accept(ElementVisitor visitor) => visitor.visitFormalElement(this);
// A parameter is defined by the declaration element.
AstElement get definingElement => declaration;
}
+/// [Element] for a formal parameter.
+///
+/// A [ParameterElementX] can be patched. A parameter of an external method is
+/// patched with the corresponding parameter of the patch method. This is done
+/// to ensure that default values on parameters are computed once (on the
+/// origin parameter) but can be found through both the origin and the patch.
+abstract class ParameterElementX extends FormalElementX
+ with PatchMixin<ParameterElement> implements ParameterElement {
+ final Expression initializer;
+
+ ParameterElementX(ElementKind elementKind,
+ FunctionElement functionDeclaration,
+ VariableDefinitions definitions,
+ Identifier identifier,
+ this.initializer)
+ : super(elementKind, functionDeclaration, definitions, identifier);
+
+ FunctionElement get functionDeclaration => enclosingElement;
+
+ ExecutableElement get executableContext => enclosingElement;
+
+ MemberElement get memberContext => executableContext.memberContext;
+
+ accept(ElementVisitor visitor) => visitor.visitParameterElement(this);
+}
+
+class LocalParameterElementX extends ParameterElementX
+ implements LocalParameterElement {
+ LocalParameterElementX(FunctionElement functionDeclaration,
+ VariableDefinitions definitions,
+ Identifier identifier,
+ Expression initializer)
+ : super(ElementKind.PARAMETER, functionDeclaration,
+ definitions, identifier, initializer);
+}
+
+/// Parameters in constructors that directly initialize fields. For example:
+/// `A(this.field)`.
+class InitializingFormalElementX extends ParameterElementX
+ implements InitializingFormalElement {
+ FieldElement fieldElement;
+
+ InitializingFormalElementX(ConstructorElement constructorDeclaration,
+ VariableDefinitions variables,
+ Identifier identifier,
+ Expression initializer,
+ this.fieldElement)
+ : super(ElementKind.INITIALIZING_FORMAL, constructorDeclaration,
+ variables, identifier, initializer);
+
+ accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);
+
+ MemberElement get memberContext => enclosingElement;
+}
+
+
class AbstractFieldElementX extends ElementX implements AbstractFieldElement {
FunctionElementX getter;
FunctionElementX setter;
@@ -1408,7 +1447,7 @@
}
bool get isInstanceMember {
- return isMember && !isStatic;
+ return isClassMember && !isStatic;
}
accept(ElementVisitor visitor) => visitor.visitAbstractFieldElement(this);
@@ -1530,7 +1569,7 @@
}
bool get isInstanceMember {
- return isMember
+ return isClassMember
&& !isConstructor
&& !isStatic;
}
@@ -1586,25 +1625,32 @@
}
abstract class FunctionElementX extends BaseFunctionElementX
- with AnalyzableElementX {
+ with AnalyzableElementX implements MemberElement {
FunctionElementX(String name,
ElementKind kind,
Modifiers modifiers,
Element enclosing,
bool hasNoBody)
: super(name, kind, modifiers, enclosing, hasNoBody);
+
+ MemberElement get memberContext => this;
}
-class LocalFunctionElementX extends BaseFunctionElementX {
+class LocalFunctionElementX extends BaseFunctionElementX
+ implements LocalFunctionElement {
final FunctionExpression node;
LocalFunctionElementX(String name,
FunctionExpression this.node,
ElementKind kind,
Modifiers modifiers,
- Element enclosing)
+ ExecutableElement enclosing)
: super(name, kind, modifiers, enclosing, false);
+ ExecutableElement get executableContext => enclosingElement;
+
+ MemberElement get memberContext => executableContext.memberContext;
+
bool get hasNode => true;
FunctionExpression parseNode(DiagnosticListener listener) => node;
@@ -1682,7 +1728,7 @@
return functionSignatureCache;
}
- bool get isMember => false;
+ bool get isClassMember => false;
bool isForeign(Compiler compiler) => true;
@@ -1707,7 +1753,7 @@
class ConstructorBodyElementX extends BaseFunctionElementX
implements ConstructorBodyElement {
- FunctionElement constructor;
+ ConstructorElement constructor;
ConstructorBodyElementX(FunctionElement constructor)
: this.constructor = constructor,
@@ -1736,6 +1782,8 @@
Element get analyzableElement => constructor.analyzableElement;
accept(ElementVisitor visitor) => visitor.visitConstructorBodyElement(this);
+
+ MemberElement get memberContext => constructor;
}
/**
@@ -2269,7 +2317,10 @@
}
bool get isNative => nativeTagInfo != null;
+
void setNative(String name) {
+ assert(invariant(this, nativeTagInfo == null,
+ message: "Native tag info set twice on $this."));
nativeTagInfo = name;
}
@@ -2514,6 +2565,9 @@
String toString() => statement.toString();
accept(ElementVisitor visitor) => visitor.visitTargetElement(this);
+
+ // TODO(johnniwinther): Remove this when [TargetElement] is a non-element.
+ get executableContext => enclosingElement;
}
class TypeVariableElementX extends ElementX with AstElementMixin
diff --git a/sdk/lib/_internal/compiler/implementation/elements/visitor.dart b/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
index 8c632f7..961bc22 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
@@ -23,8 +23,11 @@
R visitPrefixElement(PrefixElement e) => visitElement(e);
R visitTypedefElement(TypedefElement e) => visitElement(e);
R visitVariableElement(VariableElement e) => visitElement(e);
+ R visitParameterElement(ParameterElement e) => visitVariableElement(e);
+ R visitFormalElement(FormalElement e) => visitElement(e);
R visitFieldElement(FieldElement e) => visitVariableElement(e);
- R visitFieldParameterElement(FieldParameterElement e) => visitElement(e);
+ R visitFieldParameterElement(InitializingFormalElement e) =>
+ visitParameterElement(e);
R visitAbstractFieldElement(AbstractFieldElement e) => visitElement(e);
R visitFunctionElement(FunctionElement e) => visitElement(e);
R visitConstructorBodyElement(ConstructorBodyElement e) => visitElement(e);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
index e467e29..1909dfb 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
@@ -1371,7 +1371,7 @@
/**
* Add [reader] to the set of [local]'s readers.
*/
- void addCapturedLocalReader(VariableElement local, FunctionElement reader) {
+ void addCapturedLocalReader(Local local, FunctionElement reader) {
capturedLocalsReaders.putIfAbsent(local, () => new Set<FunctionElement>())
.add(reader);
}
@@ -2266,7 +2266,7 @@
final result = currentWorkItem.environment.lookupType(element);
if (result != null) return result;
}
- if (element.isParameter || element.isFieldParameter) {
+ if (element.isParameter || element.isInitializingFormal) {
return inferredParameterTypes[element];
} else if (element.isField) {
return inferredFieldTypes[element];
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
index 938ba14..c427573 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
@@ -369,7 +369,7 @@
}
}
- void update(TypedElement local, T type, Node node) {
+ void update(LocalElement local, T type, Node node) {
assert(type != null);
if (compiler.trustTypeAnnotations || compiler.enableTypeAssertions) {
type = types.narrowType(type, local.type);
@@ -783,7 +783,7 @@
} else {
Element element = elements[node];
if (Elements.isLocal(element)) {
- TypedElement local = element;
+ LocalElement local = element;
return locals.use(local);
}
return null;
@@ -803,8 +803,8 @@
}
void updateIsChecks(List<Node> tests, {bool usePositive}) {
- void narrow(var element, DartType type, Node node) {
- if (element is Local) {
+ void narrow(Element element, DartType type, Node node) {
+ if (element is LocalElement) {
T existing = locals.use(element);
T newType = types.narrowType(existing, type, isNullable: false);
locals.update(element, newType, node);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
index 35be403..12aa1df 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
@@ -392,7 +392,7 @@
bool isNativeElement(Element element) {
if (element.isNative) return true;
- return element.isMember
+ return element.isClassMember
&& element.enclosingClass.isNative
&& element.isField;
}
@@ -491,20 +491,21 @@
if (analyzedElement.isGenerativeConstructor) {
isThisExposed = false;
- signature.forEachParameter((element) {
+ signature.forEachParameter((ParameterElement element) {
T parameterType = inferrer.typeOfElement(element);
- if (element.kind == ElementKind.FIELD_PARAMETER) {
- if (element.fieldElement.modifiers.isFinal) {
+ if (element.isInitializingFormal) {
+ InitializingFormalElement initializingFormal = element;
+ if (initializingFormal.fieldElement.isFinal) {
inferrer.recordTypeOfFinalField(
node,
analyzedElement,
- element.fieldElement,
+ initializingFormal.fieldElement,
parameterType);
} else {
- locals.updateField(element.fieldElement, parameterType);
+ locals.updateField(initializingFormal.fieldElement, parameterType);
inferrer.recordTypeOfNonFinalField(
- element.parseNode(compiler),
- element.fieldElement,
+ initializingFormal.node,
+ initializingFormal.fieldElement,
parameterType);
}
}
@@ -538,8 +539,8 @@
if (!isConstructorRedirect) {
// Iterate over all instance fields, and give a null type to
// fields that we haven't initialized for sure.
- cls.forEachInstanceField((_, field) {
- if (field.modifiers.isFinal) return;
+ cls.forEachInstanceField((_, FieldElement field) {
+ if (field.isFinal) return;
T type = locals.fieldScope.readField(field);
if (type == null && field.initializer == null) {
inferrer.recordTypeOfNonFinalField(node, field, types.nullType);
@@ -842,7 +843,7 @@
handleDynamicSend(node, setterSelector, receiverType,
new ArgumentsTypes<T>([newType], null));
} else if (Elements.isLocal(element)) {
- TypedElement local = element;
+ LocalElement local = element;
getterType = locals.use(local);
newType = handleDynamicSend(
node, operatorSelector, getterType, operatorArguments);
@@ -1079,7 +1080,7 @@
} else if (Elements.isErroneousElement(element)) {
return types.dynamicType;
} else if (Elements.isLocal(element)) {
- TypedElement local = element;
+ LocalElement local = element;
assert(locals.use(local) != null);
return locals.use(local);
} else {
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index 40a747f..e17ce9c 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -251,7 +251,7 @@
factory ElementTypeInformation(Element element) {
var assignments = null;
if (element.enclosingElement.isInstanceMember &&
- (element.isParameter || element.isFieldParameter)) {
+ (element.isParameter || element.isInitializingFormal)) {
assignments = new ParameterAssignments();
}
return new ElementTypeInformation.internal(element, assignments);
@@ -321,7 +321,7 @@
}
if (element.isField ||
element.isParameter ||
- element.isFieldParameter) {
+ element.isInitializingFormal) {
if (!inferrer.compiler.backend.canBeUsedForGlobalOptimizations(element)) {
// Do not infer types for fields and parameters being assigned
// by synthesized calls.
@@ -370,7 +370,7 @@
TypeGraphInferrerEngine inferrer) {
Compiler compiler = inferrer.compiler;
// Parameters are being explicitly checked in the method.
- if (element.isParameter || element.isFieldParameter) return mask;
+ if (element.isParameter || element.isInitializingFormal) return mask;
if (!compiler.trustTypeAnnotations && !compiler.enableTypeAssertions) {
return mask;
}
diff --git a/sdk/lib/_internal/compiler/implementation/js/js.dart b/sdk/lib/_internal/compiler/implementation/js/js.dart
index daf216c..03700c7 100644
--- a/sdk/lib/_internal/compiler/implementation/js/js.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/js.dart
@@ -12,6 +12,8 @@
// CodeBuffer).
import '../dart2jslib.dart' as leg;
+import '../dump_info.dart';
+
part 'nodes.dart';
part 'builder.dart';
part 'printer.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js/printer.dart b/sdk/lib/_internal/compiler/implementation/js/printer.dart
index 5b9fe43..ecc0be5 100644
--- a/sdk/lib/_internal/compiler/implementation/js/printer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/printer.dart
@@ -15,11 +15,15 @@
final LocalNamer localNamer;
bool pendingSemicolon = false;
bool pendingSpace = false;
+ DumpInfoTask monitor = null;
+
static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]');
static final expressionContinuationRegExp = new RegExp(r'^[-+([]');
- Printer(leg.Compiler compiler, { allowVariableMinification: true })
+ Printer(leg.Compiler compiler, DumpInfoTask monitor,
+ { allowVariableMinification: true })
: shouldCompressOutput = compiler.enableMinification,
+ monitor = monitor,
this.compiler = compiler,
outBuffer = new leg.CodeBuffer(),
danglingElseVisitor = new DanglingElseVisitor(compiler),
@@ -122,7 +126,11 @@
visit(Node node) {
beginSourceRange(node);
+ if (monitor != null) monitor.enteringAst(node, outBuffer.length);
+
node.accept(this);
+
+ if (monitor != null) monitor.exitingAst(node, outBuffer.length);
endSourceRange(node);
}
@@ -1026,9 +1034,10 @@
leg.CodeBuffer prettyPrint(Node node, leg.Compiler compiler,
- { allowVariableMinification: true }) {
+ {DumpInfoTask monitor,
+ allowVariableMinification: true}) {
Printer printer =
- new Printer(compiler,
+ new Printer(compiler, monitor,
allowVariableMinification: allowVariableMinification);
printer.visit(node);
return printer.outBuffer;
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index c765845..45b3ada 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -417,7 +417,7 @@
bool usedByBackend(Element element) {
if (element.isParameter
- || element.isFieldParameter
+ || element.isInitializingFormal
|| element.isField) {
if (usedByBackend(element.enclosingElement)) return true;
}
@@ -425,7 +425,7 @@
}
bool invokedReflectively(Element element) {
- if (element.isParameter || element.isFieldParameter) {
+ if (element.isParameter || element.isInitializingFormal) {
ParameterElement parameter = element;
if (invokedReflectively(parameter.functionDeclaration)) return true;
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
index b3228f6..0f8ae3d 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
@@ -26,6 +26,7 @@
import '../util/util.dart';
import '../compilation_info.dart';
+import '../dump_info.dart';
part 'backend.dart';
part 'checked_mode_helpers.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index d8b928a..51167f6 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -627,7 +627,7 @@
String className = element.enclosingClass.name;
name = '${className}_${Elements.reconstructConstructorName(element)}';
} else if (Elements.isStaticOrTopLevel(element)) {
- if (element.isMember) {
+ if (element.isClassMember) {
ClassElement enclosingClass = element.enclosingClass;
name = "${enclosingClass.name}_"
"${element.name}";
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index d875829..061c781 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -287,10 +287,10 @@
if (compiler.hasIncrementalSupport) {
builder = cachedBuilders[classElement];
if (builder != null) return builder;
- builder = new ClassBuilder(backend.namer);
+ builder = new ClassBuilder(classElement, backend.namer);
cachedBuilders[classElement] = builder;
} else {
- builder = new ClassBuilder(backend.namer);
+ builder = new ClassBuilder(classElement, backend.namer);
}
// TODO(sra): Issue #13731- this is commented out as part of custom element
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
index f39b26e..7d96726 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
@@ -15,12 +15,13 @@
String functionType;
List<jsAst.Node> fieldMetadata;
+ final Element element;
final Namer namer;
/// Set to true by user if class is indistinguishable from its superclass.
bool isTrivial = false;
- ClassBuilder(this.namer);
+ ClassBuilder(this.element, this.namer);
// Has the same signature as [DefineStubFunction].
void addProperty(String name, jsAst.Expression value) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
index a9e66df..c936173 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
@@ -34,7 +34,7 @@
task.needsMixinSupport = true;
}
- ClassBuilder builder = new ClassBuilder(namer);
+ ClassBuilder builder = new ClassBuilder(classElement, namer);
emitClassConstructor(classElement, builder, onlyForRti: onlyForRti);
emitFields(classElement, builder, superName, onlyForRti: onlyForRti);
emitClassGettersSetters(classElement, builder, onlyForRti: onlyForRti);
@@ -325,9 +325,15 @@
}
List<jsAst.Property> statics = new List<jsAst.Property>();
- ClassBuilder staticsBuilder = new ClassBuilder(namer);
+ ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer);
if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
- statics.add(staticsBuilder.toObjectInitializer().properties.single);
+ jsAst.ObjectInitializer initializer =
+ staticsBuilder.toObjectInitializer();
+ compiler.dumpInfoTask.registerElementAst(classElement,
+ initializer);
+ jsAst.Node property = initializer.properties.single;
+ compiler.dumpInfoTask.registerElementAst(classElement, property);
+ statics.add(property);
}
Map<OutputUnit, ClassBuilder> classPropertyLists =
@@ -346,7 +352,9 @@
}
// TODO(ahe): This method (generateClass) should return a jsAst.Expression.
- enclosingBuilder.addProperty(className, classBuilder.toObjectInitializer());
+ jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer();
+ compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue);
+ enclosingBuilder.addProperty(className, propertyValue);
String reflectionName = task.getReflectionName(classElement, className);
if (reflectionName != null) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 56b6ce4..97e459c 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -778,7 +778,7 @@
if (compiler.hasIncrementalSupport) {
ClassBuilder builder =
cachedClassBuilders.putIfAbsent(classElement, () {
- ClassBuilder builder = new ClassBuilder(namer);
+ ClassBuilder builder = new ClassBuilder(classElement, namer);
classEmitter.generateClass(
classElement, builder, additionalProperties[classElement]);
return builder;
@@ -857,7 +857,7 @@
backend.generatedCode.keys.where(isStaticFunction);
for (Element element in Elements.sortedByPosition(elements)) {
- ClassBuilder builder = new ClassBuilder(namer);
+ ClassBuilder builder = new ClassBuilder(element, namer);
containerBuilder.addMember(element, builder);
getElementDecriptor(element).properties.addAll(builder.properties);
}
@@ -878,9 +878,9 @@
js('$isolateProperties.# = #',
[namer.getNameOfGlobalField(element),
constantEmitter.referenceInInitializationContext(initialValue)]);
- buffer.write(jsAst.prettyPrint(init, compiler));
+ buffer.write(jsAst.prettyPrint(init, compiler,
+ monitor: compiler.dumpInfoTask));
buffer.write('$N');
- compiler.dumpInfoTask.registerGeneratedCode(element, init);
});
}
}
@@ -911,7 +911,8 @@
js.string(namer.getLazyInitializerName(element)),
code,
getter == null ? [] : [getter]]);
- buffer.write(jsAst.prettyPrint(init, compiler));
+ buffer.write(jsAst.prettyPrint(init, compiler,
+ monitor: compiler.dumpInfoTask));
buffer.write("$N");
}
}
@@ -939,7 +940,7 @@
jsAst.Expression init = js('#.# = #',
[namer.globalObjectForConstant(constant), name,
constantInitializerExpression(constant)]);
- buffer.write(jsAst.prettyPrint(init, compiler));
+ buffer.write(jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask));
buffer.write('$N');
}
if (compiler.hasIncrementalSupport && isMainBuffer) {
@@ -992,7 +993,7 @@
}''',
[namer.isolateName, makeConstListProperty, initName,
initName]),
- compiler));
+ compiler, monitor: compiler.dumpInfoTask));
buffer.write(N);
}
@@ -1070,14 +1071,14 @@
if (backend.needToInitializeIsolateAffinityTag) {
buffer.write(
jsAst.prettyPrint(generateIsolateAffinityTagInitialization(),
- compiler));
+ compiler, monitor: compiler.dumpInfoTask));
buffer.write(N);
}
if (backend.needToInitializeDispatchProperty) {
assert(backend.needToInitializeIsolateAffinityTag);
buffer.write(
jsAst.prettyPrint(generateDispatchPropertyNameInitialization(),
- compiler));
+ compiler, monitor: compiler.dumpInfoTask));
buffer.write(N);
}
@@ -1118,7 +1119,8 @@
})$N''', [mainCallClosure, mainCallClosure]);
buffer.write(';');
- buffer.write(jsAst.prettyPrint(invokeMain, compiler));
+ buffer.write(jsAst.prettyPrint(invokeMain,
+ compiler, monitor: compiler.dumpInfoTask));
buffer.write(N);
addComment('END invoke [main].', buffer);
}
@@ -1263,7 +1265,8 @@
buildLazyInitializerFunctionIfNecessary(),
buildFinishIsolateConstructor()]);
- buffer.write(jsAst.prettyPrint(decl, compiler).getText());
+ buffer.write(jsAst.prettyPrint(decl,
+ compiler, monitor: compiler.dumpInfoTask).getText());
if (compiler.enableMinification) buffer.write('\n');
}
@@ -1315,7 +1318,8 @@
for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) {
ClassBuilder descriptor =
- descriptors.putIfAbsent(outputUnit, () => new ClassBuilder(namer));
+ descriptors.putIfAbsent(outputUnit,
+ () => new ClassBuilder(library, namer));
if (descriptor.properties.isEmpty) continue;
bool isDeferred =
outputUnit != compiler.deferredLoadTask.mainOutputUnit;
@@ -1326,19 +1330,23 @@
CodeBuffer outputBuffer =
outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer());
int sizeBefore = outputBuffer.length;
+ compiler.dumpInfoTask.registerElementAst(library, metadata);
+ compiler.dumpInfoTask.registerElementAst(library, initializers);
outputBuffers[outputUnit]
..write('["$libraryName",$_')
..write('"${uri}",$_')
- ..write(metadata == null ? "" : jsAst.prettyPrint(metadata, compiler))
+ ..write(metadata == null ? "" : jsAst.prettyPrint(metadata,
+ compiler,
+ monitor: compiler.dumpInfoTask))
..write(',$_')
..write(namer.globalObjectFor(library))
..write(',$_')
- ..write(jsAst.prettyPrint(initializers, compiler))
+ ..write(jsAst.prettyPrint(initializers,
+ compiler,
+ monitor: compiler.dumpInfoTask))
..write(library == compiler.mainApp ? ',${n}1' : "")
..write('],$n');
int sizeAfter = outputBuffer.length;
- compiler.dumpInfoTask.codeSizeCounter
- .countCode(library, sizeAfter - sizeBefore);
}
}
@@ -1434,12 +1442,16 @@
// not see libraries that only have fields.
if (element.isLibrary) {
LibraryElement library = element;
- ClassBuilder builder = new ClassBuilder(namer);
+ ClassBuilder builder = new ClassBuilder(library, namer);
if (classEmitter.emitFields(
library, builder, null, emitStatics: true)) {
OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit;
+ jsAst.ObjectInitializer initializer =
+ builder.toObjectInitializer();
+ compiler.dumpInfoTask.registerElementAst(builder.element,
+ initializer);
getElementDescriptorForOutputUnit(library, mainUnit)
- .properties.addAll(builder.toObjectInitializer().properties);
+ .properties.addAll(initializer.properties);
}
}
}
@@ -1455,7 +1467,9 @@
var map = new jsAst.ObjectInitializer(properties);
mainBuffer.write(
jsAst.prettyPrint(
- js.statement('init.mangledNames = #', map), compiler));
+ js.statement('init.mangledNames = #', map),
+ compiler,
+ monitor: compiler.dumpInfoTask));
if (compiler.enableMinification) {
mainBuffer.write(';');
}
@@ -1472,7 +1486,8 @@
mainBuffer.write(
jsAst.prettyPrint(
js.statement('init.mangledGlobalNames = #', map),
- compiler));
+ compiler,
+ monitor: compiler.dumpInfoTask));
if (compiler.enableMinification) {
mainBuffer.write(';');
}
@@ -1624,6 +1639,7 @@
mainBuffer.write(
jsAst.prettyPrint(
precompiledFunctionAst, compiler,
+ monitor: compiler.dumpInfoTask,
allowVariableMinification: false).getText());
}
@@ -1693,7 +1709,7 @@
elementDescriptors.putIfAbsent(
element, () => new Map<OutputUnit, ClassBuilder>());
return descriptors.putIfAbsent(outputUnit,
- () => new ClassBuilder(namer));
+ () => new ClassBuilder(element, namer));
}
ClassBuilder getElementDecriptor(Element element) {
@@ -1741,7 +1757,7 @@
..write(
jsAst.prettyPrint(
getReflectionDataParser(classesCollector, backend),
- compiler))
+ compiler, monitor: compiler.dumpInfoTask))
..write(')')
..write('([$n')
..addBuffer(outputBuffer)
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
index 1049944..c4142ce 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
@@ -305,7 +305,9 @@
'function(#) { return #.#(#); }',
[ parameters, buildGetter(), closureCallName, arguments]);
+ compiler.dumpInfoTask.registerElementAst(member, function);
addProperty(invocationName, function);
+
}
}
}
@@ -386,11 +388,13 @@
canTearOff || canBeReflected || canBeApplied;
if (!needStructuredInfo) {
builder.addProperty(name, code);
+ compiler.dumpInfoTask.registerElementAst(member, code);
if (needsStubs) {
addParameterStubs(
member,
(Selector selector, jsAst.Fun function) {
builder.addProperty(namer.invocationName(selector), function);
+ compiler.dumpInfoTask.registerElementAst(member, function);
});
}
return;
@@ -539,7 +543,10 @@
} else if (isClosure && canBeApplied) {
expressions.add(js.string(member.name));
}
- builder.addProperty(name, new jsAst.ArrayInitializer.from(expressions));
+ jsAst.ArrayInitializer arrayInit =
+ new jsAst.ArrayInitializer.from(expressions);
+ builder.addProperty(name, arrayInit);
+ compiler.dumpInfoTask.registerElementAst(member, arrayInit);
}
void addMemberField(VariableElement member, ClassBuilder builder) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
index cd51594..3ec8830 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -60,10 +60,10 @@
ClosureClassMap closureData =
compiler.closureToClassMapper.closureMappingCache[node];
if (closureData != null) {
- ClosureFieldElement thisElement =
+ ClosureFieldElement thisLocal =
closureData.getFreeVariableElement(closureData.thisLocal);
- if (thisElement != null) {
- String thisName = namer.instanceFieldPropertyName(thisElement);
+ if (thisLocal != null) {
+ String thisName = namer.instanceFieldPropertyName(thisLocal);
thisAccess = js('this.#', thisName);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
index 2a3bcc1..7f3899a 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
@@ -166,25 +166,26 @@
final bool isNamed;
factory Dart2JsParameterMirror(Dart2JsDeclarationMirror owner,
- ParameterElement element,
+ FormalElement element,
{bool isOptional: false,
bool isNamed: false}) {
- if (element is FieldParameterElement) {
+ if (element is InitializingFormalElement) {
return new Dart2JsFieldParameterMirror(
owner, element, isOptional, isNamed);
+ } else {
+ return new Dart2JsParameterMirror._normal(
+ owner, element, isOptional, isNamed);
}
- return new Dart2JsParameterMirror._normal(
- owner, element, isOptional, isNamed);
}
Dart2JsParameterMirror._normal(Dart2JsDeclarationMirror owner,
- ParameterElement element,
+ FormalElement element,
this.isOptional,
this.isNamed)
: this.owner = owner,
super(owner.mirrorSystem, element);
- ParameterElement get _element => super._element;
+ FormalElement get _element => super._element;
TypeMirror get type => owner._getTypeMirror(_element.type);
@@ -196,18 +197,23 @@
if (hasDefaultValue) {
// TODO(johnniwinther): Get the constant from the [TreeElements]
// associated with the enclosing method.
+ ParameterElement parameter = _element;
Constant constant = mirrorSystem.compiler.constants
- .getConstantForVariable(_element);
- assert(invariant(_element, constant != null,
+ .getConstantForVariable(parameter);
+ assert(invariant(parameter, constant != null,
message: "Missing constant for parameter "
- "$_element with default value."));
+ "$parameter with default value."));
return _convertConstantToInstanceMirror(mirrorSystem, constant);
}
return null;
}
bool get hasDefaultValue {
- return _element.initializer != null;
+ if (_element is ParameterElement) {
+ ParameterElement parameter = _element;
+ return parameter.initializer != null;
+ }
+ return false;
}
bool get isInitializingFormal => false;
@@ -218,12 +224,12 @@
class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror {
Dart2JsFieldParameterMirror(Dart2JsDeclarationMirror method,
- FieldParameterElement element,
+ InitializingFormalElement element,
bool isOptional,
bool isNamed)
: super._normal(method, element, isOptional, isNamed);
- FieldParameterElement get _fieldParameterElement => _element;
+ InitializingFormalElement get _fieldParameterElement => _element;
bool get isInitializingFormal => true;
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
index c7dab3d..c3851f0 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
@@ -491,8 +491,9 @@
static ResolvedNode defaultValueSyntaxOf(Dart2JsParameterMirror parameter) {
if (!parameter.hasDefaultValue) return null;
- var node = parameter._element.initializer;
- var treeElements = parameter._element.treeElements;
+ ParameterElement parameterElement = parameter._element;
+ var node = parameterElement.initializer;
+ var treeElements = parameterElement.treeElements;
return new ResolvedNode(node, treeElements, parameter.mirrorSystem);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 8e84eb7..5fd785e 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -786,6 +786,110 @@
static NativeBehavior NONE = new NativeBehavior();
+ /// Processes the type specification string of a call to JS and stores the
+ /// result in the [typesReturned] and [typesInstantiated].
+ ///
+ /// Two forms of the string is supported:
+ /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn'
+ /// which defines the types returned and for the later form also created by
+ /// the call to JS.
+ /// 2) A sequence of the form '<tag>:<type-string>;' where <tag> is either
+ /// 'returns' or 'creates' and where <type-string> is a type string like in
+ /// 1). The type string marked by 'returns' defines the types returned and
+ /// 'creates' defines the types created by the call to JS. Each tag kind
+ /// can only occur once in the sequence.
+ ///
+ /// [specString] is the specification string, [resolveType] resolves named
+ /// types into type values, [typesReturned] and [typesInstantiated] collects
+ /// the types defined by the specification string, and [objectType] and
+ /// [nullType] define the types for `Object` and `Null`, respectively. The
+ /// latter is used for the type strings of the form '' and 'var'.
+ // TODO(johnniwinther): Use ';' as a separator instead of a terminator.
+ static void processSpecString(
+ DiagnosticListener listener,
+ Spannable spannable,
+ String specString,
+ {dynamic resolveType(String typeString),
+ List typesReturned, List typesInstantiated,
+ objectType, nullType}) {
+
+ /// Resolve a type string of one of the three forms:
+ /// * 'void' - in which case [onVoid] is called,
+ /// * '' or 'var' - in which case [onVar] is called,
+ /// * 'T1|...|Tn' - in which case [onType] is called for each Ti.
+ void resolveTypesString(String typesString,
+ {onVoid(), onVar(), onType(type)}) {
+ // Various things that are not in fact types.
+ if (typesString == 'void') {
+ if (onVoid != null) {
+ onVoid();
+ }
+ return;
+ }
+ if (typesString == '' || typesString == 'var') {
+ if (onVar != null) {
+ onVar();
+ }
+ return;
+ }
+ for (final typeString in typesString.split('|')) {
+ onType(resolveType(typeString));
+ }
+ }
+
+ if (specString.contains(':')) {
+ /// Find and remove a substring of the form 'tag:<type-string>;' from
+ /// [specString].
+ String getTypesString(String tag) {
+ String marker = '$tag:';
+ int startPos = specString.indexOf(marker);
+ if (startPos == -1) return null;
+ int endPos = specString.indexOf(';', startPos);
+ if (endPos == -1) return null;
+ String typeString =
+ specString.substring(startPos + marker.length, endPos);
+ specString = '${specString.substring(0, startPos)}'
+ '${specString.substring(endPos + 1)}'.trim();
+ return typeString;
+ }
+
+ String returns = getTypesString('returns');
+ if (returns != null) {
+ resolveTypesString(returns, onVar: () {
+ typesReturned.add(objectType);
+ typesReturned.add(nullType);
+ }, onType: (type) {
+ typesReturned.add(type);
+ });
+ }
+
+ String creates = getTypesString('creates');
+ if (creates != null) {
+ resolveTypesString(creates, onVoid: () {
+ listener.internalError(spannable,
+ "Invalid type string 'creates:$creates'");
+ }, onVar: () {
+ listener.internalError(spannable,
+ "Invalid type string 'creates:$creates'");
+ }, onType: (type) {
+ typesInstantiated.add(type);
+ });
+ }
+
+ if (!specString.isEmpty) {
+ listener.internalError(spannable, "Invalid JS type string.");
+ }
+ } else {
+ resolveTypesString(specString, onVar: () {
+ typesReturned.add(objectType);
+ typesReturned.add(nullType);
+ }, onType: (type) {
+ typesInstantiated.add(type);
+ typesReturned.add(type);
+ });
+ }
+ }
+
static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
// The first argument of a JS-call is a string encoding various attributes
// of the code.
@@ -810,26 +914,30 @@
compiler.internalError(argNodes.head, "Unexpected JS first argument.");
}
- var behavior = new NativeBehavior();
- behavior.codeTemplate = js.js.parseForeignJS(code.dartString.slowToString());
- new SideEffectsVisitor(behavior.sideEffects).visit(behavior.codeTemplate.ast);
+ NativeBehavior behavior = new NativeBehavior();
+ behavior.codeTemplate =
+ js.js.parseForeignJS(code.dartString.slowToString());
+ new SideEffectsVisitor(behavior.sideEffects)
+ .visit(behavior.codeTemplate.ast);
String specString = specLiteral.dartString.slowToString();
- // Various things that are not in fact types.
- if (specString == 'void') return behavior;
- if (specString == '' || specString == 'var') {
- behavior.typesReturned.add(compiler.objectClass.computeType(compiler));
- behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
- return behavior;
- }
- for (final typeString in specString.split('|')) {
- var type = _parseType(typeString, compiler,
+
+ resolveType(String typeString) {
+ return _parseType(
+ typeString,
+ compiler,
(name) => resolver.resolveTypeFromString(specLiteral, name),
jsCall);
- behavior.typesInstantiated.add(type);
- behavior.typesReturned.add(type);
}
+ processSpecString(compiler, jsCall,
+ specString,
+ resolveType: resolveType,
+ typesReturned: behavior.typesReturned,
+ typesInstantiated: behavior.typesInstantiated,
+ objectType: compiler.objectClass.computeType(compiler),
+ nullType: compiler.nullClass.computeType(compiler));
+
return behavior;
}
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 541091c..22c2d9d 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -230,11 +230,11 @@
}
}
-void patchElement(leg.DiagnosticListener listener,
+void patchElement(leg.Compiler compiler,
Element origin,
Element patch) {
if (origin == null) {
- listener.reportError(
+ compiler.reportError(
patch, leg.MessageKind.PATCH_NON_EXISTING, {'name': patch.name});
return;
}
@@ -243,48 +243,168 @@
origin.isFunction ||
origin.isAbstractField)) {
// TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- listener.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE);
+ compiler.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE);
return;
}
if (patch.isClass) {
- tryPatchClass(listener, origin, patch);
+ tryPatchClass(compiler, origin, patch);
} else if (patch.isGetter) {
- tryPatchGetter(listener, origin, patch);
+ tryPatchGetter(compiler, origin, patch);
} else if (patch.isSetter) {
- tryPatchSetter(listener, origin, patch);
+ tryPatchSetter(compiler, origin, patch);
} else if (patch.isConstructor) {
- tryPatchConstructor(listener, origin, patch);
+ tryPatchConstructor(compiler, origin, patch);
} else if(patch.isFunction) {
- tryPatchFunction(listener, origin, patch);
+ tryPatchFunction(compiler, origin, patch);
} else {
// TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- listener.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE);
+ compiler.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE);
}
}
-void tryPatchClass(leg.DiagnosticListener listener,
- Element origin,
- ClassElement patch) {
+void tryPatchClass(leg.Compiler compiler,
+ Element origin,
+ ClassElement patch) {
if (!origin.isClass) {
- listener.reportError(
+ compiler.reportError(
origin, leg.MessageKind.PATCH_NON_CLASS, {'className': patch.name});
- listener.reportInfo(
+ compiler.reportInfo(
patch, leg.MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name});
return;
}
- patchClass(listener, origin, patch);
+ patchClass(compiler, origin, patch);
}
-void patchClass(leg.DiagnosticListener listener,
+void patchClass(leg.Compiler compiler,
ClassElementX origin,
ClassElementX patch) {
if (origin.isPatched) {
- listener.internalError(origin,
+ compiler.internalError(origin,
"Patching the same class more than once.");
}
origin.applyPatch(patch);
+ checkNativeAnnotation(compiler, patch);
}
+/// Check whether [cls] has a `@Native(...)` annotation, and if so, set its
+/// native name from the annotation.
+checkNativeAnnotation(leg.Compiler compiler, ClassElement cls) {
+ EagerAnnotationHandler.checkAnnotation(compiler, cls,
+ const NativeAnnotationHandler());
+}
+
+/// Abstract interface for pre-resolution detection of metadata.
+///
+/// The detection is handled in two steps:
+/// - match the annotation syntactically and assume that the annotation is valid
+/// if it looks correct,
+/// - setup a deferred action to check that the annotation has a valid constant
+/// value and report an internal error if not.
+abstract class EagerAnnotationHandler {
+ /// Checks that [annotation] looks like a matching annotation and optionally
+ /// applies actions on [element]. Returns `true` if the annotation matched.
+ bool apply(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation);
+
+ /// Checks that the annotation value is valid.
+ void validate(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation,
+ leg.Constant constant);
+
+
+ /// Checks [element] for metadata matching the [handler]. Return `true` if
+ /// matching metadata was found.
+ static bool checkAnnotation(leg.Compiler compiler,
+ Element element,
+ EagerAnnotationHandler handler) {
+ for (Link<MetadataAnnotation> link = element.metadata;
+ !link.isEmpty;
+ link = link.tail) {
+ MetadataAnnotation annotation = link.head;
+ if (handler.apply(compiler, element, annotation)) {
+ // TODO(johnniwinther): Perform this check in
+ // [Compiler.onLibrariesLoaded].
+ compiler.enqueuer.resolution.addDeferredAction(element, () {
+ annotation.ensureResolved(compiler);
+ handler.validate(compiler, element, annotation, annotation.value);
+ });
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/// Annotation handler for pre-resolution detection of `@Native(...)`
+/// annotations.
+class NativeAnnotationHandler implements EagerAnnotationHandler {
+ const NativeAnnotationHandler();
+
+ String getNativeAnnotation(MetadataAnnotation annotation) {
+ if (annotation.beginToken != null &&
+ annotation.beginToken.next.value == 'Native') {
+ // Skipping '@', 'Native', and '('.
+ Token argument = annotation.beginToken.next.next.next;
+ if (argument is StringToken) {
+ return argument.value;
+ }
+ }
+ return null;
+ }
+
+ bool apply(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation) {
+ if (element.isClass) {
+ String native = getNativeAnnotation(annotation);
+ if (native != null) {
+ ClassElementX declaration = element.declaration;
+ declaration.setNative(native);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void validate(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation,
+ leg.Constant constant) {
+ if (constant.computeType(compiler).element !=
+ compiler.nativeAnnotationClass) {
+ compiler.internalError(annotation, 'Invalid @Native(...) annotation.');
+ }
+ }
+}
+
+/// Annotation handler for pre-resolution detection of `@patch` annotations.
+class PatchAnnotationHandler implements EagerAnnotationHandler {
+ const PatchAnnotationHandler();
+
+ bool isPatchAnnotation(MetadataAnnotation annotation) {
+ return annotation.beginToken != null &&
+ annotation.beginToken.next.value == 'patch';
+ }
+
+ bool apply(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation) {
+ return isPatchAnnotation(annotation);
+ }
+
+ void validate(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation,
+ leg.Constant constant) {
+ if (constant != compiler.patchConstant) {
+ compiler.internalError(annotation, 'Invalid patch annotation.');
+ }
+ }
+}
+
+
void tryPatchGetter(leg.DiagnosticListener listener,
Element origin,
FunctionElement patch) {
@@ -381,24 +501,6 @@
// TODO(johnniwinther): Add unittest when patch is (real) metadata.
bool isPatchElement(leg.Compiler compiler, Element element) {
- // TODO(lrn): More checks needed if we introduce metadata for real.
- // In that case, it must have the identifier "native" as metadata.
- for (Link<MetadataAnnotation> link = element.metadata;
- !link.isEmpty;
- link = link.tail) {
- MetadataAnnotation annotation = link.head;
- if (annotation.beginToken != null &&
- annotation.beginToken.next.value == 'patch') {
- // TODO(johnniwinther): Perform this check in
- // [Compiler.onLibrariesLoaded].
- compiler.enqueuer.resolution.addDeferredAction(element, () {
- annotation.ensureResolved(compiler);
- if (annotation.value != compiler.patchConstant) {
- compiler.internalError(annotation, 'Invalid patch annotation.');
- }
- });
- return true;
- }
- }
- return false;
+ return EagerAnnotationHandler.checkAnnotation(compiler, element,
+ const PatchAnnotationHandler());
}
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 5a4654b..0061fd7 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1183,7 +1183,8 @@
return measure(() => SignatureResolver.analyze(
compiler, node.parameters, node.returnType, element,
new ResolutionRegistry(compiler, element),
- defaultValuesError: defaultValuesError));
+ defaultValuesError: defaultValuesError,
+ createRealParameters: true));
});
}
@@ -1293,13 +1294,13 @@
MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name});
}
- void checkForDuplicateInitializers(VariableElementX field, Node init) {
+ void checkForDuplicateInitializers(FieldElementX field, Node init) {
// [field] can be null if it could not be resolved.
if (field == null) return;
String name = field.name;
if (initialized.containsKey(field)) {
reportDuplicateInitializerError(field, init, initialized[field]);
- } else if (field.modifiers.isFinal) {
+ } else if (field.isFinal) {
field.parseNode(visitor.compiler);
Expression initializer = field.initializer;
if (initializer != null) {
@@ -1463,9 +1464,9 @@
// that we can ensure that fields are initialized only once.
FunctionSignature functionParameters = constructor.functionSignature;
functionParameters.forEachParameter((ParameterElement element) {
- if (identical(element.kind, ElementKind.FIELD_PARAMETER)) {
- FieldParameterElement fieldParameter = element;
- checkForDuplicateInitializers(fieldParameter.fieldElement,
+ if (element.isInitializingFormal) {
+ InitializingFormalElement initializingFormal = element;
+ checkForDuplicateInitializers(initializingFormal.fieldElement,
element.initializer);
}
});
@@ -1508,7 +1509,7 @@
Compiler compiler = visitor.compiler;
FunctionSignature signature = constructor.functionSignature;
signature.forEachParameter((ParameterElement parameter) {
- if (parameter.isFieldParameter) {
+ if (parameter.isInitializingFormal) {
Node node = parameter.node;
error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
}
@@ -2032,7 +2033,7 @@
// fields.
inInstanceContext = (element.isInstanceMember && !element.isField)
|| element.isGenerativeConstructor,
- this.currentClass = element.isMember ? element.enclosingClass
+ this.currentClass = element.isClassMember ? element.enclosingClass
: null,
this.statementScope = new StatementScope(),
scope = useEnclosingScope
@@ -2222,7 +2223,7 @@
Node parameterNode = variableDefinitions.definitions.nodes.head;
// Field parameters (this.x) are not visible inside the constructor. The
// fields they reference are visible, but must be resolved independently.
- if (element.kind == ElementKind.FIELD_PARAMETER) {
+ if (element.isInitializingFormal) {
registry.useElement(parameterNode, element);
} else {
defineElement(parameterNode, element);
@@ -2323,7 +2324,7 @@
enclosingElement);
function.functionSignatureCache =
SignatureResolver.analyze(compiler, node.parameters, node.returnType,
- function, registry);
+ function, registry, createRealParameters: true);
Scope oldScope = scope; // The scope is modified by [setupFunction].
setupFunction(node, function);
defineElement(node, function, doAddToScope: node.name != null);
@@ -3854,7 +3855,7 @@
element.functionSignature = signature;
scope = new MethodScope(scope, element);
- signature.forEachParameter((ParameterElement element) {
+ signature.forEachParameter((FormalElement element) {
defineElement(element.node, element);
});
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
index 1c06c20..a5f8778 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
@@ -14,11 +14,14 @@
show BaseClassElementX,
ConstructorElementX,
ErroneousElementX,
- FieldParameterElementX,
+ FieldElementX,
+ FormalElementX,
FunctionElementX,
FunctionSignatureX,
+ InitializingFormalElementX,
LabelElementX,
LocalFunctionElementX,
+ LocalParameterElementX,
LocalVariableElementX,
MetadataAnnotationX,
MixinApplicationElementX,
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
index 97b9ec0..08bb37f 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
@@ -7,11 +7,12 @@
/**
* [SignatureResolver] resolves function signatures.
*/
-class SignatureResolver extends MappingVisitor<ParameterElementX> {
+class SignatureResolver extends MappingVisitor<FormalElementX> {
final ResolverVisitor resolver;
final FunctionTypedElement enclosingElement;
final Scope scope;
final MessageKind defaultValuesError;
+ final bool createRealParameters;
Link<Element> optionalParameters = const Link<Element>();
int optionalParameterCount = 0;
bool isOptionalParameter = false;
@@ -21,7 +22,8 @@
SignatureResolver(Compiler compiler,
FunctionTypedElement enclosingElement,
ResolutionRegistry registry,
- {this.defaultValuesError})
+ {this.defaultValuesError,
+ this.createRealParameters})
: this.enclosingElement = enclosingElement,
this.scope = enclosingElement.buildScope(),
this.resolver =
@@ -43,7 +45,7 @@
optionalParameters = elements.toLink();
}
- ParameterElementX visitVariableDefinitions(VariableDefinitions node) {
+ FormalElementX visitVariableDefinitions(VariableDefinitions node) {
Link<Node> definitions = node.definitions.nodes;
if (definitions.isEmpty) {
internalError(node, 'no parameter definition');
@@ -68,7 +70,7 @@
internalError(node, 'function type parameters not supported');
}
currentDefinitions = node;
- ParameterElementX element = definition.accept(this);
+ FormalElementX element = definition.accept(this);
if (currentDefinitions.metadata != null) {
element.metadata = compiler.resolver.resolveMetadata(element, node);
}
@@ -85,7 +87,7 @@
}
}
- void computeParameterType(ParameterElementX element,
+ void computeParameterType(FormalElementX element,
[VariableElement fieldElement]) {
void computeFunctionType(FunctionExpression functionExpression) {
FunctionSignature functionSignature = SignatureResolver.analyze(
@@ -149,22 +151,27 @@
// The only valid [Send] can be in constructors and must be of the form
// [:this.x:] (where [:x:] represents an instance field).
- FieldParameterElementX visitSend(Send node) {
+ InitializingFormalElementX visitSend(Send node) {
return createFieldParameter(node, null);
}
- ParameterElementX createParameter(Identifier name, Expression initializer) {
+ FormalElementX createParameter(Identifier name, Expression initializer) {
validateName(name);
- ParameterElementX parameter = new ParameterElementX(
- ElementKind.PARAMETER, enclosingElement,
- currentDefinitions, name, initializer);
+ FormalElementX parameter;
+ if (createRealParameters) {
+ parameter = new LocalParameterElementX(
+ enclosingElement, currentDefinitions, name, initializer);
+ } else {
+ parameter = new FormalElementX(
+ ElementKind.PARAMETER, enclosingElement, currentDefinitions, name);
+ }
computeParameterType(parameter);
return parameter;
}
- FieldParameterElementX createFieldParameter(Send node,
- Expression initializer) {
- FieldParameterElementX element;
+ InitializingFormalElementX createFieldParameter(Send node,
+ Expression initializer) {
+ InitializingFormalElementX element;
if (node.receiver.asIdentifier() == null ||
!node.receiver.asIdentifier().isThis()) {
error(node, MessageKind.INVALID_PARAMETER);
@@ -182,7 +189,7 @@
} else if (!fieldElement.isInstanceMember) {
error(node, MessageKind.NOT_INSTANCE_FIELD, {'fieldName': name});
}
- element = new FieldParameterElementX(enclosingElement,
+ element = new InitializingFormalElementX(enclosingElement,
currentDefinitions, name, initializer, fieldElement);
computeParameterType(element, fieldElement);
}
@@ -191,7 +198,7 @@
/// A [SendSet] node is an optional parameter with a default value.
Element visitSendSet(SendSet node) {
- ParameterElementX element;
+ FormalElementX element;
if (node.receiver != null) {
element = createFieldParameter(node, node.arguments.first);
} else if (node.selector.asIdentifier() != null ||
@@ -239,15 +246,21 @@
/**
* Resolves formal parameters and return type of a [FunctionExpression]
* to a [FunctionSignature].
+ *
+ * If [createRealParameters] is `true`, the parameters will be
+ * real parameters implementing the [ParameterElement] interface. Otherwise,
+ * the parameters will only implement [FormalElement].
*/
static FunctionSignature analyze(Compiler compiler,
NodeList formalParameters,
Node returnNode,
FunctionTypedElement element,
ResolutionRegistry registry,
- {MessageKind defaultValuesError}) {
+ {MessageKind defaultValuesError,
+ bool createRealParameters: false}) {
SignatureResolver visitor = new SignatureResolver(compiler, element,
- registry, defaultValuesError: defaultValuesError);
+ registry, defaultValuesError: defaultValuesError,
+ createRealParameters: createRealParameters);
Link<Element> parameters = const Link<Element>();
int requiredParameterCount = 0;
if (formalParameters == null) {
@@ -297,7 +310,7 @@
}
}
LinkBuilder<DartType> parameterTypes = new LinkBuilder<DartType>();
- for (ParameterElement parameter in parameters) {
+ for (FormalElement parameter in parameters) {
parameterTypes.addLast(parameter.type);
}
List<DartType> optionalParameterTypes = const <DartType>[];
@@ -313,7 +326,7 @@
LinkBuilder<String> namedParametersBuilder = new LinkBuilder<String>();
LinkBuilder<DartType> namedParameterTypesBuilder =
new LinkBuilder<DartType>();
- for (ParameterElement parameter in orderedOptionalParameters) {
+ for (FormalElement parameter in orderedOptionalParameters) {
namedParametersBuilder.addLast(parameter.name);
namedParameterTypesBuilder.addLast(parameter.type);
}
@@ -324,7 +337,7 @@
// TODO(karlklose); replace when [visitor.optinalParameters] is a [List].
LinkBuilder<DartType> optionalParameterTypesBuilder =
new LinkBuilder<DartType>();
- for (ParameterElement parameter in visitor.optionalParameters) {
+ for (FormalElement parameter in visitor.optionalParameters) {
optionalParameterTypesBuilder.addLast(parameter.type);
}
optionalParameterTypes = optionalParameterTypesBuilder.toLink()
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index e76413f..3be7141 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -918,7 +918,7 @@
int id = idGenerator();
PartialClassElement element = new PartialClassElement(
name.source, beginToken, endToken, compilationUnitElement, id);
- element.nativeTagInfo = nativeTagInfo;
+ element.setNative(nativeTagInfo);
pushElement(element);
rejectBuiltInIdentifier(name);
}
@@ -2220,7 +2220,7 @@
FunctionExpression parseNode(DiagnosticListener listener) {
if (cachedNode != null) return cachedNode;
parseFunction(Parser p) {
- if (isMember && modifiers.isFactory) {
+ if (isClassMember && modifiers.isFactory) {
p.parseFactoryMethod(beginToken);
} else {
p.parseFunction(beginToken, getOrSet);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 2b13266..460614d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -10,8 +10,9 @@
/// try-catch statement.
class SyntheticLocal extends Local {
final String name;
+ final ExecutableElement executableContext;
- SyntheticLocal(this.name);
+ SyntheticLocal(this.name, this.executableContext);
}
class SsaBuilderTask extends CompilerTask {
@@ -65,7 +66,7 @@
}
if (compiler.tracer.isEnabled) {
String name;
- if (element.isMember) {
+ if (element.isClassMember) {
String className = element.enclosingClass.name;
String memberName = element.name;
name = "$className.$memberName";
@@ -110,12 +111,15 @@
new Map<Local, CapturedVariable>();
SsaBuilder builder;
ClosureClassMap closureData;
+ Map<TypeVariableType, TypeVariableLocal> typeVariableLocals =
+ new Map<TypeVariableType, TypeVariableLocal>();
+ final ExecutableElement executableContext;
/// The class that defines the current type environment or null if no type
/// variables are in scope.
- final ClassElement contextClass;
+ ClassElement get contextClass => executableContext.contextClass;
- LocalsHandler(this.builder, this.contextClass);
+ LocalsHandler(this.builder, this.executableContext);
/// Substituted type variables occurring in [type] into the context of
/// [contextClass].
@@ -140,7 +144,7 @@
LocalsHandler.from(LocalsHandler other)
: directLocals = new Map<Local, HInstruction>.from(other.directLocals),
redirectionMapping = other.redirectionMapping,
- contextClass = other.contextClass,
+ executableContext = other.executableContext,
builder = other.builder,
closureData = other.closureData;
@@ -189,7 +193,7 @@
// Make sure that accesses to the boxed locals go into the box. We also
// need to make sure that parameters are copied into the box if necessary.
scopeData.forEachCapturedVariable(
- (VariableElement from, BoxFieldElement to) {
+ (LocalVariableElement from, BoxFieldElement to) {
// The [from] can only be a parameter for function-scopes and not
// loop scopes.
if (from.isParameter && !element.isGenerativeConstructorBody) {
@@ -214,12 +218,12 @@
* of elements from the old box into the new box.
*/
void updateCaptureBox(BoxLocal boxElement,
- List<VariableElement> toBeCopiedElements) {
+ List<LocalVariableElement> toBeCopiedElements) {
// Create a new box and copy over the values from the old box into the
// new one.
HInstruction oldBox = readLocal(boxElement);
HInstruction newBox = createBox();
- for (VariableElement boxedVariable in toBeCopiedElements) {
+ for (LocalVariableElement boxedVariable in toBeCopiedElements) {
// [readLocal] uses the [boxElement] to find its box. By replacing it
// behind its back we can still get to the old values.
updateLocal(boxElement, oldBox);
@@ -303,7 +307,7 @@
if (backend.isInterceptedMethod(element)) {
bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
String name = isInterceptorClass ? 'receiver' : '_';
- SyntheticLocal parameter = new SyntheticLocal(name);
+ SyntheticLocal parameter = new SyntheticLocal(name, executableContext);
HParameterValue value =
new HParameterValue(parameter, builder.getTypeOfThis());
builder.graph.explicitReceiverParameter = value;
@@ -314,7 +318,8 @@
directLocals[closureData.thisLocal] = value;
}
} else if (isNativeUpgradeFactory) {
- SyntheticLocal parameter = new SyntheticLocal('receiver');
+ SyntheticLocal parameter =
+ new SyntheticLocal('receiver', executableContext);
// Unlike `this`, receiver is nullable since direct calls to generative
// constructor call the constructor with `null`.
HParameterValue value =
@@ -424,6 +429,12 @@
});
}
+ Local getTypeVariableAsLocal(TypeVariableType type) {
+ return typeVariableLocals.putIfAbsent(type, () {
+ return new TypeVariableLocal(type, executableContext);
+ });
+ }
+
/**
* Sets the [element] to [value]. If the element is boxed or stored in a
* closure then the method generates code to set the value.
@@ -588,7 +599,7 @@
otherLocals.directLocals.forEach((Local local,
HInstruction instruction) {
// We know 'this' cannot be modified.
- if (identical(local, closureData.thisLocal)) {
+ if (local == closureData.thisLocal) {
assert(directLocals[local] == instruction);
joinedLocals[local] = instruction;
} else {
@@ -978,7 +989,7 @@
this.work = work,
this.rti = backend.rti,
super(work.resolutionTree, backend.compiler) {
- localsHandler = new LocalsHandler(this, work.element.contextClass);
+ localsHandler = new LocalsHandler(this, work.element);
sourceElementStack.add(work.element);
}
@@ -1376,8 +1387,8 @@
TypeMask getTypeOfThis() {
TypeMask result = cachedTypeOfThis;
if (result == null) {
- ThisLocal element = localsHandler.closureData.thisLocal;
- ClassElement cls = element.enclosingClass;
+ ThisLocal local = localsHandler.closureData.thisLocal;
+ ClassElement cls = local.enclosingClass;
if (compiler.world.isUsedAsMixin(cls)) {
// If the enclosing class is used as a mixin, [:this:] can be
// of the class that mixins the enclosing class. These two
@@ -1510,7 +1521,7 @@
return bodyElement;
}
- HParameterValue addParameter(Local parameter, TypeMask type) {
+ HParameterValue addParameter(Entity parameter, TypeMask type) {
assert(inliningStack.isEmpty);
HParameterValue result = new HParameterValue(parameter, type);
if (lastAddedParameter == null) {
@@ -1533,11 +1544,11 @@
*/
void setupStateForInlining(FunctionElement function,
List<HInstruction> compiledArguments) {
- localsHandler = new LocalsHandler(this, function.contextClass);
+ localsHandler = new LocalsHandler(this, function);
localsHandler.closureData =
compiler.closureToClassMapper.computeClosureToClassMapping(
function, function.node, elements);
- returnLocal = new SyntheticLocal("result");
+ returnLocal = new SyntheticLocal("result", function);
localsHandler.updateLocal(returnLocal,
graph.addConstantNull(compiler));
@@ -1560,7 +1571,8 @@
&& backend.classNeedsRti(enclosing)) {
enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
HInstruction argument = compiledArguments[argumentIndex++];
- localsHandler.updateLocal(typeVariable.element, argument);
+ localsHandler.updateLocal(
+ localsHandler.getTypeVariableAsLocal(typeVariable), argument);
});
}
assert(argumentIndex == compiledArguments.length);
@@ -1666,14 +1678,15 @@
variables.moveNext();
TypeVariableType typeVariable = variables.current;
localsHandler.updateLocal(
- typeVariable.element,
+ localsHandler.getTypeVariableAsLocal(typeVariable),
analyzeTypeArgument(argument));
});
} else {
// If the supertype is a raw type, we need to set to null the
// type variables.
for (TypeVariableType variable in typeVariables) {
- localsHandler.updateLocal(variable.element,
+ localsHandler.updateLocal(
+ localsHandler.getTypeVariableAsLocal(variable),
graph.addConstantNull(compiler));
}
}
@@ -1699,8 +1712,8 @@
localsHandler.updateLocal(parameter, argument);
// Don't forget to update the field, if the parameter is of the
// form [:this.x:].
- if (parameter.isFieldParameter) {
- FieldParameterElement fieldParameterElement = parameter;
+ if (parameter.isInitializingFormal) {
+ InitializingFormalElement fieldParameterElement = parameter;
fieldValues[fieldParameterElement.fieldElement] = argument;
}
});
@@ -1902,10 +1915,10 @@
// Compile field-parameters such as [:this.x:].
FunctionSignature params = functionElement.functionSignature;
params.orderedForEachParameter((ParameterElement parameter) {
- if (parameter.isFieldParameter) {
+ if (parameter.isInitializingFormal) {
// If the [element] is a field-parameter then
// initialize the field element with its value.
- FieldParameterElement fieldParameter = parameter;
+ InitializingFormalElement fieldParameter = parameter;
HInstruction parameterValue =
localsHandler.readLocal(fieldParameter);
fieldValues[fieldParameter.fieldElement] = parameterValue;
@@ -2021,7 +2034,8 @@
List<HInstruction> typeArguments = <HInstruction>[];
classElement.typeVariables.forEach((TypeVariableType typeVariable) {
- HInstruction argument = localsHandler.readLocal(typeVariable.element);
+ HInstruction argument = localsHandler.readLocal(
+ localsHandler.getTypeVariableAsLocal(typeVariable));
if (allIndexed && !isIndexedTypeArgumentGet(argument)) {
allIndexed = false;
}
@@ -2076,7 +2090,8 @@
currentClass.typeVariables.forEach((TypeVariableType argument) {
// TODO(johnniwinther): Substitute [argument] with
// `localsHandler.substInContext(argument)`.
- bodyCallInputs.add(localsHandler.readLocal(argument.element));
+ bodyCallInputs.add(localsHandler.readLocal(
+ localsHandler.getTypeVariableAsLocal(argument)));
});
}
@@ -2131,7 +2146,8 @@
enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
HParameterValue param = addParameter(
typeVariable.element, backend.nonNullType);
- localsHandler.directLocals[typeVariable.element] = param;
+ localsHandler.directLocals[
+ localsHandler.getTypeVariableAsLocal(typeVariable)] = param;
});
}
@@ -2873,7 +2889,7 @@
visitFunctionDeclaration(ast.FunctionDeclaration node) {
assert(isReachable);
visit(node.function);
- FunctionElement localFunction = elements[node];
+ LocalFunctionElement localFunction = elements[node];
localsHandler.updateLocal(localFunction, pop());
}
@@ -3069,7 +3085,7 @@
noSuchMethodTargetSymbolString(element, 'get'),
argumentNodes: const Link<ast.Node>());
} else {
- TypedElement local = element;
+ LocalElement local = element;
stack.add(localsHandler.readLocal(local));
}
}
@@ -3123,7 +3139,7 @@
argumentValues: arguments);
} else {
stack.add(value);
- TypedElement local = element;
+ LocalElement local = element;
// If the value does not already have a name, give it here.
if (value.sourceElement == null) {
value.sourceElement = local;
@@ -3378,7 +3394,7 @@
visit(node.selector);
closureTarget = pop();
} else {
- TypedElement local = element;
+ LocalElement local = element;
closureTarget = localsHandler.readLocal(local);
}
var inputs = <HInstruction>[];
@@ -3880,7 +3896,7 @@
// fixed.
bool hasDirectLocal(Local local) {
return !localsHandler.isAccessedDirectly(local) ||
- localsHandler.directLocals[local] != null;
+ localsHandler.directLocals[local] != null;
}
/**
@@ -3897,24 +3913,25 @@
}
bool isInConstructorContext = member.isConstructor ||
member.isGenerativeConstructorBody;
+ Local typeVariableLocal = localsHandler.getTypeVariableAsLocal(type);
if (isClosure) {
if (member.isFactoryConstructor ||
- (isInConstructorContext && hasDirectLocal(type.element))) {
+ (isInConstructorContext && hasDirectLocal(typeVariableLocal))) {
// The type variable is used from a closure in a factory constructor.
// The value of the type argument is stored as a local on the closure
// itself.
- return localsHandler.readLocal(type.element);
+ return localsHandler.readLocal(typeVariableLocal);
} else if (member.isFunction ||
- member.isGetter ||
- member.isSetter ||
- isInConstructorContext) {
+ member.isGetter ||
+ member.isSetter ||
+ isInConstructorContext) {
// The type variable is stored on the "enclosing object" and needs to be
// accessed using the this-reference in the closure.
return readTypeVariable(member.enclosingClass, type.element);
} else {
assert(member.isField);
// The type variable is stored in a parameter of the method.
- return localsHandler.readLocal(type.element);
+ return localsHandler.readLocal(typeVariableLocal);
}
} else if (isInConstructorContext ||
// When [member] is a field, we can be either
@@ -3924,7 +3941,7 @@
// always return true when seeing one.
(member.isField && !isBuildingFor(member))) {
// The type variable is stored in a parameter of the method.
- return localsHandler.readLocal(type.element);
+ return localsHandler.readLocal(typeVariableLocal);
} else if (member.isInstanceMember) {
// The type variable is stored on the object.
return readTypeVariable(member.enclosingClass,
@@ -4935,7 +4952,7 @@
ast.Node definition = link.head;
if (definition is ast.Identifier) {
HInstruction initialValue = graph.addConstantNull(compiler);
- VariableElement local = elements[definition];
+ LocalElement local = elements[definition];
localsHandler.updateLocal(local, initialValue);
} else {
assert(definition is ast.SendSet);
@@ -5631,7 +5648,8 @@
startCatchBlock = graph.addNewBlock();
open(startCatchBlock);
// Note that the name of this local is irrelevant.
- SyntheticLocal local = new SyntheticLocal('exception');
+ SyntheticLocal local =
+ new SyntheticLocal('exception', localsHandler.executableContext);
exception = new HLocalValue(local, backend.nonNullType);
add(exception);
HInstruction oldRethrowableException = rethrowableException;
@@ -5676,7 +5694,8 @@
ast.CatchBlock catchBlock = link.head;
link = link.tail;
if (catchBlock.exception != null) {
- VariableElement exceptionVariable = elements[catchBlock.exception];
+ LocalVariableElement exceptionVariable =
+ elements[catchBlock.exception];
localsHandler.updateLocal(exceptionVariable,
unwrappedException);
}
@@ -5684,7 +5703,7 @@
if (trace != null) {
pushInvokeStatic(trace, backend.getTraceFromException(), [exception]);
HInstruction traceInstruction = pop();
- VariableElement traceVariable = elements[trace];
+ LocalVariableElement traceVariable = elements[trace];
localsHandler.updateLocal(traceVariable, traceInstruction);
}
visit(catchBlock);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index e8f5746..608b5c2 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -2052,7 +2052,7 @@
* value from the start, whereas [HLocalValue]s need to be initialized first.
*/
class HLocalValue extends HInstruction {
- HLocalValue(Local variable, TypeMask type)
+ HLocalValue(Entity variable, TypeMask type)
: super(<HInstruction>[], type) {
sourceElement = variable;
}
@@ -2062,7 +2062,7 @@
}
class HParameterValue extends HLocalValue {
- HParameterValue(Local variable, type) : super(variable, type);
+ HParameterValue(Entity variable, type) : super(variable, type);
toString() => 'parameter ${sourceElement.name}';
accept(HVisitor visitor) => visitor.visitParameterValue(this);
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 4f56b63..f0391fe 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -589,8 +589,8 @@
returnType = const VoidType();
element.functionSignature.forEachParameter((ParameterElement parameter) {
- if (parameter.isFieldParameter) {
- FieldParameterElement fieldParameter = parameter;
+ if (parameter.isInitializingFormal) {
+ InitializingFormalElement fieldParameter = parameter;
checkAssignable(parameter, parameter.type,
fieldParameter.fieldElement.computeType(compiler));
}
@@ -995,7 +995,7 @@
return new TypeLiteralAccess(elements.getTypeLiteralType(node));
}
return createResolvedAccess(node, name, element);
- } else if (element.isMember) {
+ } else if (element.isClassMember) {
// foo() where foo is a member.
return lookupMember(node, thisType, name, memberKind, null,
lookupClassMember: element.isStatic);
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 6a933db..ee87577 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -670,7 +670,7 @@
bool appliesUnnamed(Element element, Compiler compiler) {
assert(sameNameHack(element, compiler));
// [TypedSelector] are only used after resolution.
- if (!element.isMember) return false;
+ if (!element.isClassMember) return false;
// A closure can be called through any typed selector:
// class A {
diff --git a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
index 8904464..5591741 100644
--- a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
+++ b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
@@ -40,7 +40,7 @@
import 'ssa/ssa.dart' as ssa;
-import 'cps_ir/cps_ir_nodes.dart' as cps_ir_nodes;
+import 'cps_ir/cps_ir_nodes_sexpr.dart' as cps_ir_nodes_sexpr;
import 'cps_ir/cps_ir_builder.dart' as ir_builder;
@@ -210,9 +210,9 @@
n.isAccessibleFrom(null);
}
-useIr(cps_ir_nodes.SExpressionStringifier stringifier,
+useIr(cps_ir_nodes_sexpr.SExpressionStringifier stringifier,
ir_builder.IrBuilderTask task) {
- new cps_ir_nodes.SExpressionStringifier();
+ new cps_ir_nodes_sexpr.SExpressionStringifier();
stringifier
..newContinuationName()
..newValueName()
diff --git a/sdk/lib/_internal/lib/annotations.dart b/sdk/lib/_internal/lib/annotations.dart
index 23f1234..1e63cf9 100644
--- a/sdk/lib/_internal/lib/annotations.dart
+++ b/sdk/lib/_internal/lib/annotations.dart
@@ -28,3 +28,9 @@
final bool value;
const IrRepresentation(this.value);
}
+
+/// Marks a class as native and defines its JavaScript name(s).
+class Native {
+ final String name;
+ const Native(this.name);
+}
diff --git a/sdk/lib/_internal/lib/js_array.dart b/sdk/lib/_internal/lib/js_array.dart
index 42ee248..7345230 100644
--- a/sdk/lib/_internal/lib/js_array.dart
+++ b/sdk/lib/_internal/lib/js_array.dart
@@ -147,7 +147,7 @@
}
Iterable<E> where(bool f(E element)) {
- return IterableMixinWorkaround.where(this, f);
+ return new IterableMixinWorkaround<E>().where(this, f);
}
Iterable expand(Iterable f(E element)) {
@@ -181,19 +181,19 @@
}
Iterable<E> take(int n) {
- return IterableMixinWorkaround.takeList(this, n);
+ return new IterableMixinWorkaround<E>().takeList(this, n);
}
Iterable<E> takeWhile(bool test(E value)) {
- return IterableMixinWorkaround.takeWhile(this, test);
+ return new IterableMixinWorkaround<E>().takeWhile(this, test);
}
Iterable<E> skip(int n) {
- return IterableMixinWorkaround.skipList(this, n);
+ return new IterableMixinWorkaround<E>().skipList(this, n);
}
Iterable<E> skipWhile(bool test(E value)) {
- return IterableMixinWorkaround.skipWhile(this, test);
+ return new IterableMixinWorkaround<E>().skipWhile(this, test);
}
E reduce(E combine(E value, E element)) {
@@ -241,7 +241,7 @@
Iterable<E> getRange(int start, int end) {
- return IterableMixinWorkaround.getRangeList(this, start, end);
+ return new IterableMixinWorkaround<E>().getRangeList(this, start, end);
}
E get first {
@@ -296,7 +296,8 @@
bool every(bool f(E element)) => IterableMixinWorkaround.every(this, f);
- Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
+ Iterable<E> get reversed =>
+ new IterableMixinWorkaround<E>().reversedList(this);
void sort([int compare(E a, E b)]) {
checkMutable('sort');
@@ -365,7 +366,7 @@
}
Map<int, E> asMap() {
- return IterableMixinWorkaround.asMapList(this);
+ return new IterableMixinWorkaround<E>().asMapList(this);
}
}
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index 41fc902..8eb4b65 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -159,6 +159,11 @@
String unmangledName = mangledNames[name];
if (unmangledName != null) {
name = unmangledName.split(':')[0];
+ } else {
+ if (mangledNames[_internalName] == null) {
+ print("Warning: '$name' is used reflectively but not in MirrorsUsed. "
+ "This will break minified code.");
+ }
}
_memberName = new _symbol_dev.Symbol.unvalidated(name);
return _memberName;
diff --git a/sdk/lib/_internal/lib/native_typed_data.dart b/sdk/lib/_internal/lib/native_typed_data.dart
index 575e827..f1ebae5 100644
--- a/sdk/lib/_internal/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/lib/native_typed_data.dart
@@ -12,13 +12,14 @@
import 'dart:_internal';
import 'dart:_interceptors' show JSIndexable, JSUInt32, JSUInt31;
import 'dart:_js_helper'
- show Creates, JavaScriptIndexingBehavior, JSName, Null, Returns;
+show Creates, JavaScriptIndexingBehavior, JSName, Native, Null, Returns;
import 'dart:_foreign_helper' show JS;
import 'dart:math' as Math;
import 'dart:typed_data';
-class NativeByteBuffer implements ByteBuffer native "ArrayBuffer" {
+@Native("ArrayBuffer")
+class NativeByteBuffer implements ByteBuffer {
@JSName('byteLength')
final int lengthInBytes;
@@ -406,7 +407,8 @@
}
}
-class NativeTypedData implements TypedData native "ArrayBufferView" {
+@Native("ArrayBufferView")
+class NativeTypedData implements TypedData {
/**
* Returns the byte buffer associated with this object.
*/
@@ -499,8 +501,8 @@
}
-class NativeByteData extends NativeTypedData implements ByteData
- native "DataView" {
+@Native("DataView")
+class NativeByteData extends NativeTypedData implements ByteData {
/**
* Creates a [ByteData] of the specified length (in elements), all of
* whose elements are initially zero.
@@ -914,10 +916,10 @@
}
+@Native("Float32Array")
class NativeFloat32List
extends NativeTypedArrayOfDouble
- implements Float32List
- native "Float32Array" {
+ implements Float32List {
factory NativeFloat32List(int length) => _create1(_checkLength(length));
@@ -951,10 +953,10 @@
}
+@Native("Float64Array")
class NativeFloat64List
extends NativeTypedArrayOfDouble
- implements Float64List
- native "Float64Array" {
+ implements Float64List {
factory NativeFloat64List(int length) => _create1(_checkLength(length));
@@ -988,10 +990,10 @@
}
+@Native("Int16Array")
class NativeInt16List
extends NativeTypedArrayOfInt
- implements Int16List
- native "Int16Array" {
+ implements Int16List {
factory NativeInt16List(int length) => _create1(_checkLength(length));
@@ -1030,10 +1032,8 @@
}
-class NativeInt32List
- extends NativeTypedArrayOfInt
- implements Int32List
- native "Int32Array" {
+@Native("Int32Array")
+class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
factory NativeInt32List(int length) => _create1(_checkLength(length));
@@ -1072,10 +1072,8 @@
}
-class NativeInt8List
- extends NativeTypedArrayOfInt
- implements Int8List
- native "Int8Array" {
+@Native("Int8Array")
+class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
factory NativeInt8List(int length) => _create1(_checkLength(length));
@@ -1114,10 +1112,8 @@
}
-class NativeUint16List
- extends NativeTypedArrayOfInt
- implements Uint16List
- native "Uint16Array" {
+@Native("Uint16Array")
+class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
factory NativeUint16List(int length) => _create1(_checkLength(length));
@@ -1156,10 +1152,8 @@
}
-class NativeUint32List
- extends NativeTypedArrayOfInt
- implements Uint32List
- native "Uint32Array" {
+@Native("Uint32Array")
+class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
factory NativeUint32List(int length) => _create1(_checkLength(length));
@@ -1198,10 +1192,10 @@
}
+@Native("Uint8ClampedArray,CanvasPixelArray")
class NativeUint8ClampedList
extends NativeTypedArrayOfInt
- implements Uint8ClampedList
- native "Uint8ClampedArray,CanvasPixelArray" {
+ implements Uint8ClampedList {
factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
@@ -1244,14 +1238,12 @@
}
-class NativeUint8List
- extends NativeTypedArrayOfInt
- implements Uint8List
- // On some browsers Uint8ClampedArray is a subtype of Uint8Array. Marking
- // Uint8List as !nonleaf ensures that the native dispatch correctly handles
- // the potential for Uint8ClampedArray to 'accidentally' pick up the
- // dispatch record for Uint8List.
- native "Uint8Array,!nonleaf" {
+// On some browsers Uint8ClampedArray is a subtype of Uint8Array. Marking
+// Uint8List as !nonleaf ensures that the native dispatch correctly handles
+// the potential for Uint8ClampedArray to 'accidentally' pick up the
+// dispatch record for Uint8List.
+@Native("Uint8Array,!nonleaf")
+class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
factory NativeUint8List(int length) => _create1(_checkLength(length));
diff --git a/sdk/lib/_internal/pub/lib/src/lock_file.dart b/sdk/lib/_internal/pub/lib/src/lock_file.dart
index a2dd6e4..128a3a9 100644
--- a/sdk/lib/_internal/pub/lib/src/lock_file.dart
+++ b/sdk/lib/_internal/pub/lib/src/lock_file.dart
@@ -4,6 +4,7 @@
library pub.lock_file;
+import 'package:path/path.dart' as p;
import 'package:source_maps/source_maps.dart';
import 'package:yaml/yaml.dart';
@@ -44,12 +45,18 @@
}
/// Parses the lockfile whose text is [contents].
+ ///
+ /// [filePath] is the system-native path to the lockfile on disc. It may be
+ /// `null`.
static LockFile _parse(String filePath, String contents,
SourceRegistry sources) {
var packages = <String, PackageId>{};
if (contents.trim() == '') return new LockFile.empty();
- var parsed = loadYamlNode(contents, sourceName: filePath);
+
+ var sourceName;
+ if (filePath != null) sourceName = p.toUri(filePath).toString();
+ var parsed = loadYamlNode(contents, sourceName: sourceName);
_validate(parsed is Map, 'The lockfile must be a YAML mapping.', parsed);
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index fbfb876..f9df64b 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -14,4 +14,3 @@
[ $runtime == vm && $system == windows ]
test/run/app_can_read_from_stdin_test: Fail # Issue 19448
-test/list_package_dirs/lockfile_error_test: Fail # Issue 20104
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index b6e1a11..6530239 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -49,7 +49,6 @@
* "package:collection/wrappers.dart" instead.
*/
abstract class ListMixin<E> implements List<E> {
-
// Iterable interface.
Iterator<E> get iterator => new ListIterator<E>(this);
diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart
index 3aa48c6..3ca1fb3 100644
--- a/sdk/lib/core/exceptions.dart
+++ b/sdk/lib/core/exceptions.dart
@@ -44,60 +44,72 @@
* A message describing the format error.
*/
final String message;
+
/**
- * The source that caused the error.
+ * The actual source input that caused the error.
*
- * This is usually a [String], but can be other types too. If it is a string,
- * parts of it may be included in the [toString] message.
+ * This is usually a [String], but can be other types too.
+ * If it is a string, parts of it may be included in the [toString] message.
*
- * May also be `null` if omitted.
+ * The source is `null` if omitted or unknown.
*/
final source;
+
/**
- * The position in source where the error was detected.
+ * The offset in [source] where the error was detected.
*
- * May be omitted. If present, [source] should also be present.
+ * A zero-based offset into the source that marks the format error causing
+ * this exception to be created. If `source` is a string, this should be a
+ * string index in the range `0 <= offset <= source.length`.
+ *
+ * If input is a string, the [toString] method may represent this offset as
+ * a line and character position. The offset should be inside the string,
+ * or at the end of the string.
+ *
+ * May be omitted. If present, [source] should also be present if possible.
*/
- final int position;
+ final int offset;
/**
* Creates a new FormatException with an optional error [message].
*
- * Optionally also supply the [source] that had the incorrect format, and
- * even the [position] in the format where this was detected.
+ * Optionally also supply the actual [source] that had the incorrect format,
+ * and an [offset] in the format where a problem was detected.
*/
- const FormatException([this.message = "", this.source, this.position]);
+ const FormatException([this.message = "", this.source, this.offset]);
/**
* Returns a description of the format exception.
*
* The description always contains the [message].
- * If [source] was provided, the description will contain (at least a part of)
- * the source.
- * If [position] is also provided, the part of the source included will
- * contain that position, and the position will be marked.
*
- * If the source contains a line break before position, only the line
- * containing position will be included, and its line number will also be
- * part of the description. Line and character offsets are 1-based.
+ * If [source] is present and is a string, the description will contain
+ * (at least a part of) the source.
+ * If [offset] is also provided, the part of the source included will
+ * contain that offset, and the offset will be marked.
+ *
+ * If the source is a string and it contains a line break before offset,
+ * only the line containing offset will be included, and its line number
+ * will also be part of the description. Line and character offsets are
+ * 1-based.
*/
String toString() {
String report = "FormatException";
if (message != null && "" != message) {
report = "$report: $message";
}
- int position = this.position;
+ int offset = this.offset;
if (source is! String) {
- if (position != null) {
- report += " (at position $position)";
+ if (offset != null) {
+ report += " (at offset $offset)";
}
return report;
}
- if (position != null && (position < 0 || position > source.length)) {
- position = null;
+ if (offset != null && (offset < 0 || offset > source.length)) {
+ offset = null;
}
- // Source is string and position is null or valid.
- if (position == null) {
+ // Source is string and offset is null or valid.
+ if (offset == null) {
String source = this.source;
if (source.length > 78) {
source = source.substring(0, 75) + "...";
@@ -107,7 +119,7 @@
int lineNum = 1;
int lineStart = 0;
bool lastWasCR;
- for (int i = 0; i < position; i++) {
+ for (int i = 0; i < offset; i++) {
int char = source.codeUnitAt(i);
if (char == 0x0a) {
if (lineStart != i || !lastWasCR) {
@@ -122,12 +134,12 @@
}
}
if (lineNum > 1) {
- report += " (at line $lineNum, character ${position - lineStart + 1})\n";
+ report += " (at line $lineNum, character ${offset - lineStart + 1})\n";
} else {
- report += " (at character ${position + 1})\n";
+ report += " (at character ${offset + 1})\n";
}
int lineEnd = source.length;
- for (int i = position; i < source.length; i++) {
+ for (int i = offset; i < source.length; i++) {
int char = source.codeUnitAt(i);
if (char == 0x0a || char == 0x0d) {
lineEnd = i;
@@ -142,22 +154,22 @@
if (length > 78) {
// Can't show entire line. Try to anchor at the nearest end, if
// one is within reach.
- int index = position - lineStart;
+ int index = offset - lineStart;
if (index < 75) {
end = start + 75;
postfix = "...";
- } else if (end - position < 75) {
+ } else if (end - offset < 75) {
start = end - 75;
prefix = "...";
} else {
- // Neither end is near, just pick an area around the position.
- start = position - 36;
- end = position + 36;
+ // Neither end is near, just pick an area around the offset.
+ start = offset - 36;
+ end = offset + 36;
prefix = postfix = "...";
}
}
String slice = source.substring(start, end);
- int markOffset = position - start + prefix.length;
+ int markOffset = offset - start + prefix.length;
return "$report$prefix$slice$postfix\n${" " * markOffset}^\n";
}
}
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index f9d3a3f..6d10da9 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -54,13 +54,14 @@
}
/**
- * Returns an Iterator that iterates over this Iterable object.
+ * Returns a new `Iterator` that allows iterating the elements of this
+ * `Iterable`.
*/
Iterator<E> get iterator;
/**
- * Returns a lazy [Iterable] where each element [:e:] of `this` is replaced
- * by the result of [:f(e):].
+ * Returns a new lazy [Iterable] with elements that are created by
+ * calling `f` on the elements of this `Iterable`.
*
* This method returns a view of the mapped elements. As long as the
* returned [Iterable] is not iterated over, the supplied function [f] will
@@ -71,7 +72,7 @@
Iterable map(f(E element));
/**
- * Returns a lazy [Iterable] with all elements that satisfy the
+ * Returns a new lazy [Iterable] with all elements that satisfy the
* predicate [test].
*
* This method returns a view of the mapped elements. As long as the
@@ -96,7 +97,7 @@
/**
* Returns true if the collection contains an element equal to [element].
*
- * The equality used to determine wheter [element] is equal to an element of
+ * The equality used to determine whether [element] is equal to an element of
* the iterable, depends on the type of iterable.
* For example, a [Set] may have a custom equality
* (see, e.g., [Set.identical]) that its `contains` uses.
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index db6d7bc..81f94f0 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -6,9 +6,10 @@
/**
* An collection of key-value pairs, from which you retrieve a value
- * by using its associated key.
+ * using its associated key.
*
- * Each key can occur at most once in a map.
+ * There is a finite number of keys in the map,
+ * and each key has exactly one value associated with it.
*
* Maps, and their keys and values, can be iterated.
* The order of iteration is defined by the individual type of map.
@@ -119,20 +120,30 @@
= LinkedHashMap<K, V>.fromIterables;
/**
- * Returns true if this map contains the given value.
+ * Returns true if this map contains the given [value].
+ *
+ * Returns true if any of the values in the map are equal to `value`
+ * according to the `==` operator.
*/
bool containsValue(Object value);
/**
- * Returns true if this map contains the given key.
+ * Returns true if this map contains the given [key].
+ *
+ * Returns true if any of the keys in the map ar equal to `key`
+ * according to the equality used by the map.
*/
bool containsKey(Object key);
/**
- * Returns the value for the given [key] or null if [key] is not
- * in the map. Because null values are supported, one should either
- * use [containsKey] to distinguish between an absent key and a null
- * value, or use the [putIfAbsent] method.
+ * Returns the value for the given [key] or null if [key] is not in the map.
+ *
+ * Some maps allows keys to have `null` as a value,
+ * For those maps, a lookup using this operator does cannot be used to
+ * distinguish between a key not being in the map, and the key having a null
+ * value.
+ * Methods like [containsKey] or [putIfAbsent] can be use if the distinction
+ * is important.
*/
V operator [](Object key);
@@ -145,9 +156,11 @@
void operator []=(K key, V value);
/**
- * If [key] is not associated to a value, calls [ifAbsent] and
- * updates the map by mapping [key] to the value returned by
- * [ifAbsent]. Returns the value in the map.
+ * Look up the value of [key], or add a new value if it isn't there.
+ *
+ * Returns the value associated to [key], if there is one.
+ * Otherwise calls [ifAbsent] to get a new value, associates [key] to
+ * that value, and then returns the new value.
*
* Map<String, int> scores = {'Bob': 36};
* for (var key in ['Bob', 'Rohan', 'Sophena']) {
@@ -157,7 +170,7 @@
* scores['Rohan']; // 5
* scores['Sophena']; // 7
*
- * The code that [ifAbsent] executes must not add or remove keys.
+ * Calling [ifAbsent] must not add or remove keys from the map.
*/
V putIfAbsent(K key, V ifAbsent());
@@ -173,10 +186,13 @@
void addAll(Map<K, V> other);
/**
- * Removes the association for the given [key]. Returns the value for
- * [key] in the map or null if [key] is not in the map. Note that values
- * can be null and a returned null value does not always imply that the
- * key is absent.
+ * Removes [key] and its associated value, if present, from the map.
+ *
+ * Returns the value associated with `key` before it was removed.
+ * Returns `null` if `key` was not in the map.
+ *
+ * Note that values can be `null` and a returned `null` value doesn't
+ * always mean that the key was absent.
*/
V remove(Object key);
@@ -188,9 +204,9 @@
void clear();
/**
- * Applies [f] to each {key, value} pair of the map.
+ * Applies [f] to each key-value pair of the map.
*
- * Adding or removing keys from the map during iteration is not allowed.
+ * Calling `f` must not add or remove keys from the map.
*/
void forEach(void f(K key, V value));
@@ -213,7 +229,8 @@
* provided matching pairs of keys and values.
*
* The returned iterable has an efficient `length` method based on the
- * [length] of the map.
+ * [length] of the map. Its [Iterable.contains] method is based on
+ * `==` comparison.
*/
Iterable<V> get values;
diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart
index 4cf8418..006b31a 100644
--- a/sdk/lib/internal/iterable.dart
+++ b/sdk/lib/internal/iterable.dart
@@ -195,11 +195,11 @@
return value;
}
- Iterable<E> skip(int count) => new SubListIterable(this, count, null);
+ Iterable<E> skip(int count) => new SubListIterable<E>(this, count, null);
Iterable<E> skipWhile(bool test(E element)) => super.skipWhile(test);
- Iterable<E> take(int count) => new SubListIterable(this, 0, count);
+ Iterable<E> take(int count) => new SubListIterable<E>(this, 0, count);
Iterable<E> takeWhile(bool test(E element)) => super.takeWhile(test);
@@ -276,17 +276,21 @@
Iterable<E> skip(int count) {
if (count < 0) throw new RangeError.value(count);
- return new SubListIterable(_iterable, _start + count, _endOrLength);
+ int newStart = _start + count;
+ if (_endOrLength != null && newStart >= _endOrLength) {
+ return new EmptyIterable<E>();
+ }
+ return new SubListIterable<E>(_iterable, newStart, _endOrLength);
}
Iterable<E> take(int count) {
if (count < 0) throw new RangeError.value(count);
if (_endOrLength == null) {
- return new SubListIterable(_iterable, _start, _start + count);
+ return new SubListIterable<E>(_iterable, _start, _start + count);
} else {
int newEnd = _start + count;
if (_endOrLength < newEnd) return this;
- return new SubListIterable(_iterable, _start, newEnd);
+ return new SubListIterable<E>(_iterable, _start, newEnd);
}
}
}
@@ -740,7 +744,7 @@
*
* The uses of this class will be replaced by mixins.
*/
-class IterableMixinWorkaround {
+class IterableMixinWorkaround<T> {
static bool contains(Iterable iterable, var element) {
for (final e in iterable) {
if (e == element) return true;
@@ -934,8 +938,8 @@
return buffer.toString();
}
- static Iterable where(Iterable iterable, bool f(var element)) {
- return new WhereIterable(iterable, f);
+ Iterable<T> where(Iterable iterable, bool f(var element)) {
+ return new WhereIterable<T>(iterable, f);
}
static Iterable map(Iterable iterable, f(var element)) {
@@ -950,28 +954,28 @@
return new ExpandIterable(iterable, f);
}
- static Iterable takeList(List list, int n) {
+ Iterable<T> takeList(List list, int n) {
// The generic type is currently lost. It will be fixed with mixins.
- return new SubListIterable(list, 0, n);
+ return new SubListIterable<T>(list, 0, n);
}
- static Iterable takeWhile(Iterable iterable, bool test(var value)) {
+ Iterable<T> takeWhile(Iterable iterable, bool test(var value)) {
// The generic type is currently lost. It will be fixed with mixins.
- return new TakeWhileIterable(iterable, test);
+ return new TakeWhileIterable<T>(iterable, test);
}
- static Iterable skipList(List list, int n) {
+ Iterable<T> skipList(List list, int n) {
// The generic type is currently lost. It will be fixed with mixins.
- return new SubListIterable(list, n, null);
+ return new SubListIterable<T>(list, n, null);
}
- static Iterable skipWhile(Iterable iterable, bool test(var value)) {
+ Iterable<T> skipWhile(Iterable iterable, bool test(var value)) {
// The generic type is currently lost. It will be fixed with mixins.
- return new SkipWhileIterable(iterable, test);
+ return new SkipWhileIterable<T>(iterable, test);
}
- static Iterable reversedList(List list) {
- return new ReversedListIterable(list);
+ Iterable<T> reversedList(List list) {
+ return new ReversedListIterable<T>(list);
}
static void sortList(List list, int compare(a, b)) {
@@ -1009,10 +1013,10 @@
}
}
- static Iterable getRangeList(List list, int start, int end) {
+ Iterable<T> getRangeList(List list, int start, int end) {
_rangeCheck(list, start, end);
// The generic type is currently lost. It will be fixed with mixins.
- return new SubListIterable(list, start, end);
+ return new SubListIterable<T>(list, start, end);
}
static void setRangeList(List list, int start, int end,
@@ -1097,8 +1101,8 @@
}
}
- static Map<int, dynamic> asMapList(List l) {
- return new ListMapView(l);
+ Map<int, T> asMapList(List l) {
+ return new ListMapView<T>(l);
}
static bool setContainsAll(Set set, Iterable other) {
diff --git a/sdk/lib/internal/list.dart b/sdk/lib/internal/list.dart
index 473a87a..43e7e6a 100644
--- a/sdk/lib/internal/list.dart
+++ b/sdk/lib/internal/list.dart
@@ -295,6 +295,8 @@
void addAll(Map<int, E> other) {
throw new UnsupportedError("Cannot modify an unmodifiable map");
}
+
+ String toString() => Maps.mapToString(this);
}
class ReversedListIterable<E> extends ListIterable<E> {
diff --git a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
index a465276..1af28e2 100644
--- a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
+++ b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
@@ -6,51 +6,13 @@
import 'dart:async';
import "package:async_helper/async_helper.dart";
import '../mock_compiler.dart';
+import '../mock_libraries.dart';
import 'package:compiler/compiler.dart';
import 'package:compiler/implementation/dart2jslib.dart' as leg;
import 'package:compiler/implementation/dart_backend/dart_backend.dart';
import 'package:compiler/implementation/elements/elements.dart';
import 'package:compiler/implementation/tree/tree.dart';
-const coreLib = r'''
-library corelib;
-class Object {
- Object();
-}
-class bool {}
-class num {}
-class int extends num {}
-class double extends num {}
-abstract class String {}
-class Function {}
-class List<T> {}
-class Map<K,V> {}
-class BoundClosure {}
-class Closure {}
-class Dynamic_ {}
-class Null {}
-class TypeError {}
-class Type {}
-class StackTrace {}
-class LinkedHashMap {
- factory LinkedHashMap._empty() => null;
- factory LinkedHashMap._literal(elements) => null;
-}
-class Math {
- static double parseDouble(String s) => 1.0;
-}
-print(x) {}
-identical(a, b) => true;
-const proxy = 0;
-''';
-
-const corePatch = r'''
-import 'dart:_js_helper';
-import 'dart:_interceptors';
-import 'dart:_isolate_helper';
-import 'dart:_foreign_helper';
-''';
-
const ioLib = r'''
library io;
class Platform {
@@ -70,24 +32,6 @@
}
''';
-const helperLib = r'''
-library js_helper;
-class JSInvocationMirror {}
-assertHelper(a) {}
-class Closure {}
-class BoundClosure {}
-const patch = 0;
-''';
-
-const foreignLib = r'''
-var JS;
-''';
-
-const isolateHelperLib = r'''
-class _WorkerStub {
-}
-''';
-
testDart2Dart(String src, {void continuation(String s), bool minify: false,
bool stripTypes: false}) {
// If continuation is not provided, check that source string remains the same.
@@ -116,20 +60,22 @@
return new Future.value(srcLibrary);
}
if (uri.path.endsWith('/core.dart')) {
- return new Future.value(coreLib);
+ return new Future.value(buildLibrarySource(DEFAULT_CORE_LIBRARY));
} else if (uri.path.endsWith('/core_patch.dart')) {
- return new Future.value(corePatch);
+ return new Future.value(DEFAULT_PATCH_CORE_SOURCE);
} else if (uri.path.endsWith('/io.dart')) {
return new Future.value(ioLib);
} else if (uri.path.endsWith('/js_helper.dart')) {
- return new Future.value(helperLib);
+ return new Future.value(buildLibrarySource(DEFAULT_JS_HELPER_LIBRARY));
} else if (uri.path.endsWith('/html_dart2js.dart')) {
// TODO(smok): The file should change to html_dartium at some point.
return new Future.value(htmlLib);
} else if (uri.path.endsWith('/foreign_helper.dart')) {
- return new Future.value(foreignLib);
+ return new Future.value(
+ buildLibrarySource(DEFAULT_FOREIGN_HELPER_LIBRARY));
} else if (uri.path.endsWith('/isolate_helper.dart')) {
- return new Future.value(isolateHelperLib);
+ return new Future.value(
+ buildLibrarySource(DEFAULT_ISOLATE_HELPER_LIBRARY));
}
return new Future.value('');
}
@@ -590,7 +536,7 @@
testStaticInvocation() {
testDart2Dart('''
main() {
- var x = Math.parseDouble("1");
+ var x = double.parseDouble("1");
}
''');
}
diff --git a/tests/compiler/dart2js/backend_dart/sexpr_test.dart b/tests/compiler/dart2js/backend_dart/sexpr_test.dart
new file mode 100644
index 0000000..a2bb628
--- /dev/null
+++ b/tests/compiler/dart2js/backend_dart/sexpr_test.dart
@@ -0,0 +1,166 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../compiler_helper.dart';
+import 'dart:async';
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import 'package:compiler/implementation/dart2jslib.dart';
+import 'package:compiler/implementation/cps_ir/cps_ir_nodes.dart';
+import 'package:compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart';
+import 'package:compiler/implementation/dart_backend/dart_backend.dart';
+
+const String CODE = """
+class Foo {
+ static int x = 1;
+ foo() => 42;
+}
+
+class Bar extends Foo {
+ int y = 2;
+ Bar() {
+ Foo.x = 2;
+ }
+ foo() => this.y + super.foo();
+}
+
+class FooBar<T> {
+ bool foobar() => T is int;
+}
+
+main() {
+ Foo foo;
+ if (foo is Foo) {
+ print("Surprise");
+ }
+
+ String inner() => "Inner function";
+ print(inner());
+
+ int j = 42;
+ for (int i = 0; i < 2; i++) {
+ print(i.toString());
+ }
+
+ print(Foo.x);
+
+ String recursive(int h) {
+ if (h < 1) {
+ return j.toString();
+ }
+ j++;
+ return "h\$\{recursive(h - 1)\}";
+ }
+ print(recursive(5));
+
+ Bar bar = new Bar();
+ print(bar.foo().toString());
+
+ bar = foo as Bar;
+ if (bar == null) {
+ var list = [1, 2, 3, 4];
+ var map = { 1: "one"
+ , 2: "two"
+ , 3: "three"
+ };
+ var double = 3.14;
+ print("\$list \$map \$double");
+ }
+
+ print(new FooBar<int>().foobar());
+}
+
+""";
+
+bool shouldOutput(Element element) {
+ return (!element.library.isPlatformLibrary &&
+ !element.isSynthesized &&
+ element.kind == ElementKind.FUNCTION);
+}
+
+/// Compiles the given dart code (which must include a 'main' function) and
+/// returns a list of all generated CPS IR definitions.
+Future<List<FunctionDefinition>> compile(String code) {
+ MockCompiler compiler = new MockCompiler.internal(
+ emitJavaScript: false,
+ enableMinification: false);
+
+ return compiler.init().then((_) {
+ compiler.parseScript(code);
+
+ Element element = compiler.mainApp.find('main');
+ if (element == null) return null;
+
+ compiler.mainFunction = element;
+ compiler.phase = Compiler.PHASE_RESOLVING;
+ compiler.backend.enqueueHelpers(compiler.enqueuer.resolution,
+ compiler.globalDependencies);
+ compiler.processQueue(compiler.enqueuer.resolution, element);
+ compiler.world.populate();
+ compiler.backend.onResolutionComplete();
+
+ compiler.irBuilder.buildNodes(useNewBackend: true);
+
+ return compiler.enqueuer.resolution.resolvedElements
+ .where(shouldOutput)
+ .map(compiler.irBuilder.getIr)
+ .toList();
+ });
+}
+
+Future<String> testStringifier(String code, List<String> expectedTokens) {
+ return compile(code)
+ .then((List<FunctionDefinition> functions) {
+ final stringifier = new SExpressionStringifier();
+ return functions.map((f) {
+ String sexpr = stringifier.visitFunctionDefinition(f);
+ Expect.isNotNull(sexpr, "S-expression generation failed");
+ return sexpr;
+ }).join("\n");
+ })
+ .then((String sexpr) {
+ Expect.isFalse(sexpr.replaceAll("Constant null", "").contains("null"),
+ "Output contains 'null':\n\n$sexpr");
+
+ expectedTokens.forEach((String token) {
+ Expect.isTrue(sexpr.contains(token),
+ "Expected token '$token' not present:\n\n$sexpr");
+ });
+
+ return sexpr;
+ });
+}
+
+void main() {
+ final tokens =
+ [ "FunctionDefinition"
+ , "IsTrue"
+
+ // Expressions
+ , "Branch"
+ , "ConcatenateStrings"
+ , "DeclareFunction"
+ , "InvokeConstructor"
+ , "InvokeContinuation"
+ , "InvokeMethod"
+ , "InvokeStatic"
+ , "InvokeSuperMethod"
+ , "LetCont"
+ , "LetPrim"
+ , "SetClosureVariable"
+ , "TypeOperator"
+
+ // Primitives
+ , "Constant"
+ , "CreateFunction"
+ , "GetClosureVariable"
+ , "LiteralList"
+ , "LiteralMap"
+ // Parameters are encoded by name only and hence are not in this list.
+ , "ReifyTypeVar"
+ , "This"
+ ];
+
+ asyncTest(() => testStringifier(CODE, tokens));
+}
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
new file mode 100644
index 0000000..72b26ab
--- /dev/null
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Unit test of the [NativeBehavior.processSpecString] method.
+
+import 'package:expect/expect.dart';
+import 'package:compiler/implementation/native_handler.dart';
+import 'package:compiler/implementation/dart2jslib.dart'
+ show DiagnosticListener;
+
+const OBJECT = 'Object';
+const NULL = 'Null';
+
+class Listener implements DiagnosticListener {
+ String errorMessage;
+ internalError(spannable, message) => errorMessage = message;
+
+ noSuchMethod(_) => null;
+}
+
+void test(String specString,
+ {List returns,
+ List creates,
+ bool expectError: false}) {
+ List actualReturns = [];
+ List actualCreates = [];
+ Listener listener = new Listener();
+ NativeBehavior.processSpecString(
+ listener,
+ null,
+ specString,
+ resolveType: (t) => t,
+ typesReturned: actualReturns, typesInstantiated: actualCreates,
+ objectType: OBJECT, nullType: NULL);
+ if (expectError) {
+ Expect.isNotNull(listener.errorMessage, 'Internal error expected.');
+ } else {
+ Expect.isNull(listener.errorMessage, 'Unexpected internal error.');
+ Expect.listEquals(returns, actualReturns, 'Unexpected returns.');
+ Expect.listEquals(creates, actualCreates, 'Unexpected creates.');
+ }
+}
+
+void main() {
+ test('void', returns: [], creates: []);
+ test('', returns: [OBJECT, NULL], creates: []);
+ test('var', returns: [OBJECT, NULL], creates: []);
+ test('A', returns: ['A'], creates: ['A']);
+ test('A|B', returns: ['A', 'B'], creates: ['A', 'B']);
+ test('A|B|C', returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
+
+ test('returns:void;', returns: [], creates: []);
+ test('returns:;', returns: [OBJECT, NULL], creates: []);
+ test('returns:var;', returns: [OBJECT, NULL], creates: []);
+ test('returns:A;', returns: ['A'], creates: []);
+ test('returns:A|B;', returns: ['A', 'B'], creates: []);
+ test('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: []);
+
+ test('creates:void;', expectError: true);
+ test('creates:;', expectError: true);
+ test('creates:var;', expectError: true);
+ test('creates:A;', returns: [], creates: ['A']);
+ test('creates:A|B;', returns: [], creates: ['A', 'B']);
+ test('creates:A|B|C;', returns: [], creates: ['A', 'B', 'C']);
+
+ test('returns:void;creates:A;', returns: [], creates: ['A']);
+ test('returns:;creates:A|B;', returns: [OBJECT, NULL], creates: ['A', 'B']);
+ test('returns:var;creates:A|B|C;',
+ returns: [OBJECT, NULL], creates: ['A', 'B', 'C']);
+ test('returns:A; creates:A|B|C; ', returns: ['A'], creates: ['A', 'B', 'C']);
+ test(' returns:A|B; creates:A|C;',
+ returns: ['A', 'B'], creates: ['A', 'C']);
+ test(' returns:A|B|C; creates:A; ',
+ returns: ['A', 'B', 'C'], creates: ['A']);
+}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index c68c58c..d700601 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -198,10 +198,11 @@
CollectingTreeElements resolveStatement(String text) {
parsedTree = parseStatement(text);
- return resolveNodeStatement(parsedTree, mainApp);
+ return resolveNodeStatement(parsedTree, new MockElement(mainApp));
}
- TreeElementMapping resolveNodeStatement(Node tree, Element element) {
+ TreeElementMapping resolveNodeStatement(Node tree,
+ ExecutableElement element) {
ResolverVisitor visitor =
new ResolverVisitor(this, element,
new ResolutionRegistry.internal(this,
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 1cb57dd..9174ae5 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -152,6 +152,7 @@
'listTypeCast': 'listTypeCast(value) {}',
'listTypeCheck': 'listTypeCheck(value) {}',
'makeLiteralMap': 'makeLiteralMap(List keyValuePairs) {}',
+ 'Native': 'class Native {}',
'NoInline': 'class NoInline {}',
'NoSideEffects': 'class NoSideEffects {}',
'NoThrows': 'class NoThrows {}',
@@ -287,14 +288,14 @@
operator |(other) => 42;
operator &(other) => 42;
operator ^(other) => 42;
-
+
operator >(other) => true;
operator >=(other) => true;
operator <(other) => true;
operator <=(other) => true;
operator ==(other) => true;
get hashCode => throw "JSNumber.hashCode not implemented.";
-
+
// We force side effects on _tdivFast to mimic the shortcomings of
// the effect analysis: because the `_tdivFast` implementation of
// the core library has calls that may not already be analyzed,
@@ -305,7 +306,7 @@
_shrBothPositive(other) => 42;
_shrReceiverPositive(other) => 42;
_shrOtherPositive(other) => 42;
-
+
abs() => (this is JSInt) ? 42 : 42.2;
remainder(other) => (this is JSInt) ? 42 : 42.2;
truncate() => 42;
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 6515eee..7f634e4 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -2140,7 +2140,7 @@
}
analyzeIn(MockCompiler compiler,
- Element element,
+ ExecutableElement element,
String text,
[expectedWarnings]) {
if (expectedWarnings == null) expectedWarnings = [];
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index fd54729..e955036 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -40,6 +40,7 @@
to_string_test: Fail # Issue 7179.
runtime_type_test: Fail, OK # Tests extected output of Type.toString().
code_motion_exception_test: Skip # Requires unminified operator names.
+mirrors_used_warning_test/minif: Fail, OK # Tests warning that minified code will be broken.
[ $compiler == dart2js && ($runtime == drt || $runtime == ff || $runtime == safari || $runtime == jsshell) ]
code_motion_exception_test: Skip # Required V8 specific format of JavaScript errors.
diff --git a/tests/compiler/dart2js_extra/mirrors_used_warning2_test.dart b/tests/compiler/dart2js_extra/mirrors_used_warning2_test.dart
new file mode 100644
index 0000000..1ac19d6
--- /dev/null
+++ b/tests/compiler/dart2js_extra/mirrors_used_warning2_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:mirrors';
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+class A {
+ noSuchMethod(Invocation invocation) {
+ return MirrorSystem.getName(invocation.memberName);
+ }
+}
+
+var lines = [];
+capturePrint(Zone self, ZoneDelegate parent, Zone origin, line) {
+ lines.add(line);
+}
+
+runTests() {
+ // No MirrorsUsed annotation anywhere.
+ // Dart2js should retain all symbols.
+ Expect.equals("foo", new A().foo);
+ Expect.isTrue(lines.isEmpty);
+ var barResult = new A().bar;
+ Expect.equals("bar", barResult);
+ Expect.isTrue(lines.isEmpty);
+}
+
+main() {
+ runZoned(runTests,
+ zoneSpecification: new ZoneSpecification(print: capturePrint));
+}
diff --git a/tests/compiler/dart2js_extra/mirrors_used_warning_test.dart b/tests/compiler/dart2js_extra/mirrors_used_warning_test.dart
new file mode 100644
index 0000000..343e090
--- /dev/null
+++ b/tests/compiler/dart2js_extra/mirrors_used_warning_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@MirrorsUsed(symbols: 'foo')
+import 'dart:mirrors';
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+class A {
+ noSuchMethod(Invocation invocation) {
+ return MirrorSystem.getName(invocation.memberName);
+ }
+}
+
+var lines = [];
+capturePrint(Zone self, ZoneDelegate parent, Zone origin, line) {
+ lines.add(line);
+}
+
+runTests() {
+ // "foo" is in MirrorsUsed and should therefore always work.
+ Expect.equals("foo", new A().foo);
+ Expect.isTrue(lines.isEmpty);
+ var barResult = new A().bar;
+ Expect.equals("bar", barResult); /// minif: ok
+ Expect.isTrue(lines.length == 1);
+ var line = lines.first;
+ Expect.isTrue(line.contains("Warning") &&
+ line.contains("bar") && /// minif: continued
+ line.contains("minif"));
+}
+
+main() {
+ runZoned(runTests,
+ zoneSpecification: new ZoneSpecification(print: capturePrint));
+}
diff --git a/tests/compiler/dart2js_native/abstract_class_test.dart b/tests/compiler/dart2js_native/abstract_class_test.dart
index 6a5989c..df5738c 100644
--- a/tests/compiler/dart2js_native/abstract_class_test.dart
+++ b/tests/compiler/dart2js_native/abstract_class_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Native classes can have subclasses that are not declared to the program. The
// subclasses are indistinguishable from the base class. This means that
// abstract native classes can appear to have instances.
-abstract class A native "A" {
+@Native("A")
+abstract class A {
}
-abstract class B native "B" {
+@Native("B")
+abstract class B {
foo() native;
}
diff --git a/tests/compiler/dart2js_native/bound_closure_test.dart b/tests/compiler/dart2js_native/bound_closure_test.dart
index 4be2c80..afbecce 100644
--- a/tests/compiler/dart2js_native/bound_closure_test.dart
+++ b/tests/compiler/dart2js_native/bound_closure_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test calling convention of property extraction closures.
@@ -11,11 +12,13 @@
foo(a, [b = 'A']) => 'AA.foo($a, $b)'; // foo has interceptor convention.
}
-class BB native "BB" {
+@Native("BB")
+class BB {
foo(a, [b = 'B']) native;
}
-class CC extends BB native "CC" {
+@Native("CC")
+class CC extends BB {
foo(a, [b = 'C']) native;
get superfoo => super.foo;
diff --git a/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart b/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart
index abeb7d6..36b7f9b 100644
--- a/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart
+++ b/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart
@@ -2,19 +2,23 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
//import 'dart:_foreign_helper' show JS;
//import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
// Test for dartNativeDispatchHooksTransformer, getTag hook.
-class T1A native "T1A" {
+@Native("T1A")
+class T1A {
}
-class T1B native "T1B" {
+@Native("T1B")
+class T1B {
}
-class T1C native "T1C" {
+@Native("T1C")
+class T1C {
}
makeT1A() native;
diff --git a/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart b/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart
index 8db4d43..56c9fb8 100644
--- a/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart
+++ b/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
//import 'dart:_foreign_helper' show JS;
//import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
@@ -9,13 +10,16 @@
// Test for dartNativeDispatchHooksTransformer, getTag hook.
// Same as browser_compat_1_prepatched_test but with prepatching disabled.
-class T1A native "T1A" {
+@Native("T1A")
+class T1A {
}
-class T1B native "T1B" {
+@Native("T1B")
+class T1B {
}
-class T1C native "T1C" {
+@Native("T1C")
+class T1C {
}
makeT1A() native;
diff --git a/tests/compiler/dart2js_native/browser_compat_2_test.dart b/tests/compiler/dart2js_native/browser_compat_2_test.dart
index 297da7c..858a067 100644
--- a/tests/compiler/dart2js_native/browser_compat_2_test.dart
+++ b/tests/compiler/dart2js_native/browser_compat_2_test.dart
@@ -2,25 +2,30 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test for dartNativeDispatchHooksTransformer
// - uncached, instance, leaf and interior caching modes.
// - composition of getTag.
-class T1A native "T1A" {
+@Native("T1A")
+class T1A {
foo() native;
}
-class T1B native "T1B" {
+@Native("T1B")
+class T1B {
foo() native;
}
-class T1C native "T1C" {
+@Native("T1C")
+class T1C {
foo() native;
}
-class T1D native "T1D" {
+@Native("T1D")
+class T1D {
foo() native;
}
diff --git a/tests/compiler/dart2js_native/call_on_native_class_test.dart b/tests/compiler/dart2js_native/call_on_native_class_test.dart
index 3b07cf6..5142982 100644
--- a/tests/compiler/dart2js_native/call_on_native_class_test.dart
+++ b/tests/compiler/dart2js_native/call_on_native_class_test.dart
@@ -2,10 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-class A native '*A' {
+import 'dart:_js_helper';
+
+@Native('*A')
+class A {
}
-class B extends A{
+class B extends A {
call() => 42;
}
diff --git a/tests/compiler/dart2js_native/core_type_check_native_test.dart b/tests/compiler/dart2js_native/core_type_check_native_test.dart
index 11890a1..41a4109 100644
--- a/tests/compiler/dart2js_native/core_type_check_native_test.dart
+++ b/tests/compiler/dart2js_native/core_type_check_native_test.dart
@@ -2,20 +2,25 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
var inscrutable = (int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
-class A native "A" {
+@Native("A")
+class A {
}
-class B implements Comparable native "B" {
+@Native("B")
+class B implements Comparable {
}
-class C implements Pattern native "C" {
+@Native("C")
+class C implements Pattern {
}
-class D implements Pattern, Comparable native "D" {
+@Native("D")
+class D implements Pattern, Comparable {
}
makeA() native;
diff --git a/tests/compiler/dart2js_native/downcast_test.dart b/tests/compiler/dart2js_native/downcast_test.dart
index 27ec4b2..6810a612 100644
--- a/tests/compiler/dart2js_native/downcast_test.dart
+++ b/tests/compiler/dart2js_native/downcast_test.dart
@@ -4,6 +4,7 @@
// Test for downcasts on native classes.
+import "dart:_js_helper";
import "package:expect/expect.dart";
abstract class J {
@@ -16,13 +17,15 @@
// Native implementation.
-class A implements I native "A" {
+@Native("A")
+class A implements I {
// The native class accepts only other native instances.
A read() native;
write(A x) native;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
}
makeA() native;
diff --git a/tests/compiler/dart2js_native/field_type2_test.dart b/tests/compiler/dart2js_native/field_type2_test.dart
index 15dbf61..6f8c35b 100644
--- a/tests/compiler/dart2js_native/field_type2_test.dart
+++ b/tests/compiler/dart2js_native/field_type2_test.dart
@@ -5,7 +5,10 @@
// Test that a closure call on a native field is recognized by the
// type inferrer.
-class Node native "Node" {
+import 'dart:_js_helper';
+
+@Native("Node")
+class Node {
final parentNode;
}
diff --git a/tests/compiler/dart2js_native/field_type_test.dart b/tests/compiler/dart2js_native/field_type_test.dart
index bd2b1c1..75297ad 100644
--- a/tests/compiler/dart2js_native/field_type_test.dart
+++ b/tests/compiler/dart2js_native/field_type_test.dart
@@ -6,9 +6,11 @@
// This regression test verifies that compiler accounts for hidden constructor
// when analysing field values.
+import "dart:_js_helper";
import "package:expect/expect.dart";
-class Node native "Node" {
+@Native("Node")
+class Node {
final Node parentNode;
diff --git a/tests/compiler/dart2js_native/fixup_get_tag_test.dart b/tests/compiler/dart2js_native/fixup_get_tag_test.dart
index 957fd25..0f68986 100644
--- a/tests/compiler/dart2js_native/fixup_get_tag_test.dart
+++ b/tests/compiler/dart2js_native/fixup_get_tag_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test for dartExperimentalFixupGetTag.
-class Foo native "A" { // There is one native class with dispatch tag 'A'.
+@Native("A")
+class Foo { // There is one native class with dispatch tag 'A'.
token() native;
}
diff --git a/tests/compiler/dart2js_native/hash_code_test.dart b/tests/compiler/dart2js_native/hash_code_test.dart
index c222de6..452c7aa 100644
--- a/tests/compiler/dart2js_native/hash_code_test.dart
+++ b/tests/compiler/dart2js_native/hash_code_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {}
+@Native("A")
+class A {}
makeA() native;
void setup() native """
diff --git a/tests/compiler/dart2js_native/is_check_test.dart b/tests/compiler/dart2js_native/is_check_test.dart
index db04502..ecc42b2 100644
--- a/tests/compiler/dart2js_native/is_check_test.dart
+++ b/tests/compiler/dart2js_native/is_check_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {}
+@Native("A")
+class A {}
main() {
var a = [new Object()];
diff --git a/tests/compiler/dart2js_native/issue9182_test.dart b/tests/compiler/dart2js_native/issue9182_test.dart
index 8d2734b..8bbee65 100644
--- a/tests/compiler/dart2js_native/issue9182_test.dart
+++ b/tests/compiler/dart2js_native/issue9182_test.dart
@@ -5,9 +5,11 @@
// Regression test for Issue 9182. The generative constructor body function
// should not have the interceptor calling convention.
+import "dart:_js_helper";
import "package:expect/expect.dart";
-class Foo native "A" {
+@Native("A")
+class Foo {
factory Foo() => makeA();
// Ensure the instance method 'Bar' uses interceptor convention.
Bar() => 123;
diff --git a/tests/compiler/dart2js_native/jsobject_test.dart b/tests/compiler/dart2js_native/jsobject_test.dart
index a63320e..dd3c991 100644
--- a/tests/compiler/dart2js_native/jsobject_test.dart
+++ b/tests/compiler/dart2js_native/jsobject_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show
JSObject, // The interface, which may be re-exported by a
// js-interop library.
diff --git a/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart b/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart
index a56cbb0..a9cb2e0 100644
--- a/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart
+++ b/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart
@@ -3,9 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:mirrors';
+import "dart:_js_helper";
import "package:expect/expect.dart";
-class B native "B" {
+@Native("B")
+class B {
// Having this field in a native class will generate accessors with
// the interceptor calling convention.
var f;
diff --git a/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart b/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart
index 285e349..b4cf449 100644
--- a/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test that native methods with unnamed* optional arguments are called with the
@@ -12,11 +13,13 @@
// * Optional positional arguments are passed in the correct position, so
// require preceding arguments to be passed.
-class A native "A" {
+@Native("A")
+class A {
int foo(int x) native;
}
-class B native "B" {
+@Native("B")
+class B {
int foo([x, y, z]) native;
}
diff --git a/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart b/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart
index 7941775..245c03c 100644
--- a/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// This is a similar test to NativeCallArity1FrogTest, but makes sure
// that subclasses also get the right number of arguments.
-class A native "A" {
+@Native("A")
+class A {
int foo([x, y]) native;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
int foo([x, y]) native;
}
diff --git a/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart b/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart
index 59c35af..0257ed9 100644
--- a/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart
@@ -2,17 +2,20 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test similar to NativeCallArity1FrogTest, but with default values to
// parameters set to null. These parameters should be treated as if they
// do not have a default value for the native methods.
-class A native "A" {
+@Native("A")
+class A {
int foo(int x) native;
}
-class B native "B" {
+@Native("B")
+class B {
int foo([x = null, y, z = null]) native;
}
diff --git a/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart b/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart
index 3edf17b..d87558d 100644
--- a/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that type checks occur on native methods.
-class A native "A" {
+@Native("A")
+class A {
int foo(int x) native;
int cmp(A other) native;
}
-class B native "B" {
+@Native("B")
+class B {
String foo(String x) native;
int cmp(B other) native;
}
diff --git a/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart b/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart
index 22b9c7a..7648da4 100644
--- a/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart
@@ -2,15 +2,18 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test that type checks occur on assignment to fields of native methods.
-class A native "A" {
+@Native("A")
+class A {
int foo;
}
-class B native "B" {
+@Native("B")
+class B {
String foo;
}
diff --git a/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart b/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
index 1d3b04b..e78544a 100644
--- a/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that hidden native class names are not used by generated code.
-class AA native "BB" {
+@Native("BB")
+class AA {
get name => 'AA';
static AA create() => makeA();
}
-class BB native "CC" {
+@Native("CC")
+class BB {
get name => 'BB';
static BB create() => makeB();
}
diff --git a/tests/compiler/dart2js_native/native_class_fields_2_test.dart b/tests/compiler/dart2js_native/native_class_fields_2_test.dart
index b7ddbf7..4e67b81 100644
--- a/tests/compiler/dart2js_native/native_class_fields_2_test.dart
+++ b/tests/compiler/dart2js_native/native_class_fields_2_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Verify that methods are not renamed to clash with native field names
// that are known from the DOM (like x, y, z).
-class A native "A" {
+@Native("A")
+class A {
int x;
int y;
int z;
diff --git a/tests/compiler/dart2js_native/native_class_fields_3_test.dart b/tests/compiler/dart2js_native/native_class_fields_3_test.dart
index cbd97a9..bfee4a7 100644
--- a/tests/compiler/dart2js_native/native_class_fields_3_test.dart
+++ b/tests/compiler/dart2js_native/native_class_fields_3_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Verify that we can have fields with names that start with g and s even
@@ -12,7 +13,8 @@
// names for clashes because it's hard - subclasses can force superclasses
// to rename getters, and that can force unrelated classes to change their
// getters too if they have a property that has the same name.
-class A native "A" {
+@Native("A")
+class A {
int bar;
int g;
int s;
diff --git a/tests/compiler/dart2js_native/native_class_fields_test.dart b/tests/compiler/dart2js_native/native_class_fields_test.dart
index 309654a..110d6c5 100644
--- a/tests/compiler/dart2js_native/native_class_fields_test.dart
+++ b/tests/compiler/dart2js_native/native_class_fields_test.dart
@@ -2,10 +2,12 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Verify that native fields on classes are not renamed by the minifier.
-class A native "A" {
+@Native("A")
+class A {
int myLongPropertyName;
int getValue;
@@ -21,7 +23,7 @@
function setter(x) {
this.getValue += 10;
}
-
+
function A(){
var a = Object.create(
{ constructor: { name: 'A'}},
diff --git a/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart
index 75a1032..65085cc 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test to see if resolving a hidden native class's method interferes with
@@ -10,11 +11,13 @@
// stored on Object.prototype.
// Version 1: It might be possible to call foo directly.
-class A1 native "A1" {
+@Native("A1")
+class A1 {
foo() native;
}
-class B1 extends A1 native "B1" {
+@Native("B1")
+class B1 extends A1 {
foo() native;
}
@@ -23,11 +26,13 @@
// Version 2: foo needs some kind of trampoline.
-class A2 native "A2" {
+@Native("A2")
+class A2 {
foo([a=99]) native;
}
-class B2 extends A2 native "B2" {
+@Native("B2")
+class B2 extends A2 {
foo([z=1000]) native;
}
diff --git a/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart
index 7177573..bb5d7fb 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test to see if resolving a hidden native class's method interferes with
@@ -9,18 +10,22 @@
// superclass caches the method in the prototype, so shadowing the dispatcher
// stored on Object.prototype.
-class A native "A" {
+@Native("A")
+class A {
foo([a=100]) native;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
}
-class C extends B native "C" {
+@Native("C")
+class C extends B {
foo([z=300]) native;
}
-class D extends C native "D" {
+@Native("D")
+class D extends C {
}
makeA() native;
diff --git a/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart
index aff6345..320da8c 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart
@@ -2,27 +2,32 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test to see if resolving a hidden native class's method to noSuchMethod
// interferes with subsequent resolving of the method. This might happen if the
// noSuchMethod is cached on Object.prototype.
-class A1 native "A1" {
+@Native("A1")
+class A1 {
}
-class B1 extends A1 native "B1" {
+@Native("B1")
+class B1 extends A1 {
}
makeA1() native;
makeB1() native;
-class A2 native "A2" {
+@Native("A2")
+class A2 {
foo([a=99]) native;
}
-class B2 extends A2 native "B2" {
+@Native("B2")
+class B2 extends A2 {
}
makeA2() native;
diff --git a/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart
index b243c59..fcd1e3a 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart
@@ -2,13 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Additional Dart code may be 'placed on' hidden native classes. With
// inheritance, the superclass method must not be reached by a call on the
// subclass.
-class A native "A" {
+@Native("A")
+class A {
var _field;
int get X => _field;
@@ -17,7 +19,8 @@
int method(int z) => _field + z;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
var _field2;
int get X => _field2;
diff --git a/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart b/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart
index e01fa1a..32d84bf 100644
--- a/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test for correct simple is-checks on hidden native classes.
@@ -13,7 +14,8 @@
// Native implementation.
-class A implements I native "A" {
+@Native("A")
+class A implements I {
// The native class accepts only other native instances.
A read() native;
write(A x) native;
diff --git a/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart b/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart
index 490e820..4a9c64d 100644
--- a/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test for correct simple is-checks on hidden native classes.
@@ -16,13 +17,15 @@
// Native implementation.
-class A implements I native "A" {
+@Native("A")
+class A implements I {
// The native class accepts only other native instances.
A read() native;
write(A x) native;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
}
makeA() native;
diff --git a/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart b/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart
index c5519e9..eb9fd25 100644
--- a/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Additional Dart code may be 'placed on' hidden native classes.
-class A native "A" {
+@Native("A")
+class A {
var _field;
diff --git a/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart b/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart
index 84b379b..943b063 100644
--- a/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
typedef void MyFunctionType();
-class A native "A" {
+@Native("A")
+class A {
setClosure(MyFunctionType f) native;
check(MyFunctionType f) native;
invoke() native;
diff --git a/tests/compiler/dart2js_native/native_constructor_name_test.dart b/tests/compiler/dart2js_native/native_constructor_name_test.dart
index 1a88b65..07a7a95 100644
--- a/tests/compiler/dart2js_native/native_constructor_name_test.dart
+++ b/tests/compiler/dart2js_native/native_constructor_name_test.dart
@@ -8,12 +8,14 @@
// This could be done by renaming the Dart constructor or by being able to check
// that objects are Dart classes.
+import "dart:_js_helper";
import "package:expect/expect.dart";
class A {
}
-class Z native "A" {
+@Native("A")
+class Z {
foo() => 100;
}
diff --git a/tests/compiler/dart2js_native/native_equals_frog_test.dart b/tests/compiler/dart2js_native/native_equals_frog_test.dart
index 9d04fc4..0d1980a 100644
--- a/tests/compiler/dart2js_native/native_equals_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_equals_frog_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {}
+@Native("A")
+class A {}
makeA() native;
void setup() native """
diff --git a/tests/compiler/dart2js_native/native_exception2_test.dart b/tests/compiler/dart2js_native/native_exception2_test.dart
index 6f26332..113e9ef 100644
--- a/tests/compiler/dart2js_native/native_exception2_test.dart
+++ b/tests/compiler/dart2js_native/native_exception2_test.dart
@@ -8,8 +8,10 @@
library native_exception2_test;
import 'native_exception_test.dart' as other;
+import 'dart:_js_helper';
-class NativeClass native "NativeClass" {
+@Native("NativeClass")
+class NativeClass {
}
makeNativeClass() native;
diff --git a/tests/compiler/dart2js_native/native_exception_test.dart b/tests/compiler/dart2js_native/native_exception_test.dart
index 9b1d346..e3d2231 100644
--- a/tests/compiler/dart2js_native/native_exception_test.dart
+++ b/tests/compiler/dart2js_native/native_exception_test.dart
@@ -7,8 +7,8 @@
library native_exception_test;
import 'dart:_foreign_helper' show JS;
-
-import "package:expect/expect.dart";
+import 'dart:_js_helper';
+import 'package:expect/expect.dart';
main() {
var previous;
diff --git a/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart b/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart
index a72911d..aa3c3d6 100644
--- a/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test that hidden native exception classes can be marked as existing.
@@ -17,14 +18,16 @@
// The exception type.
-class E native "E" {
+@Native("E")
+class E {
E._used() native; // Bogus native constructor, called only from fake body.
final int code;
}
// Type with exception-throwing methods.
-class A native "A" {
+@Native("A")
+class A {
op(int x) native {
// Fake body calls constructor to mark the exception class (E) as used.
throw new E._used();
diff --git a/tests/compiler/dart2js_native/native_field_invocation2_test.dart b/tests/compiler/dart2js_native/native_field_invocation2_test.dart
index 29c261c..7b6dc90 100644
--- a/tests/compiler/dart2js_native/native_field_invocation2_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation2_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class NNative native "NNative" {
+@Native("NNative")
+class NNative {
var status;
var f;
diff --git a/tests/compiler/dart2js_native/native_field_invocation3_test.dart b/tests/compiler/dart2js_native/native_field_invocation3_test.dart
index 5946db7..f0559b6 100644
--- a/tests/compiler/dart2js_native/native_field_invocation3_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation3_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
makeCC() native;
@@ -12,7 +13,8 @@
""";
-class ClickCounter native "CC" {
+@Native("CC")
+class ClickCounter {
var status;
var foo;
diff --git a/tests/compiler/dart2js_native/native_field_invocation4_test.dart b/tests/compiler/dart2js_native/native_field_invocation4_test.dart
index 2840926..e0a5c00 100644
--- a/tests/compiler/dart2js_native/native_field_invocation4_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation4_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {
+@Native("A")
+class A {
var foo;
}
diff --git a/tests/compiler/dart2js_native/native_field_invocation5_test.dart b/tests/compiler/dart2js_native/native_field_invocation5_test.dart
index 8288344..e5a0440 100644
--- a/tests/compiler/dart2js_native/native_field_invocation5_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation5_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
makeCC() native;
@@ -17,7 +18,8 @@
foo(x) => x;
}
-class ClickCounter native "CC" {
+@Native("CC")
+class ClickCounter {
var status;
var foo;
diff --git a/tests/compiler/dart2js_native/native_field_invocation6_test.dart b/tests/compiler/dart2js_native/native_field_invocation6_test.dart
index bd8e9c2..cd2d93b 100644
--- a/tests/compiler/dart2js_native/native_field_invocation6_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation6_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
makeA() native;
@@ -15,7 +16,8 @@
""";
-class A native "A" {
+@Native("A")
+class A {
var _foo;
get foo => _foo;
diff --git a/tests/compiler/dart2js_native/native_field_invocation_test.dart b/tests/compiler/dart2js_native/native_field_invocation_test.dart
index 95081bf..54eaf50 100644
--- a/tests/compiler/dart2js_native/native_field_invocation_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {
+@Native("A")
+class A {
var foo;
}
diff --git a/tests/compiler/dart2js_native/native_field_name_test.dart b/tests/compiler/dart2js_native/native_field_name_test.dart
index 8eab52b..42af8880 100644
--- a/tests/compiler/dart2js_native/native_field_name_test.dart
+++ b/tests/compiler/dart2js_native/native_field_name_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Check that native fields are not incorrectly renamed.
-class A native "A" {
+@Native("A")
+class A {
int myLongPropertyName;
int getValue;
diff --git a/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart b/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart
index 8b2a1d6..755da14 100644
--- a/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart
@@ -7,9 +7,10 @@
// for the field must be based on the field's name, not the field's jsname.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
-class A native "A" {
+@Native("A")
+class A {
int key; // jsname is 'key'
int getKey() => key;
}
@@ -20,7 +21,8 @@
int getKey() => key;
}
-class X native "X" {
+@Native("X")
+class X {
@JSName('key')
int native_key_method() native;
// This should cause B.key to be renamed, but not A.key.
diff --git a/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart b/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart
index 2bd4481..8a85ab3 100644
--- a/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart
@@ -7,13 +7,14 @@
// for the field must be based on the field's name, not the field's jsname.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
abstract class I {
int key;
}
-class A implements I native "A" {
+@Native("A")
+class A implements I {
int key; // jsname is 'key'
int getKey() => key;
}
@@ -24,7 +25,8 @@
int getKey() => key;
}
-class X native "X" {
+@Native("X")
+class X {
@JSName('key')
int native_key_method() native;
// This should cause B.key to be renamed, but not A.key.
diff --git a/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart b/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart
index 558e619..9ea0f42 100644
--- a/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart
+++ b/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart
@@ -6,9 +6,11 @@
library lib2;
import 'native_library_same_name_used_lib1.dart'; // To get abstract class I.
+import 'dart:_js_helper';
// Native impl has same name as abstract class.
-class Impl implements I native "I" {
+@Native("I")
+class Impl implements I {
Impl read() native;
write(Impl x) native;
}
diff --git a/tests/compiler/dart2js_native/native_method_inlining_test.dart b/tests/compiler/dart2js_native/native_method_inlining_test.dart
index 8509685..a3aee2c 100644
--- a/tests/compiler/dart2js_native/native_method_inlining_test.dart
+++ b/tests/compiler/dart2js_native/native_method_inlining_test.dart
@@ -6,11 +6,12 @@
// number of arguments in the call site AND the call site is inlined.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show NoInline;
+import 'dart:_js_helper' show Native, NoInline;
typedef int Int2Int(int x);
-class A native "A" {
+@Native("A")
+class A {
int foo([x, y, z]) native;
// Calls can be inlined provided they don't pass an argument.
diff --git a/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart b/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart
index 286e588..22e2eac 100644
--- a/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart
@@ -5,9 +5,10 @@
// Test the feature where the native string declares the native method's name.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
-class A native "A" {
+@Native("A")
+class A {
@JSName('fooA')
int foo() native;
diff --git a/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart b/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart
index 31fb465..2fd79c8 100644
--- a/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart
@@ -5,14 +5,16 @@
// Test the feature where the native string declares the native method's name.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
-class A native "A" {
+@Native("A")
+class A {
@JSName('fooA')
int foo() native;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
@JSName('fooB')
int foo() native;
}
diff --git a/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart b/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart
index f7455b3..433ff45 100644
--- a/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart
@@ -6,14 +6,16 @@
// #3. The name does not get
import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
-class A native "A" {
+@Native("A")
+class A {
@JSName('fooA')
int foo() native;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
@JSName('fooB')
int foo() native;
int fooA() => 333;
diff --git a/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart b/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart
index 989312d..26ac11b 100644
--- a/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart
+++ b/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Make sure we can have a native with a name that is a JavaScript keyword.
-class A native "A" {
+@Native("A")
+class A {
int delete() native;
}
@@ -26,5 +28,5 @@
var a = makeA();
Expect.equals(87, a.delete());
A aa = a;
- Expect.equals(87, aa.delete());
+ Expect.equals(87, aa.delete());
}
diff --git a/tests/compiler/dart2js_native/native_mirror_test.dart b/tests/compiler/dart2js_native/native_mirror_test.dart
index 79b842c..58e8ffe 100644
--- a/tests/compiler/dart2js_native/native_mirror_test.dart
+++ b/tests/compiler/dart2js_native/native_mirror_test.dart
@@ -10,9 +10,11 @@
// convention for others, making this fail.
import "package:expect/expect.dart";
+import "dart:_js_helper";
import "dart:mirrors";
-class A native "A" {
+@Native("A")
+class A {
final foo;
}
diff --git a/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart b/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart
index b630d23..72ffbc6 100644
--- a/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {
+@Native("A")
+class A {
}
makeA() native;
diff --git a/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart b/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart
index 7d473ab..5a083d7 100644
--- a/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {
+@Native("A")
+class A {
}
makeA() native;
diff --git a/tests/compiler/dart2js_native/native_mixin_field_test.dart b/tests/compiler/dart2js_native/native_mixin_field_test.dart
index 8ccda28..7ef9e2d 100644
--- a/tests/compiler/dart2js_native/native_mixin_field_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_field_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that native classes can use ordinary Dart classes with fields
// as mixins.
-class A native "A" {
+@Native("A")
+class A {
var foo;
}
-class B extends A with M1, M2 native "B" {
+@Native("B")
+class B extends A with M1, M2 {
var bar;
}
diff --git a/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart b/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart
index cf372f6..f59d2e1 100644
--- a/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart
@@ -2,15 +2,18 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test that native classes can access methods defined only by mixins.
-class A native "A" {
+@Native("A")
+class A {
foo(x, [y]) => '$x;$y';
}
-class B extends A with M1, M2, M3 native "B" {
+@Native("B")
+class B extends A with M1, M2, M3 {
}
class M1 {}
diff --git a/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart b/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart
index 50340e4..1bd434b 100644
--- a/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test that native classes and plain classes can access methods defined only by
@@ -23,13 +24,16 @@
class M3 { }
-class A native "A" {
+@Native("A")
+class A {
foo() => 'A.foo';
}
-class B extends A with M1, M2, M3 native "B" {}
+@Native("B")
+class B extends A with M1, M2, M3 {}
-class C extends B native "C" {
+@Native("C")
+class C extends B {
foo() => 'C.foo';
}
diff --git a/tests/compiler/dart2js_native/native_mixin_multiple_test.dart b/tests/compiler/dart2js_native/native_mixin_multiple_test.dart
index 4e930c7..031f6c1 100644
--- a/tests/compiler/dart2js_native/native_mixin_multiple_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_multiple_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that native classes can use ordinary Dart classes as mixins.
-class A native "A" {
+@Native("A")
+class A {
foo() => "A-foo";
baz() => "A-baz";
}
-class B extends A with M1, M2 native "B" {
+@Native("B")
+class B extends A with M1, M2 {
bar() => baz();
}
diff --git a/tests/compiler/dart2js_native/native_mixin_test.dart b/tests/compiler/dart2js_native/native_mixin_test.dart
index d63f306..7cac689 100644
--- a/tests/compiler/dart2js_native/native_mixin_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that native classes can use ordinary Dart classes as mixins.
-class A native "A" {
+@Native("A")
+class A {
foo() => "A-foo";
baz() => "A-baz";
}
-class B extends A with M native "B" {
+@Native("B")
+class B extends A with M {
bar() => baz();
}
diff --git a/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart b/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart
index c21e0b3..3708603 100644
--- a/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart
@@ -2,18 +2,21 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that native classes and ordinary Dart classes can both use the same
// ordinary Dart classes as a mixin.
-class A native "A" {
+@Native("A")
+class A {
final String aa;
foo() => "A-foo $aa";
baz() => "A-baz $aa";
}
-class B extends A with M native "B" {
+@Native("B")
+class B extends A with M {
bar() => 'B-bar -> ${baz()}';
get mm => 'B.mm($aa)';
}
diff --git a/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart b/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart
index 2620f96..b0d63e2 100644
--- a/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart
@@ -2,13 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Native class with named constructors and static methods.
-class A native "A" {
+@Native("A")
+class A {
factory A(int len) => _construct(len);
diff --git a/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart b/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart
index 001c4ae..fa4c14c 100644
--- a/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart
@@ -2,13 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Hidden native class with factory constructors and NO static methods.
// Regression test.
-class A native "A" {
+@Native("A")
+class A {
// No static methods in this class.
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart
index 1c2f5a9..f7581b2 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart
@@ -2,12 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {
+@Native("A")
+class A {
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
foo() native;
}
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart
index 886e33f..0f1d009 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:mirrors" show reflect;
+import "dart:_js_helper";
import "package:expect/expect.dart";
class GetName {
@@ -11,11 +12,13 @@
String getName(im) => reflect(new GetName()).delegate(im);
-class A native "A" {
+@Native("A")
+class A {
bar() => 42;
}
-class B native "B" {
+@Native("B")
+class B {
foo() => 42;
}
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart
index fed9ce8..ee0af94 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:mirrors" show reflect;
+import "dart:_js_helper";
import "package:expect/expect.dart";
class GetName {
@@ -12,12 +13,14 @@
String getName(im) => reflect(new GetName()).delegate(im);;
-class A native "A" {
+@Native("A")
+class A {
bar() => 42;
noSuchMethod(x) => "native(${getName(x)}:${x.positionalArguments})";
}
-class B native "B" {
+@Native("B")
+class B {
baz() => 42;
}
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart
index 87b3a37..98041ec 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:mirrors" show reflect;
+import "dart:_js_helper";
import "package:expect/expect.dart";
class GetName {
@@ -12,12 +13,14 @@
String getName(im) => reflect(new GetName()).delegate(im);
-class A native "A" {
+@Native("A")
+class A {
bar() => 42;
noSuchMethod(x) => "native(${getName(x)}:${x.positionalArguments})";
}
-class B native "B" {
+@Native("B")
+class B {
baz() => 42;
}
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart
index 007de7f..2319106 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart
@@ -2,13 +2,16 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {
+@Native("A")
+class A {
bar() => 42;
}
-class B native "B" {
+@Native("B")
+class B {
foo() => 42;
}
diff --git a/tests/compiler/dart2js_native/native_novel_html_test.dart b/tests/compiler/dart2js_native/native_novel_html_test.dart
index 660685a..fba8be7 100644
--- a/tests/compiler/dart2js_native/native_novel_html_test.dart
+++ b/tests/compiler/dart2js_native/native_novel_html_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test to see if novel HTML tags are interpreted as HTMLElement.
-class Element native "HTMLElement" {
+@Native("HTMLElement")
+class Element {
String dartMethod(int x) => 'dartMethod(${nativeMethod(x+1)})';
String nativeMethod(int x) native;
}
diff --git a/tests/compiler/dart2js_native/native_null_closure_frog_test.dart b/tests/compiler/dart2js_native/native_null_closure_frog_test.dart
index 6c08375..69f9e0c 100644
--- a/tests/compiler/dart2js_native/native_null_closure_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_null_closure_frog_test.dart
@@ -4,13 +4,14 @@
// Test that exception unwrapping handle cases like ({foo:null}).foo().
-import 'dart:_js_helper';
+import "dart:_js_helper";
import "package:expect/expect.dart";
typedef void MyFunctionType();
-class A native "A" {
+@Native("A")
+class A {
setClosure(MyFunctionType f) native;
check(MyFunctionType f) native;
invoke() native;
diff --git a/tests/compiler/dart2js_native/native_null_frog_test.dart b/tests/compiler/dart2js_native/native_null_frog_test.dart
index 846c9b4..7a92684 100644
--- a/tests/compiler/dart2js_native/native_null_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_null_frog_test.dart
@@ -2,12 +2,14 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test for values of some basic types.
-class A native "A" {
+@Native("A")
+class A {
returnNull() native;
returnUndefined() native;
returnEmptyString() native;
diff --git a/tests/compiler/dart2js_native/native_property_frog_test.dart b/tests/compiler/dart2js_native/native_property_frog_test.dart
index 5814994..04cca4d 100644
--- a/tests/compiler/dart2js_native/native_property_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_property_frog_test.dart
@@ -5,9 +5,11 @@
// Properties on hidden native classes.
import "package:expect/expect.dart";
+import "dart:_js_helper";
import 'dart:_foreign_helper' show JS;
-class A native "A" {
+@Native("A")
+class A {
// Setters and getters should be similar to these methods:
int getX() => JS('int', '#._x', this);
diff --git a/tests/compiler/dart2js_native/native_to_string_frog_test.dart b/tests/compiler/dart2js_native/native_to_string_frog_test.dart
index c15dc55..3b9a47a 100644
--- a/tests/compiler/dart2js_native/native_to_string_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_to_string_frog_test.dart
@@ -2,9 +2,11 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
-class A native "A" {}
+@Native("A")
+class A {}
makeA() native;
void setup() native """
diff --git a/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart b/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart
index 8c89d38..1f529c9 100644
--- a/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart
@@ -2,16 +2,19 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that we put native names and not Dart names into the dynamic
// dispatch table.
-class A native "NativeA" {
+@Native("NativeA")
+class A {
foo() native;
}
-class B extends A native "NativeB" {
+@Native("NativeB")
+class B extends A {
}
A makeA() native { return new A(); }
@@ -22,7 +25,7 @@
if (child.prototype.__proto__) {
child.prototype.__proto__ = parent.prototype;
} else {
- function tmp() {};
+ function tmp() {};
tmp.prototype = parent.prototype;
child.prototype = new tmp();
child.prototype.constructor = child;
@@ -44,10 +47,10 @@
var a = makeA();
Expect.equals(42, a.foo());
A aa = a;
- Expect.equals(42, aa.foo());
+ Expect.equals(42, aa.foo());
var b = makeB();
Expect.equals(42, b.foo());
B bb = b;
- Expect.equals(42, bb.foo());
+ Expect.equals(42, bb.foo());
}
diff --git a/tests/compiler/dart2js_native/native_window1_frog_test.dart b/tests/compiler/dart2js_native/native_window1_frog_test.dart
index f6b727a..b0588ec 100644
--- a/tests/compiler/dart2js_native/native_window1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_window1_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
abstract class Window {
@@ -10,7 +11,8 @@
// Defining this global object makes Frog eager on optimizing
// call sites where the receiver is typed 'Window'.
-class _DOMWindowJs implements Window native "@*DOMWindow" {
+@Native("@*DOMWindow")
+class _DOMWindowJs implements Window {
final int document;
}
diff --git a/tests/compiler/dart2js_native/native_window2_frog_test.dart b/tests/compiler/dart2js_native/native_window2_frog_test.dart
index c1cecef..c252e46 100644
--- a/tests/compiler/dart2js_native/native_window2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_window2_frog_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
abstract class Window {
@@ -10,7 +11,8 @@
// Defining this global object makes Frog eager on optimizing
// call sites where the receiver is typed 'Window'.
-class _DOMWindowJs implements Window native "@*DOMWindow" {
+@Native("@*DOMWindow")
+class _DOMWindowJs implements Window {
final int document;
}
diff --git a/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart b/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart
index 22f2f3e..72de377 100644
--- a/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
+import "dart:_js_helper";
typedef void Callback0();
typedef void Callback1(arg1);
typedef void Callback2(arg1, arg2);
-class A native "A" {
+@Native("A")
+class A {
foo1(Callback1 closure, [arg1 = 0]) native;
foo2(Callback2 closure, [arg1 = 0, arg2 = 1]) native;
}
diff --git a/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart b/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart
index eca6639..1095c6c 100644
--- a/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart
@@ -2,13 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
typedef void Callback0();
typedef void Callback1(arg1);
typedef void Callback2(arg1, arg2);
-class A native "A" {
+@Native("A")
+class A {
foo0(Callback0 closure) native;
foo1(Callback1 closure, arg1) native;
foo2(Callback2 closure, arg1, arg2) native;
diff --git a/tests/compiler/dart2js_native/oddly_named_fields_test.dart b/tests/compiler/dart2js_native/oddly_named_fields_test.dart
index b2dae29..984e4d1 100644
--- a/tests/compiler/dart2js_native/oddly_named_fields_test.dart
+++ b/tests/compiler/dart2js_native/oddly_named_fields_test.dart
@@ -61,7 +61,8 @@
// See section 11.2 "Left-Hand-Side Expressions" which states that a
// "MemberExpression" includes: "MemberExpression . IdentifierName".
-class NativeClassWithOddNames native "NativeClassWithOddNames" {
+@Native("NativeClassWithOddNames")
+class NativeClassWithOddNames {
@JSName('break') bool breakValue;
@JSName('case') bool caseValue;
@JSName('catch') bool catchValue;
diff --git a/tests/compiler/dart2js_native/rti_only_native_test.dart b/tests/compiler/dart2js_native/rti_only_native_test.dart
index 634f752..981f411 100644
--- a/tests/compiler/dart2js_native/rti_only_native_test.dart
+++ b/tests/compiler/dart2js_native/rti_only_native_test.dart
@@ -7,7 +7,10 @@
// See my explanation in https://codereview.chromium.org/14018036/.
// -- ahe
-class A native "A" {
+import "dart:_js_helper";
+
+@Native("A")
+class A {
// Just making sure the field name is unique.
var rti_only_native_test_field;
}
diff --git a/tests/compiler/dart2js_native/runtimetype_test.dart b/tests/compiler/dart2js_native/runtimetype_test.dart
index dc8d7a4..460dfd0 100644
--- a/tests/compiler/dart2js_native/runtimetype_test.dart
+++ b/tests/compiler/dart2js_native/runtimetype_test.dart
@@ -3,15 +3,18 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
+import "dart:_js_helper";
import 'dart:_foreign_helper' show JS;
// Test to see runtimeType works on native classes and does not use the native
// constructor name.
-class A native "TAGX" {
+@Native("TAGX")
+class A {
}
-class B extends A native "TAGY" {
+@Native("TAGY")
+class B extends A {
}
makeA() native;
diff --git a/tests/compiler/dart2js_native/subclassing_1_test.dart b/tests/compiler/dart2js_native/subclassing_1_test.dart
index b90366a..b86130f 100644
--- a/tests/compiler/dart2js_native/subclassing_1_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_1_test.dart
@@ -3,13 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show findInterceptorForType;
// Test that subclasses of native classes can be defined by setting the dispatch
// record.
-class A native "A" {
+@Native("A")
+class A {
foo(x) => '$x,${this.oof()}';
oof() => 'A';
}
diff --git a/tests/compiler/dart2js_native/subclassing_2_test.dart b/tests/compiler/dart2js_native/subclassing_2_test.dart
index f8b93aa..db588dd 100644
--- a/tests/compiler/dart2js_native/subclassing_2_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_2_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show findInterceptorForType;
// Test calling convention of methods introduced on subclasses of native
@@ -11,7 +11,8 @@
doFoo(r, x) => '$x,${r.oof()}';
-class A native "A" {
+@Native("A")
+class A {
foo(x) => (doFoo)(this, x);
}
diff --git a/tests/compiler/dart2js_native/subclassing_3_test.dart b/tests/compiler/dart2js_native/subclassing_3_test.dart
index d73f0c8..70595cb 100644
--- a/tests/compiler/dart2js_native/subclassing_3_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_3_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show Interceptor, findInterceptorForType;
// Test calling convention of methods introduced on subclasses of native
@@ -15,7 +15,8 @@
miz() => 'M';
}
-class N native "N" {
+@Native("N")
+class N {
foo(x) => (doFoo)(this, x);
}
diff --git a/tests/compiler/dart2js_native/subclassing_4_test.dart b/tests/compiler/dart2js_native/subclassing_4_test.dart
index 9d25e1a..4997bb2 100644
--- a/tests/compiler/dart2js_native/subclassing_4_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_4_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show Interceptor, findInterceptorForType;
// Test calling convention on subclasses of native classes.
@@ -12,7 +12,8 @@
miz() => 'M';
}
-class N native "N" {}
+@Native("N")
+class N {}
class A extends N {}
diff --git a/tests/compiler/dart2js_native/subclassing_5_test.dart b/tests/compiler/dart2js_native/subclassing_5_test.dart
index 39703d1..b1117db 100644
--- a/tests/compiler/dart2js_native/subclassing_5_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_5_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show Interceptor, findInterceptorForType;
// Test type checks.
@@ -14,7 +14,8 @@
miz() => 'M';
}
-class N native "N" {}
+@Native("N")
+class N {}
class A extends N {}
diff --git a/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart b/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
index 36fed2e..a1e7105 100644
--- a/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
@@ -4,7 +4,7 @@
import "package:expect/expect.dart";
import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show
findInterceptorForType, findConstructorForNativeSubclassType;
@@ -15,7 +15,8 @@
var log;
-class A native "A" {
+@Native("A")
+class A {
final a1 = log(101); // Only initialized IF named constructor called.
final a2; // Initialized by native constructor.
final a3; // Initialized only by A.two.
diff --git a/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart b/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart
index 75e321c..2b9f6c5 100644
--- a/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart
@@ -2,12 +2,14 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Test that native classes and subclasses of native classes cannot be directly
// created via a generative constructor.
-class A native "A" {
+@Native("A")
+class A {
A.one();
}
diff --git a/tests/compiler/dart2js_native/subclassing_super_call_test.dart b/tests/compiler/dart2js_native/subclassing_super_call_test.dart
index f13a42e..a424b95 100644
--- a/tests/compiler/dart2js_native/subclassing_super_call_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_super_call_test.dart
@@ -4,16 +4,18 @@
import "package:expect/expect.dart";
import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show
findInterceptorForType, findConstructorForNativeSubclassType;
// Test for super access from classes that extend native classes.
-class N1 native "N1" {
+@Native("N1")
+class N1 {
}
-class N2 extends N1 native "N2" {
+@Native("N2")
+class N2 extends N1 {
N2.init();
String text;
foo() native;
diff --git a/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart b/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart
index 250c884..97da995 100644
--- a/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart
@@ -4,13 +4,14 @@
import "package:expect/expect.dart";
import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show
findInterceptorForType, findConstructorForNativeSubclassType;
// Test for shadowed fields in classes that extend native classes.
-class N native "N" {
+@Native("N")
+class N {
N.init();
}
diff --git a/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart b/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart
index dca071b..f325a727 100644
--- a/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart
@@ -4,14 +4,15 @@
import "package:expect/expect.dart";
import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show
findInterceptorForType, findConstructorForNativeSubclassType;
// Test for fields with same name as native fields. We expect N.foo to have the
// property name 'foo' and A.foo and B.foo to have non-conflicting names.
-class N native "N" {
+@Native("N")
+class N {
var foo;
N.init();
}
diff --git a/tests/compiler/dart2js_native/subclassing_type_test.dart b/tests/compiler/dart2js_native/subclassing_type_test.dart
index 34748bf..abcb629 100644
--- a/tests/compiler/dart2js_native/subclassing_type_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_type_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
import 'dart:_interceptors' show Interceptor, findInterceptorForType;
// Test that type checks and casts work for subclasses of native classes and
@@ -11,7 +11,8 @@
class M {}
-class N native "N" {}
+@Native("N")
+class N {}
class A extends N {}
diff --git a/tests/compiler/dart2js_native/super_call_test.dart b/tests/compiler/dart2js_native/super_call_test.dart
index 68cccb7..ccb6f09 100644
--- a/tests/compiler/dart2js_native/super_call_test.dart
+++ b/tests/compiler/dart2js_native/super_call_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test to see if resolving a hidden native class's method interferes with
@@ -9,21 +10,25 @@
// superclass caches the method in the prototype, so shadowing the dispatcher
// stored on Object.prototype.
-class A native "A" {
+@Native("A")
+class A {
foo() => 'A.foo ${bar()}';
bar() => 'A.bar';
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
bar() => 'B.bar';
}
-class C extends B native "C" {
+@Native("C")
+class C extends B {
foo() => 'C.foo; super.foo = ${super.foo()}';
bar() => 'C.bar';
}
-class D extends C native "D" {
+@Native("D")
+class D extends C {
bar() => 'D.bar';
}
diff --git a/tests/compiler/dart2js_native/super_property_test.dart b/tests/compiler/dart2js_native/super_property_test.dart
index 003a4de..b2c89ea 100644
--- a/tests/compiler/dart2js_native/super_property_test.dart
+++ b/tests/compiler/dart2js_native/super_property_test.dart
@@ -2,18 +2,21 @@
// for 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:_js_helper";
import "package:expect/expect.dart";
// Tests super setter where the HInvokeSuper is using interceptor aka
// explicit-receiver calling convention.
-class A native "A" {
+@Native("A")
+class A {
var foo;
get_foo() => foo;
set bar(value) => foo = value;
}
-class B extends A native "B" {
+@Native("B")
+class B extends A {
set foo(value) {
super.foo = value;
}
diff --git a/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart b/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
index 61f3b604..43efdb6 100644
--- a/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
+++ b/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:_js_helper";
import "package:expect/expect.dart";
// Test for uninstantiated native classes as type parameters.
@@ -9,7 +10,8 @@
class UA {
}
-class UB native "B" {
+@Native("B")
+class UB {
}
class C<T> {
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index c9d4411..9e3b7aa 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -43,6 +43,9 @@
symbol_operator_test/03: Fail # bug 11669
string_case_test/01: Fail # Bug 18061
+iterable_return_type_test/01: RuntimeError # Issue 13646
+iterable_return_type_test/02: RuntimeError # Issue 13646
+
[ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
main_test: Fail # Dartium needs to check for both main() and main(args).
@@ -67,6 +70,8 @@
error_stack_trace1_test: RuntimeError # Issue 12399
hash_set_test/01: RuntimeError # Issue 11551
integer_to_string_test/01: RuntimeError # Issue 1533
+iterable_return_type_test/01: RuntimeError # Issue 20085
+iterable_return_type_test/02: RuntimeError # Dart2js does not support Uint64*.
big_integer_vm_test: RuntimeError, OK # VM specific test.
bit_twiddling_bigint_test: RuntimeError # Requires bigint support.
diff --git a/tests/corelib/format_exception_test.dart b/tests/corelib/format_exception_test.dart
index f17bcdc..121494c 100644
--- a/tests/corelib/format_exception_test.dart
+++ b/tests/corelib/format_exception_test.dart
@@ -5,10 +5,10 @@
library format_exception_test;
import "package:expect/expect.dart";
-test(exn, message, source, position, toString) {
+test(exn, message, source, offset, toString) {
Expect.equals(message, exn.message);
Expect.equals(source, exn.source);
- Expect.equals(position, exn.position);
+ Expect.equals(offset, exn.offset);
Expect.equals(toString, exn.toString());
}
@@ -39,7 +39,7 @@
var o = new Object();
e = new FormatException("message", o, 10);
- test(e, "message", o, 10, "FormatException: message (at position 10)");
+ test(e, "message", o, 10, "FormatException: message (at offset 10)");
e = new FormatException("message", "source", 3);
test(e, "message", "source", 3,
diff --git a/tests/corelib/iterable_return_type_test.dart b/tests/corelib/iterable_return_type_test.dart
new file mode 100644
index 0000000..a16e1e5
--- /dev/null
+++ b/tests/corelib/iterable_return_type_test.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js where [List.addAll] was not typed
+// correctly.
+
+import "package:expect/expect.dart";
+
+import 'dart:collection';
+import 'dart:typed_data';
+
+testIntIterable(iterable) {
+ Expect.isTrue(iterable is Iterable<int>);
+ Expect.isFalse(iterable is Iterable<String>);
+}
+
+void testIterable(Iterable<int> iterable, [int depth = 3]) {
+ testIntIterable(iterable);
+ if (depth > 0) {
+ testIterable(iterable, depth - 1);
+ testIterable(iterable.where((x) => true), depth - 1);
+ testIterable(iterable.skip(1), depth - 1);
+ testIterable(iterable.take(1), depth - 1);
+ testIterable(iterable.skipWhile((x) => false), depth - 1);
+ testIterable(iterable.takeWhile((x) => true), depth - 1);
+ testList(iterable.toList(growable: true), depth - 1);
+ testList(iterable.toList(growable: false), depth - 1);
+ testIterable(iterable.toSet(), depth - 1);
+ }
+}
+
+void testList(List<int> list, [int depth = 3]) {
+ testIterable(list, depth);
+ if (depth > 0) {
+ testIterable(list.getRange(0, list.length), depth - 1);
+ testIterable(list.reversed, depth - 1);
+ testMap(list.asMap(), depth - 1);
+ }
+}
+
+void testMap(Map<int, int> map, [int depth = 3]) {
+ Expect.isTrue(map is Map<int,int>);
+ Expect.isFalse(map is Map<int,String>);
+ Expect.isFalse(map is Map<String,int>);
+ if (depth > 0) {
+ testIterable(map.keys, depth - 1);
+ testIterable(map.values, depth - 1);
+ }
+}
+
+main() {
+ // Empty lists.
+ testList(<int>[]);
+ testList(new List<int>(0));
+ testList(new List<int>());
+ testList(const <int>[]);
+ testList(new List<int>.generate(0, (x) => x + 1));
+ // Singleton lists.
+ testList(<int>[1]);
+ testList(new List<int>(1)..[0] = 1);
+ testList(new List<int>()..add(1));
+ testList(const <int>[1]);
+ testList(new List<int>.generate(1, (x) => x + 1));
+
+ // Typed lists.
+ testList(new Uint8List(1)..[0] = 1); /// 01: ok
+ testList(new Int8List(1)..[0] = 1); /// 01: continued
+ testList(new Uint16List(1)..[0] = 1); /// 01: continued
+ testList(new Int16List(1)..[0] = 1); /// 01: continued
+ testList(new Uint32List(1)..[0] = 1); /// 01: continued
+ testList(new Int32List(1)..[0] = 1); /// 01: continued
+ testList(new Uint64List(1)..[0] = 1); /// 02: ok
+ testList(new Int64List(1)..[0] = 1); /// 02: continued
+
+ testIterable(new Set<int>()..add(1));
+ testIterable(new HashSet<int>()..add(1));
+ testIterable(new LinkedHashSet<int>()..add(1));
+ testIterable(new SplayTreeSet<int>()..add(1));
+
+ testIterable(new Queue<int>()..add(1));
+ testIterable(new DoubleLinkedQueue<int>()..add(1));
+ testIterable(new ListQueue<int>()..add(1));
+
+ testMap(new Map<int,int>()..[1] = 1);
+ testMap(new HashMap<int,int>()..[1] = 1);
+ testMap(new LinkedHashMap<int,int>()..[1] = 1);
+ testMap(new SplayTreeMap<int,int>()..[1] = 1);
+ testMap(<int,int>{1:1});
+ testMap(const <int,int>{1:1});
+}
diff --git a/tests/language/const_constructor_nonconst_field_test.dart b/tests/language/const_constructor_nonconst_field_test.dart
new file mode 100644
index 0000000..9571a40
--- /dev/null
+++ b/tests/language/const_constructor_nonconst_field_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ final int i = f(); /// 01: compile-time error
+ final int j = 1;
+ const A();
+}
+int f() {
+ return 3;
+}
+main() {
+ Expect.equals(const A().j, 1);
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 2d031678..5e8b8c5 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -137,3 +137,6 @@
[ $compiler == none && $runtime == vm && $arch == mips && $mode == debug ]
stack_overflow_test: Skip # Crashes. Issue 17440.
stack_overflow_stacktrace_test: Skip # Crashes. Issue 17440.
+
+[ $compiler == none || $compiler == dart2analyzer ]
+const_constructor_nonconst_field_test/01: Fail # Issue 18779, 18780
diff --git a/tests/language/vm/allocation_sinking_vm_test.dart b/tests/language/vm/allocation_sinking_vm_test.dart
index 619235a..55b5f35 100644
--- a/tests/language/vm/allocation_sinking_vm_test.dart
+++ b/tests/language/vm/allocation_sinking_vm_test.dart
@@ -163,6 +163,111 @@
Expect.equals(84, test_vm_field());
}
+class CompoundA {
+ var b;
+ CompoundA(this.b);
+}
+
+class CompoundB {
+ var c;
+ CompoundB(this.c);
+}
+
+class CompoundC {
+ var d;
+ var root;
+ CompoundC(this.d);
+}
+
+class NoopSink {
+ const NoopSink();
+ call(val) { }
+}
+
+testCompound1() {
+ f(d, [sink = const NoopSink()]) {
+ var c = new CompoundC(d);
+ var a = new CompoundA(new CompoundB(c));
+ sink(a);
+ return c.d;
+ }
+
+ Expect.equals(0.1, f(0.1));
+ for (var i = 0; i < 100; i++) f(0.1);
+ Expect.equals(0.1, f(0.1));
+ Expect.equals(0.1, f(0.1, (val) {
+ Expect.isTrue(val is CompoundA);
+ Expect.isTrue(val.b is CompoundB);
+ Expect.isTrue(val.b.c is CompoundC);
+ Expect.isNull(val.b.c.root);
+ Expect.equals(0.1, val.b.c.d);
+ }));
+}
+
+
+testCompound2() {
+ f(d, [sink = const NoopSink()]) {
+ var c = new CompoundC(d);
+ var a = new CompoundA(new CompoundB(c));
+ c.root = a;
+ sink(a);
+ return c.d;
+ }
+
+ Expect.equals(0.1, f(0.1));
+ for (var i = 0; i < 100; i++) f(0.1);
+ Expect.equals(0.1, f(0.1));
+ Expect.equals(0.1, f(0.1, (val) {
+ Expect.isTrue(val is CompoundA);
+ Expect.isTrue(val.b is CompoundB);
+ Expect.isTrue(val.b.c is CompoundC);
+ Expect.equals(val, val.b.c.root);
+ Expect.equals(0.1, val.b.c.d);
+ }));
+}
+
+
+testCompound3() {
+ f(d, [sink = const NoopSink()]) {
+ var c = new CompoundC(d);
+ c.root = c;
+ sink(c);
+ return c.d;
+ }
+
+ Expect.equals(0.1, f(0.1));
+ for (var i = 0; i < 100; i++) f(0.1);
+ Expect.equals(0.1, f(0.1));
+ Expect.equals(0.1, f(0.1, (val) {
+ Expect.isTrue(val is CompoundC);
+ Expect.equals(val, val.root);
+ Expect.equals(0.1, val.d);
+ }));
+}
+
+
+testCompound4() {
+ f(d, [sink = const NoopSink()]) {
+ var c = new CompoundC(d);
+ c.root = c;
+ for (var i = 0; i < 10; i++) {
+ c.d += 1.0;
+ }
+ sink(c);
+ return c.d - 1.0 * 10;
+ }
+
+ Expect.equals(1.0, f(1.0));
+ for (var i = 0; i < 100; i++) f(1.0);
+ Expect.equals(1.0, f(1.0));
+ Expect.equals(1.0, f(1.0, (val) {
+ Expect.isTrue(val is CompoundC);
+ Expect.equals(val, val.root);
+ Expect.equals(11.0, val.d);
+ }));
+}
+
+
main() {
var c = new C(new Point(0.1, 0.2));
@@ -220,4 +325,8 @@
testFinalField();
testVMField();
+ testCompound1();
+ testCompound2();
+ testCompound3();
+ testCompound4();
}
diff --git a/tests/language/vm/load_to_load_forwarding_vm_test.dart b/tests/language/vm/load_to_load_forwarding_vm_test.dart
index 5926305..86c5de7 100644
--- a/tests/language/vm/load_to_load_forwarding_vm_test.dart
+++ b/tests/language/vm/load_to_load_forwarding_vm_test.dart
@@ -240,49 +240,217 @@
return a[0] + a[1];
}
-testIndexedAliasedStore(a, b) {
- a[0] = 1;
- a[1] = 2;
- if (a == b) {
- b[0] = 3;
- }
- return a[0] + a[1];
-}
+//
+// Tests for indexed store aliases were autogenerated to have extensive
+// coverage for all interesting aliasing combinations within the alias
+// lattice (*[*], *[C], X[*], X[C])
+//
-testIndexedAliasedStore1(a, b) {
- a[0] = 1;
- a[1] = 2;
- if (a == b) {
- b[0] = 3;
- }
- return a[0] + a[1];
-}
-
-testIndexedAliasedStore2(a, b, i) {
- a[0] = 1;
- a[1] = 2;
- if (a == b) {
- b[i] = 3;
- }
- return a[0] + a[1];
-}
-
-
-testIndexedAliasedStore3(i) {
+testIndexedAliasedStore1(i) {
var a = new List(2);
- a[0] = 1;
- a[i] = 3;
+ a[0] = 1; // X[C]
+ a[i] = 2; // X[*]
return a[0];
}
-
-testIndexedAliasedStore4(b) {
+testIndexedAliasedStore2(f, c) {
var a = new List(2);
- a[0] = 1;
- b[0] = 3;
+ var d = f ? a : c;
+ a[0] = 1; // X[C]
+ d[0] = 2; // *[C]
return a[0];
}
+testIndexedAliasedStore3(f, c, i) {
+ var a = new List(2);
+ var d = f ? a : c;
+ a[0] = 1; // X[C]
+ d[i] = 2; // *[*]
+ return a[0];
+}
+
+testIndexedAliasedStore4(i) {
+ var a = new List(2);
+ a[i] = 1; // X[*]
+ a[0] = 2; // X[C]
+ return a[i];
+}
+
+testIndexedAliasedStore5(i, j) {
+ var a = new List(2);
+ a[i] = 1; // X[*]
+ a[j] = 2; // X[*]
+ return a[i];
+}
+
+testIndexedAliasedStore6(i, f, c) {
+ var a = new List(2);
+ var d = f ? a : c;
+ a[i] = 1; // X[*]
+ d[0] = 2; // *[C]
+ return a[i];
+}
+
+testIndexedAliasedStore7(i, f, c) {
+ var a = new List(2);
+ var d = f ? a : c;
+ a[i] = 1; // X[*]
+ d[i] = 2; // *[*]
+ return a[i];
+}
+
+testIndexedAliasedStore8(c, i) {
+ c[0] = 1; // *[C]
+ c[i] = 2; // *[*]
+ return c[0];
+}
+
+testIndexedAliasedStore9(c, f) {
+ var a = new List(2);
+ var d = f ? a : c;
+ c[0] = 1; // *[C]
+ d[0] = 2; // *[C]
+ return c[0];
+}
+
+testIndexedAliasedStore10(c, i) {
+ c[i] = 1; // *[*]
+ c[0] = 2; // *[C]
+ return c[i];
+}
+
+testIndexedAliasedStore11(c, i, j) {
+ c[i] = 1; // *[*]
+ c[j] = 2; // *[*]
+ return c[i];
+}
+
+testIndexedAliasedStore12(f, c) {
+ var a = new List(2);
+ var d = f ? a : c;
+ d[0] = 1; // *[C]
+ a[0] = 2; // X[C]
+ return d[0];
+}
+
+testIndexedAliasedStore13(f, c, i) {
+ var a = new List(2);
+ var d = f ? a : c;
+ d[0] = 1; // *[C]
+ a[i] = 2; // X[*]
+ return d[0];
+}
+
+testIndexedAliasedStore14(f, c, i) {
+ var a = new List(2);
+ var d = f ? a : c;
+ d[i] = 1; // *[*]
+ a[0] = 2; // X[C]
+ return d[i];
+}
+
+testIndexedAliasedStore15(f, c, i) {
+ var a = new List(2);
+ var d = f ? a : c;
+ d[i] = 1; // *[*]
+ a[i] = 2; // X[*]
+ return d[i];
+}
+
+testIndexedAliasedStores() {
+ var arr = new List(2);
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(2, testIndexedAliasedStore1(0));
+ Expect.equals(1, testIndexedAliasedStore1(1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore2(false, arr));
+ Expect.equals(2, testIndexedAliasedStore2(true, arr));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore3(false, arr, 0));
+ Expect.equals(1, testIndexedAliasedStore3(false, arr, 1));
+ Expect.equals(2, testIndexedAliasedStore3(true, arr, 0));
+ Expect.equals(1, testIndexedAliasedStore3(true, arr, 1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(2, testIndexedAliasedStore4(0));
+ Expect.equals(1, testIndexedAliasedStore4(1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(2, testIndexedAliasedStore5(0, 0));
+ Expect.equals(1, testIndexedAliasedStore5(0, 1));
+ Expect.equals(1, testIndexedAliasedStore5(1, 0));
+ Expect.equals(2, testIndexedAliasedStore5(1, 1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore6(0, false, arr));
+ Expect.equals(2, testIndexedAliasedStore6(0, true, arr));
+ Expect.equals(1, testIndexedAliasedStore6(1, false, arr));
+ Expect.equals(1, testIndexedAliasedStore6(1, true, arr));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore7(0, false, arr));
+ Expect.equals(2, testIndexedAliasedStore7(0, true, arr));
+ Expect.equals(1, testIndexedAliasedStore7(1, false, arr));
+ Expect.equals(2, testIndexedAliasedStore7(1, true, arr));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(2, testIndexedAliasedStore8(arr, 0));
+ Expect.equals(1, testIndexedAliasedStore8(arr, 1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(2, testIndexedAliasedStore9(arr, false));
+ Expect.equals(1, testIndexedAliasedStore9(arr, true));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(2, testIndexedAliasedStore10(arr, 0));
+ Expect.equals(1, testIndexedAliasedStore10(arr, 1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(2, testIndexedAliasedStore11(arr, 0, 0));
+ Expect.equals(1, testIndexedAliasedStore11(arr, 0, 1));
+ Expect.equals(1, testIndexedAliasedStore11(arr, 1, 0));
+ Expect.equals(2, testIndexedAliasedStore11(arr, 1, 1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore12(false, arr));
+ Expect.equals(2, testIndexedAliasedStore12(true, arr));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore13(false, arr, 0));
+ Expect.equals(1, testIndexedAliasedStore13(false, arr, 1));
+ Expect.equals(2, testIndexedAliasedStore13(true, arr, 0));
+ Expect.equals(1, testIndexedAliasedStore13(true, arr, 1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore14(false, arr, 0));
+ Expect.equals(1, testIndexedAliasedStore14(false, arr, 1));
+ Expect.equals(2, testIndexedAliasedStore14(true, arr, 0));
+ Expect.equals(1, testIndexedAliasedStore14(true, arr, 1));
+ }
+
+ for (var i = 0; i < 50; i++) {
+ Expect.equals(1, testIndexedAliasedStore15(false, arr, 0));
+ Expect.equals(1, testIndexedAliasedStore15(false, arr, 1));
+ Expect.equals(2, testIndexedAliasedStore15(true, arr, 0));
+ Expect.equals(2, testIndexedAliasedStore15(true, arr, 1));
+ }
+}
var indices = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
@@ -316,7 +484,7 @@
final obj = new X(new X(new X(null)));
- final cs = new C(0, new C(1, new C(2, null)));
+ final cs = new C(0, new C(1, new C(2, null)));
for (var i = 0; i < 20; i++) {
Expect.listEquals([0x02010000, 0x03020100], foo(new A(0, 0)));
@@ -361,22 +529,8 @@
for (var i = 0; i < 20; i++) {
Expect.equals(3, testIndexedNoAlias(array));
}
- for (var i = 0; i < 20; i++) {
- Expect.equals(5, testIndexedAliasedStore1(array, array));
- }
- for (var i = 0; i < 20; i++) {
- Expect.equals(4, testIndexedAliasedStore2(array, array, indices[1]));
- }
- for (var i = 0; i < 20; i++) {
- Expect.equals(3, testIndexedAliasedStore3(indices[0]));
- }
- for (var i = 0; i < 20; i++) {
- Expect.equals(1, testIndexedAliasedStore3(indices[1]));
- }
- for (var i = 0; i < 20; i++) {
- Expect.equals(1, testIndexedAliasedStore4(array));
- }
+ testIndexedAliasedStores();
var test_array = new List(1);
for (var i = 0; i < 20; i++) {
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ff99e8d..687e9ab 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -319,6 +319,9 @@
convert/chunked_conversion_utf88_test: Skip # Pass, Slow Issue 12644.
convert/utf85_test: Skip # Pass, Slow Issue 12644.
+[ $arch == simarm64 ]
+convert/utf85_test: Skip # Pass, Slow Issue 20111.
+
# These tests use "const Symbol('void')".
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
mirrors/basic_types_in_dart_core_test: CompileTimeError
diff --git a/tools/VERSION b/tools/VERSION
index e2e56d1..e468720 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 6
PATCH 0
-PRERELEASE 4
+PRERELEASE 5
PRERELEASE_PATCH 0
diff --git a/tools/build.py b/tools/build.py
index 96fdeac..81c9ca4 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -134,8 +134,8 @@
# If no cross compiler is specified, only try to figure one out on Linux.
if not HOST_OS in ['linux']:
- print "Unless --toolchain is used cross-building is only supported on Linux"
- return None
+ raise Exception('Unless --toolchain is used cross-building is only '
+ 'supported on Linux.')
# For ARM Linux, by default use the Linux distribution's cross-compiler.
if arch == 'arm':
@@ -368,7 +368,7 @@
filter_xcodebuild_output = False
-def BuildOneConfig(options, target, target_os, mode, arch, override_tools=True):
+def BuildOneConfig(options, target, target_os, mode, arch, override_tools):
global filter_xcodebuild_output
start_time = time.time()
os.environ['DART_BUILD_MODE'] = mode
@@ -476,7 +476,7 @@
return 1
# Then, build the runtime for the target arch.
- if BuildOneConfig(options, 'runtime', target_os, mode, arch) != 0:
+ if BuildOneConfig(options, 'runtime', target_os, mode, arch, True) != 0:
return 1
# TODO(zra): verify that no platform specific details leak into the snapshots
@@ -529,11 +529,12 @@
for target_os in options.os:
for mode in options.mode:
for arch in options.arch:
- if target in ['create_sdk'] and utils.IsCrossBuild(target_os, arch):
+ cross_build = utils.IsCrossBuild(target_os, arch)
+ if target in ['create_sdk'] and cross_build:
if BuildCrossSdk(options, target_os, mode, arch) != 0:
return 1
else:
- if BuildOneConfig(options, target, target_os, mode, arch) != 0:
+ if BuildOneConfig(options, target, target_os, mode, arch, cross_build) != 0:
return 1
return 0
diff --git a/tools/dartium/update_deps.py b/tools/dartium/update_deps.py
index e2ea7d6..452421f 100755
--- a/tools/dartium/update_deps.py
+++ b/tools/dartium/update_deps.py
@@ -41,7 +41,7 @@
########################################################################
BRANCH_CURRENT="dart/1985"
-BRANCH_NEXT="dart/1985"
+BRANCH_NEXT="dart/dartium"
BRANCH_MULTIVM="dart/multivm"
TARGETS = {