mirror of
https://github.com/dart-lang/sdk
synced 2024-09-22 00:21:20 +00:00
Merge remote-tracking branch 'origin/master' into analyzer-breaking-0.27
This commit is contained in:
commit
7d3c4743db
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -19,6 +19,33 @@
|
|||
* `Platform` added an `isiOS` getter and `Platform.operatingSystem` may now
|
||||
return `ios`.
|
||||
|
||||
### Tool changes
|
||||
|
||||
* Pub
|
||||
|
||||
* **Breaking:** Pub now eagerly emits an error when a pubspec's "name" field
|
||||
is not a valid Dart identifier. Since packages with non-identifier names
|
||||
were never allowed to be published, and some of them already caused crashes
|
||||
when being written to a `.packages` file, this is unlikely to break many
|
||||
people in practice.
|
||||
|
||||
* `pub serve` now GZIPs the assets it serves to make load times more similar
|
||||
to real-world use-cases.
|
||||
|
||||
* `pub deps` now supports a `--no-dev` flag, which causes it to emit the
|
||||
dependency tree as it would be if no `dev_dependencies` were in use. This
|
||||
makes it easier to see your package's dependency footprint as your users
|
||||
will experience it.
|
||||
|
||||
* `pub global run` now detects when a global executable's SDK constraint is no
|
||||
longer met and errors out, rather than trying to run the executable anyway.
|
||||
|
||||
* Fixed a crashing bug when using `pub global run` on a global script that
|
||||
didn't exist.
|
||||
|
||||
* Fixed a crashing bug when a pubspec contains a dependency without a source
|
||||
declared.
|
||||
|
||||
## 1.13.0 - 2015-11-18
|
||||
|
||||
### Core library changes
|
||||
|
|
8
DEPS
8
DEPS
|
@ -67,14 +67,14 @@ vars = {
|
|||
"intl_rev": "@32047558bd220a53c1f4d93a26d54b83533b1475",
|
||||
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
|
||||
"json_rpc_2_tag": "@1.1.1",
|
||||
"linter_rev": "@afde8f4e2325b234db5c23f99b8386e4f8e10145",
|
||||
"linter_rev": "@e5281475126efdc556c3eba6a8b6683fd814b033",
|
||||
"logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
|
||||
"markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
|
||||
"matcher_tag": "@0.12.0",
|
||||
"metatest_rev": "@e5aa8e4e19fc4188ac2f6d38368a47d8f07c3df1",
|
||||
"mime_rev": "@75890811d4af5af080351ba8a2853ad4c8df98dd",
|
||||
"mustache4dart_rev" : "@5724cfd85151e5b6b53ddcd3380daf188fe47f92",
|
||||
"oauth2_rev": "@1bff41f4d54505c36f2d1a001b83b8b745c452f5",
|
||||
"oauth2_tag": "@1.0.0",
|
||||
"observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
|
||||
"observatory_pub_packages_rev": "@5c199c5954146747f75ed127871207718dc87786",
|
||||
"package_config_rev": "@0.1.3",
|
||||
|
@ -83,7 +83,7 @@ vars = {
|
|||
"ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
|
||||
"plugin_tag": "@0.1.0",
|
||||
"pool_rev": "@e454b4b54d2987e8d2f0fbd3ac519641ada9bd0f",
|
||||
"pub_rev": "@1c08b841158e33b8090bb07e5c39df830db58d44",
|
||||
"pub_rev": "@8c091bf6332e8b392fdac63ae297426fb65ed925",
|
||||
"pub_cache_tag": "@v0.1.0",
|
||||
"pub_semver_tag": "@1.2.1",
|
||||
"quiver_tag": "@0.21.4",
|
||||
|
@ -230,7 +230,7 @@ deps = {
|
|||
+ "/external/github.com/valotas/mustache4dart.git"
|
||||
+ Var("mustache4dart_rev"),
|
||||
Var("dart_root") + "/third_party/pkg/oauth2":
|
||||
(Var("github_mirror") % "oauth2") + Var("oauth2_rev"),
|
||||
(Var("github_mirror") % "oauth2") + Var("oauth2_tag"),
|
||||
Var("dart_root") + "/third_party/pkg/observe":
|
||||
(Var("github_mirror") % "observe") + Var("observe_rev"),
|
||||
Var("dart_root") + "/third_party/observatory_pub_packages":
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -938,6 +938,176 @@ class AnalysisGetHoverResult implements HasToJson {
|
|||
return JenkinsSmiHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* analysis.getReachableSources params
|
||||
*
|
||||
* {
|
||||
* "file": FilePath
|
||||
* }
|
||||
*
|
||||
* Clients may not extend, implement or mix-in this class.
|
||||
*/
|
||||
class AnalysisGetReachableSourcesParams implements HasToJson {
|
||||
String _file;
|
||||
|
||||
/**
|
||||
* The file for which reachable source information is being requested.
|
||||
*/
|
||||
String get file => _file;
|
||||
|
||||
/**
|
||||
* The file for which reachable source information is being requested.
|
||||
*/
|
||||
void set file(String value) {
|
||||
assert(value != null);
|
||||
this._file = value;
|
||||
}
|
||||
|
||||
AnalysisGetReachableSourcesParams(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
factory AnalysisGetReachableSourcesParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
|
||||
if (json == null) {
|
||||
json = {};
|
||||
}
|
||||
if (json is Map) {
|
||||
String file;
|
||||
if (json.containsKey("file")) {
|
||||
file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
|
||||
} else {
|
||||
throw jsonDecoder.missingKey(jsonPath, "file");
|
||||
}
|
||||
return new AnalysisGetReachableSourcesParams(file);
|
||||
} else {
|
||||
throw jsonDecoder.mismatch(jsonPath, "analysis.getReachableSources params", json);
|
||||
}
|
||||
}
|
||||
|
||||
factory AnalysisGetReachableSourcesParams.fromRequest(Request request) {
|
||||
return new AnalysisGetReachableSourcesParams.fromJson(
|
||||
new RequestDecoder(request), "params", request._params);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
Map<String, dynamic> result = {};
|
||||
result["file"] = file;
|
||||
return result;
|
||||
}
|
||||
|
||||
Request toRequest(String id) {
|
||||
return new Request(id, "analysis.getReachableSources", toJson());
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => JSON.encode(toJson());
|
||||
|
||||
@override
|
||||
bool operator==(other) {
|
||||
if (other is AnalysisGetReachableSourcesParams) {
|
||||
return file == other.file;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
int hash = 0;
|
||||
hash = JenkinsSmiHash.combine(hash, file.hashCode);
|
||||
return JenkinsSmiHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* analysis.getReachableSources result
|
||||
*
|
||||
* {
|
||||
* "sources": Map<String, List<String>>
|
||||
* }
|
||||
*
|
||||
* Clients may not extend, implement or mix-in this class.
|
||||
*/
|
||||
class AnalysisGetReachableSourcesResult implements HasToJson {
|
||||
Map<String, List<String>> _sources;
|
||||
|
||||
/**
|
||||
* A mapping from source URIs to directly reachable source URIs. For example,
|
||||
* a file "foo.dart" that imports "bar.dart" would have the corresponding
|
||||
* mapping { "file:///foo.dart" : ["file:///bar.dart"] }. If "bar.dart" has
|
||||
* further imports (or exports) there will be a mapping from the URI
|
||||
* "file:///bar.dart" to them. To check if a specific URI is reachable from a
|
||||
* given file, clients can check for its presence in the resulting key set.
|
||||
*/
|
||||
Map<String, List<String>> get sources => _sources;
|
||||
|
||||
/**
|
||||
* A mapping from source URIs to directly reachable source URIs. For example,
|
||||
* a file "foo.dart" that imports "bar.dart" would have the corresponding
|
||||
* mapping { "file:///foo.dart" : ["file:///bar.dart"] }. If "bar.dart" has
|
||||
* further imports (or exports) there will be a mapping from the URI
|
||||
* "file:///bar.dart" to them. To check if a specific URI is reachable from a
|
||||
* given file, clients can check for its presence in the resulting key set.
|
||||
*/
|
||||
void set sources(Map<String, List<String>> value) {
|
||||
assert(value != null);
|
||||
this._sources = value;
|
||||
}
|
||||
|
||||
AnalysisGetReachableSourcesResult(Map<String, List<String>> sources) {
|
||||
this.sources = sources;
|
||||
}
|
||||
|
||||
factory AnalysisGetReachableSourcesResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
|
||||
if (json == null) {
|
||||
json = {};
|
||||
}
|
||||
if (json is Map) {
|
||||
Map<String, List<String>> sources;
|
||||
if (json.containsKey("sources")) {
|
||||
sources = jsonDecoder.decodeMap(jsonPath + ".sources", json["sources"], valueDecoder: (String jsonPath, Object json) => jsonDecoder.decodeList(jsonPath, json, jsonDecoder.decodeString));
|
||||
} else {
|
||||
throw jsonDecoder.missingKey(jsonPath, "sources");
|
||||
}
|
||||
return new AnalysisGetReachableSourcesResult(sources);
|
||||
} else {
|
||||
throw jsonDecoder.mismatch(jsonPath, "analysis.getReachableSources result", json);
|
||||
}
|
||||
}
|
||||
|
||||
factory AnalysisGetReachableSourcesResult.fromResponse(Response response) {
|
||||
return new AnalysisGetReachableSourcesResult.fromJson(
|
||||
new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response._result);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
Map<String, dynamic> result = {};
|
||||
result["sources"] = sources;
|
||||
return result;
|
||||
}
|
||||
|
||||
Response toResponse(String id) {
|
||||
return new Response(id, result: toJson());
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => JSON.encode(toJson());
|
||||
|
||||
@override
|
||||
bool operator==(other) {
|
||||
if (other is AnalysisGetReachableSourcesResult) {
|
||||
return mapEqual(sources, other.sources, (List<String> a, List<String> b) => listEqual(a, b, (String a, String b) => a == b));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
int hash = 0;
|
||||
hash = JenkinsSmiHash.combine(hash, sources.hashCode);
|
||||
return JenkinsSmiHash.finish(hash);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* analysis.getLibraryDependencies params
|
||||
*
|
||||
|
@ -13920,6 +14090,7 @@ class RequestError implements HasToJson {
|
|||
* FORMAT_WITH_ERRORS
|
||||
* GET_ERRORS_INVALID_FILE
|
||||
* GET_NAVIGATION_INVALID_FILE
|
||||
* GET_REACHABLE_SOURCES_INVALID_FILE
|
||||
* INVALID_ANALYSIS_ROOT
|
||||
* INVALID_EXECUTION_CONTEXT
|
||||
* INVALID_OVERLAY_CHANGE
|
||||
|
@ -13977,6 +14148,12 @@ class RequestErrorCode implements Enum {
|
|||
*/
|
||||
static const GET_NAVIGATION_INVALID_FILE = const RequestErrorCode._("GET_NAVIGATION_INVALID_FILE");
|
||||
|
||||
/**
|
||||
* An "analysis.getReachableSources" request specified a FilePath which does
|
||||
* not match a file currently subject to analysis.
|
||||
*/
|
||||
static const GET_REACHABLE_SOURCES_INVALID_FILE = const RequestErrorCode._("GET_REACHABLE_SOURCES_INVALID_FILE");
|
||||
|
||||
/**
|
||||
* A path passed as an argument to a request (such as analysis.reanalyze) is
|
||||
* required to be an analysis root, but isn't.
|
||||
|
@ -14083,7 +14260,7 @@ class RequestErrorCode implements Enum {
|
|||
/**
|
||||
* A list containing all of the enum values that are defined.
|
||||
*/
|
||||
static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FILE_NOT_ANALYZED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, ORGANIZE_DIRECTIVES_ERROR, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
|
||||
static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FILE_NOT_ANALYZED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, GET_REACHABLE_SOURCES_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, ORGANIZE_DIRECTIVES_ERROR, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
|
||||
|
||||
final String name;
|
||||
|
||||
|
@ -14103,6 +14280,8 @@ class RequestErrorCode implements Enum {
|
|||
return GET_ERRORS_INVALID_FILE;
|
||||
case "GET_NAVIGATION_INVALID_FILE":
|
||||
return GET_NAVIGATION_INVALID_FILE;
|
||||
case "GET_REACHABLE_SOURCES_INVALID_FILE":
|
||||
return GET_REACHABLE_SOURCES_INVALID_FILE;
|
||||
case "INVALID_ANALYSIS_ROOT":
|
||||
return INVALID_ANALYSIS_ROOT;
|
||||
case "INVALID_EXECUTION_CONTEXT":
|
||||
|
|
|
@ -410,6 +410,16 @@ class Response {
|
|||
RequestErrorCode.GET_NAVIGATION_INVALID_FILE,
|
||||
'Error during `analysis.getNavigation`: invalid file.'));
|
||||
|
||||
/**
|
||||
* Initialize a newly created instance to represent the
|
||||
* GET_REACHABLE_SOURCES_INVALID_FILE error condition.
|
||||
*/
|
||||
Response.getReachableSourcesInvalidFile(Request request)
|
||||
: this(request.id,
|
||||
error: new RequestError(
|
||||
RequestErrorCode.GET_REACHABLE_SOURCES_INVALID_FILE,
|
||||
'Error during `analysis.getReachableSources`: invalid file.'));
|
||||
|
||||
/**
|
||||
* Initialize a newly created instance to represent an error condition caused
|
||||
* by an analysis.reanalyze [request] that specifies an analysis root that is
|
||||
|
|
|
@ -26,6 +26,7 @@ const String ANALYSIS_GET_HOVER = 'analysis.getHover';
|
|||
const String ANALYSIS_GET_LIBRARY_DEPENDENCIES =
|
||||
'analysis.getLibraryDependencies';
|
||||
const String ANALYSIS_GET_NAVIGATION = 'analysis.getNavigation';
|
||||
const String ANALYSIS_GET_REACHABLE_SOURCES = 'analysis.getReachableSources';
|
||||
const String ANALYSIS_REANALYZE = 'analysis.reanalyze';
|
||||
const String ANALYSIS_SET_ANALYSIS_ROOTS = 'analysis.setAnalysisRoots';
|
||||
const String ANALYSIS_SET_GENERAL_SUBSCRIPTIONS =
|
||||
|
|
|
@ -21,6 +21,7 @@ import 'package:analysis_server/src/operation/operation_analysis.dart'
|
|||
import 'package:analysis_server/src/protocol/protocol_internal.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart';
|
||||
import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
|
||||
import 'package:analysis_server/src/services/dependencies/reachable_source_collector.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
|
@ -164,6 +165,22 @@ class AnalysisDomainHandler implements RequestHandler {
|
|||
return Response.DELAYED_RESPONSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the `analysis.getReachableSources` request.
|
||||
*/
|
||||
Response getReachableSources(Request request) {
|
||||
AnalysisGetReachableSourcesParams params =
|
||||
new AnalysisGetReachableSourcesParams.fromRequest(request);
|
||||
ContextSourcePair pair = server.getContextSourcePair(params.file);
|
||||
if (pair.context == null || pair.source == null) {
|
||||
return new Response.getReachableSourcesInvalidFile(request);
|
||||
}
|
||||
Map<String, List<String>> sources = new ReachableSourceCollector(
|
||||
pair.source, pair.context).collectSources();
|
||||
return new AnalysisGetReachableSourcesResult(sources)
|
||||
.toResponse(request.id);
|
||||
}
|
||||
|
||||
@override
|
||||
Response handleRequest(Request request) {
|
||||
try {
|
||||
|
@ -176,6 +193,8 @@ class AnalysisDomainHandler implements RequestHandler {
|
|||
return getLibraryDependencies(request);
|
||||
} else if (requestName == ANALYSIS_GET_NAVIGATION) {
|
||||
return getNavigation(request);
|
||||
} else if (requestName == ANALYSIS_GET_REACHABLE_SOURCES) {
|
||||
return getReachableSources(request);
|
||||
} else if (requestName == ANALYSIS_REANALYZE) {
|
||||
return reanalyze(request);
|
||||
} else if (requestName == ANALYSIS_SET_ANALYSIS_ROOTS) {
|
||||
|
|
|
@ -101,7 +101,7 @@ class CompletionDomainHandler implements RequestHandler {
|
|||
}
|
||||
_discardManager();
|
||||
}
|
||||
_manager = createCompletionManager(context, source, searchEngine);
|
||||
_manager = createCompletionManager(server, context, source);
|
||||
if (context != null) {
|
||||
_sourcesChangedSubscription =
|
||||
context.onSourcesChanged.listen(sourcesChanged);
|
||||
|
@ -123,8 +123,9 @@ class CompletionDomainHandler implements RequestHandler {
|
|||
}
|
||||
|
||||
CompletionManager createCompletionManager(
|
||||
AnalysisContext context, Source source, SearchEngine searchEngine) {
|
||||
return new CompletionManager.create(context, source, searchEngine);
|
||||
AnalysisServer server, AnalysisContext context, Source source) {
|
||||
return new CompletionManager.create(context, source, server.searchEngine,
|
||||
server.serverPlugin.completionContributors);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -189,8 +189,9 @@ class ServerPlugin implements Plugin {
|
|||
* Return a list containing all of the completion contributors that were
|
||||
* contributed.
|
||||
*/
|
||||
List<CompletionContributor> get completionContributors =>
|
||||
completionContributorExtensionPoint.extensions;
|
||||
Iterable<CompletionContributor> get completionContributors =>
|
||||
completionContributorExtensionPoint.extensions
|
||||
.map((CompletionContributorFactory factory) => factory());
|
||||
|
||||
/**
|
||||
* Return a list containing all of the fix contributors that were contributed.
|
||||
|
@ -370,10 +371,10 @@ class ServerPlugin implements Plugin {
|
|||
* valid completion contributor.
|
||||
*/
|
||||
void _validateCompletionContributorExtension(Object extension) {
|
||||
if (extension is! CompletionContributor) {
|
||||
if (extension is! CompletionContributorFactory) {
|
||||
String id = completionContributorExtensionPoint.uniqueIdentifier;
|
||||
throw new ExtensionError(
|
||||
'Extensions to $id must be an CompletionContributor');
|
||||
'Extensions to $id must be an CompletionContributorFactory');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
* Support for client code that extends the analysis server by adding new code
|
||||
* completion contributors.
|
||||
*
|
||||
* Plugins can register completion contributors. The registered contributors
|
||||
* will be used to get completions any time a client issues a
|
||||
* 'completion.getSuggestions' request.
|
||||
* Plugins can register completion contributor factories.
|
||||
* The registered contributor factories will be used to instantiate new
|
||||
* contributors to get completions any time a client issues
|
||||
* a 'completion.getSuggestions' request.
|
||||
*
|
||||
* If a plugin wants to add completions, it should implement the class
|
||||
* [CompletionContributor] and then register the contributor by including code
|
||||
* If a plugin wants to add completions, it should implement
|
||||
* [CompletionContributorFactory] by including code
|
||||
* like the following in the plugin's registerExtensions method:
|
||||
*
|
||||
* @override
|
||||
|
@ -19,20 +20,19 @@
|
|||
* ...
|
||||
* registerExtension(
|
||||
* COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
|
||||
* new MyCompletionContributor());
|
||||
* () => new MyCompletionContributor());
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
library analysis_server.src.provisional.completion.completion;
|
||||
library analysis_server.src.provisional.completion.core;
|
||||
|
||||
import 'package:analysis_server/src/plugin/server_plugin.dart';
|
||||
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
|
||||
import 'package:plugin/plugin.dart';
|
||||
|
||||
/**
|
||||
* The identifier of the extension point that allows plugins to register code
|
||||
* completion contributors. The object used as an extension must be a
|
||||
* [CompletionContributor].
|
||||
* [CompletionContributorFactory].
|
||||
*/
|
||||
final String COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
|
||||
ServerPlugin.UNIQUE_IDENTIFIER,
|
||||
|
|
|
@ -18,6 +18,13 @@ import 'package:analyzer/src/generated/source.dart';
|
|||
*/
|
||||
const EMPTY_LIST = const <CompletionSuggestion>[];
|
||||
|
||||
/**
|
||||
* An object used to instantiate a [CompletionContributor] instance
|
||||
* for each 'completion.getSuggestions' request.
|
||||
* Contributors should *not* be cached between requests.
|
||||
*/
|
||||
typedef CompletionContributor CompletionContributorFactory();
|
||||
|
||||
/**
|
||||
* An object used to produce completions at a specific location within a file.
|
||||
*
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* ...
|
||||
* }
|
||||
*/
|
||||
library analysis_server.src.provisional.completion.completion;
|
||||
library analysis_server.src.provisional.completion.dart;
|
||||
|
||||
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
|
||||
import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
|
||||
|
@ -33,7 +33,7 @@ import 'package:plugin/plugin.dart';
|
|||
/**
|
||||
* The identifier of the extension point that allows plugins to register code
|
||||
* completion contributors. The object used as an extension must be a
|
||||
* [DartCompletionContributor].
|
||||
* [DartCompletionContributorFactory].
|
||||
*/
|
||||
final String DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
|
||||
DartCompletionPlugin.UNIQUE_IDENTIFIER,
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
library analysis_server.src.provisional.completion.dart.plugin;
|
||||
|
||||
import 'package:analysis_server/src/provisional/completion/completion.dart';
|
||||
import 'package:analysis_server/src/provisional/completion/dart/completion.dart';
|
||||
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
|
||||
import 'package:plugin/plugin.dart';
|
||||
|
||||
|
@ -38,11 +40,11 @@ class DartCompletionPlugin implements Plugin {
|
|||
String get uniqueIdentifier => UNIQUE_IDENTIFIER;
|
||||
|
||||
/**
|
||||
* Return a list containing all of the Dart specific completion contributor
|
||||
* factories that were contributed.
|
||||
* Return a list containing all of the Dart specific completion contributors.
|
||||
*/
|
||||
List<DartCompletionContributorFactory> get contributorFactories =>
|
||||
_contributorExtensionPoint.extensions;
|
||||
Iterable<DartCompletionContributorFactory> get contributors =>
|
||||
_contributorExtensionPoint.extensions
|
||||
.map((DartCompletionContributorFactory factory) => factory());
|
||||
|
||||
@override
|
||||
void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
|
||||
|
@ -53,6 +55,15 @@ class DartCompletionPlugin implements Plugin {
|
|||
|
||||
@override
|
||||
void registerExtensions(RegisterExtension registerExtension) {
|
||||
//
|
||||
// Register DartCompletionManager as a CompletionContributor
|
||||
// which delegates to all the DartCompletionContributors
|
||||
//
|
||||
registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
|
||||
() => new DartCompletionManager());
|
||||
//
|
||||
// Register the default DartCompletionContributors
|
||||
//
|
||||
registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
|
||||
() => new KeywordContributor());
|
||||
}
|
||||
|
|
|
@ -198,6 +198,12 @@ class _ArgSuggestionBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (parent is Annotation) {
|
||||
Element element = parent.element;
|
||||
if (element is ExecutableElement) {
|
||||
_addSuggestions(element.parameters);
|
||||
}
|
||||
}
|
||||
return new Future.value(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:analysis_server/plugin/protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/provisional/completion/completion_core.dart'
|
||||
show CompletionRequest, CompletionResult;
|
||||
show CompletionContributor, CompletionContributorFactory, CompletionRequest, CompletionResult;
|
||||
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
|
||||
import 'package:analysis_server/src/services/search/search_engine.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
|
@ -57,14 +57,14 @@ abstract class CompletionManager {
|
|||
* Create a manager for the given request.
|
||||
*/
|
||||
factory CompletionManager.create(
|
||||
AnalysisContext context, Source source, SearchEngine searchEngine) {
|
||||
AnalysisContext context,
|
||||
Source source,
|
||||
SearchEngine searchEngine,
|
||||
Iterable<CompletionContributor> newContributors) {
|
||||
if (context != null) {
|
||||
if (AnalysisEngine.isDartFileName(source.shortName)) {
|
||||
return new DartCompletionManager.create(context, searchEngine, source);
|
||||
}
|
||||
if (AnalysisEngine.isHtmlFileName(source.shortName)) {
|
||||
//TODO (danrubel) implement
|
||||
// return new HtmlCompletionManager(context, searchEngine, source, offset);
|
||||
return new DartCompletionManager.create(
|
||||
context, searchEngine, source, newContributors);
|
||||
}
|
||||
}
|
||||
return new NoOpCompletionManager(source);
|
||||
|
|
|
@ -44,18 +44,10 @@ class DartCompletionManager implements CompletionContributor {
|
|||
*/
|
||||
Future<List<CompletionSuggestion>> _computeDartSuggestions(
|
||||
DartCompletionRequest request) async {
|
||||
// Build the Dart specific completion contributors
|
||||
List<DartCompletionContributor> contributors =
|
||||
<DartCompletionContributor>[];
|
||||
for (DartCompletionContributorFactory contributorFactory
|
||||
in dartCompletionPlugin.contributorFactories) {
|
||||
contributors.add(contributorFactory());
|
||||
}
|
||||
|
||||
// Request Dart specific completions from each contributor
|
||||
List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
|
||||
for (DartCompletionContributor contributor in contributors) {
|
||||
suggestions.addAll(await contributor.computeSuggestions(request));
|
||||
for (DartCompletionContributor c in dartCompletionPlugin.contributors) {
|
||||
suggestions.addAll(await c.computeSuggestions(request));
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@ import 'package:analysis_server/src/services/completion/combinator_contributor.d
|
|||
import 'package:analysis_server/src/services/completion/completion_core.dart';
|
||||
import 'package:analysis_server/src/services/completion/completion_manager.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/common_usage_sorter.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'
|
||||
as newImpl;
|
||||
import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
|
||||
import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
|
||||
|
@ -87,7 +85,7 @@ class DartCompletionManager extends CompletionManager {
|
|||
final SearchEngine searchEngine;
|
||||
final DartCompletionCache cache;
|
||||
List<DartCompletionContributor> contributors;
|
||||
List<CompletionContributor> newContributors;
|
||||
Iterable<CompletionContributor> newContributors;
|
||||
DartContributionSorter contributionSorter;
|
||||
|
||||
DartCompletionManager(
|
||||
|
@ -114,7 +112,7 @@ class DartCompletionManager extends CompletionManager {
|
|||
if (newContributors == null) {
|
||||
newContributors = <CompletionContributor>[
|
||||
// TODO(danrubel) initialize using plugin API
|
||||
new newImpl.DartCompletionManager(),
|
||||
//new newImpl.DartCompletionManager(),
|
||||
];
|
||||
}
|
||||
if (contributionSorter == null) {
|
||||
|
@ -126,9 +124,12 @@ class DartCompletionManager extends CompletionManager {
|
|||
* Create a new initialized Dart source completion manager
|
||||
*/
|
||||
factory DartCompletionManager.create(
|
||||
AnalysisContext context, SearchEngine searchEngine, Source source) {
|
||||
AnalysisContext context,
|
||||
SearchEngine searchEngine,
|
||||
Source source,
|
||||
Iterable<CompletionContributor> newContributors) {
|
||||
return new DartCompletionManager(context, searchEngine, source,
|
||||
new DartCompletionCache(context, source));
|
||||
new DartCompletionCache(context, source), null, newContributors);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -127,6 +127,8 @@ class DartFixKind {
|
|||
static const CHANGE_TO = const FixKind('CHANGE_TO', 49, "Change to '{0}'");
|
||||
static const CHANGE_TO_STATIC_ACCESS = const FixKind(
|
||||
'CHANGE_TO_STATIC_ACCESS', 50, "Change access to static using '{0}'");
|
||||
static const CHANGE_TYPE_ANNOTATION = const FixKind(
|
||||
'CHANGE_TYPE_ANNOTATION', 50, "Change '{0}' to '{1}' type annotation");
|
||||
static const CREATE_CLASS =
|
||||
const FixKind('CREATE_CLASS', 50, "Create class '{0}'");
|
||||
static const CREATE_CONSTRUCTOR =
|
||||
|
|
|
@ -292,6 +292,9 @@ class FixProcessor {
|
|||
_addFix_useStaticAccess_method();
|
||||
_addFix_useStaticAccess_property();
|
||||
}
|
||||
if (errorCode == StaticTypeWarningCode.INVALID_ASSIGNMENT) {
|
||||
_addFix_changeTypeAnnotation();
|
||||
}
|
||||
if (errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) {
|
||||
_addFix_removeParentheses_inGetterInvocation();
|
||||
}
|
||||
|
@ -489,6 +492,29 @@ class FixProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
void _addFix_changeTypeAnnotation() {
|
||||
AstNode declaration = coveredNode.parent;
|
||||
if (declaration is VariableDeclaration &&
|
||||
declaration.initializer == coveredNode) {
|
||||
AstNode variableList = declaration.parent;
|
||||
if (variableList is VariableDeclarationList &&
|
||||
variableList.variables.length == 1) {
|
||||
TypeName typeNode = variableList.type;
|
||||
if (typeNode != null) {
|
||||
Expression initializer = coveredNode;
|
||||
DartType newType = initializer.bestType;
|
||||
if (newType is InterfaceType || newType is FunctionType) {
|
||||
String newTypeSource =
|
||||
utils.getTypeSource(newType, librariesToImport);
|
||||
_addReplaceEdit(rf.rangeNode(typeNode), newTypeSource);
|
||||
_addFix(DartFixKind.CHANGE_TYPE_ANNOTATION,
|
||||
[typeNode.type.displayName, newTypeSource]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _addFix_createClass() {
|
||||
Element prefixElement = null;
|
||||
String name = null;
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library services.dependencies.reachable_source_collector;
|
||||
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/task/dart.dart';
|
||||
|
||||
/// Collects reachable sources.
|
||||
class ReachableSourceCollector {
|
||||
final Map<String, List<String>> _sourceMap =
|
||||
new HashMap<String, List<String>>();
|
||||
|
||||
final Source source;
|
||||
final AnalysisContext context;
|
||||
ReachableSourceCollector(this.source, this.context) {
|
||||
if (source == null) {
|
||||
throw new ArgumentError.notNull('source');
|
||||
}
|
||||
if (context == null) {
|
||||
throw new ArgumentError.notNull('context');
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect reachable sources.
|
||||
Map<String, List<String>> collectSources() {
|
||||
_addDependencies(source);
|
||||
return _sourceMap;
|
||||
}
|
||||
|
||||
void _addDependencies(Source source) {
|
||||
|
||||
String sourceUri = source.uri.toString();
|
||||
|
||||
// Careful not to revisit.
|
||||
if (_sourceMap[source.uri.toString()] != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Source> sources = <Source>[];
|
||||
sources.addAll(context.computeResult(source, IMPORTED_LIBRARIES));
|
||||
sources.addAll(context.computeResult(source, EXPORTED_LIBRARIES));
|
||||
|
||||
_sourceMap[sourceUri] =
|
||||
sources.map((source) => source.uri.toString()).toList();
|
||||
|
||||
sources.forEach((s) => _addDependencies(s));
|
||||
}
|
||||
}
|
|
@ -50,6 +50,9 @@ class AstWriter extends UnifyingAstVisitor with TreeWriter {
|
|||
} else if (node is ExportDirective) {
|
||||
properties['element'] = node.element;
|
||||
properties['source'] = node.source;
|
||||
} else if (node is FunctionDeclaration) {
|
||||
properties['external keyword'] = node.externalKeyword;
|
||||
properties['property keyword'] = node.propertyKeyword;
|
||||
} else if (node is FunctionExpressionInvocation) {
|
||||
properties['static element'] = node.staticElement;
|
||||
properties['static type'] = node.staticType;
|
||||
|
@ -60,6 +63,11 @@ class AstWriter extends UnifyingAstVisitor with TreeWriter {
|
|||
properties['source'] = node.source;
|
||||
} else if (node is LibraryDirective) {
|
||||
properties['element'] = node.element;
|
||||
} else if (node is MethodDeclaration) {
|
||||
properties['external keyword'] = node.externalKeyword;
|
||||
properties['modifier keyword'] = node.modifierKeyword;
|
||||
properties['operator keyword'] = node.operatorKeyword;
|
||||
properties['property keyword'] = node.propertyKeyword;
|
||||
} else if (node is PartDirective) {
|
||||
properties['element'] = node.element;
|
||||
properties['source'] = node.source;
|
||||
|
|
|
@ -678,6 +678,7 @@ class GetHandler {
|
|||
List<Folder> allContexts = <Folder>[];
|
||||
Map<Folder, List<CacheEntry>> entryMap =
|
||||
new HashMap<Folder, List<CacheEntry>>();
|
||||
StringBuffer invalidKeysBuffer = new StringBuffer();
|
||||
analysisServer.folderMap
|
||||
.forEach((Folder folder, InternalAnalysisContext context) {
|
||||
Source source = context.sourceFactory.forUri(sourceUri);
|
||||
|
@ -694,7 +695,15 @@ class GetHandler {
|
|||
entries = <CacheEntry>[];
|
||||
entryMap[folder] = entries;
|
||||
}
|
||||
entries.add(iterator.value);
|
||||
CacheEntry value = iterator.value;
|
||||
if (value == null) {
|
||||
if (invalidKeysBuffer.isNotEmpty) {
|
||||
invalidKeysBuffer.write(', ');
|
||||
}
|
||||
invalidKeysBuffer.write(iterator.key.toString());
|
||||
} else {
|
||||
entries.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -706,6 +715,11 @@ class GetHandler {
|
|||
_writeResponse(request, (StringBuffer buffer) {
|
||||
_writePage(buffer, 'Analysis Server - Cache Entry',
|
||||
['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
|
||||
if (invalidKeysBuffer.isNotEmpty) {
|
||||
buffer.write('<h3>Targets with null Entries</h3><p>');
|
||||
buffer.write(invalidKeysBuffer.toString());
|
||||
buffer.write('</p>');
|
||||
}
|
||||
List<CacheEntry> entries = entryMap[folder];
|
||||
buffer.write('<h3>Analyzing Contexts</h3><p>');
|
||||
bool first = true;
|
||||
|
|
|
@ -55,6 +55,46 @@ main() {
|
|||
group('updateContent', testUpdateContent);
|
||||
|
||||
group('AnalysisDomainHandler', () {
|
||||
group('getReachableSources', () {
|
||||
test('valid sources', () async {
|
||||
String fileA = '/project/a.dart';
|
||||
String fileB = '/project/b.dart';
|
||||
resourceProvider.newFile(fileA, 'import "b.dart";');
|
||||
resourceProvider.newFile(fileB, '');
|
||||
|
||||
server.setAnalysisRoots('0', ['/project/'], [], {});
|
||||
|
||||
await server.onAnalysisComplete;
|
||||
|
||||
var request =
|
||||
new AnalysisGetReachableSourcesParams(fileA).toRequest('0');
|
||||
var response = handler.handleRequest(request);
|
||||
|
||||
var json = response.toJson()[Response.RESULT];
|
||||
|
||||
// Sanity checks.
|
||||
expect(json['sources'], hasLength(6));
|
||||
expect(json['sources']['file:///project/a.dart'],
|
||||
unorderedEquals(['dart:core', 'file:///project/b.dart']));
|
||||
expect(json['sources']['file:///project/b.dart'], ['dart:core']);
|
||||
});
|
||||
|
||||
test('invalid source', () async {
|
||||
resourceProvider.newFile('/project/a.dart', 'import "b.dart";');
|
||||
server.setAnalysisRoots('0', ['/project/'], [], {});
|
||||
|
||||
await server.onAnalysisComplete;
|
||||
|
||||
var request =
|
||||
new AnalysisGetReachableSourcesParams('/does/not/exist.dart')
|
||||
.toRequest('0');
|
||||
var response = handler.handleRequest(request);
|
||||
expect(response.error, isNotNull);
|
||||
expect(response.error.code,
|
||||
RequestErrorCode.GET_REACHABLE_SOURCES_INVALID_FILE);
|
||||
});
|
||||
});
|
||||
|
||||
group('setAnalysisRoots', () {
|
||||
Response testSetAnalysisRoots(
|
||||
List<String> included, List<String> excluded) {
|
||||
|
|
|
@ -831,7 +831,7 @@ class Test_CompletionDomainHandler extends CompletionDomainHandler {
|
|||
}
|
||||
|
||||
CompletionManager createCompletionManager(
|
||||
AnalysisContext context, Source source, SearchEngine searchEngine) {
|
||||
AnalysisServer server, AnalysisContext context, Source source) {
|
||||
return new MockCompletionManager(mockContext, source, searchEngine);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,6 +237,41 @@ abstract class IntegrationTestMixin {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transitive closure of reachable sources for a given file.
|
||||
*
|
||||
* If a request is made for a file which does not exist, or which is not
|
||||
* currently subject to analysis (e.g. because it is not associated with any
|
||||
* analysis root specified to analysis.setAnalysisRoots), an error of type
|
||||
* GET_REACHABLE_SOURCES_INVALID_FILE will be generated.
|
||||
*
|
||||
* Parameters
|
||||
*
|
||||
* file ( FilePath )
|
||||
*
|
||||
* The file for which reachable source information is being requested.
|
||||
*
|
||||
* Returns
|
||||
*
|
||||
* sources ( Map<String, List<String>> )
|
||||
*
|
||||
* A mapping from source URIs to directly reachable source URIs. For
|
||||
* example, a file "foo.dart" that imports "bar.dart" would have the
|
||||
* corresponding mapping { "file:///foo.dart" : ["file:///bar.dart"] }. If
|
||||
* "bar.dart" has further imports (or exports) there will be a mapping from
|
||||
* the URI "file:///bar.dart" to them. To check if a specific URI is
|
||||
* reachable from a given file, clients can check for its presence in the
|
||||
* resulting key set.
|
||||
*/
|
||||
Future<AnalysisGetReachableSourcesResult> sendAnalysisGetReachableSources(String file) {
|
||||
var params = new AnalysisGetReachableSourcesParams(file).toJson();
|
||||
return server.send("analysis.getReachableSources", params)
|
||||
.then((result) {
|
||||
ResponseDecoder decoder = new ResponseDecoder(null);
|
||||
return new AnalysisGetReachableSourcesResult.fromJson(decoder, 'result', result);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return library dependency information for use in client-side indexing and
|
||||
* package URI resolution.
|
||||
|
|
|
@ -152,6 +152,30 @@ final Matcher isAnalysisGetHoverResult = new LazyMatcher(() => new MatchesJsonOb
|
|||
"hovers": isListOf(isHoverInformation)
|
||||
}));
|
||||
|
||||
/**
|
||||
* analysis.getReachableSources params
|
||||
*
|
||||
* {
|
||||
* "file": FilePath
|
||||
* }
|
||||
*/
|
||||
final Matcher isAnalysisGetReachableSourcesParams = new LazyMatcher(() => new MatchesJsonObject(
|
||||
"analysis.getReachableSources params", {
|
||||
"file": isFilePath
|
||||
}));
|
||||
|
||||
/**
|
||||
* analysis.getReachableSources result
|
||||
*
|
||||
* {
|
||||
* "sources": Map<String, List<String>>
|
||||
* }
|
||||
*/
|
||||
final Matcher isAnalysisGetReachableSourcesResult = new LazyMatcher(() => new MatchesJsonObject(
|
||||
"analysis.getReachableSources result", {
|
||||
"sources": isMapOf(isString, isListOf(isString))
|
||||
}));
|
||||
|
||||
/**
|
||||
* analysis.getLibraryDependencies params
|
||||
*/
|
||||
|
@ -2077,6 +2101,7 @@ final Matcher isRequestError = new LazyMatcher(() => new MatchesJsonObject(
|
|||
* FORMAT_WITH_ERRORS
|
||||
* GET_ERRORS_INVALID_FILE
|
||||
* GET_NAVIGATION_INVALID_FILE
|
||||
* GET_REACHABLE_SOURCES_INVALID_FILE
|
||||
* INVALID_ANALYSIS_ROOT
|
||||
* INVALID_EXECUTION_CONTEXT
|
||||
* INVALID_OVERLAY_CHANGE
|
||||
|
@ -2102,6 +2127,7 @@ final Matcher isRequestErrorCode = new MatchesEnum("RequestErrorCode", [
|
|||
"FORMAT_WITH_ERRORS",
|
||||
"GET_ERRORS_INVALID_FILE",
|
||||
"GET_NAVIGATION_INVALID_FILE",
|
||||
"GET_REACHABLE_SOURCES_INVALID_FILE",
|
||||
"INVALID_ANALYSIS_ROOT",
|
||||
"INVALID_EXECUTION_CONTEXT",
|
||||
"INVALID_OVERLAY_CHANGE",
|
||||
|
|
|
@ -91,7 +91,6 @@ class ArgListContributorTest extends AbstractCompletionTest {
|
|||
}
|
||||
|
||||
test_Annotation_local_constructor_named_param() {
|
||||
//
|
||||
addTestSource('''
|
||||
class A { A({int one, String two: 'defaultValue'}) { } }
|
||||
@A(^) main() { }''');
|
||||
|
@ -101,6 +100,16 @@ class A { A({int one, String two: 'defaultValue'}) { } }
|
|||
});
|
||||
}
|
||||
|
||||
test_Annotation_imported_constructor_named_param() {
|
||||
addSource('/libA.dart', '''
|
||||
library libA; class A { A({int one, String two: 'defaultValue'}) { } }''');
|
||||
addTestSource('import "/libA.dart"; @A(^) main() { }');
|
||||
computeFast();
|
||||
return computeFull((bool result) {
|
||||
assertSuggestArguments(namedArguments: ['one','two']);
|
||||
});
|
||||
}
|
||||
|
||||
test_ArgumentList_getter() {
|
||||
addTestSource('class A {int get foo => 7; main() {foo(^)}');
|
||||
computeFast();
|
||||
|
|
|
@ -66,7 +66,8 @@ class DartCompletionManagerTest extends AbstractSingleUnitTest {
|
|||
index = createLocalMemoryIndex();
|
||||
searchEngine = new SearchEngineImpl(index);
|
||||
source = addSource('/does/not/exist.dart', '');
|
||||
manager = new DartCompletionManager.create(context, searchEngine, source);
|
||||
manager =
|
||||
new DartCompletionManager.create(context, searchEngine, source, []);
|
||||
suggestion1 = new CompletionSuggestion(CompletionSuggestionKind.INVOCATION,
|
||||
DART_RELEVANCE_DEFAULT, "suggestion1", 1, 1, false, false);
|
||||
suggestion2 = new CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER,
|
||||
|
@ -83,7 +84,6 @@ class DartCompletionManagerTest extends AbstractSingleUnitTest {
|
|||
contributor1 = new MockCompletionContributor(suggestion1, null);
|
||||
contributor2 = new MockCompletionContributor(null, suggestion2);
|
||||
manager.contributors = [contributor1, contributor2];
|
||||
manager.newContributors = [];
|
||||
int count = 0;
|
||||
bool done = false;
|
||||
CompletionRequest completionRequest =
|
||||
|
@ -121,7 +121,6 @@ class DartCompletionManagerTest extends AbstractSingleUnitTest {
|
|||
contributor1 = new MockCompletionContributor(suggestion1, null);
|
||||
contributor2 = new MockCompletionContributor(suggestion2, null);
|
||||
manager.contributors = [contributor1, contributor2];
|
||||
manager.newContributors = [];
|
||||
int count = 0;
|
||||
bool done = false;
|
||||
CompletionRequest completionRequest =
|
||||
|
|
|
@ -24,25 +24,25 @@ class CompletionManagerTest extends AbstractContextTest {
|
|||
|
||||
test_dart() {
|
||||
Source source = addSource('/does/not/exist.dart', '');
|
||||
var manager = new CompletionManager.create(context, source, null);
|
||||
var manager = new CompletionManager.create(context, source, null, []);
|
||||
expect(manager.runtimeType, DartCompletionManager);
|
||||
}
|
||||
|
||||
test_html() {
|
||||
Source source = addSource('/does/not/exist.html', '');
|
||||
var manager = new CompletionManager.create(context, source, null);
|
||||
var manager = new CompletionManager.create(context, source, null, []);
|
||||
expect(manager.runtimeType, NoOpCompletionManager);
|
||||
}
|
||||
|
||||
test_null_context() {
|
||||
Source source = addSource('/does/not/exist.dart', '');
|
||||
var manager = new CompletionManager.create(null, source, null);
|
||||
var manager = new CompletionManager.create(null, source, null, []);
|
||||
expect(manager.runtimeType, NoOpCompletionManager);
|
||||
}
|
||||
|
||||
test_other() {
|
||||
Source source = addSource('/does/not/exist.foo', '');
|
||||
var manager = new CompletionManager.create(context, source, null);
|
||||
var manager = new CompletionManager.create(context, source, null, []);
|
||||
expect(manager.runtimeType, NoOpCompletionManager);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,8 @@ abstract class AbstractCompletionTest extends AbstractContextTest {
|
|||
content.substring(completionOffset + 1);
|
||||
testSource = addSource(testFile, content);
|
||||
cache = new DartCompletionCache(context, testSource);
|
||||
request = new DartCompletionRequest(context, provider, searchEngine,
|
||||
testSource, completionOffset, cache);
|
||||
request = new DartCompletionRequest(
|
||||
context, provider, searchEngine, testSource, completionOffset, cache);
|
||||
}
|
||||
|
||||
void assertHasNoParameterInfo(CompletionSuggestion suggestion) {
|
||||
|
|
|
@ -107,7 +107,7 @@ class CommonUsageSorterTest extends AbstractAnalysisTest {
|
|||
source,
|
||||
new DartCompletionCache(context, source),
|
||||
null,
|
||||
null,
|
||||
server.serverPlugin.completionContributors,
|
||||
new CommonUsageSorter(selectorRelevance));
|
||||
|
||||
Response response =
|
||||
|
|
|
@ -597,6 +597,55 @@ main(B b) {
|
|||
''');
|
||||
}
|
||||
|
||||
test_changeTypeAnnotation_BAD_multipleVariables() async {
|
||||
resolveTestUnit('''
|
||||
main() {
|
||||
String a, b = 42;
|
||||
}
|
||||
''');
|
||||
await assertNoFix(DartFixKind.CHANGE_TYPE_ANNOTATION);
|
||||
}
|
||||
|
||||
test_changeTypeAnnotation_BAD_notVariableDeclaration() async {
|
||||
resolveTestUnit('''
|
||||
main() {
|
||||
String v;
|
||||
v = 42;
|
||||
}
|
||||
''');
|
||||
await assertNoFix(DartFixKind.CHANGE_TYPE_ANNOTATION);
|
||||
}
|
||||
|
||||
test_changeTypeAnnotation_OK_generic() async {
|
||||
resolveTestUnit('''
|
||||
main() {
|
||||
String v = <int>[];
|
||||
}
|
||||
''');
|
||||
await assertHasFix(
|
||||
DartFixKind.CHANGE_TYPE_ANNOTATION,
|
||||
'''
|
||||
main() {
|
||||
List<int> v = <int>[];
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_changeTypeAnnotation_OK_simple() async {
|
||||
resolveTestUnit('''
|
||||
main() {
|
||||
String v = 'abc'.length;
|
||||
}
|
||||
''');
|
||||
await assertHasFix(
|
||||
DartFixKind.CHANGE_TYPE_ANNOTATION,
|
||||
'''
|
||||
main() {
|
||||
int v = 'abc'.length;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_createClass() async {
|
||||
resolveTestUnit('''
|
||||
main() {
|
||||
|
|
|
@ -34,7 +34,7 @@ class LibraryDependenciesTest extends AbstractContextTest {
|
|||
// Cycles
|
||||
expect(libs, contains('/lib1.dart'));
|
||||
expect(libs, contains('/lib2.dart'));
|
||||
// Regular sourcs
|
||||
// Regular sources
|
||||
expect(libs, contains('/lib3.dart'));
|
||||
expect(libs, contains('/lib4.dart'));
|
||||
// Non-source, referenced by source
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library test.services.dependencies.import_collector;
|
||||
|
||||
import 'package:analysis_server/src/services/dependencies/reachable_source_collector.dart';
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
||||
import '../../abstract_context.dart';
|
||||
import '../../utils.dart';
|
||||
|
||||
main() {
|
||||
initializeTestEnvironment();
|
||||
defineReflectiveTests(ReachableSourceCollectorTest);
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class ReachableSourceCollectorTest extends AbstractContextTest {
|
||||
CompilationUnit addLibrary(String path, String contents) =>
|
||||
resolveLibraryUnit(addSource(path, contents));
|
||||
|
||||
Map<String, List<String>> importsFor(Source source) =>
|
||||
new ReachableSourceCollector(source, context).collectSources();
|
||||
|
||||
test_null_context() {
|
||||
Source lib = addSource('/lib.dart', '');
|
||||
expect(() => new ReachableSourceCollector(lib, null),
|
||||
throwsA(new isInstanceOf<ArgumentError>()));
|
||||
}
|
||||
|
||||
test_null_source() {
|
||||
expect(() => new ReachableSourceCollector(null, context),
|
||||
throwsA(new isInstanceOf<ArgumentError>()));
|
||||
}
|
||||
|
||||
test_sources() {
|
||||
Source lib1 = addSource(
|
||||
'/lib1.dart',
|
||||
'''
|
||||
import "lib2.dart";
|
||||
import "dart:html";''');
|
||||
Source lib2 = addSource('/lib2.dart', 'import "lib1.dart";');
|
||||
|
||||
Source lib3 = addSource('/lib3.dart', 'import "lib4.dart";');
|
||||
addSource('/lib4.dart', 'import "lib3.dart";');
|
||||
|
||||
Map<String, List<String>> imports = importsFor(lib1);
|
||||
|
||||
// Verify keys.
|
||||
expect(
|
||||
imports.keys,
|
||||
unorderedEquals([
|
||||
'dart:_internal',
|
||||
'dart:async',
|
||||
'dart:core',
|
||||
'dart:html',
|
||||
'dart:math',
|
||||
'file:///lib1.dart',
|
||||
'file:///lib2.dart',
|
||||
]));
|
||||
// Values.
|
||||
expect(imports['file:///lib1.dart'],
|
||||
unorderedEquals(['dart:core', 'dart:html', 'file:///lib2.dart']));
|
||||
|
||||
// Check transitivity.
|
||||
expect(importsFor(lib2).keys, contains('dart:html'));
|
||||
|
||||
// Cycles should be OK.
|
||||
expect(
|
||||
importsFor(lib3).keys,
|
||||
unorderedEquals([
|
||||
'dart:_internal',
|
||||
'dart:async',
|
||||
'dart:core',
|
||||
'dart:math',
|
||||
'file:///lib3.dart',
|
||||
'file:///lib4.dart'
|
||||
]));
|
||||
}
|
||||
}
|
|
@ -7,12 +7,14 @@ library test.services.dependencies;
|
|||
import 'package:unittest/unittest.dart';
|
||||
|
||||
import '../../utils.dart';
|
||||
import 'library_dependencies_test.dart' as library_dependencies_test;
|
||||
import 'library_dependencies_test.dart' as library_dependencies;
|
||||
import 'reachable_source_collector_test.dart' as reachable_source_collector;
|
||||
|
||||
/// Utility for manually running all tests.
|
||||
main() {
|
||||
initializeTestEnvironment();
|
||||
group('dependencies', () {
|
||||
library_dependencies_test.main();
|
||||
library_dependencies.main();
|
||||
reachable_source_collector.main();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -118,6 +118,20 @@ public interface AnalysisServer {
|
|||
*/
|
||||
public void analysis_getNavigation(String file, int offset, int length, GetNavigationConsumer consumer);
|
||||
|
||||
/**
|
||||
* {@code analysis.getReachableSources}
|
||||
*
|
||||
* Return the transitive closure of reachable sources for a given file.
|
||||
*
|
||||
* If a request is made for a file which does not exist, or which is not currently subject to
|
||||
* analysis (e.g. because it is not associated with any analysis root specified to
|
||||
* analysis.setAnalysisRoots), an error of type GET_REACHABLE_SOURCES_INVALID_FILE will be
|
||||
* generated.
|
||||
*
|
||||
* @param file The file for which reachable source information is being requested.
|
||||
*/
|
||||
public void analysis_getReachableSources(String file, GetReachableSourcesConsumer consumer);
|
||||
|
||||
/**
|
||||
* {@code analysis.reanalyze}
|
||||
*
|
||||
|
|
|
@ -58,6 +58,12 @@ public class RequestErrorCode {
|
|||
*/
|
||||
public static final String GET_NAVIGATION_INVALID_FILE = "GET_NAVIGATION_INVALID_FILE";
|
||||
|
||||
/**
|
||||
* An "analysis.getReachableSources" request specified a FilePath which does not match a file
|
||||
* currently subject to analysis.
|
||||
*/
|
||||
public static final String GET_REACHABLE_SOURCES_INVALID_FILE = "GET_REACHABLE_SOURCES_INVALID_FILE";
|
||||
|
||||
/**
|
||||
* A path passed as an argument to a request (such as analysis.reanalyze) is required to be an
|
||||
* analysis root, but isn't.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<h1>Analysis Server API Specification</h1>
|
||||
<h1 style="color:#999999">Version <version>1.12.0</version></h1>
|
||||
<h1 style="color:#999999">Version <version>1.13.0</version></h1>
|
||||
<p>
|
||||
This document contains a specification of the API provided by the
|
||||
analysis server. The API in this document is currently under
|
||||
|
@ -395,6 +395,42 @@
|
|||
</field>
|
||||
</result>
|
||||
</request>
|
||||
<request method="getReachableSources">
|
||||
<p>
|
||||
Return the transitive closure of reachable sources for a given file.
|
||||
</p>
|
||||
<p>
|
||||
If a request is made for a file which does not exist, or
|
||||
which is not currently subject to analysis (e.g. because it
|
||||
is not associated with any analysis root specified to
|
||||
analysis.setAnalysisRoots), an error of type
|
||||
<tt>GET_REACHABLE_SOURCES_INVALID_FILE</tt> will be generated.
|
||||
</p>
|
||||
<params>
|
||||
<field name="file">
|
||||
<ref>FilePath</ref>
|
||||
<p>
|
||||
The file for which reachable source information is being requested.
|
||||
</p>
|
||||
</field>
|
||||
</params>
|
||||
<result>
|
||||
<field name="sources">
|
||||
<map>
|
||||
<key><ref>String</ref></key>
|
||||
<value><list>><ref>String</ref></list></value>
|
||||
</map>
|
||||
<p>
|
||||
A mapping from source URIs to directly reachable source URIs. For example,
|
||||
a file "foo.dart" that imports "bar.dart" would have the corresponding mapping
|
||||
{ "file:///foo.dart" : ["file:///bar.dart"] }. If "bar.dart" has further imports
|
||||
(or exports) there will be a mapping from the URI "file:///bar.dart" to them.
|
||||
To check if a specific URI is reachable from a given file, clients can check
|
||||
for its presence in the resulting key set.
|
||||
</p>
|
||||
</field>
|
||||
</result>
|
||||
</request>
|
||||
<request method="getLibraryDependencies">
|
||||
<p>
|
||||
Return library dependency information for use in client-side indexing
|
||||
|
@ -3649,6 +3685,14 @@
|
|||
analysis.
|
||||
</p>
|
||||
</value>
|
||||
<value>
|
||||
<code>GET_REACHABLE_SOURCES_INVALID_FILE</code>
|
||||
<p>
|
||||
An "analysis.getReachableSources" request specified a FilePath
|
||||
which does not match a file currently subject to
|
||||
analysis.
|
||||
</p>
|
||||
</value>
|
||||
<value>
|
||||
<code>INVALID_ANALYSIS_ROOT</code>
|
||||
<p>
|
||||
|
|
|
@ -257,6 +257,9 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
this._options.preserveComments != options.preserveComments ||
|
||||
this._options.strongMode != options.strongMode ||
|
||||
this._options.enableAssertMessage != options.enableAssertMessage ||
|
||||
((options is AnalysisOptionsImpl)
|
||||
? this._options.strongModeHints != options.strongModeHints
|
||||
: false) ||
|
||||
this._options.enableStrictCallChecks !=
|
||||
options.enableStrictCallChecks ||
|
||||
this._options.enableGenericMethods != options.enableGenericMethods ||
|
||||
|
@ -281,6 +284,9 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
this._options.lint = options.lint;
|
||||
this._options.preserveComments = options.preserveComments;
|
||||
this._options.strongMode = options.strongMode;
|
||||
if (options is AnalysisOptionsImpl) {
|
||||
this._options.strongModeHints = options.strongModeHints;
|
||||
}
|
||||
if (needsRecompute) {
|
||||
for (WorkManager workManager in workManagers) {
|
||||
workManager.onAnalysisOptionsChanged();
|
||||
|
|
|
@ -1349,6 +1349,14 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
* A flag indicating whether strong-mode analysis should be used.
|
||||
*/
|
||||
bool strongMode = false;
|
||||
|
||||
/**
|
||||
* A flag indicating whether strong-mode inference hints should be
|
||||
* used. This flag is not exposed in the interface, and should be
|
||||
* replaced by something more general.
|
||||
*/
|
||||
// TODO(leafp): replace this with something more general
|
||||
bool strongModeHints = false;
|
||||
|
||||
/**
|
||||
* Initialize a newly created set of analysis options to have their default
|
||||
|
@ -1378,6 +1386,9 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
lint = options.lint;
|
||||
preserveComments = options.preserveComments;
|
||||
strongMode = options.strongMode;
|
||||
if (options is AnalysisOptionsImpl) {
|
||||
strongModeHints = options.strongModeHints;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1401,6 +1412,9 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
lint = options.lint;
|
||||
preserveComments = options.preserveComments;
|
||||
strongMode = options.strongMode;
|
||||
if (options is AnalysisOptionsImpl) {
|
||||
strongModeHints = options.strongModeHints;
|
||||
}
|
||||
}
|
||||
|
||||
bool get analyzeFunctionBodies {
|
||||
|
|
|
@ -2150,13 +2150,18 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
|
|||
_findIdentifier(_enclosingUnit.functions, functionName);
|
||||
}
|
||||
} else {
|
||||
PropertyAccessorElement accessor =
|
||||
_findIdentifier(_enclosingUnit.accessors, functionName);
|
||||
if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
|
||||
accessor = accessor.variable.setter;
|
||||
functionName.staticElement = accessor;
|
||||
if (_enclosingExecutable != null) {
|
||||
_enclosingExecutable =
|
||||
_findIdentifier(_enclosingExecutable.functions, functionName);
|
||||
} else {
|
||||
PropertyAccessorElement accessor =
|
||||
_findIdentifier(_enclosingUnit.accessors, functionName);
|
||||
if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
|
||||
accessor = accessor.variable.setter;
|
||||
functionName.staticElement = accessor;
|
||||
}
|
||||
_enclosingExecutable = accessor;
|
||||
}
|
||||
_enclosingExecutable = accessor;
|
||||
}
|
||||
node.functionExpression.element = _enclosingExecutable;
|
||||
return super.visitFunctionDeclaration(node);
|
||||
|
@ -5335,6 +5340,11 @@ class InferenceContext {
|
|||
*/
|
||||
final AnalysisErrorListener _errorListener;
|
||||
|
||||
/**
|
||||
* If true, emit hints when types are inferred
|
||||
*/
|
||||
final bool _inferenceHints;
|
||||
|
||||
/**
|
||||
* Type provider, needed for type matching.
|
||||
*/
|
||||
|
@ -5356,8 +5366,8 @@ class InferenceContext {
|
|||
*/
|
||||
List<DartType> _returnStack = <DartType>[];
|
||||
|
||||
InferenceContext._(
|
||||
this._errorListener, TypeProvider typeProvider, this._typeSystem)
|
||||
InferenceContext._(this._errorListener, TypeProvider typeProvider,
|
||||
this._typeSystem, this._inferenceHints)
|
||||
: _typeProvider = typeProvider,
|
||||
_rules = new TypeRules(typeProvider);
|
||||
|
||||
|
@ -5401,7 +5411,7 @@ class InferenceContext {
|
|||
*/
|
||||
void recordInference(Expression node, DartType type) {
|
||||
StaticInfo info = InferredType.create(_rules, node, type);
|
||||
if (info == null) {
|
||||
if (!_inferenceHints || info == null) {
|
||||
return;
|
||||
}
|
||||
AnalysisError error = info.toAnalysisError();
|
||||
|
@ -8285,8 +8295,13 @@ class ResolverVisitor extends ScopedVisitor {
|
|||
}
|
||||
this.elementResolver = new ElementResolver(this);
|
||||
this.typeSystem = definingLibrary.context.typeSystem;
|
||||
this.inferenceContext =
|
||||
new InferenceContext._(errorListener, typeProvider, typeSystem);
|
||||
bool strongModeHints = false;
|
||||
AnalysisOptions options = definingLibrary.context.analysisOptions;
|
||||
if (options is AnalysisOptionsImpl) {
|
||||
strongModeHints = options.strongModeHints;
|
||||
}
|
||||
this.inferenceContext = new InferenceContext._(
|
||||
errorListener, typeProvider, typeSystem, strongModeHints);
|
||||
if (typeAnalyzerFactory == null) {
|
||||
this.typeAnalyzer = new StaticTypeAnalyzer(this);
|
||||
} else {
|
||||
|
|
|
@ -1828,7 +1828,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
|||
if (element is ExecutableElement &&
|
||||
fnType is FunctionTypeImpl &&
|
||||
ts is StrongTypeSystemImpl) {
|
||||
List<Expression> arguments = node.argumentList.arguments;
|
||||
// We may have too many (or too few) arguments. Only use arguments
|
||||
// which have been matched up with a static parameter.
|
||||
Iterable<Expression> arguments = node.argumentList.arguments
|
||||
.where((e) => e.staticParameterElement != null);
|
||||
List<DartType> argTypes = arguments.map((e) => e.staticType).toList();
|
||||
List<DartType> paramTypes =
|
||||
arguments.map((e) => e.staticParameterElement.type).toList();
|
||||
|
@ -1847,11 +1850,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
|||
correspondingParams.add(inferredParameters[i]);
|
||||
}
|
||||
node.argumentList.correspondingStaticParameters = correspondingParams;
|
||||
|
||||
_recordStaticType(node.methodName, inferred);
|
||||
_recordStaticType(node, inferred.returnType);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -50,11 +50,11 @@ class StrongTypeSystemImpl implements TypeSystem {
|
|||
FunctionTypeImpl fnType,
|
||||
List<DartType> correspondingParameterTypes,
|
||||
List<DartType> argumentTypes) {
|
||||
ExecutableElement element = fnType.element;
|
||||
TypeParameterizedElement element = fnType.element;
|
||||
if (element.typeParameters.isEmpty) {
|
||||
return fnType;
|
||||
}
|
||||
|
||||
assert(correspondingParameterTypes.length == argumentTypes.length);
|
||||
int numParams = element.typeParameters.length;
|
||||
List<DartType> fnTypeParams = fnType.typeArguments;
|
||||
fnTypeParams = fnTypeParams.sublist(0, numParams);
|
||||
|
|
|
@ -3487,13 +3487,13 @@ class ParseDartTask extends SourceBasedAnalysisTask {
|
|||
/**
|
||||
* Return a map from the names of the inputs of this kind of task to the task
|
||||
* input descriptors describing those inputs for a task with the given
|
||||
* [source].
|
||||
* [target].
|
||||
*/
|
||||
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
|
||||
return <String, TaskInput>{
|
||||
LINE_INFO_INPUT_NAME: LINE_INFO.of(target),
|
||||
MODIFICATION_TIME_INPUT_NAME: MODIFICATION_TIME.of(target),
|
||||
TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.of(target)
|
||||
TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.of(target, flushOnAccess: true)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -583,8 +583,13 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
@override
|
||||
void visitRedirectingConstructorInvocation(
|
||||
RedirectingConstructorInvocation node) {
|
||||
var type = node.staticElement.type;
|
||||
checkArgumentList(node.argumentList, type);
|
||||
var type = node.staticElement?.type;
|
||||
// TODO(leafp): There's a TODO in visitRedirectingConstructorInvocation
|
||||
// in the element_resolver to handle the case that the element is null
|
||||
// and emit an error. In the meantime, just be defensive here.
|
||||
if (type != null) {
|
||||
checkArgumentList(node.argumentList, type);
|
||||
}
|
||||
node.visitChildren(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -321,6 +321,10 @@ class TypeRules {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (t1.isVoid || t2.isVoid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t2.isDartCoreFunction) {
|
||||
if (t1 is FunctionType) return true;
|
||||
if (t1.element is ClassElement) {
|
||||
|
|
98
pkg/analyzer/test/generated/declaration_resolver_test.dart
Normal file
98
pkg/analyzer/test/generated/declaration_resolver_test.dart
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library engine.declaration_resolver_test;
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
import 'package:analyzer/src/generated/resolver.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
||||
import '../reflective_tests.dart';
|
||||
import '../utils.dart';
|
||||
import 'resolver_test.dart';
|
||||
import 'test_support.dart';
|
||||
|
||||
main() {
|
||||
initializeTestEnvironment();
|
||||
runReflectiveTests(DeclarationResolverTest);
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class DeclarationResolverTest extends ResolverTestCase {
|
||||
@override
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
void test_functionDeclaration_getter() {
|
||||
String code = r'''
|
||||
int get zzz => 42;
|
||||
''';
|
||||
CompilationUnit unit = resolveSource(code);
|
||||
PropertyAccessorElement getterElement =
|
||||
findSimpleIdentifier(unit, code, 'zzz =>').staticElement;
|
||||
expect(getterElement.isGetter, isTrue);
|
||||
// re-resolve
|
||||
CompilationUnit unit2 = _cloneResolveUnit(unit);
|
||||
SimpleIdentifier getterName = findSimpleIdentifier(unit2, code, 'zzz =>');
|
||||
expect(getterName.staticElement, same(getterElement));
|
||||
}
|
||||
|
||||
void test_functionDeclaration_setter() {
|
||||
String code = r'''
|
||||
void set zzz(_) {}
|
||||
''';
|
||||
CompilationUnit unit = resolveSource(code);
|
||||
PropertyAccessorElement setterElement =
|
||||
findSimpleIdentifier(unit, code, 'zzz(_)').staticElement;
|
||||
expect(setterElement.isSetter, isTrue);
|
||||
// re-resolve
|
||||
CompilationUnit unit2 = _cloneResolveUnit(unit);
|
||||
SimpleIdentifier getterName = findSimpleIdentifier(unit2, code, 'zzz(_)');
|
||||
expect(getterName.staticElement, same(setterElement));
|
||||
}
|
||||
|
||||
void test_invalid_functionDeclaration_getter_inFunction() {
|
||||
String code = r'''
|
||||
main() {
|
||||
int get zzz => 42;
|
||||
}
|
||||
''';
|
||||
CompilationUnit unit = resolveSource(code);
|
||||
FunctionElement getterElement =
|
||||
findSimpleIdentifier(unit, code, 'zzz =>').staticElement;
|
||||
// re-resolve
|
||||
CompilationUnit unit2 = _cloneResolveUnit(unit);
|
||||
SimpleIdentifier getterName = findSimpleIdentifier(unit2, code, 'zzz =>');
|
||||
expect(getterName.staticElement, same(getterElement));
|
||||
}
|
||||
|
||||
void test_invalid_functionDeclaration_setter_inFunction() {
|
||||
String code = r'''
|
||||
main() {
|
||||
set zzz(x) {}
|
||||
}
|
||||
''';
|
||||
CompilationUnit unit = resolveSource(code);
|
||||
FunctionElement setterElement =
|
||||
findSimpleIdentifier(unit, code, 'zzz(x)').staticElement;
|
||||
// re-resolve
|
||||
CompilationUnit unit2 = _cloneResolveUnit(unit);
|
||||
SimpleIdentifier setterName = findSimpleIdentifier(unit2, code, 'zzz(x)');
|
||||
expect(setterName.staticElement, same(setterElement));
|
||||
}
|
||||
|
||||
static SimpleIdentifier findSimpleIdentifier(
|
||||
AstNode root, String code, String search) {
|
||||
return EngineTestCase.findNode(
|
||||
root, code, search, (n) => n is SimpleIdentifier);
|
||||
}
|
||||
|
||||
static CompilationUnit _cloneResolveUnit(CompilationUnit unit) {
|
||||
CompilationUnit clonedUnit = AstCloner.clone(unit);
|
||||
new DeclarationResolver().resolve(clonedUnit, unit.element);
|
||||
return clonedUnit;
|
||||
}
|
||||
}
|
|
@ -12184,6 +12184,18 @@ class StrongModeDownwardsInferenceTest extends ResolverTestCase {
|
|||
expect(functionReturnValue(4).staticType, typeProvider.stringType);
|
||||
}
|
||||
|
||||
void test_inference_hints() {
|
||||
Source source = addSource(r'''
|
||||
void main () {
|
||||
var x = 3;
|
||||
List<int> l0 = [];
|
||||
}
|
||||
''');
|
||||
LibraryElement library = resolve2(source);
|
||||
assertNoErrors(source);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
void test_instanceCreation() {
|
||||
String code = r'''
|
||||
class A<S, T> {
|
||||
|
|
|
@ -10,6 +10,7 @@ import '../utils.dart';
|
|||
import 'all_the_rest_test.dart' as all_the_rest;
|
||||
import 'ast_test.dart' as ast_test;
|
||||
import 'compile_time_error_code_test.dart' as compile_time_error_code_test;
|
||||
import 'declaration_resolver_test.dart' as declaration_resolver_test;
|
||||
import 'element_test.dart' as element_test;
|
||||
import 'engine_test.dart' as engine_test;
|
||||
import 'incremental_resolver_test.dart' as incremental_resolver_test;
|
||||
|
@ -33,6 +34,7 @@ main() {
|
|||
all_the_rest.main();
|
||||
ast_test.main();
|
||||
compile_time_error_code_test.main();
|
||||
declaration_resolver_test.main();
|
||||
element_test.main();
|
||||
engine_test.main();
|
||||
incremental_resolver_test.main();
|
||||
|
|
|
@ -675,6 +675,13 @@ class StrongSubtypingTest {
|
|||
subtypes: subtypes);
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/dart-lang/sdk/issues/25069
|
||||
void test_isSubtypeOf_simple_function_void() {
|
||||
FunctionType functionType =
|
||||
TypeBuilder.functionType(<DartType>[intType], objectType);
|
||||
_checkIsNotSubtypeOf(voidType, functionType);
|
||||
}
|
||||
|
||||
void test_isSubtypeOf_simple_function() {
|
||||
FunctionType top =
|
||||
TypeBuilder.functionType(<DartType>[intType], objectType);
|
||||
|
|
|
@ -2913,6 +2913,13 @@ part 'test.dart';
|
|||
expect(outputs[UNITS], hasLength(1));
|
||||
}
|
||||
|
||||
test_perform_flushTokenStream() {
|
||||
_performParseTask(r'''
|
||||
class Test {}
|
||||
''');
|
||||
expect(analysisCache.getState(source, TOKEN_STREAM), CacheState.FLUSHED);
|
||||
}
|
||||
|
||||
test_perform_invalidDirectives() {
|
||||
_performParseTask(r'''
|
||||
library lib;
|
||||
|
|
|
@ -276,6 +276,17 @@ void main() {
|
|||
'''
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/dart-lang/sdk/issues/25069
|
||||
testChecker('Void subtyping', {
|
||||
'/main.dart': '''
|
||||
typedef int Foo();
|
||||
void foo() {}
|
||||
void main () {
|
||||
Foo x = /*severe:StaticTypeError*/foo();
|
||||
}
|
||||
'''
|
||||
});
|
||||
|
||||
testChecker('Ground type subtyping: dynamic is top', {
|
||||
'/main.dart': '''
|
||||
|
||||
|
@ -1105,6 +1116,15 @@ void main() {
|
|||
'''
|
||||
});
|
||||
|
||||
// This is a regression test for https://github.com/dart-lang/sdk/issues/25071
|
||||
testChecker('unbound redirecting constructor', {
|
||||
'/main.dart': '''
|
||||
class Foo {
|
||||
Foo() : this.init();
|
||||
}
|
||||
'''
|
||||
});
|
||||
|
||||
testChecker('redirecting constructor', {
|
||||
'/main.dart': '''
|
||||
class A {
|
||||
|
|
|
@ -227,6 +227,7 @@ void testChecker(String name, Map<String, String> testFiles) {
|
|||
// Enable task model strong mode
|
||||
var context = AnalysisEngine.instance.createAnalysisContext();
|
||||
context.analysisOptions.strongMode = true;
|
||||
context.analysisOptions.strongModeHints = true;
|
||||
|
||||
context.sourceFactory = new SourceFactory([
|
||||
new MockDartSdk(mockSdkSources, reportMissing: true).resolver,
|
||||
|
|
|
@ -257,16 +257,23 @@ class TypeMaskSystem implements AbstractValueDomain {
|
|||
|
||||
void associateConstantValueWithElement(ConstantValue constant,
|
||||
Element element) {
|
||||
if (constant is ListConstantValue) {
|
||||
_constantMasks[constant] = inferrer.getGuaranteedTypeOfElement(element);
|
||||
// TODO(25093): Replace this code with an approach that works for anonymous
|
||||
// constants and non-constant literals.
|
||||
if (constant is ListConstantValue || constant is MapConstantValue) {
|
||||
// Inferred type is usually better (e.g. a ContainerTypeMask) but is
|
||||
// occasionally less general.
|
||||
TypeMask computed = computeTypeMask(inferrer.compiler, constant);
|
||||
TypeMask inferred = inferrer.getGuaranteedTypeOfElement(element);
|
||||
TypeMask best = intersection(inferred, computed);
|
||||
assert(!best.isEmpty);
|
||||
_constantMasks[constant] = best;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
TypeMask getTypeOf(ConstantValue constant) {
|
||||
TypeMask mask = _constantMasks[constant];
|
||||
if (mask != null) return mask;
|
||||
return computeTypeMask(inferrer.compiler, constant);
|
||||
return _constantMasks[constant] ??
|
||||
computeTypeMask(inferrer.compiler, constant);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -387,7 +387,7 @@ class ConstantPropagationLattice {
|
|||
|
||||
AbstractConstantValue closedOnInt(AbstractConstantValue left,
|
||||
AbstractConstantValue right) {
|
||||
if (isDefinitelyInt(left) && isDefinitelyInt(right)) {
|
||||
if (isDefinitelyInt(left) && isDefinitelyInt(right, allowNull: true)) {
|
||||
return nonConstant(typeSystem.intType);
|
||||
}
|
||||
return null;
|
||||
|
@ -395,7 +395,7 @@ class ConstantPropagationLattice {
|
|||
|
||||
AbstractConstantValue closedOnUint(AbstractConstantValue left,
|
||||
AbstractConstantValue right) {
|
||||
if (isDefinitelyUint(left) && isDefinitelyUint(right)) {
|
||||
if (isDefinitelyUint(left) && isDefinitelyUint(right, allowNull: true)) {
|
||||
return nonConstant(typeSystem.uintType);
|
||||
}
|
||||
return null;
|
||||
|
@ -403,7 +403,7 @@ class ConstantPropagationLattice {
|
|||
|
||||
AbstractConstantValue closedOnUint31(AbstractConstantValue left,
|
||||
AbstractConstantValue right) {
|
||||
if (isDefinitelyUint31(left) && isDefinitelyUint31(right)) {
|
||||
if (isDefinitelyUint31(left) && isDefinitelyUint31(right, allowNull: true)) {
|
||||
return nonConstant(typeSystem.uint31Type);
|
||||
}
|
||||
return null;
|
||||
|
@ -414,7 +414,8 @@ class ConstantPropagationLattice {
|
|||
AbstractConstantValue folded = foldBinary(constantSystem.add, left, right);
|
||||
if (folded != null) return folded;
|
||||
if (isDefinitelyNum(left)) {
|
||||
if (isDefinitelyUint31(left) && isDefinitelyUint31(right)) {
|
||||
if (isDefinitelyUint31(left) &&
|
||||
isDefinitelyUint31(right, allowNull: true)) {
|
||||
return nonConstant(typeSystem.uint32Type);
|
||||
}
|
||||
return closedOnUint(left, right) ?? closedOnInt(left, right);
|
||||
|
@ -450,7 +451,7 @@ class ConstantPropagationLattice {
|
|||
if (isDefinitelyUint32(left) && isDefinitelyIntInRange(right, min: 2)) {
|
||||
return nonConstant(typeSystem.uint31Type);
|
||||
}
|
||||
if (isDefinitelyUint(right)) {
|
||||
if (isDefinitelyUint(right, allowNull: true)) {
|
||||
// `0` will be an exception, other values will shrink the result.
|
||||
if (isDefinitelyUint31(left)) return nonConstant(typeSystem.uint31Type);
|
||||
if (isDefinitelyUint32(left)) return nonConstant(typeSystem.uint32Type);
|
||||
|
@ -501,7 +502,8 @@ class ConstantPropagationLattice {
|
|||
foldBinary(constantSystem.bitAnd, left, right);
|
||||
if (folded != null) return folded;
|
||||
if (isDefinitelyNum(left)) {
|
||||
if (isDefinitelyUint31(left) || isDefinitelyUint31(right)) {
|
||||
if (isDefinitelyUint31(left) ||
|
||||
isDefinitelyUint31(right, allowNull: true)) {
|
||||
// Either 31-bit argument will truncate the other.
|
||||
return nonConstant(typeSystem.uint31Type);
|
||||
}
|
||||
|
|
|
@ -140,9 +140,15 @@ class NativeBehavior {
|
|||
///
|
||||
/// 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.
|
||||
/// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn' which
|
||||
/// defines the types returned, and, for the last form, the types also
|
||||
/// created by the call to JS. 'var' (and '') are like 'dynamic' or
|
||||
/// 'Object' except that 'dynamic' would indicate that objects of any type
|
||||
/// are created, which defeats tree-shaking. Think of 'var' (and '') as
|
||||
/// meaning 'any pre-existing type'.
|
||||
///
|
||||
/// The types Ti are non-nullable, so add class `Null` to specify a
|
||||
/// nullable type, e.g `'String|Null'`.
|
||||
///
|
||||
/// 2) A sequence of <tag>:<value> pairs of the following kinds
|
||||
///
|
||||
|
@ -155,7 +161,7 @@ class NativeBehavior {
|
|||
/// A <type-tag> is either 'returns' or 'creates' and <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.
|
||||
/// JS. If 'creates' is missing, it defaults to 'returns'.
|
||||
///
|
||||
/// An <effect-tag> is either 'effects' or 'depends' and <effect-string> is
|
||||
/// either 'all', 'none' or a comma-separated list of 'no-index',
|
||||
|
@ -309,23 +315,30 @@ class NativeBehavior {
|
|||
|
||||
String returns = values['returns'];
|
||||
if (returns != null) {
|
||||
resolveTypesString(returns, onVar: () {
|
||||
typesReturned.add(objectType);
|
||||
typesReturned.add(nullType);
|
||||
}, onType: (type) {
|
||||
typesReturned.add(type);
|
||||
});
|
||||
resolveTypesString(returns,
|
||||
onVar: () {
|
||||
typesReturned.add(objectType);
|
||||
typesReturned.add(nullType);
|
||||
},
|
||||
onType: (type) {
|
||||
typesReturned.add(type);
|
||||
});
|
||||
}
|
||||
|
||||
String creates = values['creates'];
|
||||
if (creates != null) {
|
||||
resolveTypesString(creates, onVoid: () {
|
||||
reportError("Invalid type string 'creates:$creates'");
|
||||
}, onVar: () {
|
||||
reportError("Invalid type string 'creates:$creates'");
|
||||
}, onType: (type) {
|
||||
typesInstantiated.add(type);
|
||||
});
|
||||
resolveTypesString(creates,
|
||||
onVoid: () {
|
||||
reportError("Invalid type string 'creates:$creates'");
|
||||
},
|
||||
onType: (type) {
|
||||
typesInstantiated.add(type);
|
||||
});
|
||||
} else if (returns != null) {
|
||||
resolveTypesString(returns,
|
||||
onType: (type) {
|
||||
typesInstantiated.add(type);
|
||||
});
|
||||
}
|
||||
|
||||
const throwsOption = const <String, NativeThrowBehavior>{
|
||||
|
|
|
@ -1625,14 +1625,17 @@ ASSEMBLER_TEST_RUN(LoadImmediateMedNeg4, test) {
|
|||
static void EnterTestFrame(Assembler* assembler) {
|
||||
__ EnterFrame(0);
|
||||
__ Push(CODE_REG);
|
||||
__ Push(THR);
|
||||
__ TagAndPushPP();
|
||||
__ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ mov(THR, R1);
|
||||
__ LoadPoolPointer(PP);
|
||||
}
|
||||
|
||||
|
||||
static void LeaveTestFrame(Assembler* assembler) {
|
||||
__ PopAndUntagPP();
|
||||
__ Pop(THR);
|
||||
__ Pop(CODE_REG);
|
||||
__ LeaveFrame();
|
||||
}
|
||||
|
@ -1652,7 +1655,7 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPSmall, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(LoadImmediatePPSmall, test) {
|
||||
EXPECT_EQ(42, test->InvokeWithCode<int64_t>());
|
||||
EXPECT_EQ(42, test->InvokeWithCodeAndThread<int64_t>());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1667,7 +1670,7 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPMed, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(LoadImmediatePPMed, test) {
|
||||
EXPECT_EQ(0xf1234123, test->InvokeWithCode<int64_t>());
|
||||
EXPECT_EQ(0xf1234123, test->InvokeWithCodeAndThread<int64_t>());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1682,7 +1685,7 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPMed2, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(LoadImmediatePPMed2, test) {
|
||||
EXPECT_EQ(0x4321f1234124, test->InvokeWithCode<int64_t>());
|
||||
EXPECT_EQ(0x4321f1234124, test->InvokeWithCodeAndThread<int64_t>());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1698,23 +1701,15 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPLarge, assembler) {
|
|||
|
||||
ASSEMBLER_TEST_RUN(LoadImmediatePPLarge, test) {
|
||||
EXPECT_EQ(static_cast<int64_t>(0x9287436598237465),
|
||||
test->InvokeWithCode<int64_t>());
|
||||
test->InvokeWithCodeAndThread<int64_t>());
|
||||
}
|
||||
|
||||
|
||||
#define ASSEMBLER_TEST_RUN_WITH_THREAD(result_type, var_name) \
|
||||
Thread* thread = Thread::Current(); \
|
||||
result_type var_name = test->InvokeWithCode<result_type>(thread);
|
||||
|
||||
|
||||
// LoadObject null.
|
||||
ASSEMBLER_TEST_GENERATE(LoadObjectNull, assembler) {
|
||||
__ SetupDartSP(kTestStackSpace);
|
||||
EnterTestFrame(assembler);
|
||||
__ Push(THR);
|
||||
__ mov(THR, R1);
|
||||
__ LoadObject(R0, Object::null_object());
|
||||
__ Pop(THR);
|
||||
LeaveTestFrame(assembler);
|
||||
__ mov(CSP, SP);
|
||||
__ ret();
|
||||
|
@ -1722,18 +1717,14 @@ ASSEMBLER_TEST_GENERATE(LoadObjectNull, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(LoadObjectNull, test) {
|
||||
ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
|
||||
EXPECT_EQ(Object::null(), result);
|
||||
EXPECT_EQ(Object::null(), test->InvokeWithCodeAndThread<RawObject*>());
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(LoadObjectTrue, assembler) {
|
||||
__ SetupDartSP(kTestStackSpace);
|
||||
EnterTestFrame(assembler);
|
||||
__ Push(THR);
|
||||
__ mov(THR, R1);
|
||||
__ LoadObject(R0, Bool::True());
|
||||
__ Pop(THR);
|
||||
LeaveTestFrame(assembler);
|
||||
__ mov(CSP, SP);
|
||||
__ ret();
|
||||
|
@ -1741,18 +1732,14 @@ ASSEMBLER_TEST_GENERATE(LoadObjectTrue, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(LoadObjectTrue, test) {
|
||||
ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
|
||||
EXPECT_EQ(Bool::True().raw(), result);
|
||||
EXPECT_EQ(Bool::True().raw(), test->InvokeWithCodeAndThread<RawObject*>());
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(LoadObjectFalse, assembler) {
|
||||
__ SetupDartSP(kTestStackSpace);
|
||||
EnterTestFrame(assembler);
|
||||
__ Push(THR);
|
||||
__ mov(THR, R1);
|
||||
__ LoadObject(R0, Bool::False());
|
||||
__ Pop(THR);
|
||||
LeaveTestFrame(assembler);
|
||||
__ mov(CSP, SP);
|
||||
__ ret();
|
||||
|
@ -1760,8 +1747,7 @@ ASSEMBLER_TEST_GENERATE(LoadObjectFalse, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(LoadObjectFalse, test) {
|
||||
ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
|
||||
EXPECT_EQ(Bool::False().raw(), result);
|
||||
EXPECT_EQ(Bool::False().raw(), test->InvokeWithCodeAndThread<RawObject*>());
|
||||
}
|
||||
|
||||
|
||||
|
@ -3591,7 +3577,7 @@ ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
|
|||
__ SetupDartSP(kTestStackSpace);
|
||||
EnterTestFrame(assembler);
|
||||
Label miss, done;
|
||||
__ ComputeRange(R0, R1, R2, &miss);
|
||||
__ ComputeRange(R0, R2, R3, &miss);
|
||||
__ b(&done);
|
||||
|
||||
__ Bind(&miss);
|
||||
|
@ -3605,7 +3591,8 @@ ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(ComputeRange, test) {
|
||||
#define RANGE_OF(arg_type, v) test->InvokeWithCode<intptr_t, arg_type>(v)
|
||||
#define RANGE_OF(arg_type, v) \
|
||||
test->InvokeWithCodeAndThread<intptr_t, arg_type>(v)
|
||||
|
||||
EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(0)));
|
||||
EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(1)));
|
||||
|
|
|
@ -785,57 +785,29 @@ void Assembler::orps(XmmRegister dst, XmmRegister src) {
|
|||
}
|
||||
|
||||
void Assembler::notps(XmmRegister dst) {
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_not_constant =
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
|
||||
LoadImmediate(
|
||||
TMP, Immediate(reinterpret_cast<intptr_t>(&float_not_constant)));
|
||||
// { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
|
||||
movq(TMP, Address(THR, Thread::float_not_address_offset()));
|
||||
xorps(dst, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::negateps(XmmRegister dst) {
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_negate_constant =
|
||||
{ 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
|
||||
LoadImmediate(
|
||||
TMP, Immediate(reinterpret_cast<intptr_t>(&float_negate_constant)));
|
||||
// { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
|
||||
movq(TMP, Address(THR, Thread::float_negate_address_offset()));
|
||||
xorps(dst, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::absps(XmmRegister dst) {
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_absolute_constant =
|
||||
{ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
|
||||
LoadImmediate(
|
||||
TMP, Immediate(reinterpret_cast<intptr_t>(&float_absolute_constant)));
|
||||
// { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF }
|
||||
movq(TMP, Address(THR, Thread::float_absolute_address_offset()));
|
||||
andps(dst, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::zerowps(XmmRegister dst) {
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_zerow_constant =
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
|
||||
LoadImmediate(
|
||||
TMP, Immediate(reinterpret_cast<intptr_t>(&float_zerow_constant)));
|
||||
// { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }
|
||||
movq(TMP, Address(THR, Thread::float_zerow_address_offset()));
|
||||
andps(dst, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
@ -1017,13 +989,8 @@ void Assembler::addpd(XmmRegister dst, XmmRegister src) {
|
|||
|
||||
|
||||
void Assembler::negatepd(XmmRegister dst) {
|
||||
static const struct ALIGN16 {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} double_negate_constant =
|
||||
{ 0x8000000000000000LL, 0x8000000000000000LL };
|
||||
LoadImmediate(
|
||||
TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
|
||||
// { 0x8000000000000000LL, 0x8000000000000000LL }
|
||||
movq(TMP, Address(THR, Thread::double_negate_address_offset()));
|
||||
xorpd(dst, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
@ -1065,13 +1032,8 @@ void Assembler::divpd(XmmRegister dst, XmmRegister src) {
|
|||
|
||||
|
||||
void Assembler::abspd(XmmRegister dst) {
|
||||
static const struct ALIGN16 {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} double_absolute_const =
|
||||
{ 0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL };
|
||||
LoadImmediate(
|
||||
TMP, Immediate(reinterpret_cast<intptr_t>(&double_absolute_const)));
|
||||
// { 0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL }
|
||||
movq(TMP, Address(THR, Thread::double_abs_address_offset()));
|
||||
andpd(dst, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
@ -3160,25 +3122,15 @@ void Assembler::IncrementSmiField(const Address& dest, int64_t increment) {
|
|||
|
||||
|
||||
void Assembler::DoubleNegate(XmmRegister d) {
|
||||
static const struct ALIGN16 {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} double_negate_constant =
|
||||
{0x8000000000000000LL, 0x8000000000000000LL};
|
||||
LoadImmediate(
|
||||
TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
|
||||
// {0x8000000000000000LL, 0x8000000000000000LL}
|
||||
movq(TMP, Address(THR, Thread::double_negate_address_offset()));
|
||||
xorpd(d, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::DoubleAbs(XmmRegister reg) {
|
||||
static const struct ALIGN16 {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} double_abs_constant =
|
||||
{0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
|
||||
LoadImmediate(TMP,
|
||||
Immediate(reinterpret_cast<intptr_t>(&double_abs_constant)));
|
||||
// {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL}
|
||||
movq(TMP, Address(THR, Thread::double_abs_address_offset()));
|
||||
andpd(reg, Address(TMP, 0));
|
||||
}
|
||||
|
||||
|
|
|
@ -2021,16 +2021,21 @@ ASSEMBLER_TEST_RUN(PackedDoubleSub, test) {
|
|||
|
||||
|
||||
static void EnterTestFrame(Assembler* assembler) {
|
||||
COMPILE_ASSERT(THR != CallingConventions::kArg1Reg);
|
||||
COMPILE_ASSERT(CODE_REG != CallingConventions::kArg2Reg);
|
||||
__ EnterFrame(0);
|
||||
__ pushq(CODE_REG);
|
||||
__ pushq(PP);
|
||||
__ pushq(THR);
|
||||
__ movq(CODE_REG, Address(CallingConventions::kArg1Reg,
|
||||
VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ movq(THR, CallingConventions::kArg2Reg);
|
||||
__ LoadPoolPointer(PP);
|
||||
}
|
||||
|
||||
|
||||
static void LeaveTestFrame(Assembler* assembler) {
|
||||
__ popq(THR);
|
||||
__ popq(PP);
|
||||
__ popq(CODE_REG);
|
||||
__ LeaveFrame();
|
||||
|
@ -2053,7 +2058,7 @@ ASSEMBLER_TEST_GENERATE(PackedDoubleNegate, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(PackedDoubleNegate, test) {
|
||||
double res = test->InvokeWithCode<double>();
|
||||
double res = test->InvokeWithCodeAndThread<double>();
|
||||
EXPECT_FLOAT_EQ(-1.0, res, 0.000001f);
|
||||
}
|
||||
|
||||
|
@ -2074,7 +2079,7 @@ ASSEMBLER_TEST_GENERATE(PackedDoubleAbsolute, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(PackedDoubleAbsolute, test) {
|
||||
double res = test->InvokeWithCode<double>();
|
||||
double res = test->InvokeWithCodeAndThread<double>();
|
||||
EXPECT_FLOAT_EQ(1.0, res, 0.000001f);
|
||||
}
|
||||
|
||||
|
@ -2520,7 +2525,7 @@ ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(PackedNegate, test) {
|
||||
float res = test->InvokeWithCode<float>();
|
||||
float res = test->InvokeWithCodeAndThread<float>();
|
||||
EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
|
||||
}
|
||||
|
||||
|
@ -2538,7 +2543,7 @@ ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
|
||||
float res = test->InvokeWithCode<float>();
|
||||
float res = test->InvokeWithCodeAndThread<float>();
|
||||
EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
|
||||
}
|
||||
|
||||
|
@ -2554,7 +2559,7 @@ ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(PackedSetWZero, test) {
|
||||
float res = test->InvokeWithCode<float>();
|
||||
float res = test->InvokeWithCodeAndThread<float>();
|
||||
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
|
||||
}
|
||||
|
||||
|
@ -2678,7 +2683,7 @@ ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(PackedLogicalNot, test) {
|
||||
uint32_t res = test->InvokeWithCode<uint32_t>();
|
||||
uint32_t res = test->InvokeWithCodeAndThread<uint32_t>();
|
||||
EXPECT_EQ(static_cast<uword>(0x0), res);
|
||||
}
|
||||
|
||||
|
@ -3103,7 +3108,7 @@ ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) {
|
|||
|
||||
|
||||
ASSEMBLER_TEST_RUN(TestObjectCompare, test) {
|
||||
bool res = test->InvokeWithCode<bool>();
|
||||
bool res = test->InvokeWithCodeAndThread<bool>();
|
||||
EXPECT_EQ(true, res);
|
||||
}
|
||||
|
||||
|
@ -3415,10 +3420,13 @@ ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, test) {
|
|||
ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
|
||||
EnterTestFrame(assembler);
|
||||
#if defined(TARGET_OS_WINDOWS)
|
||||
// First argument is code object, MSVC passes second argument in XMM1.
|
||||
__ DoubleAbs(XMM1);
|
||||
__ movaps(XMM0, XMM1);
|
||||
// First argument is code object, second argument is thread. MSVC passes
|
||||
// third argument in XMM2.
|
||||
__ DoubleAbs(XMM2);
|
||||
__ movaps(XMM0, XMM2);
|
||||
#else
|
||||
// SysV ABI allocates integral and double registers for arguments
|
||||
// independently.
|
||||
__ DoubleAbs(XMM0);
|
||||
#endif
|
||||
LeaveTestFrame(assembler);
|
||||
|
@ -3428,10 +3436,10 @@ ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
|
|||
|
||||
ASSEMBLER_TEST_RUN(DoubleAbs, test) {
|
||||
double val = -12.45;
|
||||
double res = test->InvokeWithCode<double, double>(val);
|
||||
double res = test->InvokeWithCodeAndThread<double, double>(val);
|
||||
EXPECT_FLOAT_EQ(-val, res, 0.001);
|
||||
val = 12.45;
|
||||
res = test->InvokeWithCode<double, double>(val);
|
||||
res = test->InvokeWithCodeAndThread<double, double>(val);
|
||||
EXPECT_FLOAT_EQ(val, res, 0.001);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,8 +149,6 @@ void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
|
|||
}
|
||||
}
|
||||
|
||||
HandleBranchOnStrictCompare(block);
|
||||
|
||||
for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
|
||||
PropagateRecursive(block->dominated_blocks()[i]);
|
||||
}
|
||||
|
@ -159,61 +157,6 @@ void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
|
|||
}
|
||||
|
||||
|
||||
void FlowGraphTypePropagator::HandleBranchOnStrictCompare(
|
||||
BlockEntryInstr* block) {
|
||||
BranchInstr* branch = block->last_instruction()->AsBranch();
|
||||
if (branch == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
StrictCompareInstr* compare = branch->comparison()->AsStrictCompare();
|
||||
if ((compare == NULL) || !compare->right()->BindsToConstant()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const intptr_t rollback_point = rollback_.length();
|
||||
|
||||
Definition* defn = compare->left()->definition();
|
||||
const Object& right = compare->right()->BoundConstant();
|
||||
intptr_t cid = right.GetClassId();
|
||||
|
||||
if (defn->IsLoadClassId() && right.IsSmi()) {
|
||||
defn = defn->AsLoadClassId()->object()->definition();
|
||||
cid = Smi::Cast(right).Value();
|
||||
}
|
||||
|
||||
if (!CheckClassInstr::IsImmutableClassId(cid)) {
|
||||
if ((cid == kOneByteStringCid) || (cid == kTwoByteStringCid)) {
|
||||
SetTypeOf(defn, ZoneCompileType::Wrap(CompileType::String()));
|
||||
PropagateRecursive((compare->kind() == Token::kEQ_STRICT) ?
|
||||
branch->true_successor() : branch->false_successor());
|
||||
RollbackTo(rollback_point);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (compare->kind() == Token::kEQ_STRICT) {
|
||||
if (cid == kNullCid) {
|
||||
branch->set_constrained_type(MarkNonNullable(defn));
|
||||
PropagateRecursive(branch->false_successor());
|
||||
}
|
||||
|
||||
SetCid(defn, cid);
|
||||
PropagateRecursive(branch->true_successor());
|
||||
} else if (compare->kind() == Token::kNE_STRICT) {
|
||||
if (cid == kNullCid) {
|
||||
branch->set_constrained_type(MarkNonNullable(defn));
|
||||
PropagateRecursive(branch->true_successor());
|
||||
}
|
||||
|
||||
SetCid(defn, cid);
|
||||
PropagateRecursive(branch->false_successor());
|
||||
}
|
||||
|
||||
RollbackTo(rollback_point);
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphTypePropagator::RollbackTo(intptr_t rollback_point) {
|
||||
for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
|
||||
types_[rollback_[i].index()] = rollback_[i].type();
|
||||
|
|
|
@ -20,7 +20,6 @@ class FlowGraphTypePropagator : public FlowGraphVisitor {
|
|||
void Propagate();
|
||||
|
||||
void PropagateRecursive(BlockEntryInstr* block);
|
||||
void HandleBranchOnStrictCompare(BlockEntryInstr* block);
|
||||
|
||||
void RollbackTo(intptr_t rollback_point);
|
||||
|
||||
|
|
|
@ -1485,6 +1485,7 @@ class Class : public Object {
|
|||
friend class Object;
|
||||
friend class Type;
|
||||
friend class Intrinsifier;
|
||||
friend class Precompiler;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -713,6 +713,7 @@ void Precompiler::DropUncompiledFunctions() {
|
|||
Class& cls = Class::Handle(Z);
|
||||
Array& functions = Array::Handle(Z);
|
||||
Function& function = Function::Handle(Z);
|
||||
Function& function2 = Function::Handle(Z);
|
||||
GrowableObjectArray& retained_functions = GrowableObjectArray::Handle(Z);
|
||||
GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
|
||||
|
||||
|
@ -729,7 +730,16 @@ void Precompiler::DropUncompiledFunctions() {
|
|||
retained_functions = GrowableObjectArray::New();
|
||||
for (intptr_t j = 0; j < functions.Length(); j++) {
|
||||
function ^= functions.At(j);
|
||||
if (function.HasCode()) {
|
||||
bool retain = function.HasCode();
|
||||
if (!retain && function.HasImplicitClosureFunction()) {
|
||||
// It can happen that all uses of an implicit closure inline their
|
||||
// target function, leaving the target function uncompiled. Keep
|
||||
// the target function anyway so we can enumerate it to bind its
|
||||
// static calls, etc.
|
||||
function2 = function.ImplicitClosureFunction();
|
||||
retain = function2.HasCode();
|
||||
}
|
||||
if (retain) {
|
||||
retained_functions.Add(function);
|
||||
function.DropUncompiledImplicitClosureFunction();
|
||||
} else {
|
||||
|
@ -780,7 +790,10 @@ void Precompiler::BindStaticCalls() {
|
|||
}
|
||||
|
||||
void VisitFunction(const Function& function) {
|
||||
ASSERT(function.HasCode());
|
||||
if (!function.HasCode()) {
|
||||
ASSERT(function.HasImplicitClosureFunction());
|
||||
return;
|
||||
}
|
||||
code_ = function.CurrentCode();
|
||||
table_ = code_.static_calls_target_table();
|
||||
|
||||
|
@ -837,6 +850,10 @@ void Precompiler::DedupStackmaps() {
|
|||
}
|
||||
|
||||
void VisitFunction(const Function& function) {
|
||||
if (!function.HasCode()) {
|
||||
ASSERT(function.HasImplicitClosureFunction());
|
||||
return;
|
||||
}
|
||||
code_ = function.CurrentCode();
|
||||
stackmaps_ = code_.stackmaps();
|
||||
if (stackmaps_.IsNull()) return;
|
||||
|
@ -876,6 +893,7 @@ void Precompiler::VisitFunctions(FunctionVisitor* visitor) {
|
|||
Library& lib = Library::Handle(Z);
|
||||
Class& cls = Class::Handle(Z);
|
||||
Array& functions = Array::Handle(Z);
|
||||
Object& object = Object::Handle(Z);
|
||||
Function& function = Function::Handle(Z);
|
||||
GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
|
||||
|
||||
|
@ -897,6 +915,15 @@ void Precompiler::VisitFunctions(FunctionVisitor* visitor) {
|
|||
visitor->VisitFunction(function);
|
||||
}
|
||||
}
|
||||
|
||||
functions = cls.invocation_dispatcher_cache();
|
||||
for (intptr_t j = 0; j < functions.Length(); j++) {
|
||||
object = functions.At(j);
|
||||
if (object.IsFunction()) {
|
||||
function ^= functions.At(j);
|
||||
visitor->VisitFunction(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closures = isolate()->object_store()->closure_functions();
|
||||
|
|
|
@ -87,6 +87,51 @@ LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT)
|
|||
}
|
||||
|
||||
|
||||
static const struct ALIGN16 {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} double_negate_constant =
|
||||
{0x8000000000000000LL, 0x8000000000000000LL};
|
||||
|
||||
static const struct ALIGN16 {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} double_abs_constant =
|
||||
{0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
|
||||
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_not_constant =
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
|
||||
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_negate_constant =
|
||||
{ 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
|
||||
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_absolute_constant =
|
||||
{ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
|
||||
|
||||
static const struct ALIGN16 {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
} float_zerow_constant =
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
|
||||
|
||||
|
||||
void Thread::InitVMConstants() {
|
||||
#define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value) \
|
||||
ASSERT((init_expr)->IsOldObject());
|
||||
|
|
|
@ -79,7 +79,6 @@ class Zone;
|
|||
V(RawCode*, invoke_dart_code_stub_, \
|
||||
StubCode::InvokeDartCode_entry()->code(), NULL) \
|
||||
|
||||
|
||||
#define CACHED_ADDRESSES_LIST(V) \
|
||||
V(uword, update_store_buffer_entry_point_, \
|
||||
StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0) \
|
||||
|
@ -87,12 +86,23 @@ class Zone;
|
|||
NativeEntry::NativeCallWrapperEntry(), 0) \
|
||||
V(RawString**, predefined_symbols_address_, \
|
||||
Symbols::PredefinedAddress(), NULL) \
|
||||
V(uword, double_negate_address_, \
|
||||
reinterpret_cast<uword>(&double_negate_constant), 0) \
|
||||
V(uword, double_abs_address_, \
|
||||
reinterpret_cast<uword>(&double_abs_constant), 0) \
|
||||
V(uword, float_not_address_, \
|
||||
reinterpret_cast<uword>(&float_not_constant), 0) \
|
||||
V(uword, float_negate_address_, \
|
||||
reinterpret_cast<uword>(&float_negate_constant), 0) \
|
||||
V(uword, float_absolute_address_, \
|
||||
reinterpret_cast<uword>(&float_absolute_constant), 0) \
|
||||
V(uword, float_zerow_address_, \
|
||||
reinterpret_cast<uword>(&float_zerow_constant), 0) \
|
||||
|
||||
#define CACHED_CONSTANTS_LIST(V) \
|
||||
CACHED_VM_OBJECTS_LIST(V) \
|
||||
CACHED_ADDRESSES_LIST(V) \
|
||||
|
||||
|
||||
// A VM thread; may be executing Dart code or performing helper tasks like
|
||||
// garbage collection or compilation. The Thread structure associated with
|
||||
// a thread is allocated by EnsureInit before entering an isolate, and destroyed
|
||||
|
|
|
@ -106,11 +106,11 @@ void ThreadRegistry::Unschedule(Thread* thread,
|
|||
OSThread* os_thread = thread->os_thread();
|
||||
ASSERT(os_thread != NULL);
|
||||
os_thread->DisableThreadInterrupts();
|
||||
os_thread->set_thread(NULL);
|
||||
OSThread::SetCurrent(os_thread);
|
||||
thread->isolate_ = NULL;
|
||||
thread->heap_ = NULL;
|
||||
thread->set_os_thread(NULL);
|
||||
os_thread->set_thread(NULL);
|
||||
OSThread::SetCurrent(os_thread);
|
||||
if (!is_mutator) {
|
||||
ASSERT(thread->api_top_scope() == NULL);
|
||||
ReturnThreadToFreelist(thread);
|
||||
|
|
|
@ -360,36 +360,44 @@ class AssemblerTest {
|
|||
|
||||
uword entry() const { return code_.EntryPoint(); }
|
||||
|
||||
// Invoke/InvokeWithCode is used to call assembler test functions using the
|
||||
// ABI calling convention.
|
||||
// Invoke/InvokeWithCodeAndThread is used to call assembler test functions
|
||||
// using the ABI calling convention.
|
||||
// ResultType is the return type of the assembler test function.
|
||||
// ArgNType is the type of the Nth argument.
|
||||
#if defined(USING_SIMULATOR)
|
||||
|
||||
#if defined(ARCH_IS_64_BIT)
|
||||
// TODO(fschneider): Make InvokeWithCode<> more general and work on 32-bit.
|
||||
// TODO(fschneider): Make InvokeWithCodeAndThread<> more general and work on
|
||||
// 32-bit.
|
||||
// Since Simulator::Call always return a int64_t, bit_cast does not work
|
||||
// on 32-bit platforms when returning an int32_t. Since template functions
|
||||
// don't support partial specialization, we'd need to introduce a helper
|
||||
// class to support 32-bit return types.
|
||||
template<typename ResultType> ResultType InvokeWithCode() {
|
||||
template<typename ResultType> ResultType InvokeWithCodeAndThread() {
|
||||
const bool fp_return = is_double<ResultType>::value;
|
||||
const bool fp_args = false;
|
||||
Thread* thread = Thread::Current();
|
||||
ASSERT(thread != NULL);
|
||||
return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
|
||||
bit_cast<intptr_t, uword>(entry()),
|
||||
reinterpret_cast<intptr_t>(&code_), 0, 0, 0, fp_return, fp_args));
|
||||
reinterpret_cast<intptr_t>(&code_),
|
||||
reinterpret_cast<intptr_t>(thread),
|
||||
0, 0, fp_return, fp_args));
|
||||
}
|
||||
template<typename ResultType, typename Arg1Type>
|
||||
ResultType InvokeWithCode(Arg1Type arg1) {
|
||||
ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
|
||||
const bool fp_return = is_double<ResultType>::value;
|
||||
const bool fp_args = is_double<Arg1Type>::value;
|
||||
// TODO(fschneider): Support double arguments for simulator calls.
|
||||
COMPILE_ASSERT(!fp_args);
|
||||
Thread* thread = Thread::Current();
|
||||
ASSERT(thread != NULL);
|
||||
return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
|
||||
bit_cast<intptr_t, uword>(entry()),
|
||||
reinterpret_cast<intptr_t>(&code_),
|
||||
reinterpret_cast<intptr_t>(thread),
|
||||
reinterpret_cast<intptr_t>(arg1),
|
||||
0, 0, fp_return, fp_args));
|
||||
0, fp_return, fp_args));
|
||||
}
|
||||
#endif // ARCH_IS_64_BIT
|
||||
|
||||
|
@ -413,15 +421,19 @@ class AssemblerTest {
|
|||
0, fp_return, fp_args);
|
||||
}
|
||||
#else
|
||||
template<typename ResultType> ResultType InvokeWithCode() {
|
||||
typedef ResultType (*FunctionType) (const Code&);
|
||||
return reinterpret_cast<FunctionType>(entry())(code_);
|
||||
template<typename ResultType> ResultType InvokeWithCodeAndThread() {
|
||||
Thread* thread = Thread::Current();
|
||||
ASSERT(thread != NULL);
|
||||
typedef ResultType (*FunctionType) (const Code&, Thread*);
|
||||
return reinterpret_cast<FunctionType>(entry())(code_, thread);
|
||||
}
|
||||
|
||||
template<typename ResultType, typename Arg1Type>
|
||||
ResultType InvokeWithCode(Arg1Type arg1) {
|
||||
typedef ResultType (*FunctionType) (const Code&, Arg1Type);
|
||||
return reinterpret_cast<FunctionType>(entry())(code_, arg1);
|
||||
ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
|
||||
Thread* thread = Thread::Current();
|
||||
ASSERT(thread != NULL);
|
||||
typedef ResultType (*FunctionType) (const Code&, Thread*, Arg1Type);
|
||||
return reinterpret_cast<FunctionType>(entry())(code_, thread, arg1);
|
||||
}
|
||||
|
||||
template<typename ResultType,
|
||||
|
|
|
@ -56,14 +56,18 @@ js_backend_cps_ir_constructor_test: Pass, Slow
|
|||
exit_code_test: Skip # This tests requires checked mode.
|
||||
|
||||
[ $checked ]
|
||||
analyze_dart2js_helpers_test: Pass, Slow
|
||||
analyze_dart2js_test: Pass, Slow
|
||||
analyze_unused_dart2js_test: Pass, Slow
|
||||
uri_retention_test: Pass, Slow
|
||||
deferred_mirrors_test: Pass, Slow
|
||||
mirror_final_field_inferrer2_test: Pass, Slow
|
||||
check_elements_invariants_test: Slow, Pass, Timeout
|
||||
import_mirrors_test: Slow, Pass
|
||||
deferred_mirrors_test: Pass, Slow
|
||||
exit_code_test: Pass, Slow
|
||||
import_mirrors_test: Slow, Pass
|
||||
interop_anonymous_unreachable_test: Pass, Slow
|
||||
mirror_final_field_inferrer2_test: Pass, Slow
|
||||
source_map_pub_build_validity_test: Pass, Slow
|
||||
sourcemaps/source_mapping_operators_test: Pass, Slow
|
||||
uri_retention_test: Pass, Slow
|
||||
value_range_test: Pass, Slow
|
||||
|
||||
[ $mode == debug ]
|
||||
|
|
|
@ -64,10 +64,11 @@ void test(String specString,
|
|||
typesReturned: actualReturns, typesInstantiated: actualCreates,
|
||||
objectType: OBJECT, nullType: NULL);
|
||||
} catch (e) {
|
||||
Expect.isTrue(expectError);
|
||||
Expect.isNotNull(listener.errorMessage, 'Error expected.');
|
||||
Expect.isTrue(expectError, 'Unexpected error "$specString"');
|
||||
Expect.isNotNull(listener.errorMessage, 'Error message expected.');
|
||||
return;
|
||||
}
|
||||
Expect.isFalse(expectError, 'Missing error for "$specString".');
|
||||
Expect.isNull(listener.errorMessage, 'Unexpected error.');
|
||||
if (returns != null) {
|
||||
Expect.listEquals(returns, actualReturns, 'Unexpected returns.');
|
||||
|
@ -217,17 +218,24 @@ void main() {
|
|||
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('returns:A;', returns: ['A'], creates: ['A']);
|
||||
test('returns:A|B;', returns: ['A', 'B'], creates: ['A', 'B']);
|
||||
test('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
|
||||
|
||||
test('creates:void;', expectError: true);
|
||||
test('creates:;', expectError: true);
|
||||
test('creates:var;', expectError: true);
|
||||
test('creates:;', creates: []);
|
||||
test('creates:var;', creates: []);
|
||||
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:', returns: [], creates: []);
|
||||
test('returns:;creates:', returns: [OBJECT, NULL], creates: []);
|
||||
test('returns:var;creates:', returns: [OBJECT, NULL], creates: []);
|
||||
test('returns:A;creates:', returns: ['A'], creates: []);
|
||||
test('returns:A|B;creates:;', returns: ['A', 'B'], creates: []);
|
||||
test('returns:A|B|C;creates:;', returns: ['A', 'B', 'C'], creates: []);
|
||||
|
||||
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;',
|
||||
|
@ -242,19 +250,32 @@ void main() {
|
|||
testWithSideEffects('returns:void;', returns: [], creates: []);
|
||||
testWithSideEffects('returns:;', returns: [OBJECT, NULL], creates: []);
|
||||
testWithSideEffects('returns:var;', returns: [OBJECT, NULL], creates: []);
|
||||
testWithSideEffects('returns:A;', returns: ['A'], creates: []);
|
||||
testWithSideEffects('returns:A|B;', returns: ['A', 'B'], creates: []);
|
||||
testWithSideEffects('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: []);
|
||||
testWithSideEffects('returns:A;', returns: ['A'], creates: ['A']);
|
||||
testWithSideEffects('returns:A|B;',
|
||||
returns: ['A', 'B'], creates: ['A', 'B']);
|
||||
testWithSideEffects('returns:A|B|C;',
|
||||
returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
|
||||
testWithSideEffects('returns: A| B |C ;',
|
||||
returns: ['A', 'B', 'C'], creates: []);
|
||||
returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
|
||||
|
||||
testWithSideEffects('creates:void;', expectError: true);
|
||||
testWithSideEffects('creates:;', expectError: true);
|
||||
testWithSideEffects('creates:var;', expectError: true);
|
||||
testWithSideEffects('creates:;', creates: []);
|
||||
testWithSideEffects('creates:var;', creates: []);
|
||||
testWithSideEffects('creates:A;', returns: [], creates: ['A']);
|
||||
testWithSideEffects('creates:A|B;', returns: [], creates: ['A', 'B']);
|
||||
testWithSideEffects('creates:A|B|C;', returns: [], creates: ['A', 'B', 'C']);
|
||||
|
||||
testWithSideEffects('returns:void;creates:;', returns: [], creates: []);
|
||||
testWithSideEffects('returns:;creates:;',
|
||||
returns: [OBJECT, NULL], creates: []);
|
||||
testWithSideEffects('returns:var;creates:;',
|
||||
returns: [OBJECT, NULL], creates: []);
|
||||
testWithSideEffects('returns:A;creates:;', returns: ['A'], creates: []);
|
||||
testWithSideEffects('returns:A|B;creates:;',
|
||||
returns: ['A', 'B'], creates: []);
|
||||
testWithSideEffects('returns:A|B|C;creates:;',
|
||||
returns: ['A', 'B', 'C'], creates: []);
|
||||
|
||||
testWithSideEffects('returns:void;creates:A;', returns: [], creates: ['A']);
|
||||
testWithSideEffects('returns:;creates:A|B;',
|
||||
returns: [OBJECT, NULL], creates: ['A', 'B']);
|
||||
|
|
56
tests/language/vm/type_propagation_test.dart
Normal file
56
tests/language/vm/type_propagation_test.dart
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
// VMOptions=--optimization-counter-threshold=1000 --max-polymorphic-checks=1
|
||||
|
||||
// Test correct loop invariant code motion and type propagation from is-checks
|
||||
// and null-comparisons.
|
||||
|
||||
class B {
|
||||
var b;
|
||||
B(this.b);
|
||||
}
|
||||
|
||||
class C {
|
||||
final f0 = null;
|
||||
|
||||
final a;
|
||||
C() : a = new B(0);
|
||||
}
|
||||
|
||||
foo(x) {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
i + i;
|
||||
i + i;
|
||||
if (x is C) {
|
||||
x.a.b < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Y { var f = null; }
|
||||
|
||||
bar(y) {
|
||||
var x = y.f;
|
||||
for (var i = 0; i < 10; i++) {
|
||||
if (x != null) {
|
||||
x.a.b < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main () {
|
||||
var o = new Y();
|
||||
o.f = new C();
|
||||
bar(o);
|
||||
o.f = null;
|
||||
bar(o);
|
||||
|
||||
for (var i = 0; i < 1000; i++) bar(o);
|
||||
|
||||
foo(new C());
|
||||
foo(0);
|
||||
|
||||
for (var i = 0; i < 1000; i++) foo(0);
|
||||
}
|
Loading…
Reference in a new issue